├── web
├── .dockerignore
├── .eslintignore
├── .gitignore
├── favicon.ico
├── src
│ ├── assets
│ │ ├── qm.png
│ │ ├── docs.png
│ │ ├── github.png
│ │ ├── kefu.png
│ │ ├── logo.jpg
│ │ ├── logo.png
│ │ ├── noBody.png
│ │ ├── video.png
│ │ ├── nav_logo.png
│ │ ├── notFound.png
│ │ ├── dashboard.png
│ │ ├── logo_login.png
│ │ ├── flipped-aurora.png
│ │ ├── login_background.jpg
│ │ └── login_right_banner.jpg
│ ├── utils
│ │ ├── doc.js
│ │ ├── bus.js
│ │ ├── closeThisPage.js
│ │ ├── btnAuth.js
│ │ ├── page.js
│ │ ├── fmtRouterTitle.js
│ │ ├── dictionary.js
│ │ ├── stringFun.js
│ │ ├── downloadImg.js
│ │ ├── format.js
│ │ ├── asyncRouter.js
│ │ ├── positionToCode.js
│ │ └── date.js
│ ├── pinia
│ │ ├── index.js
│ │ └── modules
│ │ │ └── dictionary.js
│ ├── view
│ │ ├── error
│ │ │ ├── reload.vue
│ │ │ └── index.vue
│ │ ├── systemTools
│ │ │ ├── formCreate
│ │ │ │ └── index.vue
│ │ │ ├── index.vue
│ │ │ ├── pubPlug
│ │ │ │ └── pubPlug.vue
│ │ │ └── installPlugin
│ │ │ │ └── index.vue
│ │ ├── example
│ │ │ └── index.vue
│ │ ├── superAdmin
│ │ │ └── index.vue
│ │ ├── routerHolder.vue
│ │ ├── dashboard
│ │ │ └── weather.js
│ │ └── layout
│ │ │ ├── bottomInfo
│ │ │ └── bottomInfo.vue
│ │ │ ├── screenfull
│ │ │ └── index.vue
│ │ │ ├── aside
│ │ │ └── asideComponent
│ │ │ │ └── index.vue
│ │ │ └── search
│ │ │ └── search.vue
│ ├── core
│ │ ├── global.js
│ │ ├── gin-vue-admin.js
│ │ └── config.js
│ ├── api
│ │ ├── email.js
│ │ ├── github.js
│ │ ├── jwt.js
│ │ ├── authorityBtn.js
│ │ ├── chatgpt.js
│ │ ├── initdb.js
│ │ ├── casbin.js
│ │ ├── breakpoint.js
│ │ ├── system.js
│ │ └── fileUploadAndDownload.js
│ ├── style
│ │ ├── element
│ │ │ └── index.scss
│ │ └── element_visiable.scss
│ ├── router
│ │ └── index.js
│ ├── App.vue
│ ├── components
│ │ ├── warningBar
│ │ │ └── warningBar.vue
│ │ ├── richtext
│ │ │ └── rich-view.vue
│ │ ├── selectFile
│ │ │ └── selectFile.vue
│ │ └── upload
│ │ │ └── common.vue
│ ├── plugin
│ │ └── email
│ │ │ ├── api
│ │ │ └── email.js
│ │ │ └── view
│ │ │ └── index.vue
│ ├── main.js
│ └── directive
│ │ └── auth.js
├── babel.config.js
├── postcss.config.js
├── .env.production
├── jsconfig.json
├── .env.development
├── tailwind.config.js
├── Dockerfile
├── openDocument.js
├── index.html
├── .docker-compose
│ └── nginx
│ │ └── conf.d
│ │ ├── my.conf
│ │ └── nginx.conf
├── vitePlugin
│ ├── fullImport
│ │ └── fullImport.js
│ ├── gvaPosition
│ │ └── index.js
│ └── codeServer
│ │ └── index.js
└── limit.js
├── .gitattributes
├── docs
└── gin-vue-admin.png
├── server
├── packfile
│ ├── notUsePackFile.go
│ └── usePackFile.go
├── model
│ ├── system
│ │ ├── response
│ │ │ ├── sys_chatgpt.go
│ │ │ ├── sys_authority_btn.go
│ │ │ ├── sys_system.go
│ │ │ ├── sys_casbin.go
│ │ │ ├── sys_captcha.go
│ │ │ ├── sys_api.go
│ │ │ ├── sys_menu.go
│ │ │ ├── sys_user.go
│ │ │ ├── sys_authority.go
│ │ │ ├── sys_auto_code.go
│ │ │ └── sys_auto_code_history.go
│ │ ├── request
│ │ │ ├── sys_authority_btn.go
│ │ │ ├── sys_chatgpt.go
│ │ │ ├── sys_dictionary.go
│ │ │ ├── sys_operation_record.go
│ │ │ ├── sys_dictionary_detail.go
│ │ │ ├── sys_auto_history.go
│ │ │ ├── sys_api.go
│ │ │ ├── jwt.go
│ │ │ ├── sys_menu.go
│ │ │ └── sys_casbin.go
│ │ ├── sys_system.go
│ │ ├── sys_jwt_blacklist.go
│ │ ├── sys_authority_btn.go
│ │ ├── sys_menu_btn.go
│ │ ├── sys_user_authority.go
│ │ ├── sys_chatgpt.go
│ │ ├── sys_api.go
│ │ ├── sys_authority_menu.go
│ │ ├── sys_dictionary.go
│ │ ├── sys_dictionary_detail.go
│ │ ├── sys_authority.go
│ │ ├── sys_autocode_history.go
│ │ └── sys_operation_record.go
│ ├── example
│ │ ├── response
│ │ │ ├── exa_customer.go
│ │ │ ├── exa_file_upload_download.go
│ │ │ └── exa_breakpoint_continue.go
│ │ ├── exa_file_upload_download.go
│ │ ├── exa_breakpoint_continue.go
│ │ └── exa_customer.go
│ └── common
│ │ ├── response
│ │ ├── common.go
│ │ └── response.go
│ │ └── request
│ │ └── common.go
├── utils
│ ├── getPointer.go
│ ├── ast
│ │ ├── ast_auto_enter_test.go
│ │ ├── ast_rollback_test.go
│ │ ├── ast_router_test.go
│ │ ├── ast_gorm_test.go
│ │ ├── ast.go
│ │ └── ast_auto_enter.go
│ ├── plugin
│ │ └── plugin.go
│ ├── reload.go
│ ├── md5.go
│ ├── hash.go
│ ├── strings.go
│ ├── human_duration.go
│ ├── db_automation.go
│ ├── upload
│ │ └── upload.go
│ ├── validator_test.go
│ ├── fmt_plus.go
│ ├── human_duration_test.go
│ ├── directory.go
│ ├── timer
│ │ └── timed_task_test.go
│ ├── zip.go
│ ├── verify.go
│ ├── captcha
│ │ └── redis.go
│ └── zipfiles.go
├── resource
│ ├── autocode_template
│ │ ├── subcontract
│ │ │ ├── api_enter.go.tpl
│ │ │ ├── router_enter.go.tpl
│ │ │ ├── service_enter.go.tpl
│ │ │ └── data.go
│ │ ├── readme.txt.tpl
│ │ └── server
│ │ │ ├── request.go.tpl
│ │ │ └── router.go.tpl
│ ├── page
│ │ ├── fonts
│ │ │ ├── element-icons.535877f5.woff
│ │ │ └── element-icons.732389de.ttf
│ │ └── index.html
│ └── plug_template
│ │ ├── api
│ │ ├── enter.go.tpl
│ │ └── api.go.tpl
│ │ ├── router
│ │ ├── enter.go.tpl
│ │ └── router.go.tpl
│ │ ├── service
│ │ ├── enter.go.tpl
│ │ └── service.go.tpl
│ │ ├── global
│ │ └── global.go.tpl
│ │ ├── config
│ │ └── config.go.tpl
│ │ ├── model
│ │ └── model.go.tpl
│ │ └── main.go.tpl
├── config
│ ├── excel.go
│ ├── oss_local.go
│ ├── redis.go
│ ├── gorm_sqlite.go
│ ├── gorm_mysql.go
│ ├── gorm_oracle.go
│ ├── gorm_mssql.go
│ ├── jwt.go
│ ├── oss_huawei.go
│ ├── oss_tencent.go
│ ├── oss_aliyun.go
│ ├── email.go
│ ├── gorm_pgsql.go
│ ├── captcha.go
│ ├── cors.go
│ ├── timer.go
│ ├── oss_qiniu.go
│ ├── oss_aws.go
│ ├── system.go
│ ├── auto_code.go
│ └── config.go
├── plugin
│ ├── email
│ │ ├── api
│ │ │ └── enter.go
│ │ ├── router
│ │ │ ├── enter.go
│ │ │ └── sys_email.go
│ │ ├── service
│ │ │ ├── enter.go
│ │ │ └── sys_email.go
│ │ ├── global
│ │ │ └── gloabl.go
│ │ ├── model
│ │ │ └── response
│ │ │ │ └── email.go
│ │ ├── config
│ │ │ └── email.go
│ │ └── main.go
│ └── plugin-tool
│ │ └── utils
│ │ └── check.go
├── router
│ ├── example
│ │ ├── enter.go
│ │ ├── exa_customer.go
│ │ └── exa_file_upload_and_download.go
│ ├── enter.go
│ └── system
│ │ ├── enter.go
│ │ ├── sys_jwt.go
│ │ ├── sys_initdb.go
│ │ ├── sys_base.go
│ │ ├── sys_chatgpt.go
│ │ ├── sys_casbin.go
│ │ ├── sys_system.go
│ │ ├── sys_auto_code_history.go
│ │ ├── sys_authority_btn.go
│ │ ├── sys_authority.go
│ │ ├── sys_operation_record.go
│ │ ├── sys_dictionary.go
│ │ ├── sys_auto_code.go
│ │ ├── sys_api.go
│ │ ├── sys_user.go
│ │ ├── sys_dictionary_detail.go
│ │ └── sys_menu.go
├── service
│ ├── example
│ │ └── enter.go
│ ├── enter.go
│ └── system
│ │ ├── enter.go
│ │ └── sys_auto_code_interface.go
├── core
│ ├── internal
│ │ ├── constant.go
│ │ └── file_rotatelogs.go
│ ├── server_other.go
│ ├── server_win.go
│ ├── zap.go
│ └── server.go
├── initialize
│ ├── register_init.go
│ ├── validator.go
│ ├── other.go
│ ├── redis.go
│ ├── internal
│ │ ├── logger.go
│ │ └── gorm.go
│ ├── timer.go
│ ├── db_list.go
│ ├── gorm_sqlite.go
│ ├── plugin.go
│ ├── gorm_pgsql.go
│ ├── gorm.go
│ └── gorm_oracle.go
├── global
│ ├── model.go
│ └── global.go
├── api
│ └── v1
│ │ ├── enter.go
│ │ ├── example
│ │ └── enter.go
│ │ └── system
│ │ └── sys_jwt_blacklist.go
├── middleware
│ ├── need_init.go
│ ├── loadtls.go
│ └── casbin_rbac.go
├── Dockerfile
└── main.go
├── SECURITY.md
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── feature_request.yaml
│ └── bug_report.yaml
└── FUNDING.yml
├── deploy
├── kubernetes
│ ├── web
│ │ ├── gva-web-ingress.yaml
│ │ ├── gva-web-service.yaml
│ │ ├── gva-web-configmap.yaml
│ │ └── gva-web-deploymemt.yaml
│ └── server
│ │ └── gva-server-service.yaml
└── docker
│ ├── entrypoint.sh
│ └── Dockerfile
├── .gitignore
├── CONTRIBUTING.md
└── gin-vue-admin.code-workspace
/web/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/web/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | src/assets
3 | public
4 | dist
5 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | package-lock.json
3 | yarn.lock
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.sql linguist-language=GO
2 | *.html linguist-language=GO
3 |
--------------------------------------------------------------------------------
/web/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/favicon.ico
--------------------------------------------------------------------------------
/docs/gin-vue-admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/docs/gin-vue-admin.png
--------------------------------------------------------------------------------
/web/src/assets/qm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/qm.png
--------------------------------------------------------------------------------
/web/src/utils/doc.js:
--------------------------------------------------------------------------------
1 | export const toDoc = (url)=>{
2 | window.open(url, '_blank')
3 | }
4 |
--------------------------------------------------------------------------------
/server/packfile/notUsePackFile.go:
--------------------------------------------------------------------------------
1 | //go:build !packfile
2 | // +build !packfile
3 |
4 | package packfile
5 |
--------------------------------------------------------------------------------
/web/src/assets/docs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/docs.png
--------------------------------------------------------------------------------
/web/src/assets/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/github.png
--------------------------------------------------------------------------------
/web/src/assets/kefu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/kefu.png
--------------------------------------------------------------------------------
/web/src/assets/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/logo.jpg
--------------------------------------------------------------------------------
/web/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/logo.png
--------------------------------------------------------------------------------
/web/src/assets/noBody.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/noBody.png
--------------------------------------------------------------------------------
/web/src/assets/video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/video.png
--------------------------------------------------------------------------------
/server/model/system/response/sys_chatgpt.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type ChatGptResponse struct {
4 | }
5 |
--------------------------------------------------------------------------------
/server/utils/getPointer.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | func Pointer[T any](in T) (out *T) {
4 | return &in
5 | }
6 |
--------------------------------------------------------------------------------
/web/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 |
4 | ],
5 | 'plugins': [
6 |
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/web/src/assets/nav_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/nav_logo.png
--------------------------------------------------------------------------------
/web/src/assets/notFound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/notFound.png
--------------------------------------------------------------------------------
/web/src/assets/dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/dashboard.png
--------------------------------------------------------------------------------
/web/src/assets/logo_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/logo_login.png
--------------------------------------------------------------------------------
/web/src/utils/bus.js:
--------------------------------------------------------------------------------
1 |
2 | // using ES6 modules
3 | import mitt from 'mitt'
4 |
5 | export const emitter = mitt()
6 |
7 |
--------------------------------------------------------------------------------
/web/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/web/src/assets/flipped-aurora.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/flipped-aurora.png
--------------------------------------------------------------------------------
/web/src/assets/login_background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/login_background.jpg
--------------------------------------------------------------------------------
/server/resource/autocode_template/subcontract/api_enter.go.tpl:
--------------------------------------------------------------------------------
1 | package {{ .PackageName }}
2 |
3 | type ApiGroup struct {
4 | }
5 |
--------------------------------------------------------------------------------
/web/src/assets/login_right_banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/web/src/assets/login_right_banner.jpg
--------------------------------------------------------------------------------
/server/config/excel.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Excel struct {
4 | Dir string `mapstructure:"dir" json:"dir" yaml:"dir"`
5 | }
6 |
--------------------------------------------------------------------------------
/server/resource/autocode_template/subcontract/router_enter.go.tpl:
--------------------------------------------------------------------------------
1 | package {{ .PackageName }}
2 |
3 | type RouterGroup struct {
4 | }
5 |
--------------------------------------------------------------------------------
/web/src/pinia/index.js:
--------------------------------------------------------------------------------
1 | import { createPinia } from 'pinia'
2 |
3 | const store = createPinia()
4 |
5 | export {
6 | store
7 | }
8 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Reporting a Vulnerability
4 |
5 | Please report security issues to qimiaojiangjizhao@gmail.com
6 |
--------------------------------------------------------------------------------
/server/plugin/email/api/enter.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | type ApiGroup struct {
4 | EmailApi
5 | }
6 |
7 | var ApiGroupApp = new(ApiGroup)
8 |
--------------------------------------------------------------------------------
/server/router/example/enter.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | type RouterGroup struct {
4 | CustomerRouter
5 | FileUploadAndDownloadRouter
6 | }
7 |
--------------------------------------------------------------------------------
/server/service/example/enter.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | type ServiceGroup struct {
4 | CustomerService
5 | FileUploadAndDownloadService
6 | }
7 |
--------------------------------------------------------------------------------
/server/resource/autocode_template/subcontract/service_enter.go.tpl:
--------------------------------------------------------------------------------
1 | package {{ .PackageName }}
2 |
3 |
4 | type ServiceGroup struct {
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_authority_btn.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type SysAuthorityBtnRes struct {
4 | Selected []uint `json:"selected"`
5 | }
6 |
--------------------------------------------------------------------------------
/server/plugin/email/router/enter.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | type RouterGroup struct {
4 | EmailRouter
5 | }
6 |
7 | var RouterGroupApp = new(RouterGroup)
8 |
--------------------------------------------------------------------------------
/web/src/utils/closeThisPage.js:
--------------------------------------------------------------------------------
1 | import { emitter } from '@/utils/bus.js'
2 |
3 | export const closeThisPage = () => {
4 | emitter.emit('closeThisPage')
5 | }
6 |
--------------------------------------------------------------------------------
/server/plugin/email/service/enter.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | type ServiceGroup struct {
4 | EmailService
5 | }
6 |
7 | var ServiceGroupApp = new(ServiceGroup)
8 |
--------------------------------------------------------------------------------
/server/resource/page/fonts/element-icons.535877f5.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/server/resource/page/fonts/element-icons.535877f5.woff
--------------------------------------------------------------------------------
/server/resource/page/fonts/element-icons.732389de.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rockyzsu/gin-vue-admin/main/server/resource/page/fonts/element-icons.732389de.ttf
--------------------------------------------------------------------------------
/server/resource/plug_template/api/enter.go.tpl:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | type ApiGroup struct {
4 | {{ .PlugName}}Api
5 | }
6 |
7 | var ApiGroupApp = new(ApiGroup)
8 |
--------------------------------------------------------------------------------
/server/resource/plug_template/router/enter.go.tpl:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | type RouterGroup struct {
4 | {{ .PlugName}}Router
5 | }
6 |
7 | var RouterGroupApp = new(RouterGroup)
8 |
--------------------------------------------------------------------------------
/server/plugin/email/global/gloabl.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/plugin/email/config"
4 |
5 | var GlobalConfig = new(config.Email)
6 |
--------------------------------------------------------------------------------
/server/resource/plug_template/service/enter.go.tpl:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | type ServiceGroup struct {
4 | {{ .PlugName}}Service
5 | }
6 |
7 | var ServiceGroupApp = new(ServiceGroup)
8 |
--------------------------------------------------------------------------------
/web/.env.production:
--------------------------------------------------------------------------------
1 | ENV = 'production'
2 |
3 | VITE_CLI_PORT = 8080
4 | VITE_SERVER_PORT = 8888
5 | VITE_BASE_API = /api
6 | VITE_FILE_API = /api
7 | #下方修改为你的线上ip
8 | VITE_BASE_PATH = https://demo.gin-vue-admin.com
9 |
--------------------------------------------------------------------------------
/web/src/utils/btnAuth.js:
--------------------------------------------------------------------------------
1 | import { useRoute } from 'vue-router'
2 | import { reactive } from 'vue'
3 | export const useBtnAuth = () => {
4 | const route = useRoute()
5 | return route.meta.btns || reactive({})
6 | }
7 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_system.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/config"
4 |
5 | type SysConfigResponse struct {
6 | Config config.Server `json:"config"`
7 | }
8 |
--------------------------------------------------------------------------------
/server/plugin/email/model/response/email.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type Email struct {
4 | To string `json:"to"` // 邮件发送给谁
5 | Subject string `json:"subject"` // 邮件标题
6 | Body string `json:"body"` // 邮件内容
7 | }
8 |
--------------------------------------------------------------------------------
/server/utils/ast/ast_auto_enter_test.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import "testing"
4 |
5 | func TestImportForAutoEnter(t *testing.T) {
6 | ImportForAutoEnter("D:\\gin-vue-admin\\server\\api\\v1\\test\\enter.go", "ApiGroup", "test")
7 | }
8 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_authority_btn.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | type SysAuthorityBtnReq struct {
4 | MenuID uint `json:"menuID"`
5 | AuthorityId uint `json:"authorityId"`
6 | Selected []uint `json:"selected"`
7 | }
8 |
--------------------------------------------------------------------------------
/server/model/system/sys_system.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/config"
5 | )
6 |
7 | // 配置文件结构体
8 | type System struct {
9 | Config config.Server `json:"config"`
10 | }
11 |
--------------------------------------------------------------------------------
/web/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@/*": ["src/*"],
6 | }
7 | },
8 | "exclude": ["node_modules", "dist"],
9 | "include": ["src/**/*"]
10 | }
--------------------------------------------------------------------------------
/server/model/example/response/exa_customer.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/model/example"
4 |
5 | type ExaCustomerResponse struct {
6 | Customer example.ExaCustomer `json:"customer"`
7 | }
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Document
4 | url: https://www.gin-vue-admin.com
5 | about: If you have any questions about the use, you can check our official documents first
6 |
--------------------------------------------------------------------------------
/server/resource/plug_template/global/global.go.tpl:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | {{- if .HasGlobal }}
4 |
5 | import "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/config"
6 |
7 | var GlobalConfig = new(config.{{ .PlugName}})
8 | {{ end -}}
--------------------------------------------------------------------------------
/server/model/example/response/exa_file_upload_download.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/model/example"
4 |
5 | type ExaFileResponse struct {
6 | File example.ExaFileUploadAndDownload `json:"file"`
7 | }
8 |
--------------------------------------------------------------------------------
/server/model/common/response/common.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type PageResult struct {
4 | List interface{} `json:"list"`
5 | Total int64 `json:"total"`
6 | Page int `json:"page"`
7 | PageSize int `json:"pageSize"`
8 | }
9 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
5 | )
6 |
7 | type PolicyPathResponse struct {
8 | Paths []request.CasbinInfo `json:"paths"`
9 | }
10 |
--------------------------------------------------------------------------------
/server/model/system/sys_jwt_blacklist.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | )
6 |
7 | type JwtBlacklist struct {
8 | global.GVA_MODEL
9 | Jwt string `gorm:"type:text;comment:jwt"`
10 | }
11 |
--------------------------------------------------------------------------------
/server/utils/ast/ast_rollback_test.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import "testing"
4 |
5 | func TestRollRouterBack(t *testing.T) {
6 | RollRouterBack("ttt", "Testttt")
7 | }
8 |
9 | func TestRollGormBack(t *testing.T) {
10 | RollGormBack("ttt", "Testttt")
11 | }
12 |
--------------------------------------------------------------------------------
/server/utils/ast/ast_router_test.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestAddRouterCode(t *testing.T) {
8 | AddRouterCode("D:\\gin-vue-admin\\server\\utils\\ast\\ast_router_test.go", "Routers", "testRouter", "GVAStruct")
9 | }
10 |
--------------------------------------------------------------------------------
/server/config/oss_local.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Local struct {
4 | Path string `mapstructure:"path" json:"path" yaml:"path"` // 本地文件访问路径
5 | StorePath string `mapstructure:"store-path" json:"store-path" yaml:"store-path"` // 本地文件存储路径
6 | }
7 |
--------------------------------------------------------------------------------
/server/resource/plug_template/config/config.go.tpl:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | {{- if .HasGlobal }}
4 | type {{ .PlugName }} struct {
5 | {{- range .Global }}
6 | {{ .Key }} {{ .Type }} {{- if ne .Desc "" }} // {{ .Desc }} {{ end -}}
7 | {{- end }}
8 | }
9 | {{ end -}}
--------------------------------------------------------------------------------
/server/model/system/response/sys_captcha.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type SysCaptchaResponse struct {
4 | CaptchaId string `json:"captchaId"`
5 | PicPath string `json:"picPath"`
6 | CaptchaLength int `json:"captchaLength"`
7 | OpenCaptcha bool `json:"openCaptcha"`
8 | }
9 |
--------------------------------------------------------------------------------
/web/src/view/error/reload.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/server/core/internal/constant.go:
--------------------------------------------------------------------------------
1 | package internal
2 |
3 | const (
4 | ConfigEnv = "GVA_CONFIG"
5 | ConfigDefaultFile = "config.yaml"
6 | ConfigTestFile = "config.test.yaml"
7 | ConfigDebugFile = "config.debug.yaml"
8 | ConfigReleaseFile = "config.release.yaml"
9 | )
10 |
--------------------------------------------------------------------------------
/server/resource/autocode_template/readme.txt.tpl:
--------------------------------------------------------------------------------
1 | 代码解压后把fe的api文件内容粘贴进前端api文件夹下并修改为自己想要的名字即可
2 |
3 | 后端代码解压后同理,放到自己想要的 mvc对应路径 并且到 initRouter中注册自动生成的路由 到registerTable中注册自动生成的model
4 |
5 | 项目github:"https://github.com/piexlmax/github.com/flipped-aurora/gin-vue-admin/server"
6 |
7 | 希望大家给个star多多鼓励
8 |
--------------------------------------------------------------------------------
/server/resource/autocode_template/subcontract/data.go:
--------------------------------------------------------------------------------
1 | package subcontract
2 |
3 | import (
4 | _ "embed"
5 | )
6 |
7 | //go:embed api_enter.go.tpl
8 | var API []byte
9 |
10 | //go:embed router_enter.go.tpl
11 | var Router []byte
12 |
13 | //go:embed service_enter.go.tpl
14 | var Server []byte
15 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_api.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/model/system"
4 |
5 | type SysAPIResponse struct {
6 | Api system.SysApi `json:"api"`
7 | }
8 |
9 | type SysAPIListResponse struct {
10 | Apis []system.SysApi `json:"apis"`
11 | }
12 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_chatgpt.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
6 | )
7 |
8 | type ChatGptRequest struct {
9 | system.ChatGpt
10 | request.PageInfo
11 | }
12 |
--------------------------------------------------------------------------------
/server/model/example/response/exa_breakpoint_continue.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/model/example"
4 |
5 | type FilePathResponse struct {
6 | FilePath string `json:"filePath"`
7 | }
8 |
9 | type FileResponse struct {
10 | File example.ExaFile `json:"file"`
11 | }
12 |
--------------------------------------------------------------------------------
/server/initialize/register_init.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | _ "github.com/flipped-aurora/gin-vue-admin/server/source/example"
5 | _ "github.com/flipped-aurora/gin-vue-admin/server/source/system"
6 | )
7 |
8 | func init() {
9 | // do nothing,only import source package so that inits can be registered
10 | }
11 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_dictionary.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
6 | )
7 |
8 | type SysDictionarySearch struct {
9 | system.SysDictionary
10 | request.PageInfo
11 | }
12 |
--------------------------------------------------------------------------------
/server/model/system/sys_authority_btn.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type SysAuthorityBtn struct {
4 | AuthorityId uint `gorm:"comment:角色ID"`
5 | SysMenuID uint `gorm:"comment:菜单ID"`
6 | SysBaseMenuBtnID uint `gorm:"comment:菜单按钮ID"`
7 | SysBaseMenuBtn SysBaseMenuBtn ` gorm:"comment:按钮详情"`
8 | }
9 |
--------------------------------------------------------------------------------
/server/config/redis.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Redis struct {
4 | DB int `mapstructure:"db" json:"db" yaml:"db"` // redis的哪个数据库
5 | Addr string `mapstructure:"addr" json:"addr" yaml:"addr"` // 服务器地址:端口
6 | Password string `mapstructure:"password" json:"password" yaml:"password"` // 密码
7 | }
8 |
--------------------------------------------------------------------------------
/server/global/model.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | import (
4 | "time"
5 |
6 | "gorm.io/gorm"
7 | )
8 |
9 | type GVA_MODEL struct {
10 | ID uint `gorm:"primarykey"` // 主键ID
11 | CreatedAt time.Time // 创建时间
12 | UpdatedAt time.Time // 更新时间
13 | DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 删除时间
14 | }
15 |
--------------------------------------------------------------------------------
/web/src/utils/page.js:
--------------------------------------------------------------------------------
1 | import { fmtTitle } from '@/utils/fmtRouterTitle'
2 | import config from '@/core/config'
3 | export default function getPageTitle(pageTitle, route) {
4 | if (pageTitle) {
5 | const title = fmtTitle(pageTitle, route)
6 | return `${title} - ${config.appName}`
7 | }
8 | return `${config.appName}`
9 | }
10 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_operation_record.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
6 | )
7 |
8 | type SysOperationRecordSearch struct {
9 | system.SysOperationRecord
10 | request.PageInfo
11 | }
12 |
--------------------------------------------------------------------------------
/server/utils/plugin/plugin.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | const (
8 | OnlyFuncName = "Plugin"
9 | )
10 |
11 | // Plugin 插件模式接口化
12 | type Plugin interface {
13 | // Register 注册路由
14 | Register(group *gin.RouterGroup)
15 |
16 | // RouterPath 用户返回注册路由
17 | RouterPath() string
18 | }
19 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_dictionary_detail.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
6 | )
7 |
8 | type SysDictionaryDetailSearch struct {
9 | system.SysDictionaryDetail
10 | request.PageInfo
11 | }
12 |
--------------------------------------------------------------------------------
/server/api/v1/enter.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/api/v1/example"
5 | "github.com/flipped-aurora/gin-vue-admin/server/api/v1/system"
6 | )
7 |
8 | type ApiGroup struct {
9 | SystemApiGroup system.ApiGroup
10 | ExampleApiGroup example.ApiGroup
11 | }
12 |
13 | var ApiGroupApp = new(ApiGroup)
14 |
--------------------------------------------------------------------------------
/server/router/enter.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/router/example"
5 | "github.com/flipped-aurora/gin-vue-admin/server/router/system"
6 | )
7 |
8 | type RouterGroup struct {
9 | System system.RouterGroup
10 | Example example.RouterGroup
11 | }
12 |
13 | var RouterGroupApp = new(RouterGroup)
14 |
--------------------------------------------------------------------------------
/server/utils/reload.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | "os"
6 | "os/exec"
7 | "runtime"
8 | "strconv"
9 | )
10 |
11 | func Reload() error {
12 | if runtime.GOOS == "windows" {
13 | return errors.New("系统不支持")
14 | }
15 | pid := os.Getpid()
16 | cmd := exec.Command("kill", "-1", strconv.Itoa(pid))
17 | return cmd.Run()
18 | }
19 |
--------------------------------------------------------------------------------
/server/config/gorm_sqlite.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "path/filepath"
5 | )
6 |
7 | type Sqlite struct {
8 | GeneralDB `yaml:",inline" mapstructure:",squash"`
9 | }
10 |
11 | func (s *Sqlite) Dsn() string {
12 | return filepath.Join(s.Path, s.Dbname+".db")
13 | }
14 |
15 | func (s *Sqlite) GetLogMode() string {
16 | return s.LogMode
17 | }
18 |
--------------------------------------------------------------------------------
/server/config/gorm_mysql.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Mysql struct {
4 | GeneralDB `yaml:",inline" mapstructure:",squash"`
5 | }
6 |
7 | func (m *Mysql) Dsn() string {
8 | return m.Username + ":" + m.Password + "@tcp(" + m.Path + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config
9 | }
10 |
11 | func (m *Mysql) GetLogMode() string {
12 | return m.LogMode
13 | }
14 |
--------------------------------------------------------------------------------
/server/model/system/sys_menu_btn.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/global"
4 |
5 | type SysBaseMenuBtn struct {
6 | global.GVA_MODEL
7 | Name string `json:"name" gorm:"comment:按钮关键key"`
8 | Desc string `json:"desc" gorm:"按钮备注"`
9 | SysBaseMenuID uint `json:"sysBaseMenuID" gorm:"comment:菜单ID"`
10 | }
11 |
--------------------------------------------------------------------------------
/server/router/system/enter.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type RouterGroup struct {
4 | ApiRouter
5 | JwtRouter
6 | SysRouter
7 | BaseRouter
8 | InitRouter
9 | MenuRouter
10 | UserRouter
11 | CasbinRouter
12 | AutoCodeRouter
13 | AuthorityRouter
14 | DictionaryRouter
15 | OperationRecordRouter
16 | DictionaryDetailRouter
17 | AuthorityBtnRouter
18 | ChatGptRouter
19 | }
20 |
--------------------------------------------------------------------------------
/server/config/gorm_oracle.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Oracle struct {
4 | GeneralDB `yaml:",inline" mapstructure:",squash"`
5 | }
6 |
7 | func (m *Oracle) Dsn() string {
8 | return "oracle://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "/" + m.Dbname + "?" + m.Config
9 |
10 | }
11 |
12 | func (m *Oracle) GetLogMode() string {
13 | return m.LogMode
14 | }
15 |
--------------------------------------------------------------------------------
/server/service/enter.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/service/example"
5 | "github.com/flipped-aurora/gin-vue-admin/server/service/system"
6 | )
7 |
8 | type ServiceGroup struct {
9 | SystemServiceGroup system.ServiceGroup
10 | ExampleServiceGroup example.ServiceGroup
11 | }
12 |
13 | var ServiceGroupApp = new(ServiceGroup)
14 |
--------------------------------------------------------------------------------
/server/model/system/sys_user_authority.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | // SysUserAuthority 是 sysUser 和 sysAuthority 的连接表
4 | type SysUserAuthority struct {
5 | SysUserId uint `gorm:"column:sys_user_id"`
6 | SysAuthorityAuthorityId uint `gorm:"column:sys_authority_authority_id"`
7 | }
8 |
9 | func (s *SysUserAuthority) TableName() string {
10 | return "sys_user_authority"
11 | }
12 |
--------------------------------------------------------------------------------
/server/utils/md5.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "crypto/md5"
5 | "encoding/hex"
6 | )
7 |
8 | //@author: [piexlmax](https://github.com/piexlmax)
9 | //@function: MD5V
10 | //@description: md5加密
11 | //@param: str []byte
12 | //@return: string
13 |
14 | func MD5V(str []byte, b ...byte) string {
15 | h := md5.New()
16 | h.Write(str)
17 | return hex.EncodeToString(h.Sum(b))
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/core/global.js:
--------------------------------------------------------------------------------
1 | import config from './config'
2 |
3 | // 统一导入el-icon图标
4 | import * as ElIconModules from '@element-plus/icons-vue'
5 | // 导入转换图标名称的函数
6 |
7 | export const register = (app) => {
8 | // 统一注册el-icon图标
9 | for (const iconName in ElIconModules) {
10 | app.component(iconName, ElIconModules[iconName])
11 | }
12 | app.config.globalProperties.$GIN_VUE_ADMIN = config
13 | }
14 |
--------------------------------------------------------------------------------
/web/.env.development:
--------------------------------------------------------------------------------
1 | ENV = 'development'
2 | VITE_CLI_PORT = 8080
3 | VITE_SERVER_PORT = 8888
4 | VITE_BASE_API = /api
5 | VITE_FILE_API = /api
6 | VITE_BASE_PATH = http://127.0.0.1
7 | VITE_EDITOR = vscode
8 | // VITE_EDITOR = webstorm 如果使用webstorm开发且要使用dom定位到代码行功能 请先自定添加 webstorm到环境变量 再将VITE_EDITOR值修改为webstorm
9 | // 如果使用docker-compose开发模式,设置为下面的地址或本机主机IP
10 | //VITE_BASE_PATH = http://177.7.0.12
11 |
12 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_menu.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/model/system"
4 |
5 | type SysMenusResponse struct {
6 | Menus []system.SysMenu `json:"menus"`
7 | }
8 |
9 | type SysBaseMenusResponse struct {
10 | Menus []system.SysBaseMenu `json:"menus"`
11 | }
12 |
13 | type SysBaseMenuResponse struct {
14 | Menu system.SysBaseMenu `json:"menu"`
15 | }
16 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_user.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
5 | )
6 |
7 | type SysUserResponse struct {
8 | User system.SysUser `json:"user"`
9 | }
10 |
11 | type LoginResponse struct {
12 | User system.SysUser `json:"user"`
13 | Token string `json:"token"`
14 | ExpiresAt int64 `json:"expiresAt"`
15 | }
16 |
--------------------------------------------------------------------------------
/web/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./index.html",
5 | "./src/**/*.{vue,js,ts,jsx,tsx}",
6 | ],
7 | important: true,
8 | theme: {
9 | extend: {
10 | backgroundColor: {
11 | "main": "#F5F5F5",
12 | }
13 | },
14 | },
15 | plugins: [],
16 | corePlugins: {
17 | preflight: false
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/web/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:16
2 |
3 | WORKDIR /gva_web/
4 | COPY . .
5 |
6 | RUN yarn && yarn build
7 |
8 | FROM nginx:alpine
9 | LABEL MAINTAINER="SliverHorn@sliver_horn@qq.com"
10 |
11 | COPY .docker-compose/nginx/conf.d/my.conf /etc/nginx/conf.d/my.conf
12 | COPY --from=0 /gva_web/dist /usr/share/nginx/html
13 | RUN cat /etc/nginx/nginx.conf
14 | RUN cat /etc/nginx/conf.d/my.conf
15 | RUN ls -al /usr/share/nginx/html
16 |
--------------------------------------------------------------------------------
/web/src/utils/fmtRouterTitle.js:
--------------------------------------------------------------------------------
1 | export const fmtTitle = (title, now) => {
2 | const reg = /\$\{(.+?)\}/
3 | const reg_g = /\$\{(.+?)\}/g
4 | const result = title.match(reg_g)
5 | if (result) {
6 | result.forEach((item) => {
7 | const key = item.match(reg)[1]
8 | const value = now.params[key] || now.query[key]
9 | title = title.replace(item, value)
10 | })
11 | }
12 | return title
13 | }
14 |
--------------------------------------------------------------------------------
/server/api/v1/example/enter.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/service"
4 |
5 | type ApiGroup struct {
6 | CustomerApi
7 | FileUploadAndDownloadApi
8 | }
9 |
10 | var (
11 | customerService = service.ServiceGroupApp.ExampleServiceGroup.CustomerService
12 | fileUploadAndDownloadService = service.ServiceGroupApp.ExampleServiceGroup.FileUploadAndDownloadService
13 | )
14 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_auto_history.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
4 |
5 | type SysAutoHistory struct {
6 | request.PageInfo
7 | }
8 |
9 | // GetById Find by id structure
10 | type RollBack struct {
11 | ID int `json:"id" form:"id"` // 主键ID
12 | DeleteTable bool `json:"deleteTable" form:"deleteTable"` // 是否删除表
13 | }
14 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_authority.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/model/system"
4 |
5 | type SysAuthorityResponse struct {
6 | Authority system.SysAuthority `json:"authority"`
7 | }
8 |
9 | type SysAuthorityCopyResponse struct {
10 | Authority system.SysAuthority `json:"authority"`
11 | OldAuthorityId uint `json:"oldAuthorityId"` // 旧角色ID
12 | }
13 |
--------------------------------------------------------------------------------
/web/src/api/email.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags email
3 | // @Summary 发送测试邮件
4 | // @Security ApiKeyAuth
5 | // @Produce application/json
6 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
7 | // @Router /email/emailTest [post]
8 | export const emailTest = (data) => {
9 | return service({
10 | url: '/email/emailTest',
11 | method: 'post',
12 | data
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/server/service/system/enter.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type ServiceGroup struct {
4 | JwtService
5 | ApiService
6 | MenuService
7 | UserService
8 | CasbinService
9 | InitDBService
10 | AutoCodeService
11 | BaseMenuService
12 | AuthorityService
13 | DictionaryService
14 | SystemConfigService
15 | AutoCodeHistoryService
16 | OperationRecordService
17 | DictionaryDetailService
18 | AuthorityBtnService
19 | ChatGptService
20 | }
21 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_api.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
6 | )
7 |
8 | // api分页条件查询及排序结构体
9 | type SearchApiParams struct {
10 | system.SysApi
11 | request.PageInfo
12 | OrderKey string `json:"orderKey"` // 排序
13 | Desc bool `json:"desc"` // 排序方式:升序false(默认)|降序true
14 | }
15 |
--------------------------------------------------------------------------------
/server/model/system/request/jwt.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/gofrs/uuid/v5"
5 | jwt "github.com/golang-jwt/jwt/v4"
6 | )
7 |
8 | // Custom claims structure
9 | type CustomClaims struct {
10 | BaseClaims
11 | BufferTime int64
12 | jwt.RegisteredClaims
13 | }
14 |
15 | type BaseClaims struct {
16 | UUID uuid.UUID
17 | ID uint
18 | Username string
19 | NickName string
20 | AuthorityId uint
21 | }
22 |
--------------------------------------------------------------------------------
/server/core/server_other.go:
--------------------------------------------------------------------------------
1 | //go:build !windows
2 | // +build !windows
3 |
4 | package core
5 |
6 | import (
7 | "time"
8 |
9 | "github.com/fvbock/endless"
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | func initServer(address string, router *gin.Engine) server {
14 | s := endless.NewServer(address, router)
15 | s.ReadHeaderTimeout = 20 * time.Second
16 | s.WriteTimeout = 20 * time.Second
17 | s.MaxHeaderBytes = 1 << 20
18 | return s
19 | }
20 |
--------------------------------------------------------------------------------
/web/src/api/github.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | const service = axios.create()
4 |
5 | export function Commits(page) {
6 | return service({
7 | url: 'https://api.github.com/repos/flipped-aurora/gin-vue-admin/commits?page=' + page,
8 | method: 'get'
9 | })
10 | }
11 |
12 | export function Members() {
13 | return service({
14 | url: 'https://api.github.com/orgs/FLIPPED-AURORA/members',
15 | method: 'get'
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/api/jwt.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags jwt
3 | // @Summary jwt加入黑名单
4 | // @Security ApiKeyAuth
5 | // @accept application/json
6 | // @Produce application/json
7 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
8 | // @Router /jwt/jsonInBlacklist [post]
9 | export const jsonInBlacklist = () => {
10 | return service({
11 | url: '/jwt/jsonInBlacklist',
12 | method: 'post'
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/server/config/gorm_mssql.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Mssql struct {
4 | GeneralDB `yaml:",inline" mapstructure:",squash"`
5 | }
6 | //dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
7 | func (m *Mssql) Dsn() string {
8 | return "sqlserver://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "?database=" + m.Dbname + "&encrypt=disable"
9 | }
10 |
11 | func (m *Mssql) GetLogMode() string {
12 | return m.LogMode
13 | }
14 |
--------------------------------------------------------------------------------
/server/router/system/sys_jwt.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type JwtRouter struct{}
9 |
10 | func (s *JwtRouter) InitJwtRouter(Router *gin.RouterGroup) {
11 | jwtRouter := Router.Group("jwt")
12 | jwtApi := v1.ApiGroupApp.SystemApiGroup.JwtApi
13 | {
14 | jwtRouter.POST("jsonInBlacklist", jwtApi.JsonInBlacklist) // jwt加入黑名单
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/deploy/kubernetes/web/gva-web-ingress.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: Ingress
3 | metadata:
4 | name: gva-ingress
5 | annotations:
6 | kubernetes.io/ingress.class: "nginx"
7 | spec:
8 | rules:
9 | - host: demo.gin-vue-admin.com
10 | http:
11 | paths:
12 | - path: /
13 | pathType: Prefix
14 | backend:
15 | service:
16 | name: gva-web
17 | port:
18 | number: 8080
--------------------------------------------------------------------------------
/server/config/jwt.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type JWT struct {
4 | SigningKey string `mapstructure:"signing-key" json:"signing-key" yaml:"signing-key"` // jwt签名
5 | ExpiresTime string `mapstructure:"expires-time" json:"expires-time" yaml:"expires-time"` // 过期时间
6 | BufferTime string `mapstructure:"buffer-time" json:"buffer-time" yaml:"buffer-time"` // 缓冲时间
7 | Issuer string `mapstructure:"issuer" json:"issuer" yaml:"issuer"` // 签发者
8 | }
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | /web/node_modules
3 | /web/dist
4 |
5 | .DS_Store
6 |
7 | # local env files
8 | .env.local
9 | .env.*.local
10 |
11 | # Log files
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
25 | /server/log/
26 | /server/gva
27 | /server/latest_log
28 |
29 | *.iml
30 | web/.pnpm-debug.log
31 | web/pnpm-lock.yaml
32 |
--------------------------------------------------------------------------------
/server/core/server_win.go:
--------------------------------------------------------------------------------
1 | //go:build windows
2 | // +build windows
3 |
4 | package core
5 |
6 | import (
7 | "net/http"
8 | "time"
9 |
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | func initServer(address string, router *gin.Engine) server {
14 | return &http.Server{
15 | Addr: address,
16 | Handler: router,
17 | ReadTimeout: 20 * time.Second,
18 | WriteTimeout: 20 * time.Second,
19 | MaxHeaderBytes: 1 << 20,
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/server/config/oss_huawei.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type HuaWeiObs struct {
4 | Path string `mapstructure:"path" json:"path" yaml:"path"`
5 | Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
6 | Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
7 | AccessKey string `mapstructure:"access-key" json:"access-key" yaml:"access-key"`
8 | SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"`
9 | }
10 |
--------------------------------------------------------------------------------
/server/resource/plug_template/model/model.go.tpl:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | {{- if .HasRequest }}
4 | type Request struct {
5 | {{- range .Request }}
6 | {{ .Key }} {{ .Type }} {{- if ne .Desc "" }} // {{ .Desc }} {{ end -}}
7 | {{- end }}
8 | }
9 | {{ end -}}
10 |
11 | {{- if .HasResponse }}
12 | type Response struct {
13 | {{- range .Response }}
14 | {{ .Key }} {{ .Type }} {{- if ne .Desc "" }} // {{ .Desc }} {{ end -}}
15 | {{- end }}
16 | }
17 | {{ end -}}
18 |
--------------------------------------------------------------------------------
/server/resource/plug_template/router/router.go.tpl:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/api"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type {{ .PlugName}}Router struct {
9 | }
10 |
11 | func (s *{{ .PlugName}}Router) Init{{ .PlugName}}Router(Router *gin.RouterGroup) {
12 | plugRouter := Router
13 | plugApi := api.ApiGroupApp.{{ .PlugName}}Api
14 | {
15 | plugRouter.POST("routerName", plugApi.ApiName)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/server/utils/hash.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "golang.org/x/crypto/bcrypt"
5 | )
6 |
7 | // BcryptHash 使用 bcrypt 对密码进行加密
8 | func BcryptHash(password string) string {
9 | bytes, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
10 | return string(bytes)
11 | }
12 |
13 | // BcryptCheck 对比明文密码和数据库的哈希值
14 | func BcryptCheck(password, hash string) bool {
15 | err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
16 | return err == nil
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/view/systemTools/formCreate/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/server/resource/plug_template/service/service.go.tpl:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | {{- if .NeedModel }}
4 | import (
5 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/model"
6 | )
7 | {{ end }}
8 |
9 | type {{ .PlugName}}Service struct{}
10 |
11 | func (e *{{ .PlugName}}Service) PlugService({{- if .HasRequest }}req model.Request {{ end -}}) ({{- if .HasResponse }}res model.Response,{{ end -}} err error) {
12 | // 写你的业务逻辑
13 | return {{- if .HasResponse }} res,{{ end }} nil
14 | }
15 |
--------------------------------------------------------------------------------
/server/router/system/sys_initdb.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type InitRouter struct{}
9 |
10 | func (s *InitRouter) InitInitRouter(Router *gin.RouterGroup) {
11 | initRouter := Router.Group("init")
12 | dbApi := v1.ApiGroupApp.SystemApiGroup.DBApi
13 | {
14 | initRouter.POST("initdb", dbApi.InitDB) // 初始化数据库
15 | initRouter.POST("checkdb", dbApi.CheckDB) // 检测是否需要初始化数据库
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/server/model/system/sys_chatgpt.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type ChatGpt struct {
4 | DBName string `json:"dbname,omitempty"`
5 | Chat string `json:"chat,omitempty"`
6 | ChatID string `json:"chatID,omitempty"`
7 | }
8 |
9 | type SysChatGptOption struct {
10 | SK string `json:"sk"`
11 | }
12 |
13 | type ChatField struct {
14 | TABLE_NAME string
15 | COLUMN_NAME string
16 | COLUMN_COMMENT string
17 | }
18 |
19 | type ChatFieldNoTable struct {
20 | COLUMN_NAME string
21 | COLUMN_COMMENT string
22 | }
23 |
--------------------------------------------------------------------------------
/server/router/system/sys_base.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type BaseRouter struct{}
9 |
10 | func (s *BaseRouter) InitBaseRouter(Router *gin.RouterGroup) (R gin.IRoutes) {
11 | baseRouter := Router.Group("base")
12 | baseApi := v1.ApiGroupApp.SystemApiGroup.BaseApi
13 | {
14 | baseRouter.POST("login", baseApi.Login)
15 | baseRouter.POST("captcha", baseApi.Captcha)
16 | }
17 | return baseRouter
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/style/element/index.scss:
--------------------------------------------------------------------------------
1 | @forward 'element-plus/theme-chalk/src/common/var.scss' with (
2 | $colors: (
3 | 'white': #ffffff,
4 | 'black': #000000,
5 | 'primary': (
6 | 'base': #4d70ff,
7 | ),
8 | 'success': (
9 | 'base': #67c23a,
10 | ),
11 | 'warning': (
12 | 'base': #e6a23c,
13 | ),
14 | 'danger': (
15 | 'base': #f56c6c,
16 | ),
17 | 'error': (
18 | 'base': #f56c6c,
19 | ),
20 | 'info': (
21 | 'base': #909399,
22 | ),
23 | )
24 | );
25 |
--------------------------------------------------------------------------------
/server/utils/ast/ast_gorm_test.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/example"
6 | "testing"
7 | )
8 |
9 | const A = 123
10 |
11 | func TestAddRegisterTablesAst(t *testing.T) {
12 | AddRegisterTablesAst("D:\\gin-vue-admin\\server\\utils\\ast_test.go", "Register", "test", "testDB", "testModel")
13 | }
14 |
15 | func Register() {
16 | test := global.GetGlobalDBByDBName("test")
17 | test.AutoMigrate(example.ExaFile{})
18 | }
19 |
--------------------------------------------------------------------------------
/deploy/kubernetes/web/gva-web-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: gva-web
5 | annotations:
6 | flipped-aurora/gin-vue-admin: ui
7 | github: "https://github.com/flipped-aurora/gin-vue-admin.git"
8 | app.kubernetes.io/version: 0.0.1
9 | labels:
10 | app: gva-web
11 | version: gva-vue3
12 | spec:
13 | # type: NodePort
14 | type: ClusterIP
15 | ports:
16 | - name: http
17 | port: 8080
18 | targetPort: 8080
19 | selector:
20 | app: gva-web
21 | version: gva-vue3
22 |
--------------------------------------------------------------------------------
/server/initialize/validator.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import "github.com/flipped-aurora/gin-vue-admin/server/utils"
4 |
5 | func init() {
6 | _ = utils.RegisterRule("PageVerify",
7 | utils.Rules{
8 | "Page": {utils.NotEmpty()},
9 | "PageSize": {utils.NotEmpty()},
10 | },
11 | )
12 | _ = utils.RegisterRule("IdVerify",
13 | utils.Rules{
14 | "Id": {utils.NotEmpty()},
15 | },
16 | )
17 | _ = utils.RegisterRule("AuthorityIdVerify",
18 | utils.Rules{
19 | "AuthorityId": {utils.NotEmpty()},
20 | },
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/server/middleware/need_init.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | // 处理跨域请求,支持options访问
10 | func NeedInit() gin.HandlerFunc {
11 | return func(c *gin.Context) {
12 | if global.GVA_DB == nil {
13 | response.OkWithDetailed(gin.H{
14 | "needInit": true,
15 | }, "前往初始化数据库", c)
16 | c.Abort()
17 | } else {
18 | c.Next()
19 | }
20 | // 处理请求
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/deploy/kubernetes/server/gva-server-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | name: gva-server
5 | annotations:
6 | flipped-aurora/gin-vue-admin: backend
7 | github: "https://github.com/flipped-aurora/gin-vue-admin.git"
8 | app.kubernetes.io/version: 0.0.1
9 | labels:
10 | app: gva-server
11 | version: gva-vue3
12 | spec:
13 | selector:
14 | app: gva-server
15 | version: gva-vue3
16 | ports:
17 | - port: 8888
18 | name: http
19 | targetPort: 8888
20 | type: ClusterIP
21 | # type: NodePort
22 |
--------------------------------------------------------------------------------
/server/model/example/exa_file_upload_download.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | )
6 |
7 | type ExaFileUploadAndDownload struct {
8 | global.GVA_MODEL
9 | Name string `json:"name" gorm:"comment:文件名"` // 文件名
10 | Url string `json:"url" gorm:"comment:文件地址"` // 文件地址
11 | Tag string `json:"tag" gorm:"comment:文件标签"` // 文件标签
12 | Key string `json:"key" gorm:"comment:编号"` // 编号
13 | }
14 |
15 | func (ExaFileUploadAndDownload) TableName() string {
16 | return "exa_file_upload_and_downloads"
17 | }
18 |
--------------------------------------------------------------------------------
/server/config/oss_tencent.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type TencentCOS struct {
4 | Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
5 | Region string `mapstructure:"region" json:"region" yaml:"region"`
6 | SecretID string `mapstructure:"secret-id" json:"secret-id" yaml:"secret-id"`
7 | SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"`
8 | BaseURL string `mapstructure:"base-url" json:"base-url" yaml:"base-url"`
9 | PathPrefix string `mapstructure:"path-prefix" json:"path-prefix" yaml:"path-prefix"`
10 | }
11 |
--------------------------------------------------------------------------------
/server/model/example/exa_breakpoint_continue.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | )
6 |
7 | // file struct, 文件结构体
8 | type ExaFile struct {
9 | global.GVA_MODEL
10 | FileName string
11 | FileMd5 string
12 | FilePath string
13 | ExaFileChunk []ExaFileChunk
14 | ChunkTotal int
15 | IsFinish bool
16 | }
17 |
18 | // file chunk struct, 切片结构体
19 | type ExaFileChunk struct {
20 | global.GVA_MODEL
21 | ExaFileID uint
22 | FileChunkNumber int
23 | FileChunkPath string
24 | }
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yaml:
--------------------------------------------------------------------------------
1 | name: 🚀 Feature request
2 | description: Suggest an idea for Gin-Vue-Admin
3 | title: "[Feature]: "
4 | labels: [feature]
5 | assignees:
6 | - piexlmax
7 | body:
8 | - type: textarea
9 | id: desc
10 | attributes:
11 | label: 功能描述以及必要性描述
12 | description: 您觉得此新功能会为框架带来什么便利.
13 | placeholder: |
14 | 1. 首先...
15 | 2. 然后...
16 | validations:
17 | required: true
18 | - type: textarea
19 | id: advise
20 | attributes:
21 | label: 建议和方案
22 | description: 您有好的建议或者修改方案可以提供给我们。
23 |
--------------------------------------------------------------------------------
/server/middleware/loadtls.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/gin-gonic/gin"
7 | "github.com/unrolled/secure"
8 | )
9 |
10 | // 用https把这个中间件在router里面use一下就好
11 |
12 | func LoadTls() gin.HandlerFunc {
13 | return func(c *gin.Context) {
14 | middleware := secure.New(secure.Options{
15 | SSLRedirect: true,
16 | SSLHost: "localhost:443",
17 | })
18 | err := middleware.Process(c.Writer, c.Request)
19 | if err != nil {
20 | // 如果出现错误,请不要继续
21 | fmt.Println(err)
22 | return
23 | }
24 | // 继续往下处理
25 | c.Next()
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_auto_code.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | type Db struct {
4 | Database string `json:"database" gorm:"column:database"`
5 | }
6 |
7 | type Table struct {
8 | TableName string `json:"tableName" gorm:"column:table_name"`
9 | }
10 |
11 | type Column struct {
12 | DataType string `json:"dataType" gorm:"column:data_type"`
13 | ColumnName string `json:"columnName" gorm:"column:column_name"`
14 | DataTypeLong string `json:"dataTypeLong" gorm:"column:data_type_long"`
15 | ColumnComment string `json:"columnComment" gorm:"column:column_comment"`
16 | }
17 |
--------------------------------------------------------------------------------
/server/utils/strings.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "strings"
4 |
5 | func FirstUpper(s string) string {
6 | if s == "" {
7 | return ""
8 | }
9 | return strings.ToUpper(s[:1]) + s[1:]
10 | }
11 |
12 | func FirstLower(s string) string {
13 | if s == "" {
14 | return ""
15 | }
16 | return strings.ToLower(s[:1]) + s[1:]
17 | }
18 |
19 | // MaheHump 将字符串转换为驼峰命名
20 | func MaheHump(s string) string {
21 | words := strings.Split(s, "-")
22 |
23 | for i := 1; i < len(words); i++ {
24 | words[i] = strings.Title(words[i])
25 | }
26 |
27 | return strings.Join(words, "")
28 | }
29 |
--------------------------------------------------------------------------------
/web/src/view/example/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
--------------------------------------------------------------------------------
/web/openDocument.js:
--------------------------------------------------------------------------------
1 | /*
2 | 商用代码公司自用产品无需授权
3 | 若作为代码出售的产品(任何涉及代码交付第三方作为后续开发)必须保留此脚本
4 | 或标注原作者信息
5 | 否则将依法维权
6 | */
7 |
8 | var child_process = require('child_process')
9 |
10 | var url = 'https://www.gin-vue-admin.com'
11 | var cmd = ''
12 | console.log(process.platform)
13 | switch (process.platform) {
14 | case 'win32':
15 | cmd = 'start'
16 | child_process.exec(cmd + ' ' + url)
17 | break
18 |
19 | case 'darwin':
20 | cmd = 'open'
21 | child_process.exec(cmd + ' ' + url)
22 | break
23 | }
24 |
--------------------------------------------------------------------------------
/web/src/view/superAdmin/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
--------------------------------------------------------------------------------
/web/src/view/systemTools/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
22 |
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/server/model/system/sys_api.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | )
6 |
7 | type SysApi struct {
8 | global.GVA_MODEL
9 | Path string `json:"path" gorm:"comment:api路径"` // api路径
10 | Description string `json:"description" gorm:"comment:api中文描述"` // api中文描述
11 | ApiGroup string `json:"apiGroup" gorm:"comment:api组"` // api组
12 | Method string `json:"method" gorm:"default:POST;comment:方法"` // 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE
13 | }
14 |
15 | func (SysApi) TableName() string {
16 | return "sys_apis"
17 | }
18 |
--------------------------------------------------------------------------------
/server/initialize/other.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | "github.com/songzhibin97/gkit/cache/local_cache"
5 |
6 | "github.com/flipped-aurora/gin-vue-admin/server/global"
7 | "github.com/flipped-aurora/gin-vue-admin/server/utils"
8 | )
9 |
10 | func OtherInit() {
11 | dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
12 | if err != nil {
13 | panic(err)
14 | }
15 | _, err = utils.ParseDuration(global.GVA_CONFIG.JWT.BufferTime)
16 | if err != nil {
17 | panic(err)
18 | }
19 |
20 | global.BlackCache = local_cache.NewCache(
21 | local_cache.SetDefaultExpire(dr),
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/web/src/api/authorityBtn.js:
--------------------------------------------------------------------------------
1 |
2 | import service from '@/utils/request'
3 |
4 | export const getAuthorityBtnApi = (data) => {
5 | return service({
6 | url: '/authorityBtn/getAuthorityBtn',
7 | method: 'post',
8 | data
9 | })
10 | }
11 |
12 | export const setAuthorityBtnApi = (data) => {
13 | return service({
14 | url: '/authorityBtn/setAuthorityBtn',
15 | method: 'post',
16 | data
17 | })
18 | }
19 |
20 | export const canRemoveAuthorityBtnApi = (params) => {
21 | return service({
22 | url: '/authorityBtn/canRemoveAuthorityBtn',
23 | method: 'post',
24 | params
25 | })
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/web/src/utils/dictionary.js:
--------------------------------------------------------------------------------
1 | import { useDictionaryStore } from '@/pinia/modules/dictionary'
2 | // 获取字典方法 使用示例 getDict('sex').then(res) 或者 async函数下 const res = await getDict('sex')
3 | export const getDict = async(type) => {
4 | const dictionaryStore = useDictionaryStore()
5 | await dictionaryStore.getDictionary(type)
6 | return dictionaryStore.dictionaryMap[type]
7 | }
8 |
9 | // 字典文字展示方法
10 | export const showDictLabel = (dict, code) => {
11 | if (!dict) {
12 | return ''
13 | }
14 | const dictMap = {}
15 | dict.forEach(item => {
16 | dictMap[item.value] = item.label
17 | })
18 | return dictMap[code]
19 | }
20 |
--------------------------------------------------------------------------------
/server/config/oss_aliyun.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type AliyunOSS struct {
4 | Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
5 | AccessKeyId string `mapstructure:"access-key-id" json:"access-key-id" yaml:"access-key-id"`
6 | AccessKeySecret string `mapstructure:"access-key-secret" json:"access-key-secret" yaml:"access-key-secret"`
7 | BucketName string `mapstructure:"bucket-name" json:"bucket-name" yaml:"bucket-name"`
8 | BucketUrl string `mapstructure:"bucket-url" json:"bucket-url" yaml:"bucket-url"`
9 | BasePath string `mapstructure:"base-path" json:"base-path" yaml:"base-path"`
10 | }
11 |
--------------------------------------------------------------------------------
/server/plugin/email/router/sys_email.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
5 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/email/api"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type EmailRouter struct{}
10 |
11 | func (s *EmailRouter) InitEmailRouter(Router *gin.RouterGroup) {
12 | emailRouter := Router.Use(middleware.OperationRecord())
13 | EmailApi := api.ApiGroupApp.EmailApi.EmailTest
14 | SendEmail := api.ApiGroupApp.EmailApi.SendEmail
15 | {
16 | emailRouter.POST("emailTest", EmailApi) // 发送测试邮件
17 | emailRouter.POST("sendEmail", SendEmail) // 发送邮件
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/web/src/api/chatgpt.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 |
3 | export const getTableApi = (data) => {
4 | return service({
5 | url: '/chatGpt/getTable',
6 | method: 'post',
7 | data
8 | })
9 | }
10 |
11 | export const createSKApi = (data) => {
12 | return service({
13 | url: '/chatGpt/createSK',
14 | method: 'post',
15 | data
16 | })
17 | }
18 |
19 | export const getSKApi = () => {
20 | return service({
21 | url: '/chatGpt/getSK',
22 | method: 'get',
23 | })
24 | }
25 |
26 | export const deleteSKApi = () => {
27 | return service({
28 | url: '/chatGpt/deleteSK',
29 | method: 'delete'
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/server/config/email.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Email struct {
4 | To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔
5 | Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口
6 | From string `mapstructure:"from" json:"from" yaml:"from"` // 收件人
7 | Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址
8 | IsSSL bool `mapstructure:"is-ssl" json:"is-ssl" yaml:"is-ssl"` // 是否SSL
9 | Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥
10 | Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称
11 | }
12 |
--------------------------------------------------------------------------------
/web/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from 'vue-router'
2 |
3 | const routes = [{
4 | path: '/',
5 | redirect: '/login'
6 | },
7 | {
8 | path: '/init',
9 | name: 'Init',
10 | component: () => import('@/view/init/index.vue')
11 | },
12 | {
13 | path: '/login',
14 | name: 'Login',
15 | component: () => import('@/view/login/index.vue')
16 | },
17 | {
18 | path: '/:catchAll(.*)',
19 | meta: {
20 | closeTab: true,
21 | },
22 | component: () => import('@/view/error/index.vue')
23 | }
24 | ]
25 |
26 | const router = createRouter({
27 | history: createWebHashHistory(),
28 | routes,
29 | })
30 |
31 | export default router
32 |
--------------------------------------------------------------------------------
/web/src/view/routerHolder.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
24 |
--------------------------------------------------------------------------------
/server/model/system/response/sys_auto_code_history.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import "time"
4 |
5 | type AutoCodeHistory struct {
6 | ID uint `json:"ID" gorm:"column:id"`
7 | CreatedAt time.Time `json:"CreatedAt" gorm:"column:created_at"`
8 | UpdatedAt time.Time `json:"UpdatedAt" gorm:"column:updated_at"`
9 | BusinessDB string `json:"businessDB" gorm:"column:business_db"`
10 | TableName string `json:"tableName" gorm:"column:table_name"`
11 | StructName string `json:"structName" gorm:"column:struct_name"`
12 | StructCNName string `json:"structCNName" gorm:"column:struct_cn_name"`
13 | Flag int `json:"flag" gorm:"column:flag"`
14 | }
15 |
--------------------------------------------------------------------------------
/server/utils/human_duration.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 | "time"
7 | )
8 |
9 | func ParseDuration(d string) (time.Duration, error) {
10 | d = strings.TrimSpace(d)
11 | dr, err := time.ParseDuration(d)
12 | if err == nil {
13 | return dr, nil
14 | }
15 | if strings.Contains(d, "d") {
16 | index := strings.Index(d, "d")
17 |
18 | hour, _ := strconv.Atoi(d[:index])
19 | dr = time.Hour * 24 * time.Duration(hour)
20 | ndr, err := time.ParseDuration(d[index+1:])
21 | if err != nil {
22 | return dr, nil
23 | }
24 | return dr + ndr, nil
25 | }
26 |
27 | dv, err := strconv.ParseInt(d, 10, 64)
28 | return time.Duration(dv), err
29 | }
30 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: gin-vue-admin
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: https://www.gin-vue-admin.com/docs/coffee
13 |
--------------------------------------------------------------------------------
/web/src/core/gin-vue-admin.js:
--------------------------------------------------------------------------------
1 | /*
2 | * gin-vue-admin web框架组
3 | *
4 | * */
5 | // 加载网站配置文件夹
6 | import { register } from './global'
7 |
8 | export default {
9 | install: (app) => {
10 | register(app)
11 | console.log(`
12 | 欢迎使用 Gin-Vue-Admin
13 | 当前版本:v2.5.7
14 | 加群方式:微信:shouzi_1994 QQ群:622360840
15 | GVA讨论社区:https://support.qq.com/products/371961
16 | 插件市场:https://plugin.gin-vue-admin.com
17 | 默认自动化文档地址:http://127.0.0.1:${import.meta.env.VITE_SERVER_PORT}/swagger/index.html
18 | 默认前端文件运行地址:http://127.0.0.1:${import.meta.env.VITE_CLI_PORT}
19 | 如果项目让您获得了收益,希望您能请团队喝杯可乐:https://www.gin-vue-admin.com/coffee/index.html
20 | `)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/deploy/docker/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | if [ ! -d "/var/lib/mysql/gva" ]; then
3 | mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysql
4 | mysqld --daemonize --user=mysql
5 | sleep 5s
6 | mysql -uroot -e "create database gva default charset 'utf8' collate 'utf8_bin'; grant all on gva.* to 'root'@'127.0.0.1' identified by '123456'; flush privileges;"
7 | else
8 | mysqld --daemonize --user=mysql
9 | fi
10 | redis-server &
11 | if [ "$1" = "actions" ]; then
12 | cd /opt/gva/server && go run main.go &
13 | cd /opt/gva/web/ && yarn serve &
14 | else
15 | /usr/sbin/nginx &
16 | cd /usr/share/nginx/html/ && ./server &
17 | fi
18 | echo "gva ALL start!!!"
19 | tail -f /dev/null
--------------------------------------------------------------------------------
/server/router/system/sys_chatgpt.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type ChatGptRouter struct{}
10 |
11 | func (s *ChatGptRouter) InitChatGptRouter(Router *gin.RouterGroup) {
12 | chatGptRouter := Router.Group("chatGpt").Use(middleware.OperationRecord())
13 | chatGptApi := v1.ApiGroupApp.SystemApiGroup.ChatGptApi
14 | {
15 | chatGptRouter.POST("createSK", chatGptApi.CreateSK)
16 | chatGptRouter.GET("getSK", chatGptApi.GetSK)
17 | chatGptRouter.DELETE("deleteSK", chatGptApi.DeleteSK)
18 | chatGptRouter.POST("getTable", chatGptApi.GetTable)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/server/router/system/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type CasbinRouter struct{}
10 |
11 | func (s *CasbinRouter) InitCasbinRouter(Router *gin.RouterGroup) {
12 | casbinRouter := Router.Group("casbin").Use(middleware.OperationRecord())
13 | casbinRouterWithoutRecord := Router.Group("casbin")
14 | casbinApi := v1.ApiGroupApp.SystemApiGroup.CasbinApi
15 | {
16 | casbinRouter.POST("updateCasbin", casbinApi.UpdateCasbin)
17 | }
18 | {
19 | casbinRouterWithoutRecord.POST("getPolicyPathByAuthorityId", casbinApi.GetPolicyPathByAuthorityId)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/web/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
15 |
20 |
35 |
--------------------------------------------------------------------------------
/web/src/style/element_visiable.scss:
--------------------------------------------------------------------------------
1 | @import '@/style/main.scss';
2 |
3 | #app {
4 | .el-button {
5 | font-weight: 400;
6 | border-radius: 2px;
7 | }
8 | }
9 |
10 | ::-webkit-scrollbar {
11 | @apply hidden;
12 | }
13 |
14 |
15 | .gva-search-box {
16 | @apply p-6 pb-0.5 bg-white rounded mb-3;
17 | }
18 |
19 | .gva-form-box {
20 | @apply p-6 bg-white rounded;
21 | }
22 |
23 | .gva-pagination {
24 | @apply flex justify-end;
25 | .el-pagination__editor {
26 | .el-input__inner {
27 | @apply h-8;
28 | }
29 | }
30 |
31 | .is-active {
32 | @apply rounded text-white;
33 | background: var(--el-color-primary);
34 | color: #ffffff !important;
35 | }
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/web/src/utils/stringFun.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export const toUpperCase = (str) => {
3 | if (str[0]) {
4 | return str.replace(str[0], str[0].toUpperCase())
5 | } else {
6 | return ''
7 | }
8 | }
9 |
10 | export const toLowerCase = (str) => {
11 | if (str[0]) {
12 | return str.replace(str[0], str[0].toLowerCase())
13 | } else {
14 | return ''
15 | }
16 | }
17 |
18 | // 驼峰转换下划线
19 | export const toSQLLine = (str) => {
20 | if (str === 'ID') return 'ID'
21 | return str.replace(/([A-Z])/g, "_$1").toLowerCase();
22 | }
23 |
24 | // 下划线转换驼峰
25 | export const toHump = (name) => {
26 | return name.replace(/\_(\w)/g, function(all, letter) {
27 | return letter.toUpperCase();
28 | });
29 | }
--------------------------------------------------------------------------------
/web/src/components/warningBar/warningBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 | {{ title }}
12 |
13 |
14 |
15 |
34 |
--------------------------------------------------------------------------------
/server/config/gorm_pgsql.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Pgsql struct {
4 | GeneralDB `yaml:",inline" mapstructure:",squash"`
5 | }
6 |
7 | // Dsn 基于配置文件获取 dsn
8 | // Author [SliverHorn](https://github.com/SliverHorn)
9 | func (p *Pgsql) Dsn() string {
10 | return "host=" + p.Path + " user=" + p.Username + " password=" + p.Password + " dbname=" + p.Dbname + " port=" + p.Port + " " + p.Config
11 | }
12 |
13 | // LinkDsn 根据 dbname 生成 dsn
14 | // Author [SliverHorn](https://github.com/SliverHorn)
15 | func (p *Pgsql) LinkDsn(dbname string) string {
16 | return "host=" + p.Path + " user=" + p.Username + " password=" + p.Password + " dbname=" + dbname + " port=" + p.Port + " " + p.Config
17 | }
18 |
19 | func (m *Pgsql) GetLogMode() string {
20 | return m.LogMode
21 | }
22 |
--------------------------------------------------------------------------------
/web/src/api/initdb.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags InitDB
3 | // @Summary 初始化用户数据库
4 | // @Produce application/json
5 | // @Param data body request.InitDB true "初始化数据库参数"
6 | // @Success 200 {string} string "{"code":0,"data":{},"msg":"自动创建数据库成功"}"
7 | // @Router /init/initdb [post]
8 | export const initDB = (data) => {
9 | return service({
10 | url: '/init/initdb',
11 | method: 'post',
12 | data
13 | })
14 | }
15 |
16 | // @Tags CheckDB
17 | // @Summary 初始化用户数据库
18 | // @Produce application/json
19 | // @Success 200 {string} string "{"code":0,"data":{},"msg":"探测完成"}"
20 | // @Router /init/checkdb [post]
21 | export const checkDB = () => {
22 | return service({
23 | url: '/init/checkdb',
24 | method: 'post'
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/server/config/captcha.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Captcha struct {
4 | KeyLong int `mapstructure:"key-long" json:"key-long" yaml:"key-long"` // 验证码长度
5 | ImgWidth int `mapstructure:"img-width" json:"img-width" yaml:"img-width"` // 验证码宽度
6 | ImgHeight int `mapstructure:"img-height" json:"img-height" yaml:"img-height"` // 验证码高度
7 | OpenCaptcha int `mapstructure:"open-captcha" json:"open-captcha" yaml:"open-captcha"` // 防爆破验证码开启此数,0代表每次登录都需要验证码,其他数字代表错误密码此数,如3代表错误三次后出现验证码
8 | OpenCaptchaTimeOut int `mapstructure:"open-captcha-timeout" json:"open-captcha-timeout" yaml:"open-captcha-timeout"` // 防爆破验证码超时时间,单位:s(秒)
9 | }
10 |
--------------------------------------------------------------------------------
/server/initialize/redis.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/flipped-aurora/gin-vue-admin/server/global"
7 |
8 | "github.com/redis/go-redis/v9"
9 | "go.uber.org/zap"
10 | )
11 |
12 | func Redis() {
13 | redisCfg := global.GVA_CONFIG.Redis
14 | client := redis.NewClient(&redis.Options{
15 | Addr: redisCfg.Addr,
16 | Password: redisCfg.Password, // no password set
17 | DB: redisCfg.DB, // use default DB
18 | })
19 | pong, err := client.Ping(context.Background()).Result()
20 | if err != nil {
21 | global.GVA_LOG.Error("redis connect ping failed, err:", zap.Error(err))
22 | } else {
23 | global.GVA_LOG.Info("redis connect ping response:", zap.String("pong", pong))
24 | global.GVA_REDIS = client
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/server/model/common/request/common.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | // PageInfo Paging common input parameter structure
4 | type PageInfo struct {
5 | Page int `json:"page" form:"page"` // 页码
6 | PageSize int `json:"pageSize" form:"pageSize"` // 每页大小
7 | Keyword string `json:"keyword" form:"keyword"` //关键字
8 | }
9 |
10 | // GetById Find by id structure
11 | type GetById struct {
12 | ID int `json:"id" form:"id"` // 主键ID
13 | }
14 |
15 | func (r *GetById) Uint() uint {
16 | return uint(r.ID)
17 | }
18 |
19 | type IdsReq struct {
20 | Ids []int `json:"ids" form:"ids"`
21 | }
22 |
23 | // GetAuthorityId Get role by id structure
24 | type GetAuthorityId struct {
25 | AuthorityId uint `json:"authorityId" form:"authorityId"` // 角色ID
26 | }
27 |
28 | type Empty struct{}
29 |
--------------------------------------------------------------------------------
/server/config/cors.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type CORS struct {
4 | Mode string `mapstructure:"mode" json:"mode" yaml:"mode"`
5 | Whitelist []CORSWhitelist `mapstructure:"whitelist" json:"whitelist" yaml:"whitelist"`
6 | }
7 |
8 | type CORSWhitelist struct {
9 | AllowOrigin string `mapstructure:"allow-origin" json:"allow-origin" yaml:"allow-origin"`
10 | AllowMethods string `mapstructure:"allow-methods" json:"allow-methods" yaml:"allow-methods"`
11 | AllowHeaders string `mapstructure:"allow-headers" json:"allow-headers" yaml:"allow-headers"`
12 | ExposeHeaders string `mapstructure:"expose-headers" json:"expose-headers" yaml:"expose-headers"`
13 | AllowCredentials bool `mapstructure:"allow-credentials" json:"allow-credentials" yaml:"allow-credentials"`
14 | }
15 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_menu.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
6 | )
7 |
8 | // Add menu authority info structure
9 | type AddMenuAuthorityInfo struct {
10 | Menus []system.SysBaseMenu `json:"menus"`
11 | AuthorityId uint `json:"authorityId"` // 角色ID
12 | }
13 |
14 | func DefaultMenu() []system.SysBaseMenu {
15 | return []system.SysBaseMenu{{
16 | GVA_MODEL: global.GVA_MODEL{ID: 1},
17 | ParentId: "0",
18 | Path: "dashboard",
19 | Name: "dashboard",
20 | Component: "view/dashboard/index.vue",
21 | Sort: 1,
22 | Meta: system.Meta{
23 | Title: "仪表盘",
24 | Icon: "setting",
25 | },
26 | }}
27 | }
28 |
--------------------------------------------------------------------------------
/web/src/utils/downloadImg.js:
--------------------------------------------------------------------------------
1 | export const downloadImage = (imgsrc, name) => { // 下载图片地址和图片名
2 | var image = new Image()
3 | image.setAttribute('crossOrigin', 'anonymous')
4 | image.onload = function() {
5 | var canvas = document.createElement('canvas')
6 | canvas.width = image.width
7 | canvas.height = image.height
8 | var context = canvas.getContext('2d')
9 | context.drawImage(image, 0, 0, image.width, image.height)
10 | var url = canvas.toDataURL('image/png') // 得到图片的base64编码数据
11 |
12 | var a = document.createElement('a') // 生成一个a元素
13 | var event = new MouseEvent('click') // 创建一个单击事件
14 | a.download = name || 'photo' // 设置图片名称
15 | a.href = url // 将生成的URL设置为a.href属性
16 | a.dispatchEvent(event) // 触发a的单击事件
17 | }
18 | image.src = imgsrc
19 | }
20 |
--------------------------------------------------------------------------------
/server/router/system/sys_system.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type SysRouter struct{}
10 |
11 | func (s *SysRouter) InitSystemRouter(Router *gin.RouterGroup) {
12 | sysRouter := Router.Group("system").Use(middleware.OperationRecord())
13 | systemApi := v1.ApiGroupApp.SystemApiGroup.SystemApi
14 | {
15 | sysRouter.POST("getSystemConfig", systemApi.GetSystemConfig) // 获取配置文件内容
16 | sysRouter.POST("setSystemConfig", systemApi.SetSystemConfig) // 设置配置文件内容
17 | sysRouter.POST("getServerInfo", systemApi.GetServerInfo) // 获取服务器信息
18 | sysRouter.POST("reloadSystem", systemApi.ReloadSystem) // 重启服务
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/server/model/system/sys_authority_menu.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | type SysMenu struct {
4 | SysBaseMenu
5 | MenuId string `json:"menuId" gorm:"comment:菜单ID"`
6 | AuthorityId uint `json:"-" gorm:"comment:角色ID"`
7 | Children []SysMenu `json:"children" gorm:"-"`
8 | Parameters []SysBaseMenuParameter `json:"parameters" gorm:"foreignKey:SysBaseMenuID;references:MenuId"`
9 | Btns map[string]uint `json:"btns" gorm:"-"`
10 | }
11 |
12 | type SysAuthorityMenu struct {
13 | MenuId string `json:"menuId" gorm:"comment:菜单ID;column:sys_base_menu_id"`
14 | AuthorityId string `json:"-" gorm:"comment:角色ID;column:sys_authority_authority_id"`
15 | }
16 |
17 | func (s SysAuthorityMenu) TableName() string {
18 | return "sys_authority_menus"
19 | }
20 |
--------------------------------------------------------------------------------
/server/config/timer.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Timer struct {
4 | Start bool `mapstructure:"start" json:"start" yaml:"start"` // 是否启用
5 | Spec string `mapstructure:"spec" json:"spec" yaml:"spec"` // CRON表达式
6 | WithSeconds bool `mapstructure:"with_seconds" json:"with_seconds" yaml:"with_seconds"` // 是否精确到秒
7 | Detail []Detail `mapstructure:"detail" json:"detail" yaml:"detail"`
8 | }
9 |
10 | type Detail struct {
11 | TableName string `mapstructure:"tableName" json:"tableName" yaml:"tableName"` // 需要清理的表名
12 | CompareField string `mapstructure:"compareField" json:"compareField" yaml:"compareField"` // 需要比较时间的字段
13 | Interval string `mapstructure:"interval" json:"interval" yaml:"interval"` // 时间间隔
14 | }
15 |
--------------------------------------------------------------------------------
/server/router/system/sys_auto_code_history.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type AutoCodeHistoryRouter struct{}
9 |
10 | func (s *AutoCodeRouter) InitAutoCodeHistoryRouter(Router *gin.RouterGroup) {
11 | autoCodeHistoryRouter := Router.Group("autoCode")
12 | autoCodeHistoryApi := v1.ApiGroupApp.SystemApiGroup.AutoCodeHistoryApi
13 | {
14 | autoCodeHistoryRouter.POST("getMeta", autoCodeHistoryApi.First) // 根据id获取meta信息
15 | autoCodeHistoryRouter.POST("rollback", autoCodeHistoryApi.RollBack) // 回滚
16 | autoCodeHistoryRouter.POST("delSysHistory", autoCodeHistoryApi.Delete) // 删除回滚记录
17 | autoCodeHistoryRouter.POST("getSysHistory", autoCodeHistoryApi.GetList) // 获取回滚记录分页
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/web/src/utils/format.js:
--------------------------------------------------------------------------------
1 | import { formatTimeToStr } from '@/utils/date'
2 | import { getDict } from '@/utils/dictionary'
3 |
4 | export const formatBoolean = (bool) => {
5 | if (bool !== null) {
6 | return bool ? '是' : '否'
7 | } else {
8 | return ''
9 | }
10 | }
11 | export const formatDate = (time) => {
12 | if (time !== null && time !== '') {
13 | var date = new Date(time)
14 | return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss')
15 | } else {
16 | return ''
17 | }
18 | }
19 |
20 | export const filterDict = (value, options) => {
21 | const rowLabel = options && options.filter(item => item.value === value)
22 | return rowLabel && rowLabel[0] && rowLabel[0].label
23 | }
24 |
25 | export const getDictFunc = async(type) => {
26 | const dicts = await getDict(type)
27 | return dicts
28 | }
29 |
--------------------------------------------------------------------------------
/web/src/view/systemTools/pubPlug/pubPlug.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 打包插件
7 |
8 |
9 |
10 |
11 |
26 |
27 |
--------------------------------------------------------------------------------
/server/router/system/sys_authority_btn.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type AuthorityBtnRouter struct{}
9 |
10 | func (s *AuthorityBtnRouter) InitAuthorityBtnRouterRouter(Router *gin.RouterGroup) {
11 | //authorityRouter := Router.Group("authorityBtn").Use(middleware.OperationRecord())
12 | authorityRouterWithoutRecord := Router.Group("authorityBtn")
13 | authorityBtnApi := v1.ApiGroupApp.SystemApiGroup.AuthorityBtnApi
14 | {
15 | authorityRouterWithoutRecord.POST("getAuthorityBtn", authorityBtnApi.GetAuthorityBtn)
16 | authorityRouterWithoutRecord.POST("setAuthorityBtn", authorityBtnApi.SetAuthorityBtn)
17 | authorityRouterWithoutRecord.POST("canRemoveAuthorityBtn", authorityBtnApi.CanRemoveAuthorityBtn)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:alpine as builder
2 |
3 | WORKDIR /go/src/github.com/flipped-aurora/gin-vue-admin/server
4 | COPY . .
5 |
6 | RUN go env -w GO111MODULE=on \
7 | && go env -w GOPROXY=https://goproxy.cn,direct \
8 | && go env -w CGO_ENABLED=0 \
9 | && go env \
10 | && go mod tidy \
11 | && go build -o server .
12 |
13 | FROM alpine:latest
14 |
15 | LABEL MAINTAINER="SliverHorn@sliver_horn@qq.com"
16 |
17 | WORKDIR /go/src/github.com/flipped-aurora/gin-vue-admin/server
18 |
19 | COPY --from=0 /go/src/github.com/flipped-aurora/gin-vue-admin/server/server ./
20 | COPY --from=0 /go/src/github.com/flipped-aurora/gin-vue-admin/server/resource ./resource/
21 | COPY --from=0 /go/src/github.com/flipped-aurora/gin-vue-admin/server/config.docker.yaml ./
22 |
23 | EXPOSE 8888
24 | ENTRYPOINT ./server -c config.docker.yaml
25 |
--------------------------------------------------------------------------------
/server/utils/db_automation.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "time"
7 |
8 | "gorm.io/gorm"
9 | )
10 |
11 | //@author: [songzhibin97](https://github.com/songzhibin97)
12 | //@function: ClearTable
13 | //@description: 清理数据库表数据
14 | //@param: db(数据库对象) *gorm.DB, tableName(表名) string, compareField(比较字段) string, interval(间隔) string
15 | //@return: error
16 |
17 | func ClearTable(db *gorm.DB, tableName string, compareField string, interval string) error {
18 | if db == nil {
19 | return errors.New("db Cannot be empty")
20 | }
21 | duration, err := time.ParseDuration(interval)
22 | if err != nil {
23 | return err
24 | }
25 | if duration < 0 {
26 | return errors.New("parse duration < 0")
27 | }
28 | return db.Debug().Exec(fmt.Sprintf("DELETE FROM %s WHERE %s < ?", tableName, compareField), time.Now().Add(-duration)).Error
29 | }
30 |
--------------------------------------------------------------------------------
/server/config/oss_qiniu.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Qiniu struct {
4 | Zone string `mapstructure:"zone" json:"zone" yaml:"zone"` // 存储区域
5 | Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` // 空间名称
6 | ImgPath string `mapstructure:"img-path" json:"img-path" yaml:"img-path"` // CDN加速域名
7 | UseHTTPS bool `mapstructure:"use-https" json:"use-https" yaml:"use-https"` // 是否使用https
8 | AccessKey string `mapstructure:"access-key" json:"access-key" yaml:"access-key"` // 秘钥AK
9 | SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"` // 秘钥SK
10 | UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"use-cdn-domains" yaml:"use-cdn-domains"` // 上传是否使用CDN上传加速
11 | }
12 |
--------------------------------------------------------------------------------
/server/model/example/exa_customer.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
6 | )
7 |
8 | type ExaCustomer struct {
9 | global.GVA_MODEL
10 | CustomerName string `json:"customerName" form:"customerName" gorm:"comment:客户名"` // 客户名
11 | CustomerPhoneData string `json:"customerPhoneData" form:"customerPhoneData" gorm:"comment:客户手机号"` // 客户手机号
12 | SysUserID uint `json:"sysUserId" form:"sysUserId" gorm:"comment:管理ID"` // 管理ID
13 | SysUserAuthorityID uint `json:"sysUserAuthorityID" form:"sysUserAuthorityID" gorm:"comment:管理角色ID"` // 管理角色ID
14 | SysUser system.SysUser `json:"sysUser" form:"sysUser" gorm:"comment:管理详情"` // 管理详情
15 | }
16 |
--------------------------------------------------------------------------------
/server/plugin/email/config/email.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Email struct {
4 | To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔 例:a@qq.com b@qq.com 正式开发中请把此项目作为参数使用
5 | From string `mapstructure:"from" json:"from" yaml:"from"` // 发件人 你自己要发邮件的邮箱
6 | Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址 例如 smtp.qq.com 请前往QQ或者你要发邮件的邮箱查看其smtp协议
7 | Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥 用于登录的密钥 最好不要用邮箱密码 去邮箱smtp申请一个用于登录的密钥
8 | Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称 发件人昵称 通常为自己的邮箱
9 | Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口 请前往QQ或者你要发邮件的邮箱查看其smtp协议 大多为 465
10 | IsSSL bool `mapstructure:"is-ssl" json:"isSSL" yaml:"is-ssl"` // 是否SSL 是否开启SSL
11 | }
12 |
--------------------------------------------------------------------------------
/server/plugin/email/service/sys_email.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/email/utils"
5 | )
6 |
7 | type EmailService struct{}
8 |
9 | //@author: [maplepie](https://github.com/maplepie)
10 | //@function: EmailTest
11 | //@description: 发送邮件测试
12 | //@return: err error
13 |
14 | func (e *EmailService) EmailTest() (err error) {
15 | subject := "test"
16 | body := "test"
17 | err = utils.EmailTest(subject, body)
18 | return err
19 | }
20 |
21 | //@author: [maplepie](https://github.com/maplepie)
22 | //@function: EmailTest
23 | //@description: 发送邮件测试
24 | //@return: err error
25 | //@params to string 收件人
26 | //@params subject string 标题(主题)
27 | //@params body string 邮件内容
28 |
29 | func (e *EmailService) SendEmail(to, subject, body string) (err error) {
30 | err = utils.Email(to, subject, body)
31 | return err
32 | }
33 |
--------------------------------------------------------------------------------
/web/src/plugin/email/api/email.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags System
3 | // @Summary 发送测试邮件
4 | // @Security ApiKeyAuth
5 | // @Produce application/json
6 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}"
7 | // @Router /email/emailTest [post]
8 | export const emailTest = (data) => {
9 | return service({
10 | url: '/email/emailTest',
11 | method: 'post',
12 | data
13 | })
14 | }
15 |
16 | // @Tags System
17 | // @Summary 发送邮件
18 | // @Security ApiKeyAuth
19 | // @Produce application/json
20 | // @Param data body email_response.Email true "发送邮件必须的参数"
21 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}"
22 | // @Router /email/sendEmail [post]
23 | export const sendEmail = (data) => {
24 | return service({
25 | url: '/email/sendEmail',
26 | method: 'post',
27 | data
28 | })
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/server/config/oss_aws.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type AwsS3 struct {
4 | Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"`
5 | Region string `mapstructure:"region" json:"region" yaml:"region"`
6 | Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"`
7 | S3ForcePathStyle bool `mapstructure:"s3-force-path-style" json:"s3-force-path-style" yaml:"s3-force-path-style"`
8 | DisableSSL bool `mapstructure:"disable-ssl" json:"disable-ssl" yaml:"disable-ssl"`
9 | SecretID string `mapstructure:"secret-id" json:"secret-id" yaml:"secret-id"`
10 | SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"`
11 | BaseURL string `mapstructure:"base-url" json:"base-url" yaml:"base-url"`
12 | PathPrefix string `mapstructure:"path-prefix" json:"path-prefix" yaml:"path-prefix"`
13 | }
14 |
--------------------------------------------------------------------------------
/server/plugin/email/main.go:
--------------------------------------------------------------------------------
1 | package email
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/email/global"
5 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/email/router"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type emailPlugin struct{}
10 |
11 | func CreateEmailPlug(To, From, Host, Secret, Nickname string, Port int, IsSSL bool) *emailPlugin {
12 | global.GlobalConfig.To = To
13 | global.GlobalConfig.From = From
14 | global.GlobalConfig.Host = Host
15 | global.GlobalConfig.Secret = Secret
16 | global.GlobalConfig.Nickname = Nickname
17 | global.GlobalConfig.Port = Port
18 | global.GlobalConfig.IsSSL = IsSSL
19 | return &emailPlugin{}
20 | }
21 |
22 | func (*emailPlugin) Register(group *gin.RouterGroup) {
23 | router.RouterGroupApp.InitEmailRouter(group)
24 | }
25 |
26 | func (*emailPlugin) RouterPath() string {
27 | return "email"
28 | }
29 |
--------------------------------------------------------------------------------
/server/resource/plug_template/main.go.tpl:
--------------------------------------------------------------------------------
1 | package {{ .Snake}}
2 |
3 | import (
4 | {{- if .HasGlobal }}
5 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/global"
6 | {{- end }}
7 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/router"
8 | "github.com/gin-gonic/gin"
9 | )
10 |
11 | type {{ .PlugName}}Plugin struct {
12 | }
13 |
14 | func Create{{ .PlugName}}Plug({{- range .Global}} {{.Key}} {{.Type}}, {{- end }})*{{ .PlugName}}Plugin {
15 | {{- if .HasGlobal }}
16 | {{- range .Global}}
17 | global.GlobalConfig.{{.Key}} = {{.Key}}
18 | {{- end }}
19 | {{ end }}
20 | return &{{ .PlugName}}Plugin{}
21 | }
22 |
23 | func (*{{ .PlugName}}Plugin) Register(group *gin.RouterGroup) {
24 | router.RouterGroupApp.Init{{ .PlugName}}Router(group)
25 | }
26 |
27 | func (*{{ .PlugName}}Plugin) RouterPath() string {
28 | return "{{ .RouterGroup}}"
29 | }
30 |
--------------------------------------------------------------------------------
/server/model/system/request/sys_casbin.go:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | // Casbin info structure
4 | type CasbinInfo struct {
5 | Path string `json:"path"` // 路径
6 | Method string `json:"method"` // 方法
7 | }
8 |
9 | // Casbin structure for input parameters
10 | type CasbinInReceive struct {
11 | AuthorityId uint `json:"authorityId"` // 权限id
12 | CasbinInfos []CasbinInfo `json:"casbinInfos"`
13 | }
14 |
15 | func DefaultCasbin() []CasbinInfo {
16 | return []CasbinInfo{
17 | {Path: "/menu/getMenu", Method: "POST"},
18 | {Path: "/jwt/jsonInBlacklist", Method: "POST"},
19 | {Path: "/base/login", Method: "POST"},
20 | {Path: "/user/admin_register", Method: "POST"},
21 | {Path: "/user/changePassword", Method: "POST"},
22 | {Path: "/user/setUserAuthority", Method: "POST"},
23 | {Path: "/user/setUserInfo", Method: "PUT"},
24 | {Path: "/user/getUserInfo", Method: "GET"},
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/server/core/zap.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "fmt"
5 | "github.com/flipped-aurora/gin-vue-admin/server/core/internal"
6 | "github.com/flipped-aurora/gin-vue-admin/server/global"
7 | "github.com/flipped-aurora/gin-vue-admin/server/utils"
8 | "go.uber.org/zap"
9 | "go.uber.org/zap/zapcore"
10 | "os"
11 | )
12 |
13 | // Zap 获取 zap.Logger
14 | // Author [SliverHorn](https://github.com/SliverHorn)
15 | func Zap() (logger *zap.Logger) {
16 | if ok, _ := utils.PathExists(global.GVA_CONFIG.Zap.Director); !ok { // 判断是否有Director文件夹
17 | fmt.Printf("create %v directory\n", global.GVA_CONFIG.Zap.Director)
18 | _ = os.Mkdir(global.GVA_CONFIG.Zap.Director, os.ModePerm)
19 | }
20 |
21 | cores := internal.Zap.GetZapCores()
22 | logger = zap.New(zapcore.NewTee(cores...))
23 |
24 | if global.GVA_CONFIG.Zap.ShowLine {
25 | logger = logger.WithOptions(zap.AddCaller())
26 | }
27 | return logger
28 | }
29 |
--------------------------------------------------------------------------------
/server/initialize/internal/logger.go:
--------------------------------------------------------------------------------
1 | package internal
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/flipped-aurora/gin-vue-admin/server/global"
7 | "gorm.io/gorm/logger"
8 | )
9 |
10 | type writer struct {
11 | logger.Writer
12 | }
13 |
14 | // NewWriter writer 构造函数
15 | // Author [SliverHorn](https://github.com/SliverHorn)
16 | func NewWriter(w logger.Writer) *writer {
17 | return &writer{Writer: w}
18 | }
19 |
20 | // Printf 格式化打印日志
21 | // Author [SliverHorn](https://github.com/SliverHorn)
22 | func (w *writer) Printf(message string, data ...interface{}) {
23 | var logZap bool
24 | switch global.GVA_CONFIG.System.DbType {
25 | case "mysql":
26 | logZap = global.GVA_CONFIG.Mysql.LogZap
27 | case "pgsql":
28 | logZap = global.GVA_CONFIG.Pgsql.LogZap
29 | }
30 | if logZap {
31 | global.GVA_LOG.Info(fmt.Sprintf(message+"\n", data...))
32 | } else {
33 | w.Writer.Printf(message, data...)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/web/.docker-compose/nginx/conf.d/my.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 8080;
3 | server_name localhost;
4 |
5 | #charset koi8-r;
6 | #access_log logs/host.access.log main;
7 |
8 | location / {
9 | root /usr/share/nginx/html;
10 | add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
11 | try_files $uri $uri/ /index.html;
12 | }
13 |
14 | location /api {
15 | proxy_set_header Host $http_host;
16 | proxy_set_header X-Real-IP $remote_addr;
17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
18 | proxy_set_header X-Forwarded-Proto $scheme;
19 | rewrite ^/api/(.*)$ /$1 break; #重写
20 | proxy_pass http://177.7.0.12:8888; # 设置代理服务器的协议和地址
21 | }
22 |
23 | location /api/swagger/index.html {
24 | proxy_pass http://127.0.0.1:8888/swagger/index.html;
25 | }
26 | }
--------------------------------------------------------------------------------
/server/model/system/sys_dictionary.go:
--------------------------------------------------------------------------------
1 | // 自动生成模板SysDictionary
2 | package system
3 |
4 | import (
5 | "github.com/flipped-aurora/gin-vue-admin/server/global"
6 | )
7 |
8 | // 如果含有time.Time 请自行import time包
9 | type SysDictionary struct {
10 | global.GVA_MODEL
11 | Name string `json:"name" form:"name" gorm:"column:name;comment:字典名(中)"` // 字典名(中)
12 | Type string `json:"type" form:"type" gorm:"column:type;comment:字典名(英)"` // 字典名(英)
13 | Status *bool `json:"status" form:"status" gorm:"column:status;comment:状态"` // 状态
14 | Desc string `json:"desc" form:"desc" gorm:"column:desc;comment:描述"` // 描述
15 | SysDictionaryDetails []SysDictionaryDetail `json:"sysDictionaryDetails" form:"sysDictionaryDetails"`
16 | }
17 |
18 | func (SysDictionary) TableName() string {
19 | return "sys_dictionaries"
20 | }
21 |
--------------------------------------------------------------------------------
/server/resource/page/index.html:
--------------------------------------------------------------------------------
1 | variant-form
--------------------------------------------------------------------------------
/deploy/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM centos:7
2 | WORKDIR /opt
3 | ENV LANG=en_US.utf8
4 | COPY deploy/docker/entrypoint.sh .
5 | COPY build/ /usr/share/nginx/html/
6 | COPY server/config.yaml /usr/share/nginx/html/config.yaml
7 | COPY web/.docker-compose/nginx/conf.d/nginx.conf /etc/nginx/conf.d/nginx.conf
8 | RUN set -ex \
9 | && echo "LANG=en_US.utf8" > /etc/locale.conf \
10 | && echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf \
11 | && echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf \
12 | && yum -y install yum -y install *epel* \
13 | && yum -y localinstall http://mirrors.ustc.edu.cn/mysql-repo/mysql57-community-release-el7.rpm \
14 | && yum -y install mysql-community-server git redis nginx go npm --nogpgcheck && chmod +x ./entrypoint.sh \
15 | && npm install -g yarn && go env -w GO111MODULE=on && go env -w GOPROXY=https://goproxy.cn,direct \
16 | && echo "start" > /dev/null
17 | EXPOSE 80
18 | ENTRYPOINT ["./entrypoint.sh"]
--------------------------------------------------------------------------------
/server/utils/upload/upload.go:
--------------------------------------------------------------------------------
1 | package upload
2 |
3 | import (
4 | "mime/multipart"
5 |
6 | "github.com/flipped-aurora/gin-vue-admin/server/global"
7 | )
8 |
9 | // OSS 对象存储接口
10 | // Author [SliverHorn](https://github.com/SliverHorn)
11 | // Author [ccfish86](https://github.com/ccfish86)
12 | type OSS interface {
13 | UploadFile(file *multipart.FileHeader) (string, string, error)
14 | DeleteFile(key string) error
15 | }
16 |
17 | // NewOss OSS的实例化方法
18 | // Author [SliverHorn](https://github.com/SliverHorn)
19 | // Author [ccfish86](https://github.com/ccfish86)
20 | func NewOss() OSS {
21 | switch global.GVA_CONFIG.System.OssType {
22 | case "local":
23 | return &Local{}
24 | case "qiniu":
25 | return &Qiniu{}
26 | case "tencent-cos":
27 | return &TencentCOS{}
28 | case "aliyun-oss":
29 | return &AliyunOSS{}
30 | case "huawei-obs":
31 | return HuaWeiObs
32 | case "aws-s3":
33 | return &AwsS3{}
34 | default:
35 | return &Local{}
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/web/vitePlugin/fullImport/fullImport.js:
--------------------------------------------------------------------------------
1 | import * as path from 'path'
2 | export default function fullImportPlugin() {
3 | let config
4 | return {
5 | name: 'fullImportElementPlus',
6 | async configResolved(conf) {
7 | config = conf
8 | },
9 | transform(code, id) {
10 | const sourcePath = path.join(config.root, 'src/main.js').split(path.sep).join('/')
11 | const targetPath = id.split(path.sep).join('/')
12 | if (sourcePath === targetPath) {
13 | const name = 'ElementPlus'
14 | // 引入 ElementPlus 和 样式
15 | code = code.replace(`import { createApp } from 'vue'`, ($1) => $1 + `\nimport ${name} from 'element-plus'`)
16 | code = code.replace(`import './style/element_visiable.scss'`, ($1) => $1 + `\nimport 'element-plus/theme-chalk/src/index.scss'`)
17 | code = code.replace('.mount(', ($1) => `.use(${name})` + $1)
18 | return code
19 | }
20 | return code
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 | ### Contributing Guide
3 | #### 1 Issue Guidelines
4 |
5 | - Issues are exclusively for bug reports, feature requests and design-related topics. Other questions may be closed directly. If any questions come up when you are using Element, please hit [Gitter](https://gitter.im/element-en/Lobby) for help.
6 |
7 | - Before submitting an issue, please check if similar problems have already been issued.
8 |
9 | #### 2 Pull Request Guidelines
10 |
11 | - Fork this repository to your own account. Do not create branches here.
12 |
13 | - Commit info should be formatted as `[File Name]: Info about commit.` (e.g. `README.md: Fix xxx bug`)
14 |
15 | - Make sure PRs are created to `develop` branch instead of `master` branch.
16 |
17 | - If your PR fixes a bug, please provide a description about the related bug.
18 |
19 | - Merging a PR takes two maintainers: one approves the changes after reviewing, and then the other reviews and merges.
20 |
--------------------------------------------------------------------------------
/server/resource/autocode_template/server/request.go.tpl:
--------------------------------------------------------------------------------
1 | package request
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/{{.Package}}"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
6 | "time"
7 | )
8 |
9 | type {{.StructName}}Search struct{
10 | {{.Package}}.{{.StructName}}
11 | StartCreatedAt *time.Time `json:"startCreatedAt" form:"startCreatedAt"`
12 | EndCreatedAt *time.Time `json:"endCreatedAt" form:"endCreatedAt"`
13 | {{- range .Fields}}
14 | {{- if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
15 | Start{{.FieldName}} *{{.FieldType}} `json:"start{{.FieldName}}" form:"start{{.FieldName}}"`
16 | End{{.FieldName}} *{{.FieldType}} `json:"end{{.FieldName}}" form:"end{{.FieldName}}"`
17 | {{- end }}
18 | {{- end }}
19 | request.PageInfo
20 | {{- if .NeedSort}}
21 | Sort string `json:"sort" form:"sort"`
22 | Order string `json:"order" form:"order"`
23 | {{- end}}
24 | }
25 |
--------------------------------------------------------------------------------
/web/src/view/error/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |

6 |
页面被神秘力量吸走了(如果您是开源版请联系我们修复)
7 |
常见问题为当前此角色无当前路由,如果确定要使用本路由,请到角色管理进行分配
8 |
↓
9 |

10 |
返回首页
11 |
12 |
13 |
14 |
15 |
16 |
21 |
22 |
32 |
--------------------------------------------------------------------------------
/server/model/system/sys_dictionary_detail.go:
--------------------------------------------------------------------------------
1 | // 自动生成模板SysDictionaryDetail
2 | package system
3 |
4 | import (
5 | "github.com/flipped-aurora/gin-vue-admin/server/global"
6 | )
7 |
8 | // 如果含有time.Time 请自行import time包
9 | type SysDictionaryDetail struct {
10 | global.GVA_MODEL
11 | Label string `json:"label" form:"label" gorm:"column:label;comment:展示值"` // 展示值
12 | Value int `json:"value" form:"value" gorm:"column:value;comment:字典值"` // 字典值
13 | Status *bool `json:"status" form:"status" gorm:"column:status;comment:启用状态"` // 启用状态
14 | Sort int `json:"sort" form:"sort" gorm:"column:sort;comment:排序标记"` // 排序标记
15 | SysDictionaryID int `json:"sysDictionaryID" form:"sysDictionaryID" gorm:"column:sys_dictionary_id;comment:关联标记"` // 关联标记
16 | }
17 |
18 | func (SysDictionaryDetail) TableName() string {
19 | return "sys_dictionary_details"
20 | }
21 |
--------------------------------------------------------------------------------
/server/utils/validator_test.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
5 | "testing"
6 | )
7 |
8 | type PageInfoTest struct {
9 | PageInfo request.PageInfo
10 | Name string
11 | }
12 |
13 | func TestVerify(t *testing.T) {
14 | PageInfoVerify := Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}, "Name": {NotEmpty()}}
15 | var testInfo PageInfoTest
16 | testInfo.Name = "test"
17 | testInfo.PageInfo.Page = 0
18 | testInfo.PageInfo.PageSize = 0
19 | err := Verify(testInfo, PageInfoVerify)
20 | if err == nil {
21 | t.Error("校验失败,未能捕捉0值")
22 | }
23 | testInfo.Name = ""
24 | testInfo.PageInfo.Page = 1
25 | testInfo.PageInfo.PageSize = 10
26 | err = Verify(testInfo, PageInfoVerify)
27 | if err == nil {
28 | t.Error("校验失败,未能正常检测name为空")
29 | }
30 | testInfo.Name = "test"
31 | testInfo.PageInfo.Page = 1
32 | testInfo.PageInfo.PageSize = 10
33 | err = Verify(testInfo, PageInfoVerify)
34 | if err != nil {
35 | t.Error("校验失败,未能正常通过检测")
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/server/router/example/exa_customer.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type CustomerRouter struct{}
10 |
11 | func (e *CustomerRouter) InitCustomerRouter(Router *gin.RouterGroup) {
12 | customerRouter := Router.Group("customer").Use(middleware.OperationRecord())
13 | customerRouterWithoutRecord := Router.Group("customer")
14 | exaCustomerApi := v1.ApiGroupApp.ExampleApiGroup.CustomerApi
15 | {
16 | customerRouter.POST("customer", exaCustomerApi.CreateExaCustomer) // 创建客户
17 | customerRouter.PUT("customer", exaCustomerApi.UpdateExaCustomer) // 更新客户
18 | customerRouter.DELETE("customer", exaCustomerApi.DeleteExaCustomer) // 删除客户
19 | }
20 | {
21 | customerRouterWithoutRecord.GET("customer", exaCustomerApi.GetExaCustomer) // 获取单一客户信息
22 | customerRouterWithoutRecord.GET("customerList", exaCustomerApi.GetExaCustomerList) // 获取客户列表
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/server/api/v1/system/sys_jwt_blacklist.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
6 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
7 | "github.com/gin-gonic/gin"
8 | "go.uber.org/zap"
9 | )
10 |
11 | type JwtApi struct{}
12 |
13 | // JsonInBlacklist
14 | // @Tags Jwt
15 | // @Summary jwt加入黑名单
16 | // @Security ApiKeyAuth
17 | // @accept application/json
18 | // @Produce application/json
19 | // @Success 200 {object} response.Response{msg=string} "jwt加入黑名单"
20 | // @Router /jwt/jsonInBlacklist [post]
21 | func (j *JwtApi) JsonInBlacklist(c *gin.Context) {
22 | token := c.Request.Header.Get("x-token")
23 | jwt := system.JwtBlacklist{Jwt: token}
24 | err := jwtService.JsonInBlacklist(jwt)
25 | if err != nil {
26 | global.GVA_LOG.Error("jwt作废失败!", zap.Error(err))
27 | response.FailWithMessage("jwt作废失败", c)
28 | return
29 | }
30 | response.OkWithMessage("jwt作废成功", c)
31 | }
32 |
--------------------------------------------------------------------------------
/server/config/system.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type System struct {
4 | Env string `mapstructure:"env" json:"env" yaml:"env"` // 环境值
5 | Addr int `mapstructure:"addr" json:"addr" yaml:"addr"` // 端口值
6 | DbType string `mapstructure:"db-type" json:"db-type" yaml:"db-type"` // 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql
7 | OssType string `mapstructure:"oss-type" json:"oss-type" yaml:"oss-type"` // Oss类型
8 | UseMultipoint bool `mapstructure:"use-multipoint" json:"use-multipoint" yaml:"use-multipoint"` // 多点登录拦截
9 | UseRedis bool `mapstructure:"use-redis" json:"use-redis" yaml:"use-redis"` // 使用redis
10 | LimitCountIP int `mapstructure:"iplimit-count" json:"iplimit-count" yaml:"iplimit-count"`
11 | LimitTimeIP int `mapstructure:"iplimit-time" json:"iplimit-time" yaml:"iplimit-time"`
12 | RouterPrefix string `mapstructure:"router-prefix" json:"router-prefix" yaml:"router-prefix"`
13 | }
14 |
--------------------------------------------------------------------------------
/web/src/utils/asyncRouter.js:
--------------------------------------------------------------------------------
1 | const viewModules = import.meta.glob('../view/**/*.vue')
2 | const pluginModules = import.meta.glob('../plugin/**/*.vue')
3 |
4 | export const asyncRouterHandle = (asyncRouter) => {
5 | asyncRouter.forEach(item => {
6 | if (item.component && typeof item.component === 'string') {
7 | if (item.component.split('/')[0] === 'view') {
8 | item.component = dynamicImport(viewModules, item.component)
9 | } else if (item.component.split('/')[0] === 'plugin') {
10 | item.component = dynamicImport(pluginModules, item.component)
11 | }
12 | }
13 | if (item.children) {
14 | asyncRouterHandle(item.children)
15 | }
16 | })
17 | }
18 |
19 | function dynamicImport(
20 | dynamicViewsModules,
21 | component
22 | ) {
23 | const keys = Object.keys(dynamicViewsModules)
24 | const matchKeys = keys.filter((key) => {
25 | const k = key.replace('../', '')
26 | return k === component
27 | })
28 | const matchKey = matchKeys[0]
29 |
30 | return dynamicViewsModules[matchKey]
31 | }
32 |
--------------------------------------------------------------------------------
/server/initialize/timer.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/robfig/cron/v3"
7 |
8 | "github.com/flipped-aurora/gin-vue-admin/server/config"
9 | "github.com/flipped-aurora/gin-vue-admin/server/global"
10 | "github.com/flipped-aurora/gin-vue-admin/server/utils"
11 | )
12 |
13 | func Timer() {
14 | if global.GVA_CONFIG.Timer.Start {
15 | for i := range global.GVA_CONFIG.Timer.Detail {
16 | go func(detail config.Detail) {
17 | var option []cron.Option
18 | if global.GVA_CONFIG.Timer.WithSeconds {
19 | option = append(option, cron.WithSeconds())
20 | }
21 | _, err := global.GVA_Timer.AddTaskByFunc("ClearDB", global.GVA_CONFIG.Timer.Spec, func() {
22 | err := utils.ClearTable(global.GVA_DB, detail.TableName, detail.CompareField, detail.Interval)
23 | if err != nil {
24 | fmt.Println("timer error:", err)
25 | }
26 | }, option...)
27 | if err != nil {
28 | fmt.Println("add timer error:", err)
29 | }
30 | }(global.GVA_CONFIG.Timer.Detail[i])
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/web/src/view/dashboard/weather.js:
--------------------------------------------------------------------------------
1 |
2 | import axios from 'axios'
3 | import { ref } from 'vue'
4 |
5 | const weatherInfo = ref('今日晴,0℃ - 10℃,天气寒冷,注意添加衣物。')
6 | const amapKey = '8e8baa8a7317586c29ec694895de6e0a'
7 |
8 | export const useWeatherInfo = () => {
9 | ip()
10 | return weatherInfo
11 | }
12 |
13 | export const ip = async() => {
14 | // key换成你自己的 https://console.amap.com/dev/index
15 | if (amapKey === '') {
16 | return false
17 | }
18 | const res = await axios.get('https://restapi.amap.com/v3/ip?key=' + amapKey)
19 | if (res.data.adcode) {
20 | getWeather(res.data.adcode)
21 | }
22 | }
23 |
24 | const getWeather = async(code) => {
25 | const response = await axios.get('https://restapi.amap.com/v3/weather/weatherInfo?key=' + amapKey + '&extensions=base&city=' + code)
26 | if (response.data.status === '1') {
27 | const s = response.data.lives[0]
28 | weatherInfo.value = s.city + ' 天气:' + s.weather + ' 温度:' + s.temperature + '摄氏度 风向:' + s.winddirection + ' 风力:' + s.windpower + '级 空气湿度:' + s.humidity
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/server/core/internal/file_rotatelogs.go:
--------------------------------------------------------------------------------
1 | package internal
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | rotatelogs "github.com/lestrrat-go/file-rotatelogs"
6 | "go.uber.org/zap/zapcore"
7 | "os"
8 | "path"
9 | "time"
10 | )
11 |
12 | var FileRotatelogs = new(fileRotatelogs)
13 |
14 | type fileRotatelogs struct{}
15 |
16 | // GetWriteSyncer 获取 zapcore.WriteSyncer
17 | // Author [SliverHorn](https://github.com/SliverHorn)
18 | func (r *fileRotatelogs) GetWriteSyncer(level string) (zapcore.WriteSyncer, error) {
19 | fileWriter, err := rotatelogs.New(
20 | path.Join(global.GVA_CONFIG.Zap.Director, "%Y-%m-%d", level+".log"),
21 | rotatelogs.WithClock(rotatelogs.Local),
22 | rotatelogs.WithMaxAge(time.Duration(global.GVA_CONFIG.Zap.MaxAge)*24*time.Hour), // 日志留存时间
23 | rotatelogs.WithRotationTime(time.Hour*24),
24 | )
25 | if global.GVA_CONFIG.Zap.LogInConsole {
26 | return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(fileWriter)), err
27 | }
28 | return zapcore.AddSync(fileWriter), err
29 | }
30 |
--------------------------------------------------------------------------------
/web/src/api/casbin.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags authority
3 | // @Summary 更改角色api权限
4 | // @Security ApiKeyAuth
5 | // @accept application/json
6 | // @Produce application/json
7 | // @Param data body api.CreateAuthorityPatams true "更改角色api权限"
8 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
9 | // @Router /casbin/UpdateCasbin [post]
10 | export const UpdateCasbin = (data) => {
11 | return service({
12 | url: '/casbin/updateCasbin',
13 | method: 'post',
14 | data
15 | })
16 | }
17 |
18 | // @Tags casbin
19 | // @Summary 获取权限列表
20 | // @Security ApiKeyAuth
21 | // @accept application/json
22 | // @Produce application/json
23 | // @Param data body api.CreateAuthorityPatams true "获取权限列表"
24 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
25 | // @Router /casbin/getPolicyPathByAuthorityId [post]
26 | export const getPolicyPathByAuthorityId = (data) => {
27 | return service({
28 | url: '/casbin/getPolicyPathByAuthorityId',
29 | method: 'post',
30 | data
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/server/initialize/db_list.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/config"
5 | "github.com/flipped-aurora/gin-vue-admin/server/global"
6 | "gorm.io/gorm"
7 | )
8 |
9 | const sys = "system"
10 |
11 | func DBList() {
12 | dbMap := make(map[string]*gorm.DB)
13 | for _, info := range global.GVA_CONFIG.DBList {
14 | if info.Disable {
15 | continue
16 | }
17 | switch info.Type {
18 | case "mysql":
19 | dbMap[info.AliasName] = GormMysqlByConfig(config.Mysql{GeneralDB: info.GeneralDB})
20 | case "mssql":
21 | dbMap[info.AliasName] = GormMssqlByConfig(config.Mssql{GeneralDB: info.GeneralDB})
22 | case "pgsql":
23 | dbMap[info.AliasName] = GormPgSqlByConfig(config.Pgsql{GeneralDB: info.GeneralDB})
24 | case "oracle":
25 | dbMap[info.AliasName] = GormOracleByConfig(config.Oracle{GeneralDB: info.GeneralDB})
26 | default:
27 | continue
28 | }
29 | }
30 | // 做特殊判断,是否有迁移
31 | // 适配低版本迁移多数据库版本
32 | if sysDB, ok := dbMap[sys]; ok {
33 | global.GVA_DB = sysDB
34 | }
35 | global.GVA_DBList = dbMap
36 | }
37 |
--------------------------------------------------------------------------------
/web/limit.js:
--------------------------------------------------------------------------------
1 | // 运行项目前通过node执行此脚本 (此脚本与 node_modules 目录同级)
2 | const fs = require('fs')
3 | const path = require('path')
4 | const wfPath = path.resolve(__dirname, './node_modules/.bin')
5 |
6 | fs.readdir(wfPath, (err, files) => {
7 | if (err) {
8 | console.log(err)
9 | } else {
10 | if (files.length !== 0) {
11 | files.forEach((item) => {
12 | if (item.split('.')[1] === 'cmd') {
13 | replaceStr(`${wfPath}/${item}`, /"%_prog%"/, '%_prog%')
14 | }
15 | })
16 | }
17 | }
18 | })
19 |
20 | // 参数:[文件路径、 需要修改的字符串、修改后的字符串] (替换对应文件内字符串的公共函数)
21 | function replaceStr(filePath, sourceRegx, targetSrt) {
22 | fs.readFile(filePath, (err, data) => {
23 | if (err) {
24 | console.log(err)
25 | } else {
26 | let str = data.toString()
27 | str = str.replace(sourceRegx, targetSrt)
28 | fs.writeFile(filePath, str, (err) => {
29 | if (err) {
30 | console.log(err)
31 | } else {
32 | console.log('\x1B[42m%s\x1B[0m', '文件修改成功')
33 | }
34 | })
35 | }
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/server/utils/fmt_plus.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | "strings"
7 | )
8 |
9 | //@author: [piexlmax](https://github.com/piexlmax)
10 | //@function: StructToMap
11 | //@description: 利用反射将结构体转化为map
12 | //@param: obj interface{}
13 | //@return: map[string]interface{}
14 |
15 | func StructToMap(obj interface{}) map[string]interface{} {
16 | obj1 := reflect.TypeOf(obj)
17 | obj2 := reflect.ValueOf(obj)
18 |
19 | data := make(map[string]interface{})
20 | for i := 0; i < obj1.NumField(); i++ {
21 | if obj1.Field(i).Tag.Get("mapstructure") != "" {
22 | data[obj1.Field(i).Tag.Get("mapstructure")] = obj2.Field(i).Interface()
23 | } else {
24 | data[obj1.Field(i).Name] = obj2.Field(i).Interface()
25 | }
26 | }
27 | return data
28 | }
29 |
30 | //@author: [piexlmax](https://github.com/piexlmax)
31 | //@function: ArrayToString
32 | //@description: 将数组格式化为字符串
33 | //@param: array []interface{}
34 | //@return: string
35 |
36 | func ArrayToString(array []interface{}) string {
37 | return strings.Replace(strings.Trim(fmt.Sprint(array), "[]"), " ", ",", -1)
38 | }
39 |
--------------------------------------------------------------------------------
/deploy/kubernetes/web/gva-web-configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: my.conf
5 | data:
6 | my.conf: |
7 | server {
8 | listen 8080;
9 | server_name localhost;
10 |
11 | #charset koi8-r;
12 | #access_log logs/host.access.log main;
13 |
14 | location / {
15 | root /usr/share/nginx/html;
16 | add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
17 | try_files $uri $uri/ /index.html;
18 | }
19 |
20 | location /api {
21 | proxy_set_header Host $http_host;
22 | proxy_set_header X-Real-IP $remote_addr;
23 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
24 | proxy_set_header X-Forwarded-Proto $scheme;
25 | rewrite ^/api/(.*)$ /$1 break; #重写
26 | proxy_pass http://gva-server:8888; # 设置代理服务器的协议和地址
27 | }
28 |
29 | location /api/swagger/index.html {
30 | proxy_pass http://gva-server:8888/swagger/index.html;
31 | }
32 | }
--------------------------------------------------------------------------------
/server/router/system/sys_authority.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type AuthorityRouter struct{}
10 |
11 | func (s *AuthorityRouter) InitAuthorityRouter(Router *gin.RouterGroup) {
12 | authorityRouter := Router.Group("authority").Use(middleware.OperationRecord())
13 | authorityRouterWithoutRecord := Router.Group("authority")
14 | authorityApi := v1.ApiGroupApp.SystemApiGroup.AuthorityApi
15 | {
16 | authorityRouter.POST("createAuthority", authorityApi.CreateAuthority) // 创建角色
17 | authorityRouter.POST("deleteAuthority", authorityApi.DeleteAuthority) // 删除角色
18 | authorityRouter.PUT("updateAuthority", authorityApi.UpdateAuthority) // 更新角色
19 | authorityRouter.POST("copyAuthority", authorityApi.CopyAuthority) // 拷贝角色
20 | authorityRouter.POST("setDataAuthority", authorityApi.SetDataAuthority) // 设置角色资源权限
21 | }
22 | {
23 | authorityRouterWithoutRecord.POST("getAuthorityList", authorityApi.GetAuthorityList) // 获取角色列表
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/server/utils/human_duration_test.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "testing"
5 | "time"
6 | )
7 |
8 | func TestParseDuration(t *testing.T) {
9 | type args struct {
10 | d string
11 | }
12 | tests := []struct {
13 | name string
14 | args args
15 | want time.Duration
16 | wantErr bool
17 | }{
18 | {
19 | name: "5h20m",
20 | args: args{"5h20m"},
21 | want: time.Hour*5 + 20*time.Minute,
22 | wantErr: false,
23 | },
24 | {
25 | name: "1d5h20m",
26 | args: args{"1d5h20m"},
27 | want: 24*time.Hour + time.Hour*5 + 20*time.Minute,
28 | wantErr: false,
29 | },
30 | {
31 | name: "1d",
32 | args: args{"1d"},
33 | want: 24 * time.Hour,
34 | wantErr: false,
35 | },
36 | }
37 | for _, tt := range tests {
38 | t.Run(tt.name, func(t *testing.T) {
39 | got, err := ParseDuration(tt.args.d)
40 | if (err != nil) != tt.wantErr {
41 | t.Errorf("ParseDuration() error = %v, wantErr %v", err, tt.wantErr)
42 | return
43 | }
44 | if got != tt.want {
45 | t.Errorf("ParseDuration() got = %v, want %v", got, tt.want)
46 | }
47 | })
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/web/src/view/layout/bottomInfo/bottomInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Powered by
6 |
7 | {{ $GIN_VUE_ADMIN.appName }}
8 |
9 |
10 |
Copyright
11 |
12 | flipped-aurora团队
13 |
14 |
15 |
16 |
17 |
24 |
25 |
33 |
34 |
--------------------------------------------------------------------------------
/web/src/utils/positionToCode.js:
--------------------------------------------------------------------------------
1 | export const initDom = () => {
2 | if (import.meta.env.MODE === 'development') {
3 | document.onmousedown = function(e) {
4 | if (e.shiftKey && e.button === 0) {
5 | e.preventDefault()
6 | sendRequestToOpenFileInEditor(getFilePath(e))
7 | }
8 | }
9 | }
10 | }
11 |
12 | const getFilePath = (e) => {
13 | let element = e
14 | if (e.target) {
15 | element = e.target
16 | }
17 | if (!element || !element.getAttribute) return null
18 | if (element.getAttribute('code-location')) {
19 | return element.getAttribute('code-location')
20 | }
21 | return getFilePath(element.parentNode)
22 | }
23 |
24 | const sendRequestToOpenFileInEditor = (filePath) => {
25 | const protocol = window.location.protocol
26 | ? window.location.protocol
27 | : 'http:'
28 | const hostname = window.location.hostname
29 | ? window.location.hostname
30 | : 'localhost'
31 | const port = window.location.port ? window.location.port : '80'
32 | fetch(`${protocol}//${hostname}:${port}/gvaPositionCode?filePath=${filePath}`)
33 | .catch((error) => {
34 | console.log(error)
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/server/model/system/sys_authority.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type SysAuthority struct {
8 | CreatedAt time.Time // 创建时间
9 | UpdatedAt time.Time // 更新时间
10 | DeletedAt *time.Time `sql:"index"`
11 | AuthorityId uint `json:"authorityId" gorm:"not null;unique;primary_key;comment:角色ID;size:90"` // 角色ID
12 | AuthorityName string `json:"authorityName" gorm:"comment:角色名"` // 角色名
13 | ParentId *uint `json:"parentId" gorm:"comment:父角色ID"` // 父角色ID
14 | DataAuthorityId []*SysAuthority `json:"dataAuthorityId" gorm:"many2many:sys_data_authority_id;"`
15 | Children []SysAuthority `json:"children" gorm:"-"`
16 | SysBaseMenus []SysBaseMenu `json:"menus" gorm:"many2many:sys_authority_menus;"`
17 | Users []SysUser `json:"-" gorm:"many2many:sys_user_authority;"`
18 | DefaultRouter string `json:"defaultRouter" gorm:"comment:默认菜单;default:dashboard"` // 默认菜单(默认dashboard)
19 | }
20 |
21 | func (SysAuthority) TableName() string {
22 | return "sys_authorities"
23 | }
24 |
--------------------------------------------------------------------------------
/server/router/system/sys_operation_record.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type OperationRecordRouter struct{}
9 |
10 | func (s *OperationRecordRouter) InitSysOperationRecordRouter(Router *gin.RouterGroup) {
11 | operationRecordRouter := Router.Group("sysOperationRecord")
12 | authorityMenuApi := v1.ApiGroupApp.SystemApiGroup.OperationRecordApi
13 | {
14 | operationRecordRouter.POST("createSysOperationRecord", authorityMenuApi.CreateSysOperationRecord) // 新建SysOperationRecord
15 | operationRecordRouter.DELETE("deleteSysOperationRecord", authorityMenuApi.DeleteSysOperationRecord) // 删除SysOperationRecord
16 | operationRecordRouter.DELETE("deleteSysOperationRecordByIds", authorityMenuApi.DeleteSysOperationRecordByIds) // 批量删除SysOperationRecord
17 | operationRecordRouter.GET("findSysOperationRecord", authorityMenuApi.FindSysOperationRecord) // 根据ID获取SysOperationRecord
18 | operationRecordRouter.GET("getSysOperationRecordList", authorityMenuApi.GetSysOperationRecordList) // 获取SysOperationRecord列表
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/server/middleware/casbin_rbac.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 |
7 | "github.com/flipped-aurora/gin-vue-admin/server/global"
8 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
9 | "github.com/flipped-aurora/gin-vue-admin/server/service"
10 | "github.com/flipped-aurora/gin-vue-admin/server/utils"
11 | "github.com/gin-gonic/gin"
12 | )
13 |
14 | var casbinService = service.ServiceGroupApp.SystemServiceGroup.CasbinService
15 |
16 | // CasbinHandler 拦截器
17 | func CasbinHandler() gin.HandlerFunc {
18 | return func(c *gin.Context) {
19 | if global.GVA_CONFIG.System.Env != "develop" {
20 | waitUse, _ := utils.GetClaims(c)
21 | //获取请求的PATH
22 | path := c.Request.URL.Path
23 | obj := strings.TrimPrefix(path, global.GVA_CONFIG.System.RouterPrefix)
24 | // 获取请求方法
25 | act := c.Request.Method
26 | // 获取用户的角色
27 | sub := strconv.Itoa(int(waitUse.AuthorityId))
28 | e := casbinService.Casbin() // 判断策略中是否存在
29 | success, _ := e.Enforce(sub, obj, act)
30 | if !success {
31 | response.FailWithDetailed(gin.H{}, "权限不足", c)
32 | c.Abort()
33 | return
34 | }
35 | }
36 | c.Next()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/gin-vue-admin.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "server",
5 | "name": "backend"
6 | },
7 | {
8 | "path": "web",
9 | "name": "frontend"
10 | },
11 | {
12 | "path": ".",
13 | "name": "root"
14 | }
15 | ],
16 | "settings": {
17 | "go.toolsEnvVars": {
18 | "GOPROXY": "https://goproxy.cn,direct",
19 | "GONOPROXY": "none;"
20 | }
21 | },
22 | "launch": {
23 | "version": "0.2.0",
24 | "configurations": [
25 | {
26 | "type": "go",
27 | "request": "launch",
28 | "name": "Backend",
29 | "cwd": "${workspaceFolder:backend}",
30 | "program": "${workspaceFolder:backend}/"
31 | },
32 | {
33 | "type": "node",
34 | "request": "launch",
35 | "cwd": "${workspaceFolder:frontend}",
36 | "name": "Frontend",
37 | "runtimeExecutable": "npm",
38 | "runtimeArgs": ["run-script", "serve"]
39 | }
40 | ],
41 | "compounds": [
42 | {
43 | "name": "Both (Backend & Frontend)",
44 | "configurations": ["Backend", "Frontend"],
45 | "stopAll": true
46 | }
47 | ]
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/web/src/main.js:
--------------------------------------------------------------------------------
1 | import 'element-plus/es/components/message/style/css'
2 | import 'element-plus/es/components/loading/style/css'
3 | import 'element-plus/es/components/notification/style/css'
4 | import 'element-plus/es/components/message-box/style/css'
5 | import './style/element_visiable.scss'
6 | import { createApp } from 'vue'
7 | // 引入gin-vue-admin前端初始化相关内容
8 | import './core/gin-vue-admin'
9 | // 引入封装的router
10 | import router from '@/router/index'
11 | import '@/permission'
12 | import run from '@/core/gin-vue-admin.js'
13 | import auth from '@/directive/auth'
14 | import { store } from '@/pinia'
15 | import App from './App.vue'
16 | import { initDom } from './utils/positionToCode'
17 |
18 | initDom()
19 | /**
20 | * @description 导入加载进度条,防止首屏加载时间过长,用户等待
21 | *
22 | * */
23 | import Nprogress from 'nprogress'
24 | import 'nprogress/nprogress.css'
25 | Nprogress.configure({ showSpinner: false, ease: 'ease', speed: 500 })
26 | Nprogress.start()
27 |
28 | /**
29 | * 无需在这块结束,会在路由中间件中结束此块内容
30 | * */
31 |
32 | const app = createApp(App)
33 | app.config.productionTip = false
34 |
35 | app
36 | .use(run)
37 | .use(store)
38 | .use(auth)
39 | .use(router)
40 | .mount('#app')
41 |
42 | export default app
43 |
--------------------------------------------------------------------------------
/server/initialize/gorm_sqlite.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/config"
5 | "github.com/flipped-aurora/gin-vue-admin/server/global"
6 | "github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
7 | "github.com/glebarez/sqlite"
8 | "gorm.io/gorm"
9 | )
10 |
11 | // GormSqlite 初始化Sqlite数据库
12 | func GormSqlite() *gorm.DB {
13 | s := global.GVA_CONFIG.Sqlite
14 | if s.Dbname == "" {
15 | return nil
16 | }
17 |
18 | if db, err := gorm.Open(sqlite.Open(s.Dsn()), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil {
19 | panic(err)
20 | } else {
21 | sqlDB, _ := db.DB()
22 | sqlDB.SetMaxIdleConns(s.MaxIdleConns)
23 | sqlDB.SetMaxOpenConns(s.MaxOpenConns)
24 | return db
25 | }
26 | }
27 |
28 | // GormSqliteByConfig 初始化Sqlite数据库用过传入配置
29 | func GormSqliteByConfig(s config.Sqlite) *gorm.DB {
30 | if s.Dbname == "" {
31 | return nil
32 | }
33 |
34 | if db, err := gorm.Open(sqlite.Open(s.Dsn()), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil {
35 | panic(err)
36 | } else {
37 | sqlDB, _ := db.DB()
38 | sqlDB.SetMaxIdleConns(s.MaxIdleConns)
39 | sqlDB.SetMaxOpenConns(s.MaxOpenConns)
40 | return db
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/server/router/system/sys_dictionary.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type DictionaryRouter struct{}
10 |
11 | func (s *DictionaryRouter) InitSysDictionaryRouter(Router *gin.RouterGroup) {
12 | sysDictionaryRouter := Router.Group("sysDictionary").Use(middleware.OperationRecord())
13 | sysDictionaryRouterWithoutRecord := Router.Group("sysDictionary")
14 | sysDictionaryApi := v1.ApiGroupApp.SystemApiGroup.DictionaryApi
15 | {
16 | sysDictionaryRouter.POST("createSysDictionary", sysDictionaryApi.CreateSysDictionary) // 新建SysDictionary
17 | sysDictionaryRouter.DELETE("deleteSysDictionary", sysDictionaryApi.DeleteSysDictionary) // 删除SysDictionary
18 | sysDictionaryRouter.PUT("updateSysDictionary", sysDictionaryApi.UpdateSysDictionary) // 更新SysDictionary
19 | }
20 | {
21 | sysDictionaryRouterWithoutRecord.GET("findSysDictionary", sysDictionaryApi.FindSysDictionary) // 根据ID获取SysDictionary
22 | sysDictionaryRouterWithoutRecord.GET("getSysDictionaryList", sysDictionaryApi.GetSysDictionaryList) // 获取SysDictionary列表
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/server/utils/ast/ast.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "fmt"
5 | "go/ast"
6 | "go/token"
7 | )
8 |
9 | // 增加 import 方法
10 | func AddImport(astNode ast.Node, imp string) {
11 | impStr := fmt.Sprintf("\"%s\"", imp)
12 | ast.Inspect(astNode, func(node ast.Node) bool {
13 | if genDecl, ok := node.(*ast.GenDecl); ok {
14 | if genDecl.Tok == token.IMPORT {
15 | for i := range genDecl.Specs {
16 | if impNode, ok := genDecl.Specs[i].(*ast.ImportSpec); ok {
17 | if impNode.Path.Value == impStr {
18 | return false
19 | }
20 | }
21 | }
22 | genDecl.Specs = append(genDecl.Specs, &ast.ImportSpec{
23 | Path: &ast.BasicLit{
24 | Kind: token.STRING,
25 | Value: impStr,
26 | },
27 | })
28 | }
29 | }
30 | return true
31 | })
32 | }
33 |
34 | // 查询特定function方法
35 | func FindFunction(astNode ast.Node, FunctionName string) *ast.FuncDecl {
36 | var funcDeclP *ast.FuncDecl
37 | ast.Inspect(astNode, func(node ast.Node) bool {
38 | if funcDecl, ok := node.(*ast.FuncDecl); ok {
39 | if funcDecl.Name.String() == FunctionName {
40 | funcDeclP = funcDecl
41 | return false
42 | }
43 | }
44 | return true
45 | })
46 | return funcDeclP
47 | }
48 |
--------------------------------------------------------------------------------
/server/utils/ast/ast_auto_enter.go:
--------------------------------------------------------------------------------
1 | package ast
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "go/ast"
7 | "go/parser"
8 | "go/printer"
9 | "go/token"
10 | "os"
11 | )
12 |
13 | func ImportForAutoEnter(path string, funcName string, code string) {
14 | src, err := os.ReadFile(path)
15 | if err != nil {
16 | fmt.Println(err)
17 | }
18 | fileSet := token.NewFileSet()
19 | astFile, err := parser.ParseFile(fileSet, "", src, 0)
20 | ast.Inspect(astFile, func(node ast.Node) bool {
21 | if typeSpec, ok := node.(*ast.TypeSpec); ok {
22 | if typeSpec.Name.Name == funcName {
23 | if st, ok := typeSpec.Type.(*ast.StructType); ok {
24 | for i := range st.Fields.List {
25 | if t, ok := st.Fields.List[i].Type.(*ast.Ident); ok {
26 | if t.Name == code {
27 | return false
28 | }
29 | }
30 | }
31 | sn := &ast.Field{
32 | Type: &ast.Ident{Name: code},
33 | }
34 | st.Fields.List = append(st.Fields.List, sn)
35 | }
36 | }
37 | }
38 | return true
39 | })
40 | var out []byte
41 | bf := bytes.NewBuffer(out)
42 | err = printer.Fprint(bf, fileSet, astFile)
43 | if err != nil {
44 | return
45 | }
46 | _ = os.WriteFile(path, bf.Bytes(), 0666)
47 | }
48 |
--------------------------------------------------------------------------------
/web/.docker-compose/nginx/conf.d/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name localhost;
4 |
5 | #charset koi8-r;
6 | #access_log logs/host.access.log main;
7 |
8 | location / {
9 | root /usr/share/nginx/html/dist;
10 | add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
11 | try_files $uri $uri/ /index.html;
12 | }
13 |
14 | location /api {
15 | proxy_set_header Host $http_host;
16 | proxy_set_header X-Real-IP $remote_addr;
17 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
18 | proxy_set_header X-Forwarded-Proto $scheme;
19 | rewrite ^/api/(.*)$ /$1 break; #重写
20 | proxy_pass http://127.0.0.1:8888; # 设置代理服务器的协议和地址
21 | }
22 | location /form-generator {
23 | proxy_set_header Host $http_host;
24 | proxy_set_header X-Real-IP $remote_addr;
25 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
26 | proxy_set_header X-Forwarded-Proto $scheme;
27 | proxy_pass http://127.0.0.1:8888;
28 | }
29 | location /api/swagger/index.html {
30 | proxy_pass http://127.0.0.1:8888/swagger/index.html;
31 | }
32 | }
--------------------------------------------------------------------------------
/web/src/api/breakpoint.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Summary 设置角色资源权限
3 | // @Security ApiKeyAuth
4 | // @accept application/json
5 | // @Produce application/json
6 | // @Param data body sysModel.SysAuthority true "设置角色资源权限"
7 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
8 | // @Router /authority/setDataAuthority [post]
9 |
10 | export const findFile = (params) => {
11 | return service({
12 | url: '/fileUploadAndDownload/findFile',
13 | method: 'get',
14 | params
15 | })
16 | }
17 |
18 | export const breakpointContinue = (data) => {
19 | return service({
20 | url: '/fileUploadAndDownload/breakpointContinue',
21 | method: 'post',
22 | donNotShowLoading: true,
23 | headers: { 'Content-Type': 'multipart/form-data' },
24 | data
25 | })
26 | }
27 |
28 | export const breakpointContinueFinish = (params) => {
29 | return service({
30 | url: '/fileUploadAndDownload/breakpointContinueFinish',
31 | method: 'post',
32 | params
33 | })
34 | }
35 |
36 | export const removeChunk = (data, params) => {
37 | return service({
38 | url: '/fileUploadAndDownload/removeChunk',
39 | method: 'post',
40 | data,
41 | params
42 | })
43 | }
44 |
--------------------------------------------------------------------------------
/server/packfile/usePackFile.go:
--------------------------------------------------------------------------------
1 | //go:build packfile
2 | // +build packfile
3 |
4 | package packfile
5 |
6 | import (
7 | "fmt"
8 | "os"
9 | "path/filepath"
10 | "strings"
11 | )
12 |
13 | //go:generate go-bindata -o=staticFile.go -pkg=packfile -tags=packfile ../resource/... ../config.yaml
14 |
15 | func writeFile(path string, data []byte) {
16 | // 如果文件夹不存在,预先创建文件夹
17 | if lastSeparator := strings.LastIndex(path, "/"); lastSeparator != -1 {
18 | dirPath := path[:lastSeparator]
19 | if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) {
20 | os.MkdirAll(dirPath, os.ModePerm)
21 | }
22 | }
23 |
24 | // 已存在的文件,不应该覆盖重写,可能在前端更改了配置文件等
25 | if _, err := os.Stat(path); os.IsNotExist(err) {
26 | if err2 := os.WriteFile(path, data, os.ModePerm); err2 != nil {
27 | fmt.Printf("Write file failed: %s\n", path)
28 | }
29 | } else {
30 | fmt.Printf("File exist, skip: %s\n", path)
31 | }
32 | }
33 |
34 | func init() {
35 | for key := range _bindata {
36 | filePath, _ := filepath.Abs(strings.TrimPrefix(key, "."))
37 | data, err := Asset(key)
38 | if err != nil {
39 | // Asset was not found.
40 | fmt.Printf("Fail to find: %s\n", filePath)
41 | } else {
42 | writeFile(filePath, data)
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/web/src/view/systemTools/installPlugin/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 | 拖拽或点击上传
15 |
16 |
17 |
18 | 请把安装包的zip拖拽至此处上传
19 |
20 |
21 |
22 |
23 |
24 |
25 |
44 |
--------------------------------------------------------------------------------
/server/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "go.uber.org/zap"
5 |
6 | "github.com/flipped-aurora/gin-vue-admin/server/core"
7 | "github.com/flipped-aurora/gin-vue-admin/server/global"
8 | "github.com/flipped-aurora/gin-vue-admin/server/initialize"
9 | )
10 |
11 | //go:generate go env -w GO111MODULE=on
12 | //go:generate go env -w GOPROXY=https://goproxy.cn,direct
13 | //go:generate go mod tidy
14 | //go:generate go mod download
15 |
16 | // @title Swagger Example API
17 | // @version 0.0.1
18 | // @description This is a sample Server pets
19 | // @securityDefinitions.apikey ApiKeyAuth
20 | // @in header
21 | // @name x-token
22 | // @BasePath /
23 | func main() {
24 | global.GVA_VP = core.Viper() // 初始化Viper
25 | initialize.OtherInit()
26 | global.GVA_LOG = core.Zap() // 初始化zap日志库
27 | zap.ReplaceGlobals(global.GVA_LOG)
28 | global.GVA_DB = initialize.Gorm() // gorm连接数据库
29 | initialize.Timer()
30 | initialize.DBList()
31 | if global.GVA_DB != nil {
32 | initialize.RegisterTables() // 初始化表
33 | // 程序结束前关闭数据库链接
34 | db, _ := global.GVA_DB.DB()
35 | defer db.Close()
36 | }
37 | core.RunWindowsServer()
38 | }
39 |
--------------------------------------------------------------------------------
/web/src/directive/auth.js:
--------------------------------------------------------------------------------
1 | // 权限按钮展示指令
2 | import { useUserStore } from '@/pinia/modules/user'
3 | export default {
4 | install: (app) => {
5 | const userStore = useUserStore()
6 | app.directive('auth', {
7 | // 当被绑定的元素插入到 DOM 中时……
8 | mounted: function(el, binding) {
9 | const userInfo = userStore.userInfo
10 | let type = ''
11 | switch (Object.prototype.toString.call(binding.value)) {
12 | case '[object Array]':
13 | type = 'Array'
14 | break
15 | case '[object String]':
16 | type = 'String'
17 | break
18 | case '[object Number]':
19 | type = 'Number'
20 | break
21 | default:
22 | type = ''
23 | break
24 | }
25 | if (type === '') {
26 | el.parentNode.removeChild(el)
27 | return
28 | }
29 | const waitUse = binding.value.toString().split(',')
30 | let flag = waitUse.some(item => Number(item) === userInfo.authorityId)
31 | if (binding.modifiers.not) {
32 | flag = !flag
33 | }
34 | if (!flag) {
35 | el.parentNode.removeChild(el)
36 | }
37 | }
38 | })
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/server/initialize/plugin.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/flipped-aurora/gin-vue-admin/server/global"
7 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
8 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/email"
9 | "github.com/flipped-aurora/gin-vue-admin/server/utils/plugin"
10 | "github.com/gin-gonic/gin"
11 | )
12 |
13 | func PluginInit(group *gin.RouterGroup, Plugin ...plugin.Plugin) {
14 | for i := range Plugin {
15 | PluginGroup := group.Group(Plugin[i].RouterPath())
16 | Plugin[i].Register(PluginGroup)
17 | }
18 | }
19 |
20 | func InstallPlugin(Router *gin.Engine) {
21 | PublicGroup := Router.Group("")
22 | fmt.Println("无鉴权插件安装==》", PublicGroup)
23 | PrivateGroup := Router.Group("")
24 | fmt.Println("鉴权插件安装==》", PrivateGroup)
25 | PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
26 | // 添加跟角色挂钩权限的插件 示例 本地示例模式于在线仓库模式注意上方的import 可以自行切换 效果相同
27 | PluginInit(PrivateGroup, email.CreateEmailPlug(
28 | global.GVA_CONFIG.Email.To,
29 | global.GVA_CONFIG.Email.From,
30 | global.GVA_CONFIG.Email.Host,
31 | global.GVA_CONFIG.Email.Secret,
32 | global.GVA_CONFIG.Email.Nickname,
33 | global.GVA_CONFIG.Email.Port,
34 | global.GVA_CONFIG.Email.IsSSL,
35 | ))
36 | }
37 |
--------------------------------------------------------------------------------
/server/utils/directory.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "errors"
5 | "os"
6 |
7 | "github.com/flipped-aurora/gin-vue-admin/server/global"
8 | "go.uber.org/zap"
9 | )
10 |
11 | //@author: [piexlmax](https://github.com/piexlmax)
12 | //@function: PathExists
13 | //@description: 文件目录是否存在
14 | //@param: path string
15 | //@return: bool, error
16 |
17 | func PathExists(path string) (bool, error) {
18 | fi, err := os.Stat(path)
19 | if err == nil {
20 | if fi.IsDir() {
21 | return true, nil
22 | }
23 | return false, errors.New("存在同名文件")
24 | }
25 | if os.IsNotExist(err) {
26 | return false, nil
27 | }
28 | return false, err
29 | }
30 |
31 | //@author: [piexlmax](https://github.com/piexlmax)
32 | //@function: CreateDir
33 | //@description: 批量创建文件夹
34 | //@param: dirs ...string
35 | //@return: err error
36 |
37 | func CreateDir(dirs ...string) (err error) {
38 | for _, v := range dirs {
39 | exist, err := PathExists(v)
40 | if err != nil {
41 | return err
42 | }
43 | if !exist {
44 | global.GVA_LOG.Debug("create directory" + v)
45 | if err := os.MkdirAll(v, os.ModePerm); err != nil {
46 | global.GVA_LOG.Error("create directory"+v, zap.Any(" error:", err))
47 | return err
48 | }
49 | }
50 | }
51 | return err
52 | }
53 |
--------------------------------------------------------------------------------
/web/src/utils/date.js:
--------------------------------------------------------------------------------
1 | // 对Date的扩展,将 Date 转化为指定格式的String
2 | // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
3 | // 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
4 | // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
5 | // (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
6 | // eslint-disable-next-line no-extend-native
7 | Date.prototype.Format = function(fmt) {
8 | var o = {
9 | 'M+': this.getMonth() + 1, // 月份
10 | 'd+': this.getDate(), // 日
11 | 'h+': this.getHours(), // 小时
12 | 'm+': this.getMinutes(), // 分
13 | 's+': this.getSeconds(), // 秒
14 | 'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
15 | 'S': this.getMilliseconds() // 毫秒
16 | }
17 | if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)) }
18 | for (var k in o) {
19 | if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) }
20 | }
21 | return fmt
22 | }
23 |
24 | export function formatTimeToStr(times, pattern) {
25 | var d = new Date(times).Format('yyyy-MM-dd hh:mm:ss')
26 | if (pattern) {
27 | d = new Date(times).Format(pattern)
28 | }
29 | return d.toLocaleString()
30 | }
31 |
--------------------------------------------------------------------------------
/server/utils/timer/timed_task_test.go:
--------------------------------------------------------------------------------
1 | package timer
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | "time"
7 |
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | var job = mockJob{}
12 |
13 | type mockJob struct{}
14 |
15 | func (job mockJob) Run() {
16 | mockFunc()
17 | }
18 |
19 | func mockFunc() {
20 | time.Sleep(time.Second)
21 | fmt.Println("1s...")
22 | }
23 |
24 | func TestNewTimerTask(t *testing.T) {
25 | tm := NewTimerTask()
26 | _tm := tm.(*timer)
27 |
28 | {
29 | _, err := tm.AddTaskByFunc("func", "@every 1s", mockFunc)
30 | assert.Nil(t, err)
31 | _, ok := _tm.taskList["func"]
32 | if !ok {
33 | t.Error("no find func")
34 | }
35 | }
36 |
37 | {
38 | _, err := tm.AddTaskByJob("job", "@every 1s", job)
39 | assert.Nil(t, err)
40 | _, ok := _tm.taskList["job"]
41 | if !ok {
42 | t.Error("no find job")
43 | }
44 | }
45 |
46 | {
47 | _, ok := tm.FindCron("func")
48 | if !ok {
49 | t.Error("no find func")
50 | }
51 | _, ok = tm.FindCron("job")
52 | if !ok {
53 | t.Error("no find job")
54 | }
55 | _, ok = tm.FindCron("none")
56 | if ok {
57 | t.Error("find none")
58 | }
59 | }
60 | {
61 | tm.Clear("func")
62 | _, ok := tm.FindCron("func")
63 | if ok {
64 | t.Error("find func")
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/web/src/api/system.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags systrm
3 | // @Summary 获取配置文件内容
4 | // @Security ApiKeyAuth
5 | // @Produce application/json
6 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
7 | // @Router /system/getSystemConfig [post]
8 | export const getSystemConfig = () => {
9 | return service({
10 | url: '/system/getSystemConfig',
11 | method: 'post'
12 | })
13 | }
14 |
15 | // @Tags system
16 | // @Summary 设置配置文件内容
17 | // @Security ApiKeyAuth
18 | // @Produce application/json
19 | // @Param data body sysModel.System true
20 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
21 | // @Router /system/setSystemConfig [post]
22 | export const setSystemConfig = (data) => {
23 | return service({
24 | url: '/system/setSystemConfig',
25 | method: 'post',
26 | data
27 | })
28 | }
29 |
30 | // @Tags system
31 | // @Summary 获取服务器运行状态
32 | // @Security ApiKeyAuth
33 | // @Produce application/json
34 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
35 | // @Router /system/getServerInfo [post]
36 | export const getSystemState = () => {
37 | return service({
38 | url: '/system/getServerInfo',
39 | method: 'post',
40 | donNotShowLoading: true
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/server/utils/zip.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "archive/zip"
5 | "fmt"
6 | "io"
7 | "os"
8 | "path/filepath"
9 | "strings"
10 | )
11 |
12 | // 解压
13 | func Unzip(zipFile string, destDir string) ([]string, error) {
14 | zipReader, err := zip.OpenReader(zipFile)
15 | var paths []string
16 | if err != nil {
17 | return []string{}, err
18 | }
19 | defer zipReader.Close()
20 |
21 | for _, f := range zipReader.File {
22 | if strings.Index(f.Name, "..") > -1 {
23 | return []string{}, fmt.Errorf("%s 文件名不合法", f.Name)
24 | }
25 | fpath := filepath.Join(destDir, f.Name)
26 | paths = append(paths, fpath)
27 | if f.FileInfo().IsDir() {
28 | os.MkdirAll(fpath, os.ModePerm)
29 | } else {
30 | if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
31 | return []string{}, err
32 | }
33 |
34 | inFile, err := f.Open()
35 | if err != nil {
36 | return []string{}, err
37 | }
38 | defer inFile.Close()
39 |
40 | outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
41 | if err != nil {
42 | return []string{}, err
43 | }
44 | defer outFile.Close()
45 |
46 | _, err = io.Copy(outFile, inFile)
47 | if err != nil {
48 | return []string{}, err
49 | }
50 | }
51 | }
52 | return paths, nil
53 | }
54 |
--------------------------------------------------------------------------------
/web/src/pinia/modules/dictionary.js:
--------------------------------------------------------------------------------
1 | import { findSysDictionary } from '@/api/sysDictionary'
2 |
3 | import { defineStore } from 'pinia'
4 | import { ref } from 'vue'
5 |
6 | export const useDictionaryStore = defineStore('dictionary', () => {
7 | const dictionaryMap = ref({})
8 |
9 | const setDictionaryMap = (dictionaryRes) => {
10 | dictionaryMap.value = { ...dictionaryMap.value, ...dictionaryRes }
11 | }
12 |
13 | const getDictionary = async(type) => {
14 | if (dictionaryMap.value[type] && dictionaryMap.value[type].length) {
15 | return dictionaryMap.value[type]
16 | } else {
17 | const res = await findSysDictionary({ type })
18 | if (res.code === 0) {
19 | const dictionaryRes = {}
20 | const dict = []
21 | res.data.resysDictionary.sysDictionaryDetails && res.data.resysDictionary.sysDictionaryDetails.forEach(item => {
22 | dict.push({
23 | label: item.label,
24 | value: item.value
25 | })
26 | })
27 | dictionaryRes[res.data.resysDictionary.type] = dict
28 | setDictionaryMap(dictionaryRes)
29 | return dictionaryMap.value[type]
30 | }
31 | }
32 | }
33 |
34 | return {
35 | dictionaryMap,
36 | setDictionaryMap,
37 | getDictionary
38 | }
39 | })
40 |
--------------------------------------------------------------------------------
/server/resource/plug_template/api/api.go.tpl:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
6 | {{ if .NeedModel }} "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/model" {{ end }}
7 | "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/service"
8 | "github.com/gin-gonic/gin"
9 | "go.uber.org/zap"
10 | )
11 |
12 | type {{ .PlugName}}Api struct{}
13 |
14 | // @Tags {{ .PlugName}}
15 | // @Summary 请手动填写接口功能
16 | // @Produce application/json
17 | // @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}"
18 | // @Router /{{ .RouterGroup}}/routerName [post]
19 | func (p *{{ .PlugName}}Api) ApiName(c *gin.Context) {
20 | {{ if .HasRequest}}
21 | var plug model.Request
22 | _ = c.ShouldBindJSON(&plug)
23 | {{ end }}
24 | if {{ if .HasResponse }} res, {{ end }} err:= service.ServiceGroupApp.PlugService({{ if .HasRequest }}plug{{ end -}}); err != nil {
25 | global.GVA_LOG.Error("失败!", zap.Error(err))
26 | response.FailWithMessage("失败", c)
27 | } else {
28 | {{if .HasResponse }}
29 | response.OkWithDetailed(res,"成功",c)
30 | {{else}}
31 | response.OkWithData("成功", c)
32 | {{ end -}}
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/server/router/system/sys_auto_code.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type AutoCodeRouter struct{}
9 |
10 | func (s *AutoCodeRouter) InitAutoCodeRouter(Router *gin.RouterGroup) {
11 | autoCodeRouter := Router.Group("autoCode")
12 | autoCodeApi := v1.ApiGroupApp.SystemApiGroup.AutoCodeApi
13 | {
14 | autoCodeRouter.GET("getDB", autoCodeApi.GetDB) // 获取数据库
15 | autoCodeRouter.GET("getTables", autoCodeApi.GetTables) // 获取对应数据库的表
16 | autoCodeRouter.GET("getColumn", autoCodeApi.GetColumn) // 获取指定表所有字段信息
17 | autoCodeRouter.POST("preview", autoCodeApi.PreviewTemp) // 获取自动创建代码预览
18 | autoCodeRouter.POST("createTemp", autoCodeApi.CreateTemp) // 创建自动化代码
19 | autoCodeRouter.POST("createPackage", autoCodeApi.CreatePackage) // 创建package包
20 | autoCodeRouter.POST("getPackage", autoCodeApi.GetPackage) // 获取package包
21 | autoCodeRouter.POST("delPackage", autoCodeApi.DelPackage) // 删除package包
22 | autoCodeRouter.POST("createPlug", autoCodeApi.AutoPlug) // 自动插件包模板
23 | autoCodeRouter.POST("installPlugin", autoCodeApi.InstallPlugin) // 自动安装插件
24 | autoCodeRouter.POST("pubPlug", autoCodeApi.PubPlug) // 打包插件
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/server/router/system/sys_api.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type ApiRouter struct{}
10 |
11 | func (s *ApiRouter) InitApiRouter(Router *gin.RouterGroup, RouterPub *gin.RouterGroup) {
12 | apiRouter := Router.Group("api").Use(middleware.OperationRecord())
13 | apiRouterWithoutRecord := Router.Group("api")
14 |
15 | apiPublicRouterWithoutRecord := RouterPub.Group("api")
16 | apiRouterApi := v1.ApiGroupApp.SystemApiGroup.SystemApiApi
17 | {
18 | apiRouter.POST("createApi", apiRouterApi.CreateApi) // 创建Api
19 | apiRouter.POST("deleteApi", apiRouterApi.DeleteApi) // 删除Api
20 | apiRouter.POST("getApiById", apiRouterApi.GetApiById) // 获取单条Api消息
21 | apiRouter.POST("updateApi", apiRouterApi.UpdateApi) // 更新api
22 | apiRouter.DELETE("deleteApisByIds", apiRouterApi.DeleteApisByIds) // 删除选中api
23 | }
24 | {
25 | apiRouterWithoutRecord.POST("getAllApis", apiRouterApi.GetAllApis) // 获取所有api
26 | apiRouterWithoutRecord.POST("getApiList", apiRouterApi.GetApiList) // 获取Api列表
27 | }
28 | {
29 | apiPublicRouterWithoutRecord.GET("freshCasbin", apiRouterApi.FreshCasbin) // 刷新casbin权限
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/server/model/common/response/response.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type Response struct {
10 | Code int `json:"code"`
11 | Data interface{} `json:"data"`
12 | Msg string `json:"msg"`
13 | }
14 |
15 | const (
16 | ERROR = 7
17 | SUCCESS = 0
18 | )
19 |
20 | func Result(code int, data interface{}, msg string, c *gin.Context) {
21 | // 开始时间
22 | c.JSON(http.StatusOK, Response{
23 | code,
24 | data,
25 | msg,
26 | })
27 | }
28 |
29 | func Ok(c *gin.Context) {
30 | Result(SUCCESS, map[string]interface{}{}, "操作成功", c)
31 | }
32 |
33 | func OkWithMessage(message string, c *gin.Context) {
34 | Result(SUCCESS, map[string]interface{}{}, message, c)
35 | }
36 |
37 | func OkWithData(data interface{}, c *gin.Context) {
38 | Result(SUCCESS, data, "查询成功", c)
39 | }
40 |
41 | func OkWithDetailed(data interface{}, message string, c *gin.Context) {
42 | Result(SUCCESS, data, message, c)
43 | }
44 |
45 | func Fail(c *gin.Context) {
46 | Result(ERROR, map[string]interface{}{}, "操作失败", c)
47 | }
48 |
49 | func FailWithMessage(message string, c *gin.Context) {
50 | Result(ERROR, map[string]interface{}{}, message, c)
51 | }
52 |
53 | func FailWithDetailed(data interface{}, message string, c *gin.Context) {
54 | Result(ERROR, data, message, c)
55 | }
56 |
--------------------------------------------------------------------------------
/web/src/api/fileUploadAndDownload.js:
--------------------------------------------------------------------------------
1 | import service from '@/utils/request'
2 | // @Tags FileUploadAndDownload
3 | // @Summary 分页文件列表
4 | // @Security ApiKeyAuth
5 | // @accept application/json
6 | // @Produce application/json
7 | // @Param data body modelInterface.PageInfo true "分页获取文件户列表"
8 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
9 | // @Router /fileUploadAndDownload/getFileList [post]
10 | export const getFileList = (data) => {
11 | return service({
12 | url: '/fileUploadAndDownload/getFileList',
13 | method: 'post',
14 | data
15 | })
16 | }
17 |
18 | // @Tags FileUploadAndDownload
19 | // @Summary 删除文件
20 | // @Security ApiKeyAuth
21 | // @Produce application/json
22 | // @Param data body dbModel.FileUploadAndDownload true "传入文件里面id即可"
23 | // @Success 200 {string} json "{"success":true,"data":{},"msg":"返回成功"}"
24 | // @Router /fileUploadAndDownload/deleteFile [post]
25 | export const deleteFile = (data) => {
26 | return service({
27 | url: '/fileUploadAndDownload/deleteFile',
28 | method: 'post',
29 | data
30 | })
31 | }
32 |
33 | /**
34 | * 编辑文件名或者备注
35 | * @param data
36 | * @returns {*}
37 | */
38 | export const editFileName = (data) => {
39 | return service({
40 | url: '/fileUploadAndDownload/editFileName',
41 | method: 'post',
42 | data
43 | })
44 | }
45 |
--------------------------------------------------------------------------------
/server/global/global.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/flipped-aurora/gin-vue-admin/server/utils/timer"
7 | "github.com/songzhibin97/gkit/cache/local_cache"
8 |
9 | "golang.org/x/sync/singleflight"
10 |
11 | "go.uber.org/zap"
12 |
13 | "github.com/flipped-aurora/gin-vue-admin/server/config"
14 |
15 | "github.com/redis/go-redis/v9"
16 | "github.com/spf13/viper"
17 | "gorm.io/gorm"
18 | )
19 |
20 | var (
21 | GVA_DB *gorm.DB
22 | GVA_DBList map[string]*gorm.DB
23 | GVA_REDIS *redis.Client
24 | GVA_CONFIG config.Server
25 | GVA_VP *viper.Viper
26 | // GVA_LOG *oplogging.Logger
27 | GVA_LOG *zap.Logger
28 | GVA_Timer timer.Timer = timer.NewTimerTask()
29 | GVA_Concurrency_Control = &singleflight.Group{}
30 |
31 | BlackCache local_cache.Cache
32 | lock sync.RWMutex
33 | )
34 |
35 | // GetGlobalDBByDBName 通过名称获取db list中的db
36 | func GetGlobalDBByDBName(dbname string) *gorm.DB {
37 | lock.RLock()
38 | defer lock.RUnlock()
39 | return GVA_DBList[dbname]
40 | }
41 |
42 | // MustGetGlobalDBByDBName 通过名称获取db 如果不存在则panic
43 | func MustGetGlobalDBByDBName(dbname string) *gorm.DB {
44 | lock.RLock()
45 | defer lock.RUnlock()
46 | db, ok := GVA_DBList[dbname]
47 | if !ok || db == nil {
48 | panic("db no init")
49 | }
50 | return db
51 | }
52 |
--------------------------------------------------------------------------------
/server/config/auto_code.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Autocode struct {
4 | TransferRestart bool `mapstructure:"transfer-restart" json:"transfer-restart" yaml:"transfer-restart"`
5 | Root string `mapstructure:"root" json:"root" yaml:"root"`
6 | Server string `mapstructure:"server" json:"server" yaml:"server"`
7 | SApi string `mapstructure:"server-api" json:"server-api" yaml:"server-api"`
8 | SPlug string `mapstructure:"server-plug" json:"server-plug" yaml:"server-plug"`
9 | SInitialize string `mapstructure:"server-initialize" json:"server-initialize" yaml:"server-initialize"`
10 | SModel string `mapstructure:"server-model" json:"server-model" yaml:"server-model"`
11 | SRequest string `mapstructure:"server-request" json:"server-request" yaml:"server-request"`
12 | SRouter string `mapstructure:"server-router" json:"server-router" yaml:"server-router"`
13 | SService string `mapstructure:"server-service" json:"server-service" yaml:"server-service"`
14 | Web string `mapstructure:"web" json:"web" yaml:"web"`
15 | WApi string `mapstructure:"web-api" json:"web-api" yaml:"web-api"`
16 | WForm string `mapstructure:"web-form" json:"web-form" yaml:"web-form"`
17 | WTable string `mapstructure:"web-table" json:"web-table" yaml:"web-table"`
18 | }
19 |
--------------------------------------------------------------------------------
/server/router/system/sys_user.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type UserRouter struct{}
10 |
11 | func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) {
12 | userRouter := Router.Group("user").Use(middleware.OperationRecord())
13 | userRouterWithoutRecord := Router.Group("user")
14 | baseApi := v1.ApiGroupApp.SystemApiGroup.BaseApi
15 | {
16 | userRouter.POST("admin_register", baseApi.Register) // 管理员注册账号
17 | userRouter.POST("changePassword", baseApi.ChangePassword) // 用户修改密码
18 | userRouter.POST("setUserAuthority", baseApi.SetUserAuthority) // 设置用户权限
19 | userRouter.DELETE("deleteUser", baseApi.DeleteUser) // 删除用户
20 | userRouter.PUT("setUserInfo", baseApi.SetUserInfo) // 设置用户信息
21 | userRouter.PUT("setSelfInfo", baseApi.SetSelfInfo) // 设置自身信息
22 | userRouter.POST("setUserAuthorities", baseApi.SetUserAuthorities) // 设置用户权限组
23 | userRouter.POST("resetPassword", baseApi.ResetPassword) // 设置用户权限组
24 | }
25 | {
26 | userRouterWithoutRecord.POST("getUserList", baseApi.GetUserList) // 分页获取用户列表
27 | userRouterWithoutRecord.GET("getUserInfo", baseApi.GetUserInfo) // 获取自身信息
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/web/src/view/layout/screenfull/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
13 |
14 |
54 |
55 |
65 |
--------------------------------------------------------------------------------
/server/router/system/sys_dictionary_detail.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type DictionaryDetailRouter struct{}
10 |
11 | func (s *DictionaryDetailRouter) InitSysDictionaryDetailRouter(Router *gin.RouterGroup) {
12 | dictionaryDetailRouter := Router.Group("sysDictionaryDetail").Use(middleware.OperationRecord())
13 | dictionaryDetailRouterWithoutRecord := Router.Group("sysDictionaryDetail")
14 | sysDictionaryDetailApi := v1.ApiGroupApp.SystemApiGroup.DictionaryDetailApi
15 | {
16 | dictionaryDetailRouter.POST("createSysDictionaryDetail", sysDictionaryDetailApi.CreateSysDictionaryDetail) // 新建SysDictionaryDetail
17 | dictionaryDetailRouter.DELETE("deleteSysDictionaryDetail", sysDictionaryDetailApi.DeleteSysDictionaryDetail) // 删除SysDictionaryDetail
18 | dictionaryDetailRouter.PUT("updateSysDictionaryDetail", sysDictionaryDetailApi.UpdateSysDictionaryDetail) // 更新SysDictionaryDetail
19 | }
20 | {
21 | dictionaryDetailRouterWithoutRecord.GET("findSysDictionaryDetail", sysDictionaryDetailApi.FindSysDictionaryDetail) // 根据ID获取SysDictionaryDetail
22 | dictionaryDetailRouterWithoutRecord.GET("getSysDictionaryDetailList", sysDictionaryDetailApi.GetSysDictionaryDetailList) // 获取SysDictionaryDetail列表
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/server/service/system/sys_auto_code_interface.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/global"
5 | "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
6 | )
7 |
8 | type Database interface {
9 | GetDB(businessDB string) (data []response.Db, err error)
10 | GetTables(businessDB string, dbName string) (data []response.Table, err error)
11 | GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error)
12 | }
13 |
14 | func (autoCodeService *AutoCodeService) Database(businessDB string) Database {
15 |
16 | if businessDB == "" {
17 | switch global.GVA_CONFIG.System.DbType {
18 | case "mysql":
19 | return AutoCodeMysql
20 | case "pgsql":
21 | return AutoCodePgsql
22 | case "sqlite":
23 | return AutoCodeSqlite
24 | default:
25 | return AutoCodeMysql
26 | }
27 | } else {
28 | for _, info := range global.GVA_CONFIG.DBList {
29 | if info.AliasName == businessDB {
30 | switch info.Type {
31 | case "mysql":
32 | return AutoCodeMysql
33 | case "mssql":
34 | return AutoCodeMssql
35 | case "pgsql":
36 | return AutoCodePgsql
37 | case "oracle":
38 | return AutoCodeOracle
39 | case "sqlite":
40 | return AutoCodeSqlite
41 | default:
42 | return AutoCodeMysql
43 | }
44 | }
45 | }
46 | return AutoCodeMysql
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/web/src/view/layout/aside/asideComponent/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
59 |
60 |
--------------------------------------------------------------------------------
/web/src/core/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 网站配置文件
3 | */
4 |
5 | const config = {
6 | appName: 'Gin-Vue-Admin',
7 | appLogo: 'https://www.gin-vue-admin.com/img/logo.png',
8 | showViteLogo: true
9 | }
10 |
11 | export const viteLogo = (env) => {
12 | if (config.showViteLogo) {
13 | const chalk = require('chalk')
14 | console.log(
15 | chalk.green(
16 | `> 欢迎使用Gin-Vue-Admin,开源地址:https://github.com/flipped-aurora/gin-vue-admin`
17 | )
18 | )
19 | console.log(
20 | chalk.green(
21 | `> 当前版本:v2.5.7`
22 | )
23 | )
24 | console.log(
25 | chalk.green(
26 | `> 加群方式:微信:shouzi_1994 QQ群:622360840`
27 | )
28 | )
29 | console.log(
30 | chalk.green(
31 | `> GVA讨论社区:https://support.qq.com/products/371961`
32 | )
33 | )
34 | console.log(
35 | chalk.green(
36 | `> 插件市场:https://plugin.gin-vue-admin.com`
37 | )
38 | )
39 | console.log(
40 | chalk.green(
41 | `> 默认自动化文档地址:http://127.0.0.1:${env.VITE_SERVER_PORT}/swagger/index.html`
42 | )
43 | )
44 | console.log(
45 | chalk.green(
46 | `> 默认前端文件运行地址:http://127.0.0.1:${env.VITE_CLI_PORT}`
47 | )
48 | )
49 | console.log(
50 | chalk.green(
51 | `> 如果项目让您获得了收益,希望您能请团队喝杯可乐:https://www.gin-vue-admin.com/coffee/index.html`
52 | )
53 | )
54 | console.log('\n')
55 | }
56 | }
57 |
58 | export default config
59 |
--------------------------------------------------------------------------------
/server/router/system/sys_menu.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type MenuRouter struct{}
10 |
11 | func (s *MenuRouter) InitMenuRouter(Router *gin.RouterGroup) (R gin.IRoutes) {
12 | menuRouter := Router.Group("menu").Use(middleware.OperationRecord())
13 | menuRouterWithoutRecord := Router.Group("menu")
14 | authorityMenuApi := v1.ApiGroupApp.SystemApiGroup.AuthorityMenuApi
15 | {
16 | menuRouter.POST("addBaseMenu", authorityMenuApi.AddBaseMenu) // 新增菜单
17 | menuRouter.POST("addMenuAuthority", authorityMenuApi.AddMenuAuthority) // 增加menu和角色关联关系
18 | menuRouter.POST("deleteBaseMenu", authorityMenuApi.DeleteBaseMenu) // 删除菜单
19 | menuRouter.POST("updateBaseMenu", authorityMenuApi.UpdateBaseMenu) // 更新菜单
20 | }
21 | {
22 | menuRouterWithoutRecord.POST("getMenu", authorityMenuApi.GetMenu) // 获取菜单树
23 | menuRouterWithoutRecord.POST("getMenuList", authorityMenuApi.GetMenuList) // 分页获取基础menu列表
24 | menuRouterWithoutRecord.POST("getBaseMenuTree", authorityMenuApi.GetBaseMenuTree) // 获取用户动态路由
25 | menuRouterWithoutRecord.POST("getMenuAuthority", authorityMenuApi.GetMenuAuthority) // 获取指定角色menu
26 | menuRouterWithoutRecord.POST("getBaseMenuById", authorityMenuApi.GetBaseMenuById) // 根据id获取菜单
27 | }
28 | return menuRouter
29 | }
30 |
--------------------------------------------------------------------------------
/server/plugin/plugin-tool/utils/check.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "github.com/flipped-aurora/gin-vue-admin/server/global"
6 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
7 | "strconv"
8 | )
9 |
10 | func RegisterApis(apis ...system.SysApi) {
11 | var count int64
12 | var apiPaths []string
13 | for i := range apis {
14 | apiPaths = append(apiPaths, apis[i].Path)
15 | }
16 | global.GVA_DB.Find(&[]system.SysApi{}, "path in (?)", apiPaths).Count(&count)
17 | if count > 0 {
18 | fmt.Println("插件已安装或存在同名路由")
19 | return
20 | }
21 | err := global.GVA_DB.Create(&apis).Error
22 | if err != nil {
23 | fmt.Println(err)
24 | }
25 | }
26 |
27 | func RegisterMenus(menus ...system.SysBaseMenu) {
28 | var count int64
29 | var menuNames []string
30 | parentMenu := menus[0]
31 | otherMenus := menus[1:]
32 | for i := range menus {
33 | menuNames = append(menuNames, menus[i].Name)
34 | }
35 | global.GVA_DB.Find(&[]system.SysBaseMenu{}, "name in (?)", menuNames).Count(&count)
36 | if count > 0 {
37 | fmt.Println("插件已安装或存在同名菜单")
38 | return
39 | }
40 | parentMenu.ParentId = "0"
41 | err := global.GVA_DB.Create(&parentMenu).Error
42 | if err != nil {
43 | fmt.Println(err)
44 | }
45 | for i := range otherMenus {
46 | pid := strconv.Itoa(int(parentMenu.ID))
47 | otherMenus[i].ParentId = pid
48 | }
49 | err = global.GVA_DB.Create(&otherMenus).Error
50 | if err != nil {
51 | fmt.Println(err)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/server/utils/verify.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | var (
4 | IdVerify = Rules{"ID": []string{NotEmpty()}}
5 | ApiVerify = Rules{"Path": {NotEmpty()}, "Description": {NotEmpty()}, "ApiGroup": {NotEmpty()}, "Method": {NotEmpty()}}
6 | MenuVerify = Rules{"Path": {NotEmpty()}, "ParentId": {NotEmpty()}, "Name": {NotEmpty()}, "Component": {NotEmpty()}, "Sort": {Ge("0")}}
7 | MenuMetaVerify = Rules{"Title": {NotEmpty()}}
8 | LoginVerify = Rules{"CaptchaId": {NotEmpty()}, "Username": {NotEmpty()}, "Password": {NotEmpty()}}
9 | RegisterVerify = Rules{"Username": {NotEmpty()}, "NickName": {NotEmpty()}, "Password": {NotEmpty()}, "AuthorityId": {NotEmpty()}}
10 | PageInfoVerify = Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}}
11 | CustomerVerify = Rules{"CustomerName": {NotEmpty()}, "CustomerPhoneData": {NotEmpty()}}
12 | AutoCodeVerify = Rules{"Abbreviation": {NotEmpty()}, "StructName": {NotEmpty()}, "PackageName": {NotEmpty()}, "Fields": {NotEmpty()}}
13 | AutoPackageVerify = Rules{"PackageName": {NotEmpty()}}
14 | AuthorityVerify = Rules{"AuthorityId": {NotEmpty()}, "AuthorityName": {NotEmpty()}}
15 | AuthorityIdVerify = Rules{"AuthorityId": {NotEmpty()}}
16 | OldAuthorityVerify = Rules{"OldAuthorityId": {NotEmpty()}}
17 | ChangePasswordVerify = Rules{"Password": {NotEmpty()}, "NewPassword": {NotEmpty()}}
18 | SetUserAuthorityVerify = Rules{"AuthorityId": {NotEmpty()}}
19 | )
20 |
--------------------------------------------------------------------------------
/server/utils/captcha/redis.go:
--------------------------------------------------------------------------------
1 | package captcha
2 |
3 | import (
4 | "context"
5 | "time"
6 |
7 | "github.com/flipped-aurora/gin-vue-admin/server/global"
8 | "github.com/mojocn/base64Captcha"
9 | "go.uber.org/zap"
10 | )
11 |
12 | func NewDefaultRedisStore() *RedisStore {
13 | return &RedisStore{
14 | Expiration: time.Second * 180,
15 | PreKey: "CAPTCHA_",
16 | }
17 | }
18 |
19 | type RedisStore struct {
20 | Expiration time.Duration
21 | PreKey string
22 | Context context.Context
23 | }
24 |
25 | func (rs *RedisStore) UseWithCtx(ctx context.Context) base64Captcha.Store {
26 | rs.Context = ctx
27 | return rs
28 | }
29 |
30 | func (rs *RedisStore) Set(id string, value string) error {
31 | err := global.GVA_REDIS.Set(rs.Context, rs.PreKey+id, value, rs.Expiration).Err()
32 | if err != nil {
33 | return err
34 | }
35 | return nil
36 | }
37 |
38 | func (rs *RedisStore) Get(key string, clear bool) string {
39 | val, err := global.GVA_REDIS.Get(rs.Context, key).Result()
40 | if err != nil {
41 | global.GVA_LOG.Error("RedisStoreGetError!", zap.Error(err))
42 | return ""
43 | }
44 | if clear {
45 | err := global.GVA_REDIS.Del(rs.Context, key).Err()
46 | if err != nil {
47 | global.GVA_LOG.Error("RedisStoreClearError!", zap.Error(err))
48 | return ""
49 | }
50 | }
51 | return val
52 | }
53 |
54 | func (rs *RedisStore) Verify(id, answer string, clear bool) bool {
55 | key := rs.PreKey + id
56 | v := rs.Get(key, clear)
57 | return v == answer
58 | }
59 |
--------------------------------------------------------------------------------
/server/core/server.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | "github.com/flipped-aurora/gin-vue-admin/server/global"
8 | "github.com/flipped-aurora/gin-vue-admin/server/initialize"
9 | "github.com/flipped-aurora/gin-vue-admin/server/service/system"
10 | "go.uber.org/zap"
11 | )
12 |
13 | type server interface {
14 | ListenAndServe() error
15 | }
16 |
17 | func RunWindowsServer() {
18 | if global.GVA_CONFIG.System.UseMultipoint || global.GVA_CONFIG.System.UseRedis {
19 | // 初始化redis服务
20 | initialize.Redis()
21 | }
22 |
23 | // 从db加载jwt数据
24 | if global.GVA_DB != nil {
25 | system.LoadAll()
26 | }
27 |
28 | Router := initialize.Routers()
29 | Router.Static("/form-generator", "./resource/page")
30 |
31 | address := fmt.Sprintf(":%d", global.GVA_CONFIG.System.Addr)
32 | s := initServer(address, Router)
33 | // 保证文本顺序输出
34 | // In order to ensure that the text order output can be deleted
35 | time.Sleep(10 * time.Microsecond)
36 | global.GVA_LOG.Info("server run success on ", zap.String("address", address))
37 |
38 | fmt.Printf(`
39 | 欢迎使用 gin-vue-admin
40 | 当前版本:v2.5.7
41 | 加群方式:微信号:shouzi_1994 QQ群:622360840
42 | 插件市场:https://plugin.gin-vue-admin.com
43 | GVA讨论社区:https://support.qq.com/products/371961
44 | 默认自动化文档地址:http://127.0.0.1%s/swagger/index.html
45 | 默认前端文件运行地址:http://127.0.0.1:8080
46 | 如果项目让您获得了收益,希望您能请团队喝杯可乐:https://www.gin-vue-admin.com/coffee/index.html
47 | `, address)
48 | global.GVA_LOG.Error(s.ListenAndServe().Error())
49 | }
50 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yaml:
--------------------------------------------------------------------------------
1 | name: 🐛 Bug report
2 | description: Report a bug to help us improve Gin-Vue-Admin
3 | title: "[Bug]: "
4 | labels: [bug]
5 | assignees:
6 | - piexlmax
7 | - songzhibin97
8 | - SliverHorn
9 | - bypanghu
10 | body:
11 | - type: input
12 | id: gva
13 | attributes:
14 | label: gin-vue-admin 版本
15 | description: 请输入您当前使用的项目版本?
16 | placeholder: 2.4.5Beta
17 | validations:
18 | required: true
19 | - type: input
20 | id: node
21 | attributes:
22 | label: Node 版本
23 | description: 请输入您当前使用的NODE版本?
24 | placeholder: v14.16.0
25 | validations:
26 | required: true
27 | - type: input
28 | id: golang
29 | attributes:
30 | label: Golang 版本
31 | description: 请输入您当前使用的GOLANG版本?
32 | placeholder: go 1.16
33 | validations:
34 | required: true
35 | - type: dropdown
36 | id: reappearance
37 | attributes:
38 | label: 是否依旧存在
39 | description: 是否可以在master分支复现此bug?
40 | options:
41 | - 可以
42 | - 不可以
43 | - 未测试
44 | validations:
45 | required: true
46 | - type: textarea
47 | id: desc
48 | attributes:
49 | label: bug描述
50 | description: 请简要描述bug以及复现过程.
51 | placeholder: |
52 | 1. 首先...
53 | 2. 然后...
54 | validations:
55 | required: true
56 | - type: textarea
57 | id: advise
58 | attributes:
59 | label: 修改建议
60 | description: 您有好的建议或者修改方案可以提供给我们。
61 |
--------------------------------------------------------------------------------
/deploy/kubernetes/web/gva-web-deploymemt.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: gva-web
5 | annotations:
6 | flipped-aurora/gin-vue-admin: ui
7 | github: "https://github.com/flipped-aurora/gin-vue-admin.git"
8 | app.kubernetes.io/version: 0.0.1
9 | labels:
10 | app: gva-web
11 | version: gva-vue3
12 | spec:
13 | replicas: 1
14 | selector:
15 | matchLabels:
16 | app: gva-web
17 | version: gva-vue3
18 | template:
19 | metadata:
20 | labels:
21 | app: gva-web
22 | version: gva-vue3
23 | spec:
24 | containers:
25 | - name: gin-vue-admin-nginx-container
26 | image: registry.cn-hangzhou.aliyuncs.com/gva/web:latest
27 | imagePullPolicy: Always
28 | ports:
29 | - containerPort: 8080
30 | name: http
31 | readinessProbe:
32 | tcpSocket:
33 | port: 8080
34 | initialDelaySeconds: 10
35 | periodSeconds: 10
36 | successThreshold: 1
37 | failureThreshold: 3
38 | resources:
39 | limits:
40 | cpu: 500m
41 | memory: 1000Mi
42 | requests:
43 | cpu: 100m
44 | memory: 100Mi
45 | volumeMounts:
46 | - mountPath: /etc/nginx/conf.d/
47 | name: nginx-config
48 | volumes:
49 | - name: nginx-config
50 | configMap:
51 | name: my.conf
52 |
--------------------------------------------------------------------------------
/web/vitePlugin/gvaPosition/index.js:
--------------------------------------------------------------------------------
1 | export default function GvaPosition() {
2 | return {
3 | name: 'gva-position',
4 | apply: 'serve',
5 | transform(code, id) {
6 | const index = id.lastIndexOf('.')
7 | const ext = id.substr(index + 1)
8 | if (ext.toLowerCase() === 'vue') {
9 | return codeLineTrack(code, id)
10 | }
11 | },
12 | }
13 | }
14 |
15 | const codeLineTrack = (code, id) => {
16 | const lineList = code.split('\n')
17 | const newList = []
18 | lineList.forEach((item, index) => {
19 | newList.push(addLineAttr(item, index + 1, id)) // 添加位置属性,index+1为具体的代码行号
20 | })
21 | return newList.join('\n')
22 | }
23 |
24 | const addLineAttr = (lineStr, line, id) => {
25 | if (!/^\s+ {
34 | const skip = [
35 | 'KeepAlive',
36 | 'template',
37 | 'keep-alive',
38 | 'transition',
39 | 'el-',
40 | 'El',
41 | 'router-view',
42 | ]
43 | if (item && !skip.some((i) => item.indexOf(i) > -1)) {
44 | const reg = new RegExp(`${item}`)
45 | const location = `${item} code-location="${id}:${line}"`
46 | lineStr = lineStr.replace(reg, location)
47 | }
48 | })
49 | }
50 | return lineStr
51 | }
52 |
--------------------------------------------------------------------------------
/server/resource/autocode_template/server/router.go.tpl:
--------------------------------------------------------------------------------
1 | package {{.Package}}
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/flipped-aurora/gin-vue-admin/server/middleware"
6 | "github.com/gin-gonic/gin"
7 | )
8 |
9 | type {{.StructName}}Router struct {
10 | }
11 |
12 | // Init{{.StructName}}Router 初始化 {{.StructName}} 路由信息
13 | func (s *{{.StructName}}Router) Init{{.StructName}}Router(Router *gin.RouterGroup) {
14 | {{.Abbreviation}}Router := Router.Group("{{.Abbreviation}}").Use(middleware.OperationRecord())
15 | {{.Abbreviation}}RouterWithoutRecord := Router.Group("{{.Abbreviation}}")
16 | var {{.Abbreviation}}Api = v1.ApiGroupApp.{{.PackageT}}ApiGroup.{{.StructName}}Api
17 | {
18 | {{.Abbreviation}}Router.POST("create{{.StructName}}", {{.Abbreviation}}Api.Create{{.StructName}}) // 新建{{.StructName}}
19 | {{.Abbreviation}}Router.DELETE("delete{{.StructName}}", {{.Abbreviation}}Api.Delete{{.StructName}}) // 删除{{.StructName}}
20 | {{.Abbreviation}}Router.DELETE("delete{{.StructName}}ByIds", {{.Abbreviation}}Api.Delete{{.StructName}}ByIds) // 批量删除{{.StructName}}
21 | {{.Abbreviation}}Router.PUT("update{{.StructName}}", {{.Abbreviation}}Api.Update{{.StructName}}) // 更新{{.StructName}}
22 | }
23 | {
24 | {{.Abbreviation}}RouterWithoutRecord.GET("find{{.StructName}}", {{.Abbreviation}}Api.Find{{.StructName}}) // 根据ID获取{{.StructName}}
25 | {{.Abbreviation}}RouterWithoutRecord.GET("get{{.StructName}}List", {{.Abbreviation}}Api.Get{{.StructName}}List) // 获取{{.StructName}}列表
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/server/model/system/sys_autocode_history.go:
--------------------------------------------------------------------------------
1 | package system
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 |
7 | "github.com/flipped-aurora/gin-vue-admin/server/global"
8 | "github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
9 | )
10 |
11 | // SysAutoCodeHistory 自动迁移代码记录,用于回滚,重放使用
12 | type SysAutoCodeHistory struct {
13 | global.GVA_MODEL
14 | Package string `json:"package"`
15 | BusinessDB string `json:"businessDB"`
16 | TableName string `json:"tableName"`
17 | RequestMeta string `gorm:"type:text" json:"requestMeta,omitempty"` // 前端传入的结构化信息
18 | AutoCodePath string `gorm:"type:text" json:"autoCodePath,omitempty"` // 其他meta信息 path;path
19 | InjectionMeta string `gorm:"type:text" json:"injectionMeta,omitempty"` // 注入的内容 RouterPath@functionName@RouterString;
20 | StructName string `json:"structName"`
21 | StructCNName string `json:"structCNName"`
22 | ApiIDs string `json:"apiIDs,omitempty"` // api表注册内容
23 | Flag int `json:"flag"` // 表示对应状态 0 代表创建, 1 代表回滚 ...
24 | }
25 |
26 | // ToRequestIds ApiIDs 转换 request.IdsReq
27 | // Author [SliverHorn](https://github.com/SliverHorn)
28 | func (m *SysAutoCodeHistory) ToRequestIds() request.IdsReq {
29 | if m.ApiIDs == "" {
30 | return request.IdsReq{}
31 | }
32 | slice := strings.Split(m.ApiIDs, ";")
33 | ids := make([]int, 0, len(slice))
34 | length := len(slice)
35 | for i := 0; i < length; i++ {
36 | id, _ := strconv.ParseInt(slice[i], 10, 32)
37 | ids = append(ids, int(id))
38 | }
39 | return request.IdsReq{Ids: ids}
40 | }
41 |
--------------------------------------------------------------------------------
/server/router/example/exa_file_upload_and_download.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type FileUploadAndDownloadRouter struct{}
9 |
10 | func (e *FileUploadAndDownloadRouter) InitFileUploadAndDownloadRouter(Router *gin.RouterGroup) {
11 | fileUploadAndDownloadRouter := Router.Group("fileUploadAndDownload")
12 | exaFileUploadAndDownloadApi := v1.ApiGroupApp.ExampleApiGroup.FileUploadAndDownloadApi
13 | {
14 | fileUploadAndDownloadRouter.POST("upload", exaFileUploadAndDownloadApi.UploadFile) // 上传文件
15 | fileUploadAndDownloadRouter.POST("getFileList", exaFileUploadAndDownloadApi.GetFileList) // 获取上传文件列表
16 | fileUploadAndDownloadRouter.POST("deleteFile", exaFileUploadAndDownloadApi.DeleteFile) // 删除指定文件
17 | fileUploadAndDownloadRouter.POST("editFileName", exaFileUploadAndDownloadApi.EditFileName) // 编辑文件名或者备注
18 | fileUploadAndDownloadRouter.POST("breakpointContinue", exaFileUploadAndDownloadApi.BreakpointContinue) // 断点续传
19 | fileUploadAndDownloadRouter.GET("findFile", exaFileUploadAndDownloadApi.FindFile) // 查询当前文件成功的切片
20 | fileUploadAndDownloadRouter.POST("breakpointContinueFinish", exaFileUploadAndDownloadApi.BreakpointContinueFinish) // 切片传输完成
21 | fileUploadAndDownloadRouter.POST("removeChunk", exaFileUploadAndDownloadApi.RemoveChunk) // 删除切片
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/web/src/components/richtext/rich-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
60 |
61 |
64 |
--------------------------------------------------------------------------------
/server/model/system/sys_operation_record.go:
--------------------------------------------------------------------------------
1 | // 自动生成模板SysOperationRecord
2 | package system
3 |
4 | import (
5 | "time"
6 |
7 | "github.com/flipped-aurora/gin-vue-admin/server/global"
8 | )
9 |
10 | // 如果含有time.Time 请自行import time包
11 | type SysOperationRecord struct {
12 | global.GVA_MODEL
13 | Ip string `json:"ip" form:"ip" gorm:"column:ip;comment:请求ip"` // 请求ip
14 | Method string `json:"method" form:"method" gorm:"column:method;comment:请求方法"` // 请求方法
15 | Path string `json:"path" form:"path" gorm:"column:path;comment:请求路径"` // 请求路径
16 | Status int `json:"status" form:"status" gorm:"column:status;comment:请求状态"` // 请求状态
17 | Latency time.Duration `json:"latency" form:"latency" gorm:"column:latency;comment:延迟" swaggertype:"string"` // 延迟
18 | Agent string `json:"agent" form:"agent" gorm:"column:agent;comment:代理"` // 代理
19 | ErrorMessage string `json:"error_message" form:"error_message" gorm:"column:error_message;comment:错误信息"` // 错误信息
20 | Body string `json:"body" form:"body" gorm:"type:text;column:body;comment:请求Body"` // 请求Body
21 | Resp string `json:"resp" form:"resp" gorm:"type:text;column:resp;comment:响应Body"` // 响应Body
22 | UserID int `json:"user_id" form:"user_id" gorm:"column:user_id;comment:用户id"` // 用户id
23 | User SysUser `json:"user"`
24 | }
25 |
--------------------------------------------------------------------------------
/server/initialize/gorm_pgsql.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | "github.com/flipped-aurora/gin-vue-admin/server/config"
5 | "github.com/flipped-aurora/gin-vue-admin/server/global"
6 | "github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
7 | "gorm.io/driver/postgres"
8 | "gorm.io/gorm"
9 | )
10 |
11 | // GormPgSql 初始化 Postgresql 数据库
12 | // Author [piexlmax](https://github.com/piexlmax)
13 | // Author [SliverHorn](https://github.com/SliverHorn)
14 | func GormPgSql() *gorm.DB {
15 | p := global.GVA_CONFIG.Pgsql
16 | if p.Dbname == "" {
17 | return nil
18 | }
19 | pgsqlConfig := postgres.Config{
20 | DSN: p.Dsn(), // DSN data source name
21 | PreferSimpleProtocol: false,
22 | }
23 | if db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config(p.Prefix, p.Singular)); err != nil {
24 | return nil
25 | } else {
26 | sqlDB, _ := db.DB()
27 | sqlDB.SetMaxIdleConns(p.MaxIdleConns)
28 | sqlDB.SetMaxOpenConns(p.MaxOpenConns)
29 | return db
30 | }
31 | }
32 |
33 | // GormPgSqlByConfig 初始化 Postgresql 数据库 通过参数
34 | func GormPgSqlByConfig(p config.Pgsql) *gorm.DB {
35 | if p.Dbname == "" {
36 | return nil
37 | }
38 | pgsqlConfig := postgres.Config{
39 | DSN: p.Dsn(), // DSN data source name
40 | PreferSimpleProtocol: false,
41 | }
42 | if db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config(p.Prefix, p.Singular)); err != nil {
43 | panic(err)
44 | } else {
45 | sqlDB, _ := db.DB()
46 | sqlDB.SetMaxIdleConns(p.MaxIdleConns)
47 | sqlDB.SetMaxOpenConns(p.MaxOpenConns)
48 | return db
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/web/src/plugin/email/view/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 发送测试邮件
17 | 发送邮件
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
56 |
57 |
--------------------------------------------------------------------------------
/server/initialize/gorm.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/flipped-aurora/gin-vue-admin/server/global"
7 | "github.com/flipped-aurora/gin-vue-admin/server/model/example"
8 | "github.com/flipped-aurora/gin-vue-admin/server/model/system"
9 |
10 | "go.uber.org/zap"
11 | "gorm.io/gorm"
12 | )
13 |
14 | // Gorm 初始化数据库并产生数据库全局变量
15 | // Author SliverHorn
16 | func Gorm() *gorm.DB {
17 | switch global.GVA_CONFIG.System.DbType {
18 | case "mysql":
19 | return GormMysql()
20 | case "pgsql":
21 | return GormPgSql()
22 | case "oracle":
23 | return GormOracle()
24 | case "mssql":
25 | return GormMssql()
26 | case "sqlite":
27 | return GormSqlite()
28 | default:
29 | return GormMysql()
30 | }
31 | }
32 |
33 | // RegisterTables 注册数据库表专用
34 | // Author SliverHorn
35 | func RegisterTables() {
36 | db := global.GVA_DB
37 | err := db.AutoMigrate(
38 | // 系统模块表
39 | system.SysApi{},
40 | system.SysUser{},
41 | system.SysBaseMenu{},
42 | system.JwtBlacklist{},
43 | system.SysAuthority{},
44 | system.SysDictionary{},
45 | system.SysOperationRecord{},
46 | system.SysAutoCodeHistory{},
47 | system.SysDictionaryDetail{},
48 | system.SysBaseMenuParameter{},
49 | system.SysBaseMenuBtn{},
50 | system.SysAuthorityBtn{},
51 | system.SysAutoCode{},
52 | system.SysChatGptOption{},
53 |
54 | example.ExaFile{},
55 | example.ExaCustomer{},
56 | example.ExaFileChunk{},
57 | example.ExaFileUploadAndDownload{},
58 | )
59 | if err != nil {
60 | global.GVA_LOG.Error("register table failed", zap.Error(err))
61 | os.Exit(0)
62 | }
63 | global.GVA_LOG.Info("register table success")
64 | }
65 |
--------------------------------------------------------------------------------
/server/utils/zipfiles.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "archive/zip"
5 | "io"
6 | "os"
7 | "strings"
8 | )
9 |
10 | //@author: [piexlmax](https://github.com/piexlmax)
11 | //@function: ZipFiles
12 | //@description: 压缩文件
13 | //@param: filename string, files []string, oldForm, newForm string
14 | //@return: error
15 |
16 | func ZipFiles(filename string, files []string, oldForm, newForm string) error {
17 | newZipFile, err := os.Create(filename)
18 | if err != nil {
19 | return err
20 | }
21 | defer func() {
22 | _ = newZipFile.Close()
23 | }()
24 |
25 | zipWriter := zip.NewWriter(newZipFile)
26 | defer func() {
27 | _ = zipWriter.Close()
28 | }()
29 |
30 | // 把files添加到zip中
31 | for _, file := range files {
32 |
33 | err = func(file string) error {
34 | zipFile, err := os.Open(file)
35 | if err != nil {
36 | return err
37 | }
38 | defer zipFile.Close()
39 | // 获取file的基础信息
40 | info, err := zipFile.Stat()
41 | if err != nil {
42 | return err
43 | }
44 |
45 | header, err := zip.FileInfoHeader(info)
46 | if err != nil {
47 | return err
48 | }
49 |
50 | // 使用上面的FileInforHeader() 就可以把文件保存的路径替换成我们自己想要的了,如下面
51 | header.Name = strings.Replace(file, oldForm, newForm, -1)
52 |
53 | // 优化压缩
54 | // 更多参考see http://golang.org/pkg/archive/zip/#pkg-constants
55 | header.Method = zip.Deflate
56 |
57 | writer, err := zipWriter.CreateHeader(header)
58 | if err != nil {
59 | return err
60 | }
61 | if _, err = io.Copy(writer, zipFile); err != nil {
62 | return err
63 | }
64 | return nil
65 | }(file)
66 | if err != nil {
67 | return err
68 | }
69 | }
70 | return nil
71 | }
72 |
--------------------------------------------------------------------------------
/server/initialize/gorm_oracle.go:
--------------------------------------------------------------------------------
1 | package initialize
2 |
3 | import (
4 | //"github.com/dzwvip/oracle"
5 | "github.com/flipped-aurora/gin-vue-admin/server/config"
6 | "github.com/flipped-aurora/gin-vue-admin/server/global"
7 | "github.com/flipped-aurora/gin-vue-admin/server/initialize/internal"
8 |
9 | //_ "github.com/godror/godror"
10 | "gorm.io/driver/mysql"
11 | "gorm.io/gorm"
12 | )
13 |
14 | // GormOracle 初始化oracle数据库
15 | // 如果需要Oracle库 放开import里的注释 把下方 mysql.Config 改为 oracle.Config ; mysql.New 改为 oracle.New
16 | func GormOracle() *gorm.DB {
17 | m := global.GVA_CONFIG.Oracle
18 | if m.Dbname == "" {
19 | return nil
20 | }
21 | oracleConfig := mysql.Config{
22 | DSN: m.Dsn(), // DSN data source name
23 | DefaultStringSize: 191, // string 类型字段的默认长度
24 | }
25 | if db, err := gorm.Open(mysql.New(oracleConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
26 | panic(err)
27 | } else {
28 | sqlDB, _ := db.DB()
29 | sqlDB.SetMaxIdleConns(m.MaxIdleConns)
30 | sqlDB.SetMaxOpenConns(m.MaxOpenConns)
31 | return db
32 | }
33 | }
34 |
35 | // GormOracleByConfig 初始化Oracle数据库用过传入配置
36 | func GormOracleByConfig(m config.Oracle) *gorm.DB {
37 | if m.Dbname == "" {
38 | return nil
39 | }
40 | oracleConfig := mysql.Config{
41 | DSN: m.Dsn(), // DSN data source name
42 | DefaultStringSize: 191, // string 类型字段的默认长度
43 | }
44 | if db, err := gorm.Open(mysql.New(oracleConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
45 | panic(err)
46 | } else {
47 | sqlDB, _ := db.DB()
48 | sqlDB.SetMaxIdleConns(m.MaxIdleConns)
49 | sqlDB.SetMaxOpenConns(m.MaxOpenConns)
50 | return db
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/web/src/components/selectFile/selectFile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 | 上传文件
14 |
15 |
16 |
17 |
18 |
65 |
66 |
75 |
--------------------------------------------------------------------------------
/server/initialize/internal/gorm.go:
--------------------------------------------------------------------------------
1 | package internal
2 |
3 | import (
4 | "gorm.io/gorm/schema"
5 | "log"
6 | "os"
7 | "time"
8 |
9 | "github.com/flipped-aurora/gin-vue-admin/server/global"
10 | "gorm.io/gorm"
11 | "gorm.io/gorm/logger"
12 | )
13 |
14 | type DBBASE interface {
15 | GetLogMode() string
16 | }
17 |
18 | var Gorm = new(_gorm)
19 |
20 | type _gorm struct{}
21 |
22 | // Config gorm 自定义配置
23 | // Author [SliverHorn](https://github.com/SliverHorn)
24 | func (g *_gorm) Config(prefix string, singular bool) *gorm.Config {
25 | config := &gorm.Config{
26 | NamingStrategy: schema.NamingStrategy{
27 | TablePrefix: prefix,
28 | SingularTable: singular,
29 | },
30 | DisableForeignKeyConstraintWhenMigrating: true,
31 | }
32 | _default := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
33 | SlowThreshold: 200 * time.Millisecond,
34 | LogLevel: logger.Warn,
35 | Colorful: true,
36 | })
37 | var logMode DBBASE
38 | switch global.GVA_CONFIG.System.DbType {
39 | case "mysql":
40 | logMode = &global.GVA_CONFIG.Mysql
41 | case "pgsql":
42 | logMode = &global.GVA_CONFIG.Pgsql
43 | case "oracle":
44 | logMode = &global.GVA_CONFIG.Oracle
45 | default:
46 | logMode = &global.GVA_CONFIG.Mysql
47 | }
48 |
49 | switch logMode.GetLogMode() {
50 | case "silent", "Silent":
51 | config.Logger = _default.LogMode(logger.Silent)
52 | case "error", "Error":
53 | config.Logger = _default.LogMode(logger.Error)
54 | case "warn", "Warn":
55 | config.Logger = _default.LogMode(logger.Warn)
56 | case "info", "Info":
57 | config.Logger = _default.LogMode(logger.Info)
58 | default:
59 | config.Logger = _default.LogMode(logger.Info)
60 | }
61 | return config
62 | }
63 |
--------------------------------------------------------------------------------
/web/src/view/layout/search/search.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
32 |
79 |
--------------------------------------------------------------------------------
/web/vitePlugin/codeServer/index.js:
--------------------------------------------------------------------------------
1 | const child_process = require('child_process')
2 | import * as dotenv from 'dotenv'
3 | import * as fs from 'fs'
4 |
5 | const NODE_ENV = process.env.NODE_ENV || 'development'
6 | const envFiles = [`.env.${NODE_ENV}`]
7 | for (const file of envFiles) {
8 | const envConfig = dotenv.parse(fs.readFileSync(file))
9 | for (const k in envConfig) {
10 | process.env[k] = envConfig[k]
11 | }
12 | }
13 |
14 | export default function GvaPositionServer() {
15 | return {
16 | name: 'gva-position-server',
17 | apply: 'serve',
18 | configureServer(server) {
19 | server.middlewares.use((req, _, next) => {
20 | if (req._parsedUrl.pathname === '/gvaPositionCode') {
21 | const path =
22 | req._parsedUrl.query && req._parsedUrl.query.split('=')[1]
23 | if (path && path !== 'null') {
24 | if (process.env.VITE_EDITOR === 'webstorm') {
25 | const linePath = path.split(':')[1]
26 | const filePath = path.split(':')[0]
27 | const platform = os()
28 | if (platform === 'win32') {
29 | child_process.exec(
30 | `webstorm64.exe --line ${linePath} ${filePath}`
31 | )
32 | } else {
33 | child_process.exec(
34 | `webstorm --line ${linePath} ${filePath}`
35 | )
36 | }
37 | } else {
38 | child_process.exec('code -r -g ' + path)
39 | }
40 | }
41 | }
42 | next()
43 | })
44 | },
45 | }
46 | }
47 |
48 | function os() {
49 | 'use strict'
50 | const os = require('os')
51 | const platform = os.platform()
52 | return platform
53 | }
54 |
--------------------------------------------------------------------------------
/server/config/config.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | type Server struct {
4 | JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
5 | Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"`
6 | Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"`
7 | Email Email `mapstructure:"email" json:"email" yaml:"email"`
8 | System System `mapstructure:"system" json:"system" yaml:"system"`
9 | Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"`
10 | // auto
11 | AutoCode Autocode `mapstructure:"autocode" json:"autocode" yaml:"autocode"`
12 | // gorm
13 | Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
14 | Mssql Mssql `mapstructure:"mssql" json:"mssql" yaml:"mssql"`
15 | Pgsql Pgsql `mapstructure:"pgsql" json:"pgsql" yaml:"pgsql"`
16 | Oracle Oracle `mapstructure:"oracle" json:"oracle" yaml:"oracle"`
17 | Sqlite Sqlite `mapstructure:"sqlite" json:"sqlite" yaml:"sqlite"`
18 | DBList []SpecializedDB `mapstructure:"db-list" json:"db-list" yaml:"db-list"`
19 | // oss
20 | Local Local `mapstructure:"local" json:"local" yaml:"local"`
21 | Qiniu Qiniu `mapstructure:"qiniu" json:"qiniu" yaml:"qiniu"`
22 | AliyunOSS AliyunOSS `mapstructure:"aliyun-oss" json:"aliyun-oss" yaml:"aliyun-oss"`
23 | HuaWeiObs HuaWeiObs `mapstructure:"hua-wei-obs" json:"hua-wei-obs" yaml:"hua-wei-obs"`
24 | TencentCOS TencentCOS `mapstructure:"tencent-cos" json:"tencent-cos" yaml:"tencent-cos"`
25 | AwsS3 AwsS3 `mapstructure:"aws-s3" json:"aws-s3" yaml:"aws-s3"`
26 |
27 | Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"`
28 | Timer Timer `mapstructure:"timer" json:"timer" yaml:"timer"`
29 |
30 | // 跨域配置
31 | Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"`
32 | }
33 |
--------------------------------------------------------------------------------
/web/src/components/upload/common.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 | 普通上传
13 |
14 |
15 |
16 |
17 |
61 |
62 |
71 |
--------------------------------------------------------------------------------