├── static
├── uploadfile
│ ├── log.txt
│ └── 77cfc1dd-535c-4e60-b34a-5909e2cf5ed0.jpg
└── form-generator
│ ├── css
│ └── parser-example.69e16e51.css
│ ├── img
│ └── logo.e1bc3747.png
│ ├── js
│ └── tinymce-example.641995ab.js
│ └── preview.html
├── _config.yml
├── config
├── db-end-mysql.sql
├── db-begin-mysql.sql
├── extend.go
├── READMEN.md
├── settings.demo.yml
├── pg.sql
├── settings.sqlite.yml
├── settings.full.yml
└── settings.yml
├── go-admin-db.db
├── common
├── actions
│ ├── type.go
│ ├── create.go
│ ├── index.go
│ ├── update.go
│ ├── delete.go
│ └── view.go
├── global
│ ├── topic.go
│ ├── adm.go
│ └── casbin.go
├── middleware
│ ├── handler
│ │ ├── ping.go
│ │ ├── httpshandler.go
│ │ ├── role.go
│ │ ├── login.go
│ │ └── user.go
│ ├── db.go
│ ├── demo.go
│ ├── trace.go
│ ├── sentinel.go
│ ├── request_id.go
│ ├── init.go
│ ├── auth.go
│ ├── customerror.go
│ ├── header.go
│ ├── settings.go
│ └── permission.go
├── models
│ ├── menu.go
│ ├── type.go
│ ├── migrate.go
│ ├── response.go
│ ├── by.go
│ └── user.go
├── dto
│ ├── order.go
│ ├── pagination.go
│ ├── type.go
│ ├── search.go
│ ├── generate.go
│ └── auto_form.go
├── file_store
│ ├── obs_test.go
│ ├── oss_test.go
│ ├── kodo_test.go
│ ├── interface.go
│ ├── initialize.go
│ ├── oss.go
│ ├── obs.go
│ └── kodo.go
├── database
│ ├── open.go
│ ├── open_sqlite3.go
│ └── initialize.go
├── service
│ └── service.go
├── ip.go
├── storage
│ └── initialize.go
└── response
│ └── binding.go
├── stop.sh
├── ssh
└── swag.sh
├── scripts
├── Dockerfile
└── k8s
│ ├── prerun.sh
│ ├── storage.yml
│ └── deploy.yml
├── cmd
├── migrate
│ └── migration
│ │ ├── version-local
│ │ └── doc.go
│ │ ├── models
│ │ ├── model.go
│ │ ├── role_dept.go
│ │ ├── tb_demo.go
│ │ ├── sys_dict_type.go
│ │ ├── sys_api.go
│ │ ├── by.go
│ │ ├── sys_post.go
│ │ ├── casbin_rule.go
│ │ ├── sys_config.go
│ │ ├── sys_dept.go
│ │ ├── sys_role.go
│ │ ├── sys_job.go
│ │ ├── sys_dict_data.go
│ │ ├── sys_login_log.go
│ │ ├── sys_menu.go
│ │ ├── sys_user.go
│ │ ├── sys_opera_log.go
│ │ ├── initdb.go
│ │ ├── sys_tables.go
│ │ └── sys_columns.go
│ │ ├── version
│ │ ├── 1653638869132_migrate.go
│ │ └── 1599190683659_tables.go
│ │ └── init.go
├── api
│ ├── jobs.go
│ └── other.go
├── version
│ └── server.go
├── cobra.go
├── config
│ └── server.go
└── app
│ └── server.go
├── template
├── cmd_api.template
├── v4
│ ├── no_actions
│ │ ├── router_no_check_role.go.template
│ │ └── router_check_role.go.template
│ ├── actions
│ │ ├── router_no_check_role.go.template
│ │ └── router_check_role.go.template
│ ├── js.go.template
│ └── model.go.template
├── migrate.template
└── router.template
├── app
├── other
│ ├── service
│ │ └── dto
│ │ │ └── sys_tables.go
│ ├── router
│ │ ├── file.go
│ │ ├── monitor.go
│ │ ├── sys_server_monitor.go
│ │ ├── init_router.go
│ │ ├── router.go
│ │ └── gen_router.go
│ ├── apis
│ │ └── tools
│ │ │ ├── db_columns.go
│ │ │ └── db_tables.go
│ └── models
│ │ └── tools
│ │ ├── db_tables.go
│ │ └── db_columns.go
├── jobs
│ ├── type.go
│ ├── router
│ │ ├── int_router.go
│ │ ├── router.go
│ │ └── sys_job.go
│ ├── examples.go
│ ├── apis
│ │ └── sys_job.go
│ ├── models
│ │ └── sys_job.go
│ └── service
│ │ └── sys_job.go
└── admin
│ ├── models
│ ├── casbin_rule.go
│ ├── sys_dict_type.go
│ ├── sys_config.go
│ ├── sys_post.go
│ ├── sys_dept.go
│ ├── sys_dict_data.go
│ ├── initdb.go
│ ├── sys_role.go
│ ├── sys_menu.go
│ ├── sys_login_log.go
│ ├── sys_user.go
│ └── sys_api.go
│ ├── router
│ ├── sys_api.go
│ ├── sys_opera_log.go
│ ├── sys_login_log.go
│ ├── sys_post.go
│ ├── sys_dept.go
│ ├── sys_menu.go
│ ├── sys_role.go
│ ├── init_router.go
│ ├── router.go
│ ├── sys_config.go
│ ├── sys_user.go
│ ├── sys_dict.go
│ └── sys_router.go
│ ├── apis
│ ├── go_admin.go
│ └── captcha.go
│ └── service
│ ├── sys_login_log.go
│ ├── dto
│ ├── sys_login_log.go
│ ├── sys_dict_type.go
│ └── sys_api.go
│ ├── sys_opera_log.go
│ └── sys_post.go
├── restart.sh
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ └── bug_report.md
├── workflows
│ ├── issue-check-inactive.yml
│ ├── mirror.yaml
│ ├── issue-close-require.yml
│ ├── go.yml
│ ├── codeql-analysis.yml
│ └── build.yml
├── PULL_REQUEST_TEMPLATE
│ └── pr_cn.md
└── PULL_REQUEST_TEMPLATE.md
├── docker-compose.yml
├── .gitignore
├── Dockerfile
├── main.go
├── Dockerfilebak
├── test
├── gen_test.go
└── model.go.template
├── LICENSE.md
└── Makefile
/static/uploadfile/log.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/config/db-end-mysql.sql:
--------------------------------------------------------------------------------
1 | SET FOREIGN_KEY_CHECKS = 1;
--------------------------------------------------------------------------------
/config/db-begin-mysql.sql:
--------------------------------------------------------------------------------
1 | SET NAMES utf8mb4;
2 | SET FOREIGN_KEY_CHECKS = 0;
--------------------------------------------------------------------------------
/go-admin-db.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/go-admin-team/go-admin/HEAD/go-admin-db.db
--------------------------------------------------------------------------------
/common/actions/type.go:
--------------------------------------------------------------------------------
1 | package actions
2 |
3 | const (
4 | PermissionKey = "dataPermission"
5 | )
6 |
--------------------------------------------------------------------------------
/static/form-generator/css/parser-example.69e16e51.css:
--------------------------------------------------------------------------------
1 | .test-form[data-v-77b1aafa]{margin:15px auto;width:800px;padding:15px}
--------------------------------------------------------------------------------
/stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | killall go-admin # kill go-admin service
3 | echo "stop go-admin success"
4 | ps -aux | grep go-admin
--------------------------------------------------------------------------------
/ssh/swag.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | swag i -g init_router.go -dir app/admin/router --instanceName admin --parseDependency -o docs/admin
4 |
--------------------------------------------------------------------------------
/scripts/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine
2 |
3 | COPY ./go-admin /
4 | EXPOSE 8000
5 |
6 | CMD ["/go-admin","server","-c", "/config/settings.yml"]
7 |
--------------------------------------------------------------------------------
/static/form-generator/img/logo.e1bc3747.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/go-admin-team/go-admin/HEAD/static/form-generator/img/logo.e1bc3747.png
--------------------------------------------------------------------------------
/scripts/k8s/prerun.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | kubectl create ns go-admin
3 | kubectl create configmap settings-admin --from-file=../../config/settings.yml -n go-admin
4 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/version-local/doc.go:
--------------------------------------------------------------------------------
1 | package version_local
2 |
3 | func init() {
4 | }
5 |
6 | /**
7 | 开发者项目的迁移脚本放在这个目录里,init写法参考version目录里的migrate或者自动生成
8 | */
9 |
--------------------------------------------------------------------------------
/common/global/topic.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | const (
4 | LoginLog = "login_log_queue"
5 | OperateLog = "operate_log_queue"
6 | ApiCheck = "api_check_queue"
7 | )
8 |
--------------------------------------------------------------------------------
/static/uploadfile/77cfc1dd-535c-4e60-b34a-5909e2cf5ed0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/go-admin-team/go-admin/HEAD/static/uploadfile/77cfc1dd-535c-4e60-b34a-5909e2cf5ed0.jpg
--------------------------------------------------------------------------------
/common/global/adm.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | const (
4 | // Version go-admin version info
5 | Version = "2.2.0"
6 | )
7 |
8 | var (
9 | // Driver 数据库驱动
10 | Driver string
11 | )
12 |
--------------------------------------------------------------------------------
/cmd/api/jobs.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import "go-admin/app/jobs/router"
4 |
5 | func init() {
6 | //注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法
7 | AppRouters = append(AppRouters, router.InitRouter)
8 | }
9 |
--------------------------------------------------------------------------------
/cmd/api/other.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import "go-admin/app/other/router"
4 |
5 | func init() {
6 | //注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法
7 | AppRouters = append(AppRouters, router.InitRouter)
8 | }
9 |
--------------------------------------------------------------------------------
/template/cmd_api.template:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import "go-admin/app/{{.appName}}/router"
4 |
5 | func init() {
6 | //注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法
7 | AppRouters = append(AppRouters, router.InitRouter)
8 | }
--------------------------------------------------------------------------------
/common/middleware/handler/ping.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | func Ping(c *gin.Context) {
8 | c.JSON(200, gin.H{
9 | "message": "ok",
10 | })
11 | }
12 |
--------------------------------------------------------------------------------
/common/models/menu.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | // Menu 菜单中的类型枚举值
4 | const (
5 | // Directory 目录
6 | Directory string = "M"
7 | // Menu 菜单
8 | Menu string = "C"
9 | // Button 按钮
10 | Button string = "F"
11 | )
12 |
--------------------------------------------------------------------------------
/common/models/type.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "gorm.io/gorm/schema"
4 |
5 | type ActiveRecord interface {
6 | schema.Tabler
7 | SetCreateBy(createBy int)
8 | SetUpdateBy(updateBy int)
9 | Generate() ActiveRecord
10 | GetId() interface{}
11 | }
12 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/model.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type BaseModel struct {
8 | CreatedAt time.Time `json:"createdAt"`
9 | UpdatedAt time.Time `json:"updatedAt"`
10 | DeletedAt *time.Time `json:"deletedAt"`
11 | }
12 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/role_dept.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysRoleDept struct {
4 | RoleId int `gorm:"size:11;primaryKey"`
5 | DeptId int `gorm:"size:11;primaryKey"`
6 | }
7 |
8 | func (SysRoleDept) TableName() string {
9 | return "sys_role_dept"
10 | }
11 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/tb_demo.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type TbDemo struct {
4 | Model
5 | Name string `json:"name" gorm:"type:varchar(128);comment:名称"`
6 | ModelTime
7 | ControlBy
8 | }
9 |
10 | func (TbDemo) TableName() string {
11 | return "tb_demo"
12 | }
13 |
--------------------------------------------------------------------------------
/common/models/migrate.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "time"
4 |
5 | type Migration struct {
6 | Version string `gorm:"primaryKey"`
7 | ApplyTime time.Time `gorm:"autoCreateTime"`
8 | }
9 |
10 | func (Migration) TableName() string {
11 | return "sys_migration"
12 | }
13 |
--------------------------------------------------------------------------------
/common/middleware/db.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-admin-team/go-admin-core/sdk"
6 | )
7 |
8 | func WithContextDb(c *gin.Context) {
9 | c.Set("db", sdk.Runtime.GetDbByKey(c.Request.Host).WithContext(c))
10 | c.Next()
11 | }
12 |
--------------------------------------------------------------------------------
/app/other/service/dto/sys_tables.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | type SysTableSearch struct {
4 | TBName string `form:"tableName" search:"type:exact;column:table_name;table:table_name"`
5 | TableComment string `form:"tableComment" search:"type:icontains;column:table_comment;table:table_comment"`
6 | }
7 |
--------------------------------------------------------------------------------
/scripts/k8s/storage.yml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: PersistentVolumeClaim
3 | metadata:
4 | name: go-admin
5 | namespace: go-admin
6 | spec:
7 | accessModes:
8 | - ReadWriteMany
9 | resources:
10 | requests:
11 | storage: "1Mi"
12 | volumeName:
13 | storageClassName: nfs-csi
--------------------------------------------------------------------------------
/config/extend.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | var ExtConfig Extend
4 |
5 | // Extend 扩展配置
6 | // extend:
7 | // demo:
8 | // name: demo-name
9 | // 使用方法: config.ExtConfig......即可!!
10 | type Extend struct {
11 | AMap AMap // 这里配置对应配置文件的结构即可
12 | }
13 |
14 | type AMap struct {
15 | Key string
16 | }
17 |
--------------------------------------------------------------------------------
/common/dto/order.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "gorm.io/gorm"
5 | "gorm.io/gorm/clause"
6 | )
7 |
8 | func OrderDest(sort string, bl bool) func(db *gorm.DB) *gorm.DB {
9 | return func(db *gorm.DB) *gorm.DB {
10 | return db.Order(clause.OrderByColumn{Column: clause.Column{Name: sort}, Desc: bl})
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/common/file_store/obs_test.go:
--------------------------------------------------------------------------------
1 | package file_store
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestOBSUpload(t *testing.T) {
8 | e := OXS{"", "", "", ""}
9 | var oxs = e.Setup(HuaweiOBS)
10 | err := oxs.UpLoad("test.png", "./test.png")
11 | if err != nil {
12 | t.Error(err)
13 | }
14 | t.Log("ok")
15 | }
16 |
--------------------------------------------------------------------------------
/app/jobs/type.go:
--------------------------------------------------------------------------------
1 | package jobs
2 |
3 | import "github.com/robfig/cron/v3"
4 |
5 | type Job interface {
6 | Run()
7 | addJob(*cron.Cron) (int, error)
8 | }
9 |
10 | type JobExec interface {
11 | Exec(arg interface{}) error
12 | }
13 |
14 | func CallExec(e JobExec, arg interface{}) error {
15 | return e.Exec(arg)
16 | }
17 |
--------------------------------------------------------------------------------
/common/file_store/oss_test.go:
--------------------------------------------------------------------------------
1 | package file_store
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestOSSUpload(t *testing.T) {
8 | // 打括号内填写自己的测试信息即可
9 | e := OXS{}
10 | var oxs = e.Setup(AliYunOSS)
11 | err := oxs.UpLoad("test.png", "./test.png")
12 | if err != nil {
13 | t.Error(err)
14 | }
15 | t.Log("ok")
16 | }
17 |
--------------------------------------------------------------------------------
/restart.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | echo "go build"
3 | go mod tidy
4 | go build -o go-admin main.go
5 | chmod +x ./go-admin
6 | echo "kill go-admin service"
7 | killall go-admin # kill go-admin service
8 | nohup ./go-admin server -c=config/settings.dev.yml >> access.log 2>&1 & #后台启动服务将日志写入access.log文件
9 | echo "run go-admin success"
10 | ps -aux | grep go-admin
11 |
--------------------------------------------------------------------------------
/common/database/open.go:
--------------------------------------------------------------------------------
1 | //go:build !sqlite3
2 |
3 | package database
4 |
5 | import (
6 | "gorm.io/driver/mysql"
7 | "gorm.io/driver/postgres"
8 | "gorm.io/driver/sqlserver"
9 | "gorm.io/gorm"
10 | )
11 |
12 | var opens = map[string]func(string) gorm.Dialector{
13 | "mysql": mysql.Open,
14 | "postgres": postgres.Open,
15 | "sqlserver": sqlserver.Open,
16 | }
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: 🆕 Create new issue
4 | url: http://new-issue.go-admin.dev
5 | about: The issue which is not created via http://new-issue.go-admin.dev will be closed immediately.
6 | - name: 🆕 创建一个新 Issue
7 | url: http://new-issue.go-admin.dev
8 | about: 不是用 http://new-issue.go-admin.dev 创建的 issue 会被机器人自动关闭。
9 |
--------------------------------------------------------------------------------
/common/dto/pagination.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | type Pagination struct {
4 | PageIndex int `form:"pageIndex"`
5 | PageSize int `form:"pageSize"`
6 | }
7 |
8 | func (m *Pagination) GetPageIndex() int {
9 | if m.PageIndex <= 0 {
10 | m.PageIndex = 1
11 | }
12 | return m.PageIndex
13 | }
14 |
15 | func (m *Pagination) GetPageSize() int {
16 | if m.PageSize <= 0 {
17 | m.PageSize = 10
18 | }
19 | return m.PageSize
20 | }
21 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 | services:
3 | go-admin-api:
4 | container_name: go-admin
5 | image: go-admin:latest
6 | privileged: true
7 | restart: always
8 | ports:
9 | - 8000:8000
10 | volumes:
11 | - ./config/:/go-admin-api/config/
12 | - ./static/:/go-admin-api/static/
13 | - ./temp/:/go-admin-api/temp/
14 | networks:
15 | - myweb
16 | networks:
17 | myweb:
18 | driver: bridge
19 |
20 |
--------------------------------------------------------------------------------
/common/database/open_sqlite3.go:
--------------------------------------------------------------------------------
1 | //go:build sqlite3
2 | // +build sqlite3
3 |
4 | package database
5 |
6 | import (
7 | "gorm.io/driver/mysql"
8 | "gorm.io/driver/postgres"
9 | "gorm.io/driver/sqlite"
10 | "gorm.io/driver/sqlserver"
11 | "gorm.io/gorm"
12 | )
13 |
14 | var opens = map[string]func(string) gorm.Dialector{
15 | "mysql": mysql.Open,
16 | "postgres": postgres.Open,
17 | "sqlite3": sqlite.Open,
18 | "sqlserver": sqlserver.Open,
19 | }
20 |
--------------------------------------------------------------------------------
/common/dto/type.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "go-admin/common/models"
6 | )
7 |
8 | type Index interface {
9 | Generate() Index
10 | Bind(ctx *gin.Context) error
11 | GetPageIndex() int
12 | GetPageSize() int
13 | GetNeedSearch() interface{}
14 | }
15 |
16 | type Control interface {
17 | Generate() Control
18 | Bind(ctx *gin.Context) error
19 | GenerateM() (models.ActiveRecord, error)
20 | GetId() interface{}
21 | }
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 | */.DS_Store
4 | static/uploadfile
5 | main.exe
6 | *.exe
7 | go-admin
8 | go-admin.exe
9 | temp/
10 | !temp
11 | vendor
12 | config/settings.dev.yml
13 | config/settings.dev.*.yml
14 | config/settings.dev.*.yml.log
15 | temp/logs
16 | config/settings.dev.yml.log
17 | config/settings.b.dev.yml
18 | cmd/migrate/migration/version-local/*
19 | !cmd/migrate/migration/version-local/doc.go
20 |
21 | # go sum
22 | go.sum
23 | config/settings.deva.yml
24 |
--------------------------------------------------------------------------------
/common/service/service.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/go-admin-team/go-admin-core/logger"
7 | "gorm.io/gorm"
8 | )
9 |
10 | type Service struct {
11 | Orm *gorm.DB
12 | Msg string
13 | MsgID string
14 | Log *logger.Helper
15 | Error error
16 | }
17 |
18 | func (db *Service) AddError(err error) error {
19 | if db.Error == nil {
20 | db.Error = err
21 | } else if err != nil {
22 | db.Error = fmt.Errorf("%v; %w", db.Error, err)
23 | }
24 | return db.Error
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_dict_type.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type DictType struct {
4 | DictId int `gorm:"primaryKey;autoIncrement;" json:"dictId"`
5 | DictName string `gorm:"size:128;" json:"dictName"` //字典名称
6 | DictType string `gorm:"size:128;" json:"dictType"` //字典类型
7 | Status int `gorm:"size:4;" json:"status"` //状态
8 | Remark string `gorm:"size:255;" json:"remark"` //备注
9 | ControlBy
10 | ModelTime
11 | }
12 |
13 | func (DictType) TableName() string {
14 | return "sys_dict_type"
15 | }
16 |
--------------------------------------------------------------------------------
/cmd/version/server.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "fmt"
5 | "github.com/spf13/cobra"
6 | "go-admin/common/global"
7 | )
8 |
9 | var (
10 | StartCmd = &cobra.Command{
11 | Use: "version",
12 | Short: "Get version info",
13 | Example: "go-admin version",
14 | PreRun: func(cmd *cobra.Command, args []string) {
15 |
16 | },
17 | RunE: func(cmd *cobra.Command, args []string) error {
18 | return run()
19 | },
20 | }
21 | )
22 |
23 | func run() error {
24 | fmt.Println(global.Version)
25 | return nil
26 | }
27 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine
2 |
3 | # ENV GOPROXY https://goproxy.cn/
4 |
5 | RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
6 |
7 | RUN apk update --no-cache
8 | RUN apk add --update gcc g++ libc6-compat
9 | RUN apk add --no-cache ca-certificates
10 | RUN apk add --no-cache tzdata
11 | ENV TZ Asia/Shanghai
12 |
13 | COPY ./main /main
14 | COPY ./config/settings.demo.yml /config/settings.yml
15 | COPY ./go-admin-db.db /go-admin-db.db
16 | EXPOSE 8000
17 | RUN chmod +x /main
18 | CMD ["/main","server","-c", "/config/settings.yml"]
--------------------------------------------------------------------------------
/app/other/router/file.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/other/apis"
7 | )
8 |
9 | func init() {
10 | routerCheckRole = append(routerCheckRole, registerFileRouter)
11 | }
12 |
13 | // 需认证的路由代码
14 | func registerFileRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
15 | var api = apis.File{}
16 | r := v1.Group("").Use(authMiddleware.MiddlewareFunc())
17 | {
18 | r.POST("/public/uploadFile", api.UploadFile)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/common/middleware/handler/httpshandler.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/unrolled/secure"
6 |
7 | "github.com/go-admin-team/go-admin-core/sdk/config"
8 | )
9 |
10 | func TlsHandler() gin.HandlerFunc {
11 | return func(c *gin.Context) {
12 | secureMiddleware := secure.New(secure.Options{
13 | SSLRedirect: true,
14 | SSLHost: config.SslConfig.Domain,
15 | })
16 | err := secureMiddleware.Process(c.Writer, c.Request)
17 | if err != nil {
18 | return
19 | }
20 | c.Next()
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_api.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysApi struct {
4 | Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"`
5 | Handle string `json:"handle" gorm:"size:128;comment:handle"`
6 | Title string `json:"title" gorm:"size:128;comment:标题"`
7 | Path string `json:"path" gorm:"size:128;comment:地址"`
8 | Type string `json:"type" gorm:"size:16;comment:接口类型"`
9 | Action string `json:"action" gorm:"size:16;comment:请求类型"`
10 | ModelTime
11 | ControlBy
12 | }
13 |
14 | func (SysApi) TableName() string {
15 | return "sys_api"
16 | }
--------------------------------------------------------------------------------
/app/other/router/monitor.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | "github.com/go-admin-team/go-admin-core/tools/transfer"
8 | "github.com/prometheus/client_golang/prometheus/promhttp"
9 | )
10 |
11 | func init() {
12 | routerNoCheckRole = append(routerNoCheckRole, registerMonitorRouter)
13 | }
14 |
15 | // 需认证的路由代码
16 | func registerMonitorRouter(v1 *gin.RouterGroup) {
17 | v1.GET("/metrics", transfer.Handler(promhttp.Handler()))
18 | //健康检查
19 | v1.GET("/health", func(c *gin.Context) {
20 | c.Status(http.StatusOK)
21 | })
22 |
23 | }
--------------------------------------------------------------------------------
/common/file_store/kodo_test.go:
--------------------------------------------------------------------------------
1 | package file_store
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestKODOUpload(t *testing.T) {
8 | e := OXS{"", "", "", ""}
9 | var oxs = e.Setup(QiNiuKodo, map[string]interface{}{"Zone": "华东"})
10 | err := oxs.UpLoad("test.png", "./test.png")
11 | if err != nil {
12 | t.Error(err)
13 | }
14 | t.Log("ok")
15 | }
16 |
17 | func TestKODOGetTempToken(t *testing.T) {
18 | e := OXS{"", "", "", ""}
19 | var oxs = e.Setup(QiNiuKodo, map[string]interface{}{"Zone": "华东"})
20 | token, _ := oxs.GetTempToken()
21 | t.Log(token)
22 | t.Log("ok")
23 | }
24 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "go-admin/cmd"
5 | )
6 |
7 | //go:generate swag init --parseDependency --parseDepth=6 --instanceName admin -o ./docs/admin
8 |
9 | // @title go-admin API
10 | // @version 2.0.0
11 | // @description 基于Gin + Vue + Element UI的前后端分离权限管理系统的接口文档
12 | // @description 添加qq群: 521386980 进入技术交流群 请先star,谢谢!
13 | // @license.name MIT
14 | // @license.url https://github.com/go-admin-team/go-admin/blob/master/LICENSE.md
15 |
16 | // @securityDefinitions.apikey Bearer
17 | // @in header
18 | // @name Authorization
19 | func main() {
20 | cmd.Execute()
21 | }
22 |
--------------------------------------------------------------------------------
/common/global/casbin.go:
--------------------------------------------------------------------------------
1 | package global
2 |
3 | import (
4 | "github.com/casbin/casbin/v2"
5 | "github.com/gin-gonic/gin"
6 | "github.com/go-admin-team/go-admin-core/sdk"
7 | "github.com/go-admin-team/go-admin-core/sdk/api"
8 | )
9 |
10 | func LoadPolicy(c *gin.Context) (*casbin.SyncedEnforcer, error) {
11 | log := api.GetRequestLogger(c)
12 | if err := sdk.Runtime.GetCasbinKey(c.Request.Host).LoadPolicy(); err == nil {
13 | return sdk.Runtime.GetCasbinKey(c.Request.Host), err
14 | } else {
15 | log.Errorf("casbin rbac_model or policy init error, %s ", err.Error())
16 | return nil, err
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/by.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 |
6 | "gorm.io/gorm"
7 | )
8 |
9 | type ControlBy struct {
10 | CreateBy int `json:"createBy" gorm:"index;comment:创建者"`
11 | UpdateBy int `json:"updateBy" gorm:"index;comment:更新者"`
12 | }
13 |
14 | type Model struct {
15 | Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"`
16 | }
17 |
18 | type ModelTime struct {
19 | CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"`
20 | UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"`
21 | DeletedAt gorm.DeletedAt `json:"-" gorm:"index;comment:删除时间"`
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_post.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysPost struct {
4 | PostId int `gorm:"primaryKey;autoIncrement" json:"postId"` //岗位编号
5 | PostName string `gorm:"size:128;" json:"postName"` //岗位名称
6 | PostCode string `gorm:"size:128;" json:"postCode"` //岗位代码
7 | Sort int `gorm:"size:4;" json:"sort"` //岗位排序
8 | Status int `gorm:"size:4;" json:"status"` //状态
9 | Remark string `gorm:"size:255;" json:"remark"` //描述
10 | ControlBy
11 | ModelTime
12 | }
13 |
14 | func (SysPost) TableName() string {
15 | return "sys_post"
16 | }
--------------------------------------------------------------------------------
/app/admin/models/casbin_rule.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type CasbinRule struct {
4 | ID uint `gorm:"primaryKey;autoIncrement"`
5 | Ptype string `gorm:"size:512;uniqueIndex:unique_index"`
6 | V0 string `gorm:"size:512;uniqueIndex:unique_index"`
7 | V1 string `gorm:"size:512;uniqueIndex:unique_index"`
8 | V2 string `gorm:"size:512;uniqueIndex:unique_index"`
9 | V3 string `gorm:"size:512;uniqueIndex:unique_index"`
10 | V4 string `gorm:"size:512;uniqueIndex:unique_index"`
11 | V5 string `gorm:"size:512;uniqueIndex:unique_index"`
12 | }
13 |
14 | func (CasbinRule) TableName() string {
15 | return "sys_casbin_rule"
16 | }
17 |
--------------------------------------------------------------------------------
/.github/workflows/issue-check-inactive.yml:
--------------------------------------------------------------------------------
1 | name: Issue Check Inactive
2 |
3 | on:
4 | schedule:
5 | - cron: "0 0 */15 * *"
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 | issue-check-inactive:
12 | permissions:
13 | issues: write # for actions-cool/issues-helper to update issues
14 | pull-requests: write # for actions-cool/issues-helper to update PRs
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: check-inactive
18 | uses: actions-cool/issues-helper@v3
19 | with:
20 | actions: 'check-inactive'
21 | inactive-label: 'Inactive'
22 | inactive-day: 30
23 |
--------------------------------------------------------------------------------
/app/other/router/sys_server_monitor.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/other/apis"
7 | "go-admin/common/middleware"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, registerSysServerMonitorRouter)
12 | }
13 |
14 | // 需认证的路由代码
15 | func registerSysServerMonitorRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | api := apis.ServerMonitor{}
17 | r := v1.Group("/server-monitor").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
18 | {
19 | r.GET("", api.ServerInfo)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/common/ip.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "strings"
6 | )
7 |
8 | func GetClientIP(c *gin.Context) string {
9 | // 优先从 X-Forwarded-For 获取 IP
10 | ip := c.Request.Header.Get("X-Forwarded-For")
11 | if ip == "" || strings.Contains(ip, "127.0.0.1") {
12 | // 如果为空或为本地地址,则尝试从 X-Real-IP 获取
13 | ip = c.Request.Header.Get("X-real-ip")
14 | }
15 | if ip == "" {
16 | // 如果仍为空,则使用 RemoteIP
17 | ip = c.RemoteIP()
18 | }
19 | if ip == "" || ip == "127.0.0.1" {
20 | // 如果仍为空或为本地地址,则使用 ClientIP
21 | ip = c.ClientIP()
22 | }
23 | if ip == "" {
24 | // 最后兜底为本地地址
25 | ip = "127.0.0.1"
26 | }
27 | return ip
28 | }
29 |
--------------------------------------------------------------------------------
/static/form-generator/js/tinymce-example.641995ab.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["tinymce-example"],{a5aa:function(e,t,n){"use strict";n.r(t);var a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("Tinymce",{attrs:{height:300,placeholder:"在这里输入文字"},model:{value:e.defaultValue,callback:function(t){e.defaultValue=t},expression:"defaultValue"}})],1)},c=[],u=n("31c6"),l={components:{Tinymce:u["a"]},props:{},data:function(){return{defaultValue:"
配置文档参阅:http://tinymce.ax-z.cn
"}},computed:{},watch:{},created:function(){},mounted:function(){},methods:{}},o=l,i=n("2877"),p=Object(i["a"])(o,a,c,!1,null,null,null);t["default"]=p.exports}}]);
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/casbin_rule.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | // CasbinRule sys_casbin_rule
4 | type CasbinRule struct {
5 | ID uint `gorm:"primaryKey;autoIncrement"`
6 | Ptype string `gorm:"size:512;uniqueIndex:unique_index"`
7 | V0 string `gorm:"size:512;uniqueIndex:unique_index"`
8 | V1 string `gorm:"size:512;uniqueIndex:unique_index"`
9 | V2 string `gorm:"size:512;uniqueIndex:unique_index"`
10 | V3 string `gorm:"size:512;uniqueIndex:unique_index"`
11 | V4 string `gorm:"size:512;uniqueIndex:unique_index"`
12 | V5 string `gorm:"size:512;uniqueIndex:unique_index"`
13 | }
14 |
15 | func (CasbinRule) TableName() string {
16 | return "sys_casbin_rule"
17 | }
18 |
--------------------------------------------------------------------------------
/app/admin/router/sys_api.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 |
7 | "go-admin/app/admin/apis"
8 | "go-admin/common/middleware"
9 | )
10 |
11 | func init() {
12 | routerCheckRole = append(routerCheckRole, registerSysApiRouter)
13 | }
14 |
15 | // registerSysApiRouter
16 | func registerSysApiRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
17 | api := apis.SysApi{}
18 | r := v1.Group("/sys-api").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
19 | {
20 | r.GET("", api.GetPage)
21 | r.GET("/:id", api.Get)
22 | r.PUT("/:id", api.Update)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/admin/router/sys_opera_log.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/admin/apis"
7 | "go-admin/common/middleware"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, registerSysOperaLogRouter)
12 | }
13 |
14 | // 需认证的路由代码
15 | func registerSysOperaLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | api := apis.SysOperaLog{}
17 | r := v1.Group("/sys-opera-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
18 | {
19 | r.GET("", api.GetPage)
20 | r.GET("/:id", api.Get)
21 | r.DELETE("", api.Delete)
22 | }
23 | }
--------------------------------------------------------------------------------
/app/admin/router/sys_login_log.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/admin/apis"
7 | "go-admin/common/middleware"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, registerSysLoginLogRouter)
12 | }
13 |
14 | // 需认证的路由代码
15 | func registerSysLoginLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | api := apis.SysLoginLog{}
17 |
18 | r := v1.Group("/sys-login-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
19 | {
20 | r.GET("", api.GetPage)
21 | r.GET("/:id", api.Get)
22 | r.DELETE("", api.Delete)
23 | }
24 | }
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_config.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysConfig struct {
4 | Model
5 | ConfigName string `json:"configName" gorm:"type:varchar(128);comment:ConfigName"`
6 | ConfigKey string `json:"configKey" gorm:"type:varchar(128);comment:ConfigKey"`
7 | ConfigValue string `json:"configValue" gorm:"type:varchar(255);comment:ConfigValue"`
8 | ConfigType string `json:"configType" gorm:"type:varchar(64);comment:ConfigType"`
9 | IsFrontend int `json:"isFrontend" gorm:"type:varchar(64);comment:是否前台"`
10 | Remark string `json:"remark" gorm:"type:varchar(128);comment:Remark"`
11 | ControlBy
12 | ModelTime
13 | }
14 |
15 | func (SysConfig) TableName() string {
16 | return "sys_config"
17 | }
18 |
--------------------------------------------------------------------------------
/app/admin/router/sys_post.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/admin/apis"
7 | "go-admin/common/middleware"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, registerSyPostRouter)
12 | }
13 |
14 | // 需认证的路由代码
15 | func registerSyPostRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | api := apis.SysPost{}
17 | r := v1.Group("/post").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
18 | {
19 | r.GET("", api.GetPage)
20 | r.GET("/:id", api.Get)
21 | r.POST("", api.Insert)
22 | r.PUT("/:id", api.Update)
23 | r.DELETE("", api.Delete)
24 | }
25 | }
--------------------------------------------------------------------------------
/common/models/response.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type Response struct {
4 | // 代码
5 | Code int `json:"code" example:"200"`
6 | // 数据集
7 | Data interface{} `json:"data"`
8 | // 消息
9 | Msg string `json:"msg"`
10 | RequestId string `json:"requestId"`
11 | }
12 |
13 | type Page struct {
14 | List interface{} `json:"list"`
15 | Count int `json:"count"`
16 | PageIndex int `json:"pageIndex"`
17 | PageSize int `json:"pageSize"`
18 | }
19 |
20 | // ReturnOK 正常返回
21 | func (res *Response) ReturnOK() *Response {
22 | res.Code = 200
23 | return res
24 | }
25 |
26 | // ReturnError 错误返回
27 | func (res *Response) ReturnError(code int) *Response {
28 | res.Code = code
29 | return res
30 | }
31 |
--------------------------------------------------------------------------------
/common/file_store/interface.go:
--------------------------------------------------------------------------------
1 | package file_store
2 |
3 | // DriverType 驱动类型
4 | type DriverType string
5 |
6 | const (
7 | // HuaweiOBS 华为云OBS
8 | HuaweiOBS DriverType = "HuaweiOBS"
9 | // AliYunOSS 阿里云OSS
10 | AliYunOSS DriverType = "AliYunOSS"
11 | // QiNiuKodo 七牛云kodo
12 | QiNiuKodo DriverType = "QiNiuKodo"
13 | )
14 |
15 | type ClientOption map[string]interface{}
16 |
17 | // TODO: FileStoreType名称待定
18 |
19 | // FileStoreType OXS
20 | type FileStoreType interface {
21 | // Setup 装载 endpoint sss
22 | Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error
23 | // UpLoad 上传
24 | UpLoad(yourObjectName string, localFile interface{}) error
25 | // GetTempToken 获取临时Token
26 | GetTempToken() (string, error)
27 | }
28 |
--------------------------------------------------------------------------------
/common/middleware/demo.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-admin-team/go-admin-core/sdk/config"
6 | "net/http"
7 | )
8 |
9 | func DemoEvn() gin.HandlerFunc {
10 | return func(c *gin.Context) {
11 | method := c.Request.Method
12 | if config.ApplicationConfig.Mode == "demo" {
13 | if method == "GET" ||
14 | method == "OPTIONS" ||
15 | c.Request.RequestURI == "/api/v1/login" ||
16 | c.Request.RequestURI == "/api/v1/logout" {
17 | c.Next()
18 | } else {
19 | c.JSON(http.StatusOK, gin.H{
20 | "code": 500,
21 | "msg": "谢谢您的参与,但为了大家更好的体验,所以本次提交就算了吧!\U0001F600\U0001F600\U0001F600",
22 | })
23 | c.Abort()
24 | return
25 | }
26 | }
27 | c.Next()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/template/v4/no_actions/router_no_check_role.go.template:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 |
7 | "go-admin/app/{{.PackageName}}/apis"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, register{{.ClassName}}Router)
12 | }
13 |
14 | // register{{.ClassName}}Router
15 | func register{{.ClassName}}Router(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | api := apis.{{.ClassName}}{}
17 | r := v1.Group("/{{.ModuleName}}").Use(authMiddleware.MiddlewareFunc())
18 | {
19 | r.GET("", api.GetPage)
20 | r.GET("/:id", api.Get)
21 | r.POST("", api.Insert)
22 | r.PUT("/:id", api.Update)
23 | r.DELETE("", api.Delete)
24 | }
25 | }
--------------------------------------------------------------------------------
/Dockerfilebak:
--------------------------------------------------------------------------------
1 | FROM golang:alpine as builder
2 |
3 | MAINTAINER lwnmengjing
4 |
5 | ENV GOPROXY https://goproxy.cn/
6 |
7 | WORKDIR /go/release
8 | #RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
9 | RUN apk update && apk add tzdata
10 |
11 | COPY go.mod ./go.mod
12 | RUN go mod tidy
13 | COPY . .
14 | RUN pwd && ls
15 |
16 | RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -installsuffix cgo -o go-admin .
17 |
18 | FROM alpine
19 |
20 | COPY --from=builder /go/release/go-admin /
21 |
22 | COPY --from=builder /go/release/config/settings.yml /config/settings.yml
23 |
24 | COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
25 |
26 | EXPOSE 8000
27 |
28 | CMD ["/go-admin","server","-c", "/config/settings.yml"]
--------------------------------------------------------------------------------
/config/READMEN.md:
--------------------------------------------------------------------------------
1 | # ⚙ 配置详情
2 |
3 | 1. 配置文件说明
4 | ```yml
5 | settings:
6 | application:
7 | # 项目启动环境
8 | mode: dev # dev开发环境 prod线上环境;
9 | host: 0.0.0.0 # 主机ip 或者域名,默认0.0.0.0
10 | # 服务名称
11 | name: go-admin
12 | # 服务端口
13 | port: 8000
14 | readtimeout: 1
15 | writertimeout: 2
16 | log:
17 | # 日志文件存放路径
18 | dir: temp/logs
19 | jwt:
20 | # JWT加密字符串
21 | secret: go-admin
22 | # 过期时间单位:秒
23 | timeout: 3600
24 | database:
25 | # 数据库名称
26 | name: dbname
27 | # 数据库类型
28 | dbtype: mysql
29 | # 数据库地址
30 | host: 127.0.0.1
31 | # 数据库密码
32 | password: password
33 | # 数据库端口
34 | port: 3306
35 | # 数据库用户名
36 | username: root
37 | ```
--------------------------------------------------------------------------------
/app/admin/models/sys_dict_type.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "go-admin/common/models"
5 | )
6 |
7 | type SysDictType struct {
8 | ID int `json:"id" gorm:"primaryKey;column:dict_id;autoIncrement;comment:主键编码"`
9 | DictName string `json:"dictName" gorm:"size:128;comment:DictName"`
10 | DictType string `json:"dictType" gorm:"size:128;comment:DictType"`
11 | Status int `json:"status" gorm:"size:4;comment:Status"`
12 | Remark string `json:"remark" gorm:"size:255;comment:Remark"`
13 | models.ControlBy
14 | models.ModelTime
15 | }
16 |
17 | func (*SysDictType) TableName() string {
18 | return "sys_dict_type"
19 | }
20 |
21 | func (e *SysDictType) Generate() models.ActiveRecord {
22 | o := *e
23 | return &o
24 | }
25 |
26 | func (e *SysDictType) GetId() interface{} {
27 | return e.ID
28 | }
29 |
--------------------------------------------------------------------------------
/common/models/by.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 |
6 | "gorm.io/gorm"
7 | )
8 |
9 | type ControlBy struct {
10 | CreateBy int `json:"createBy" gorm:"index;comment:创建者"`
11 | UpdateBy int `json:"updateBy" gorm:"index;comment:更新者"`
12 | }
13 |
14 | // SetCreateBy 设置创建人id
15 | func (e *ControlBy) SetCreateBy(createBy int) {
16 | e.CreateBy = createBy
17 | }
18 |
19 | // SetUpdateBy 设置修改人id
20 | func (e *ControlBy) SetUpdateBy(updateBy int) {
21 | e.UpdateBy = updateBy
22 | }
23 |
24 | type Model struct {
25 | Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"`
26 | }
27 |
28 | type ModelTime struct {
29 | CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"`
30 | UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"`
31 | DeletedAt gorm.DeletedAt `json:"-" gorm:"index;comment:删除时间"`
32 | }
--------------------------------------------------------------------------------
/common/middleware/trace.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/opentracing/opentracing-go"
6 | )
7 |
8 | // Trace 链路追踪
9 | func Trace() gin.HandlerFunc {
10 | return func(ctx *gin.Context) {
11 | var sp opentracing.Span
12 | opName := ctx.Request.URL.Path
13 | // Attempt to join a trace by getting trace context from the headers.
14 | wireContext, err := opentracing.GlobalTracer().Extract(
15 | opentracing.TextMap,
16 | opentracing.HTTPHeadersCarrier(ctx.Request.Header))
17 | if err != nil {
18 | // If for whatever reason we can't join, go ahead and start a new root span.
19 | sp = opentracing.StartSpan(opName)
20 | } else {
21 | sp = opentracing.StartSpan(opName, opentracing.ChildOf(wireContext))
22 | }
23 | ctx.Set("traceSpan", sp)
24 | ctx.Next()
25 | sp.Finish()
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/admin/router/sys_dept.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/admin/apis"
7 | "go-admin/common/middleware"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, registerSysDeptRouter)
12 | }
13 |
14 | // 需认证的路由代码
15 | func registerSysDeptRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | api := apis.SysDept{}
17 |
18 | r := v1.Group("/dept").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
19 | {
20 | r.GET("", api.GetPage)
21 | r.GET("/:id", api.Get)
22 | r.POST("", api.Insert)
23 | r.PUT("/:id", api.Update)
24 | r.DELETE("", api.Delete)
25 | }
26 |
27 | r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc())
28 | {
29 | r1.GET("/deptTree", api.Get2Tree)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/common/middleware/sentinel.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/alibaba/sentinel-golang/core/system"
5 | sentinel "github.com/alibaba/sentinel-golang/pkg/adapters/gin"
6 | "github.com/gin-gonic/gin"
7 |
8 | log "github.com/go-admin-team/go-admin-core/logger"
9 | )
10 |
11 | // Sentinel 限流
12 | func Sentinel() gin.HandlerFunc {
13 | if _, err := system.LoadRules([]*system.Rule{
14 | {
15 | MetricType: system.InboundQPS,
16 | TriggerCount: 200,
17 | Strategy: system.BBR,
18 | },
19 | }); err != nil {
20 | log.Fatalf("Unexpected error: %+v", err)
21 | }
22 | return sentinel.SentinelMiddleware(
23 | sentinel.WithBlockFallback(func(ctx *gin.Context) {
24 | ctx.AbortWithStatusJSON(200, map[string]interface{}{
25 | "msg": "too many request; the quota used up!",
26 | "code": 500,
27 | })
28 | }),
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_dept.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysDept struct {
4 | DeptId int `json:"deptId" gorm:"primaryKey;autoIncrement;"` //部门编码
5 | ParentId int `json:"parentId" gorm:""` //上级部门
6 | DeptPath string `json:"deptPath" gorm:"size:255;"` //
7 | DeptName string `json:"deptName" gorm:"size:128;"` //部门名称
8 | Sort int `json:"sort" gorm:"size:4;"` //排序
9 | Leader string `json:"leader" gorm:"size:128;"` //负责人
10 | Phone string `json:"phone" gorm:"size:11;"` //手机
11 | Email string `json:"email" gorm:"size:64;"` //邮箱
12 | Status int `json:"status" gorm:"size:4;"` //状态
13 | ControlBy
14 | ModelTime
15 | }
16 |
17 | func (SysDept) TableName() string {
18 | return "sys_dept"
19 | }
20 |
--------------------------------------------------------------------------------
/app/jobs/router/int_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | //"github.com/go-admin-team/go-admin-core/sdk/pkg"
5 | "os"
6 |
7 | "github.com/gin-gonic/gin"
8 | log "github.com/go-admin-team/go-admin-core/logger"
9 | "github.com/go-admin-team/go-admin-core/sdk"
10 | common "go-admin/common/middleware"
11 | )
12 |
13 | // InitRouter 路由初始化,不要怀疑,这里用到了
14 | func InitRouter() {
15 | var r *gin.Engine
16 | h := sdk.Runtime.GetEngine()
17 | if h == nil {
18 | log.Fatal("not found engine...")
19 | os.Exit(-1)
20 | }
21 | switch h.(type) {
22 | case *gin.Engine:
23 | r = h.(*gin.Engine)
24 | default:
25 | log.Fatal("not support other engine")
26 | os.Exit(-1)
27 | }
28 |
29 | authMiddleware, err := common.AuthInit()
30 | if err != nil {
31 | log.Fatalf("JWT Init Error, %s", err.Error())
32 | }
33 |
34 | // 注册业务路由
35 | initRouter(r, authMiddleware)
36 | }
37 |
--------------------------------------------------------------------------------
/config/settings.demo.yml:
--------------------------------------------------------------------------------
1 | settings:
2 | application:
3 | demomsg: "谢谢您的参与,但为了大家更好的体验,所以本次提交就算了吧!\U0001F600\U0001F600\U0001F600"
4 | enabledp: true
5 | host: 0.0.0.0
6 | mode: demo
7 | name: testApp
8 | port: 8000
9 | readtimeout: 10000
10 | writertimeout: 20000
11 | database:
12 | driver: sqlite3
13 | source: ./go-admin-db.db
14 | gen:
15 | dbname: testhhh
16 | frontpath: ../go-admin-ui/src
17 | jwt:
18 | secret: go-admin
19 | timeout: 3600
20 | logger:
21 | # 日志存放路径
22 | path: temp/logs
23 | # 日志输出,file:文件,default:命令行,其他:命令行
24 | stdout: '' #控制台日志,启用后,不输出到文件
25 | # 日志等级, trace, debug, info, warn, error, fatal
26 | level: trace
27 | # 数据库日志开关
28 | enableddb: true
29 | queue:
30 | memory:
31 | poolSize: 100
32 | extend:
33 | amap:
34 | key: de7a062c984bf828d5d1b3a631a517e4
--------------------------------------------------------------------------------
/app/other/router/init_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/gin-gonic/gin"
7 | log "github.com/go-admin-team/go-admin-core/logger"
8 | "github.com/go-admin-team/go-admin-core/sdk"
9 | common "go-admin/common/middleware"
10 | )
11 |
12 | // InitRouter 路由初始化,不要怀疑,这里用到了
13 | func InitRouter() {
14 | var r *gin.Engine
15 | h := sdk.Runtime.GetEngine()
16 | if h == nil {
17 | log.Fatal("not found engine...")
18 | os.Exit(-1)
19 | }
20 | switch h.(type) {
21 | case *gin.Engine:
22 | r = h.(*gin.Engine)
23 | default:
24 | log.Fatal("not support other engine")
25 | os.Exit(-1)
26 | }
27 | // the jwt middleware
28 | authMiddleware, err := common.AuthInit()
29 | if err != nil {
30 | log.Fatalf("JWT Init Error, %s", err.Error())
31 | }
32 |
33 | // 注册业务路由
34 | // TODO: 这里可存放业务路由,里边并无实际路由只有演示代码
35 | initRouter(r, authMiddleware)
36 | }
37 |
--------------------------------------------------------------------------------
/app/jobs/examples.go:
--------------------------------------------------------------------------------
1 | package jobs
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | // InitJob
9 | // 需要将定义的struct 添加到字典中;
10 | // 字典 key 可以配置到 自动任务 调用目标 中;
11 | func InitJob() {
12 | jobList = map[string]JobExec{
13 | "ExamplesOne": ExamplesOne{},
14 | // ...
15 | }
16 | }
17 |
18 | // ExamplesOne
19 | // 新添加的job 必须按照以下格式定义,并实现Exec函数
20 | type ExamplesOne struct {
21 | }
22 |
23 | func (t ExamplesOne) Exec(arg interface{}) error {
24 | str := time.Now().Format(timeFormat) + " [INFO] JobCore ExamplesOne exec success"
25 | // TODO: 这里需要注意 Examples 传入参数是 string 所以 arg.(string);请根据对应的类型进行转化;
26 | switch arg.(type) {
27 |
28 | case string:
29 | if arg.(string) != "" {
30 | fmt.Println("string", arg.(string))
31 | fmt.Println(str, arg.(string))
32 | } else {
33 | fmt.Println("arg is nil")
34 | fmt.Println(str, "arg is nil")
35 | }
36 | break
37 | }
38 |
39 | return nil
40 | }
41 |
--------------------------------------------------------------------------------
/app/admin/apis/go_admin.go:
--------------------------------------------------------------------------------
1 | package apis
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | const INDEX = `
8 |
9 |
10 |
11 |
12 | GO-ADMIN欢迎您
13 |
20 |
21 |
29 |
30 |
31 |
32 |
33 |
34 | `
35 |
36 | func GoAdmin(c *gin.Context) {
37 | c.Header("Content-Type", "text/html; charset=utf-8")
38 | c.String(200, INDEX)
39 | }
40 |
--------------------------------------------------------------------------------
/app/admin/router/sys_menu.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/admin/apis"
7 | "go-admin/common/middleware"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, registerSysMenuRouter)
12 | }
13 |
14 | // 需认证的路由代码
15 | func registerSysMenuRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
16 | api := apis.SysMenu{}
17 |
18 | r := v1.Group("/menu").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
19 | {
20 | r.GET("", api.GetPage)
21 | r.GET("/:id", api.Get)
22 | r.POST("", api.Insert)
23 | r.PUT("/:id", api.Update)
24 | r.DELETE("", api.Delete)
25 | }
26 |
27 | r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc())
28 | {
29 | r1.GET("/menurole", api.GetMenuRole)
30 | //r1.GET("/menuids", api.GetMenuIDS)
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/app/admin/router/sys_role.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 |
7 | "go-admin/app/admin/apis"
8 | "go-admin/common/middleware"
9 | )
10 |
11 | func init() {
12 | routerCheckRole = append(routerCheckRole, registerSysRoleRouter)
13 | }
14 |
15 | // 需认证的路由代码
16 | func registerSysRoleRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
17 | api := apis.SysRole{}
18 | r := v1.Group("/role").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
19 | {
20 | r.GET("", api.GetPage)
21 | r.GET("/:id", api.Get)
22 | r.POST("", api.Insert)
23 | r.PUT("/:id", api.Update)
24 | r.DELETE("", api.Delete)
25 | }
26 | r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc())
27 | {
28 | r1.PUT("/role-status", api.Update2Status)
29 | r1.PUT("/roledatascope", api.Update2DataScope)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.github/workflows/mirror.yaml:
--------------------------------------------------------------------------------
1 | name: 'GitHub Actions Mirror'
2 |
3 | on: [push, delete]
4 |
5 | jobs:
6 | mirror_to_gitee:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - name: 'Checkout'
10 | uses: actions/checkout@v1
11 | - name: 'Mirror to gitee'
12 | uses: pixta-dev/repository-mirroring-action@v1
13 | with:
14 | target_repo_url:
15 | git@gitee.com:go-admin-team/go-admin.git
16 | ssh_private_key:
17 | ${{ secrets.GITEE_KEY }}
18 | mirror_to_gitlab:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: 'Checkout'
22 | uses: actions/checkout@v1
23 | - name: 'Mirror to gitlab'
24 | uses: pixta-dev/repository-mirroring-action@v1
25 | with:
26 | target_repo_url:
27 | git@gitlab.com:go-admin-team/go-admin.git
28 | ssh_private_key:
29 | ${{ secrets.GITLAB_KEY }}
30 |
--------------------------------------------------------------------------------
/app/admin/models/sys_config.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "go-admin/common/models"
5 | )
6 |
7 | type SysConfig struct {
8 | models.Model
9 | ConfigName string `json:"configName" gorm:"size:128;comment:ConfigName"` //
10 | ConfigKey string `json:"configKey" gorm:"size:128;comment:ConfigKey"` //
11 | ConfigValue string `json:"configValue" gorm:"size:255;comment:ConfigValue"` //
12 | ConfigType string `json:"configType" gorm:"size:64;comment:ConfigType"`
13 | IsFrontend string `json:"isFrontend" gorm:"size:64;comment:是否前台"` //
14 | Remark string `json:"remark" gorm:"size:128;comment:Remark"` //
15 | models.ControlBy
16 | models.ModelTime
17 | }
18 |
19 | func (*SysConfig) TableName() string {
20 | return "sys_config"
21 | }
22 |
23 | func (e *SysConfig) Generate() models.ActiveRecord {
24 | o := *e
25 | return &o
26 | }
27 |
28 | func (e *SysConfig) GetId() interface{} {
29 | return e.Id
30 | }
31 |
--------------------------------------------------------------------------------
/template/v4/no_actions/router_check_role.go.template:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 |
7 | "go-admin/app/{{.PackageName}}/apis"
8 | "go-admin/common/middleware"
9 | "go-admin/common/actions"
10 | )
11 |
12 | func init() {
13 | routerCheckRole = append(routerCheckRole, register{{.ClassName}}Router)
14 | }
15 |
16 | // register{{.ClassName}}Router
17 | func register{{.ClassName}}Router(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
18 | api := apis.{{.ClassName}}{}
19 | r := v1.Group("/{{.ModuleName}}").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
20 | {
21 | r.GET("", actions.PermissionAction(), api.GetPage)
22 | r.GET("/:id", actions.PermissionAction(), api.Get)
23 | r.POST("", api.Insert)
24 | r.PUT("/:id", actions.PermissionAction(), api.Update)
25 | r.DELETE("", api.Delete)
26 | }
27 | }
--------------------------------------------------------------------------------
/app/admin/router/init_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/gin-gonic/gin"
7 | log "github.com/go-admin-team/go-admin-core/logger"
8 | "github.com/go-admin-team/go-admin-core/sdk"
9 | common "go-admin/common/middleware"
10 | )
11 |
12 | // InitRouter 路由初始化,不要怀疑,这里用到了
13 | func InitRouter() {
14 | var r *gin.Engine
15 | h := sdk.Runtime.GetEngine()
16 | if h == nil {
17 | log.Fatal("not found engine...")
18 | os.Exit(-1)
19 | }
20 | switch h.(type) {
21 | case *gin.Engine:
22 | r = h.(*gin.Engine)
23 | default:
24 | log.Fatal("not support other engine")
25 | os.Exit(-1)
26 | }
27 |
28 | // the jwt middleware
29 | authMiddleware, err := common.AuthInit()
30 | if err != nil {
31 | log.Fatalf("JWT Init Error, %s", err.Error())
32 | }
33 |
34 | // 注册系统路由
35 | InitSysRouter(r, authMiddleware)
36 |
37 | // 注册业务路由
38 | // TODO: 这里可存放业务路由,里边并无实际路由只有演示代码
39 | InitExamplesRouter(r, authMiddleware)
40 | }
41 |
--------------------------------------------------------------------------------
/app/admin/models/sys_post.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "go-admin/common/models"
4 |
5 | type SysPost struct {
6 | PostId int `gorm:"primaryKey;autoIncrement" json:"postId"` //岗位编号
7 | PostName string `gorm:"size:128;" json:"postName"` //岗位名称
8 | PostCode string `gorm:"size:128;" json:"postCode"` //岗位代码
9 | Sort int `gorm:"size:4;" json:"sort"` //岗位排序
10 | Status int `gorm:"size:4;" json:"status"` //状态
11 | Remark string `gorm:"size:255;" json:"remark"` //描述
12 | models.ControlBy
13 | models.ModelTime
14 |
15 | DataScope string `gorm:"-" json:"dataScope"`
16 | Params string `gorm:"-" json:"params"`
17 | }
18 |
19 | func (*SysPost) TableName() string {
20 | return "sys_post"
21 | }
22 |
23 | func (e *SysPost) Generate() models.ActiveRecord {
24 | o := *e
25 | return &o
26 | }
27 |
28 | func (e *SysPost) GetId() interface{} {
29 | return e.PostId
30 | }
31 |
--------------------------------------------------------------------------------
/config/pg.sql:
--------------------------------------------------------------------------------
1 | -- 开始初始化数据 ;
2 | create sequence if not exists sys_role_role_id_seq;
3 | create sequence if not exists sys_user_user_id_seq;
4 | create sequence if not exists sys_post_post_id_seq;
5 | create sequence if not exists sys_menu_menu_id_seq;
6 | create sequence if not exists sys_dict_type_dict_id_seq;
7 | create sequence if not exists sys_dict_data_dict_code_seq;
8 | create sequence if not exists sys_dept_dept_id_seq;
9 | create sequence if not exists sys_config_config_id_seq;
10 | create sequence if not exists sys_job_id_seq;
11 |
12 | select setval('sys_role_role_id_seq',4);
13 | select setval('sys_user_user_id_seq',5);
14 | select setval('sys_post_post_id_seq',4);
15 | select setval('sys_menu_menu_id_seq',543);
16 | select setval('sys_dict_type_dict_id_seq',12);
17 | select setval('sys_dict_data_dict_code_seq',34);
18 | select setval('sys_dept_dept_id_seq',11);
19 | select setval('sys_config_config_id_seq',6);
20 | select setval('sys_job_id_seq',3);
21 | -- 数据完成 ;
22 |
--------------------------------------------------------------------------------
/common/middleware/request_id.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/go-admin-team/go-admin-core/logger"
5 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
6 | "net/http"
7 | "strings"
8 |
9 | "github.com/gin-gonic/gin"
10 | "github.com/google/uuid"
11 | )
12 |
13 | // RequestId 自动增加requestId
14 | func RequestId(trafficKey string) gin.HandlerFunc {
15 | return func(c *gin.Context) {
16 | if c.Request.Method == http.MethodOptions {
17 | c.Next()
18 | return
19 | }
20 | requestId := c.GetHeader(trafficKey)
21 | if requestId == "" {
22 | requestId = c.GetHeader(strings.ToLower(trafficKey))
23 | }
24 | if requestId == "" {
25 | requestId = uuid.New().String()
26 | }
27 | c.Request.Header.Set(trafficKey, requestId)
28 | c.Set(trafficKey, requestId)
29 | c.Set(pkg.LoggerKey,
30 | logger.NewHelper(logger.DefaultLogger).
31 | WithFields(map[string]interface{}{
32 | trafficKey: requestId,
33 | }))
34 | c.Next()
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/config/settings.sqlite.yml:
--------------------------------------------------------------------------------
1 | settings:
2 | application:
3 | # dev开发环境 test测试环境 prod线上环境
4 | mode: dev
5 | # 服务器ip,默认使用 0.0.0.0
6 | host: 0.0.0.0
7 | # 服务名称
8 | name: testApp
9 | # 端口号
10 | port: 8000 # 服务端口号
11 | readtimeout: 3000
12 | writertimeout: 2000
13 | # 数据权限功能开关
14 | enabledp: false
15 | logger:
16 | # 日志存放路径
17 | path: temp/logs
18 | # 日志输出,file:文件,default:命令行,其他:命令行
19 | stdout: '' #控制台日志,启用后,不输出到文件
20 | # 日志等级, trace, debug, info, warn, error, fatal
21 | level: trace
22 | # 数据库日志开关
23 | enableddb: false
24 | jwt:
25 | # token 密钥,生产环境时及的修改
26 | secret: go-admin
27 | # token 过期时间 单位:秒
28 | timeout: 3600
29 | database:
30 | # 数据库类型 mysql,sqlite3, postgres
31 | driver: sqlite3
32 | # 数据库连接sqlite3数据文件的路径
33 | source: go-admin-db.db
34 | gen:
35 | # 代码生成读取的数据库名称
36 | dbname: dbname
37 | # 代码生成是使用前端代码存放位置,需要指定到src文件夹,相对路径
38 | frontpath: ../go-admin-ui/src
39 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_role.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysRole struct {
4 | RoleId int `json:"roleId" gorm:"primaryKey;autoIncrement"` // 角色编码
5 | RoleName string `json:"roleName" gorm:"size:128;"` // 角色名称
6 | Status string `json:"status" gorm:"size:4;"` //
7 | RoleKey string `json:"roleKey" gorm:"size:128;"` //角色代码
8 | RoleSort int `json:"roleSort" gorm:""` //角色排序
9 | Flag string `json:"flag" gorm:"size:128;"` //
10 | Remark string `json:"remark" gorm:"size:255;"` //备注
11 | Admin bool `json:"admin" gorm:"size:4;"`
12 | DataScope string `json:"dataScope" gorm:"size:128;"`
13 | SysMenu []SysMenu `json:"sysMenu" gorm:"many2many:sys_role_menu;foreignKey:RoleId;joinForeignKey:role_id;references:MenuId;joinReferences:menu_id;"`
14 | ControlBy
15 | ModelTime
16 | }
17 |
18 | func (SysRole) TableName() string {
19 | return "sys_role"
20 | }
--------------------------------------------------------------------------------
/common/middleware/handler/role.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import "go-admin/common/models"
4 |
5 | type SysRole struct {
6 | RoleId int `json:"roleId" gorm:"primaryKey;autoIncrement"` // 角色编码
7 | RoleName string `json:"roleName" gorm:"size:128;"` // 角色名称
8 | Status string `json:"status" gorm:"size:4;"` //
9 | RoleKey string `json:"roleKey" gorm:"size:128;"` //角色代码
10 | RoleSort int `json:"roleSort" gorm:""` //角色排序
11 | Flag string `json:"flag" gorm:"size:128;"` //
12 | Remark string `json:"remark" gorm:"size:255;"` //备注
13 | Admin bool `json:"admin" gorm:"size:4;"`
14 | DataScope string `json:"dataScope" gorm:"size:128;"`
15 | Params string `json:"params" gorm:"-"`
16 | MenuIds []int `json:"menuIds" gorm:"-"`
17 | DeptIds []int `json:"deptIds" gorm:"-"`
18 | models.ControlBy
19 | models.ModelTime
20 | }
21 |
22 | func (SysRole) TableName() string {
23 | return "sys_role"
24 | }
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/template/migrate.template:
--------------------------------------------------------------------------------
1 | package {{.Package}}
2 |
3 | import (
4 | "gorm.io/gorm"
5 | "runtime"
6 |
7 | "go-admin/cmd/migrate/migration"
8 | common "go-admin/common/models"
9 | )
10 |
11 | func init() {
12 | _, fileName, _, _ := runtime.Caller(0)
13 | migration.Migrate.SetVersion(migration.GetFilename(fileName), _{{.GenerateTime}}Test)
14 | }
15 |
16 | func _{{.GenerateTime}}Test(db *gorm.DB, version string) error {
17 | return db.Transaction(func(tx *gorm.DB) error {
18 |
19 | // TODO: 这里开始写入要变更的内容
20 |
21 | // TODO: 例如 修改表字段 使用过程中请删除此段代码
22 | //err := tx.Migrator().RenameColumn(&models.SysConfig{}, "config_id", "id")
23 | //if err != nil {
24 | // return err
25 | //}
26 |
27 | // TODO: 例如 新增表结构 使用过程中请删除此段代码
28 | //err = tx.Debug().Migrator().AutoMigrate(
29 | // new(models.CasbinRule),
30 | // )
31 | //if err != nil {
32 | // return err
33 | //}
34 |
35 |
36 | return tx.Create(&common.Migration{
37 | Version: version,
38 | }).Error
39 | })
40 | }
41 |
--------------------------------------------------------------------------------
/app/admin/apis/captcha.go:
--------------------------------------------------------------------------------
1 | package apis
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-admin-team/go-admin-core/sdk/api"
6 | "github.com/go-admin-team/go-admin-core/sdk/pkg/captcha"
7 | )
8 |
9 | type System struct {
10 | api.Api
11 | }
12 |
13 | // GenerateCaptchaHandler 获取验证码
14 | // @Summary 获取验证码
15 | // @Description 获取验证码
16 | // @Tags 登陆
17 | // @Success 200 {object} response.Response{data=string,id=string,msg=string} "{"code": 200, "data": [...]}"
18 | // @Router /api/v1/captcha [get]
19 | func (e System) GenerateCaptchaHandler(c *gin.Context) {
20 | if err := e.MakeContext(c).Errors; err != nil {
21 | e.Error(500, err, "服务初始化失败!")
22 | return
23 | }
24 | id, b64s, answer, err := captcha.DriverDigitFunc()
25 | if err != nil {
26 | e.Logger.Errorf("DriverDigitFunc error, %s", err.Error())
27 | e.Error(500, err, "验证码获取失败")
28 | return
29 | }
30 | e.Logger.Infof("DriverDigitFunc answer: %s", answer)
31 | e.Custom(gin.H{
32 | "code": 200,
33 | "data": b64s,
34 | "id": id,
35 | "msg": "success",
36 | })
37 | }
38 |
--------------------------------------------------------------------------------
/app/jobs/router/router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | )
7 |
8 | var (
9 | routerNoCheckRole = make([]func(*gin.RouterGroup), 0)
10 | routerCheckRole = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0)
11 | )
12 |
13 | // initRouter 路由示例
14 | func initRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine {
15 |
16 | // 无需认证的路由
17 | noCheckRoleRouter(r)
18 | // 需要认证的路由
19 | checkRoleRouter(r, authMiddleware)
20 |
21 | return r
22 | }
23 |
24 | // noCheckRoleRouter 无需认证的路由示例
25 | func noCheckRoleRouter(r *gin.Engine) {
26 | // 可根据业务需求来设置接口版本
27 | v1 := r.Group("/api/v1")
28 |
29 | for _, f := range routerNoCheckRole {
30 | f(v1)
31 | }
32 | }
33 |
34 | // checkRoleRouter 需要认证的路由示例
35 | func checkRoleRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) {
36 | // 可根据业务需求来设置接口版本
37 | v1 := r.Group("/api/v1")
38 |
39 | for _, f := range routerCheckRole {
40 | f(v1, authMiddleware)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/other/router/router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | )
7 |
8 | var (
9 | routerNoCheckRole = make([]func(*gin.RouterGroup), 0)
10 | routerCheckRole = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0)
11 | )
12 |
13 | // initRouter 路由示例
14 | func initRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine {
15 |
16 | // 无需认证的路由
17 | noCheckRoleRouter(r)
18 | // 需要认证的路由
19 | checkRoleRouter(r, authMiddleware)
20 |
21 | return r
22 | }
23 |
24 | // noCheckRoleRouter 无需认证的路由示例
25 | func noCheckRoleRouter(r *gin.Engine) {
26 | // 可根据业务需求来设置接口版本
27 | v1 := r.Group("/api/v1")
28 |
29 | for _, f := range routerNoCheckRole {
30 | f(v1)
31 | }
32 | }
33 |
34 | // checkRoleRouter 需要认证的路由示例
35 | func checkRoleRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) {
36 | // 可根据业务需求来设置接口版本
37 | v1 := r.Group("/api/v1")
38 |
39 | for _, f := range routerCheckRole {
40 | f(v1, authMiddleware)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/common/middleware/init.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-admin-team/go-admin-core/sdk"
6 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
7 | "go-admin/common/actions"
8 | )
9 |
10 | const (
11 | JwtTokenCheck string = "JwtToken"
12 | RoleCheck string = "AuthCheckRole"
13 | PermissionCheck string = "PermissionAction"
14 | )
15 |
16 | func InitMiddleware(r *gin.Engine) {
17 | r.Use(DemoEvn())
18 | // 数据库链接
19 | r.Use(WithContextDb)
20 | // 日志处理
21 | r.Use(LoggerToFile())
22 | // 自定义错误处理
23 | r.Use(CustomError)
24 | // NoCache is a middleware function that appends headers
25 | r.Use(NoCache)
26 | // 跨域处理
27 | r.Use(Options)
28 | // Secure is a middleware function that appends security
29 | r.Use(Secure)
30 | // 链路追踪
31 | //r.Use(middleware.Trace())
32 | sdk.Runtime.SetMiddleware(JwtTokenCheck, (*jwt.GinJWTMiddleware).MiddlewareFunc)
33 | sdk.Runtime.SetMiddleware(RoleCheck, AuthCheckRole())
34 | sdk.Runtime.SetMiddleware(PermissionCheck, actions.PermissionAction())
35 | }
36 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_job.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysJob struct {
4 | JobId int `json:"jobId" gorm:"primaryKey;autoIncrement"` // 编码
5 | JobName string `json:"jobName" gorm:"size:255;"` // 名称
6 | JobGroup string `json:"jobGroup" gorm:"size:255;"` // 任务分组
7 | JobType int `json:"jobType" gorm:"size:1;"` // 任务类型
8 | CronExpression string `json:"cronExpression" gorm:"size:255;"` // cron表达式
9 | InvokeTarget string `json:"invokeTarget" gorm:"size:255;"` // 调用目标
10 | Args string `json:"args" gorm:"size:255;"` // 目标参数
11 | MisfirePolicy int `json:"misfirePolicy" gorm:"size:255;"` // 执行策略
12 | Concurrent int `json:"concurrent" gorm:"size:1;"` // 是否并发
13 | Status int `json:"status" gorm:"size:1;"` // 状态
14 | EntryId int `json:"entry_id" gorm:"size:11;"` // job启动时返回的id
15 | ModelTime
16 | ControlBy
17 | }
18 |
19 | func (SysJob) TableName() string {
20 | return "sys_job"
21 | }
22 |
--------------------------------------------------------------------------------
/.github/workflows/issue-close-require.yml:
--------------------------------------------------------------------------------
1 | name: Issue Close Require
2 |
3 | on:
4 | schedule:
5 | - cron: "0 0 * * *"
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 | issue-close-require:
12 | permissions:
13 | issues: write # for actions-cool/issues-helper to update issues
14 | pull-requests: write # for actions-cool/issues-helper to update PRs
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: need reproduce
18 | uses: actions-cool/issues-helper@v3
19 | with:
20 | actions: 'close-issues'
21 | labels: '🤔 Need Reproduce'
22 | inactive-day: 3
23 |
24 | - name: needs more info
25 | uses: actions-cool/issues-helper@v3
26 | with:
27 | actions: 'close-issues'
28 | labels: 'needs-more-info'
29 | inactive-day: 3
30 | body: |
31 | Since the issue was labeled with `needs-more-info`, but no response in 3 days. This issue will be closed. If you have any questions, you can comment and reply.
32 | 由于该 issue 被标记为需要更多信息,却 3 天未收到回应。现关闭 issue,若有任何问题,可评论回复。
33 |
--------------------------------------------------------------------------------
/app/admin/router/router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | _ "github.com/gin-gonic/gin"
6 | "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
7 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
8 | )
9 |
10 | var (
11 | routerNoCheckRole = make([]func(*gin.RouterGroup), 0)
12 | routerCheckRole = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0)
13 | )
14 |
15 | func InitExamplesRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine {
16 |
17 | // 无需认证的路由
18 | examplesNoCheckRoleRouter(r)
19 | // 需要认证的路由
20 | examplesCheckRoleRouter(r, authMiddleware)
21 |
22 | return r
23 | }
24 |
25 | // 无需认证的路由示例
26 | func examplesNoCheckRoleRouter(r *gin.Engine) {
27 | // 可根据业务需求来设置接口版本
28 | v1 := r.Group("/api/v1")
29 | for _, f := range routerNoCheckRole {
30 | f(v1)
31 | }
32 | }
33 |
34 | // 需要认证的路由示例
35 | func examplesCheckRoleRouter(r *gin.Engine, authMiddleware *jwtauth.GinJWTMiddleware) {
36 | // 可根据业务需求来设置接口版本
37 | v1 := r.Group("/api/v1")
38 | for _, f := range routerCheckRole {
39 | f(v1, authMiddleware)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/test/gen_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | //"go-admin/models/tools"
5 | //"os"
6 | "testing"
7 | //"text/template"
8 | )
9 |
10 | func TestGoModelTemplate(t *testing.T) {
11 | //t1, err := template.ParseFiles("model.go.template")
12 | //if err != nil {
13 | // t.Error(err)
14 | //}
15 | //table := tools.SysTables{}
16 | //table.TBName = "sys_tables"
17 | //tab, err := table.Get()
18 | //if err != nil {
19 | // t.Error(err)
20 | //}
21 | //file, err := os.Create("models/" + table.PackageName + ".go")
22 | //if err != nil {
23 | // t.Error(err)
24 | //}
25 | //defer file.Close()
26 | //
27 | //_ = t1.Execute(file, tab)
28 | t.Log("")
29 | }
30 |
31 | func TestGoApiTemplate(t *testing.T) {
32 | //t1, err := template.ParseFiles("api.go.template")
33 | //if err != nil {
34 | // t.Error(err)
35 | //}
36 | //table := tools.SysTables{}
37 | //table.TBName = "sys_tables"
38 | //tab, _ := table.Get()
39 | //file, err := os.Create("apis/" + table.PackageName + ".go")
40 | //if err != nil {
41 | // t.Error(err)
42 | //}
43 | //defer file.Close()
44 | //
45 | //_ = t1.Execute(file, tab)
46 | t.Log("")
47 | }
48 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 go-admin-team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/admin/router/sys_config.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "go-admin/app/admin/apis"
5 | "go-admin/common/middleware"
6 |
7 | "github.com/gin-gonic/gin"
8 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
9 | )
10 |
11 | func init() {
12 | routerCheckRole = append(routerCheckRole, registerSysConfigRouter)
13 | }
14 |
15 | // 需认证的路由代码
16 | func registerSysConfigRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
17 | api := apis.SysConfig{}
18 | r := v1.Group("/config").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
19 | {
20 | r.GET("", api.GetPage)
21 | r.GET("/:id", api.Get)
22 | r.POST("", api.Insert)
23 | r.PUT("/:id", api.Update)
24 | r.DELETE("", api.Delete)
25 | }
26 |
27 | r1 := v1.Group("/configKey").Use(authMiddleware.MiddlewareFunc())
28 | {
29 | r1.GET("/:configKey", api.GetSysConfigByKEYForService)
30 | }
31 |
32 | r2 := v1.Group("/app-config")
33 | {
34 | r2.GET("", api.Get2SysApp)
35 | }
36 |
37 | r3 := v1.Group("/set-config").Use(authMiddleware.MiddlewareFunc())
38 | {
39 | r3.PUT("", api.Update2Set)
40 | r3.GET("", api.Get2Set)
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/common/middleware/handler/login.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | log "github.com/go-admin-team/go-admin-core/logger"
5 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
6 | "gorm.io/gorm"
7 | )
8 |
9 | type Login struct {
10 | Username string `form:"UserName" json:"username" binding:"required"`
11 | Password string `form:"Password" json:"password" binding:"required"`
12 | Code string `form:"Code" json:"code" binding:"required"`
13 | UUID string `form:"UUID" json:"uuid" binding:"required"`
14 | }
15 |
16 | func (u *Login) GetUser(tx *gorm.DB) (user SysUser, role SysRole, err error) {
17 | err = tx.Table("sys_user").Where("username = ? and status = '2'", u.Username).First(&user).Error
18 | if err != nil {
19 | log.Errorf("get user error, %s", err.Error())
20 | return
21 | }
22 | _, err = pkg.CompareHashAndPassword(user.Password, u.Password)
23 | if err != nil {
24 | log.Errorf("user login error, %s", err.Error())
25 | return
26 | }
27 | err = tx.Table("sys_role").Where("role_id = ? ", user.RoleId).First(&role).Error
28 | if err != nil {
29 | log.Errorf("get role error, %s", err.Error())
30 | return
31 | }
32 | return
33 | }
34 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/pr_cn.md:
--------------------------------------------------------------------------------
1 |
8 |
9 | [[English Template / 英文模板](https://github.com/go-admin-team/go-admin/blob/master/.github/PULL_REQUEST_TEMPLATE.md)]
10 |
11 | ### 🤔 这个变动的性质是?
12 |
13 | - [ ] 新特性提交
14 | - [ ] 日常 bug 修复
15 | - [ ] 站点、文档改进
16 | - [ ] 演示代码改进
17 | - [ ] 组件样式/交互改进
18 | - [ ] TypeScript 定义更新
19 | - [ ] 包体积优化
20 | - [ ] 性能优化
21 | - [ ] 功能增强
22 | - [ ] 国际化改进
23 | - [ ] 重构
24 | - [ ] 代码风格优化
25 | - [ ] 测试用例
26 | - [ ] 分支合并
27 | - [ ] 其他改动(是关于什么的改动?)
28 |
29 | ### 🔗 相关 Issue
30 |
31 |
34 |
35 | ### 💡 需求背景和解决方案
36 |
37 |
42 |
43 | ### 📝 更新日志
44 |
45 |
48 |
49 | | 语言 | 更新描述 |
50 | | ------- | -------- |
51 | | 🇺🇸 英文 | |
52 | | 🇨🇳 中文 | |
53 |
54 | ### ☑️ 请求合并前的自查清单
55 |
56 | ⚠️ 请自检并全部**勾选全部选项**。⚠️
57 |
58 | - [ ] 文档已补充或无须补充
59 | - [ ] 代码演示已提供或无须提供
60 | - [ ] TypeScript 定义已补充或无须补充
61 | - [ ] Changelog 已提供或无须提供
62 |
--------------------------------------------------------------------------------
/template/v4/actions/router_no_check_role.go.template:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "go-admin/app/{{.PackageName}}/middleware"
7 | "go-admin/app/{{.PackageName}}/models"
8 | "go-admin/app/{{.PackageName}}/service/dto"
9 | "go-admin/common/actions"
10 | )
11 |
12 | func init() {
13 | routerNoCheckRole = append(routerNoCheckRole, register{{.ClassName}}Router)
14 | }
15 |
16 | // 无需认证的路由代码
17 | func register{{.ClassName}}Router(v1 *gin.RouterGroup) {
18 | r := v1.Group("/{{.ModuleName}}")
19 | {
20 | model := &models.{{.ClassName}}{}
21 | r.GET("", actions.IndexAction(model, new(dto.{{.ClassName}}Search), func() interface{} {
22 | list := make([]models.{{.ClassName}}, 0)
23 | return &list
24 | }))
25 | r.GET("/:id", actions.ViewAction(new(dto.{{.ClassName}}ById), nil))
26 | r.POST("", actions.CreateAction(new(dto.{{.ClassName}}Control)))
27 | r.PUT("/:id", actions.UpdateAction(new(dto.{{.ClassName}}Control)))
28 | r.DELETE("", actions.DeleteAction(new(dto.{{.ClassName}}ById)))
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/common/middleware/auth.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/go-admin-team/go-admin-core/sdk/config"
7 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
8 | "go-admin/common/middleware/handler"
9 | )
10 |
11 | // AuthInit jwt验证new
12 | func AuthInit() (*jwt.GinJWTMiddleware, error) {
13 | timeout := time.Hour
14 | if config.ApplicationConfig.Mode == "dev" {
15 | timeout = time.Duration(876010) * time.Hour
16 | } else {
17 | if config.JwtConfig.Timeout != 0 {
18 | timeout = time.Duration(config.JwtConfig.Timeout) * time.Second
19 | }
20 | }
21 | return jwt.New(&jwt.GinJWTMiddleware{
22 | Realm: "test zone",
23 | Key: []byte(config.JwtConfig.Secret),
24 | Timeout: timeout,
25 | MaxRefresh: time.Hour,
26 | PayloadFunc: handler.PayloadFunc,
27 | IdentityHandler: handler.IdentityHandler,
28 | Authenticator: handler.Authenticator,
29 | Authorizator: handler.Authorizator,
30 | Unauthorized: handler.Unauthorized,
31 | TokenLookup: "header: Authorization, query: token, cookie: jwt",
32 | TokenHeadName: "Bearer",
33 | TimeFunc: time.Now,
34 | })
35 |
36 | }
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_dict_data.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type DictData struct {
4 | DictCode int `gorm:"primaryKey;autoIncrement;" json:"dictCode" example:"1"` //字典编码
5 | DictSort int `gorm:"" json:"dictSort"` //显示顺序
6 | DictLabel string `gorm:"size:128;" json:"dictLabel"` //数据标签
7 | DictValue string `gorm:"size:255;" json:"dictValue"` //数据键值
8 | DictType string `gorm:"size:64;" json:"dictType"` //字典类型
9 | CssClass string `gorm:"size:128;" json:"cssClass"` //
10 | ListClass string `gorm:"size:128;" json:"listClass"` //
11 | IsDefault string `gorm:"size:8;" json:"isDefault"` //
12 | Status int `gorm:"size:4;" json:"status"` //状态
13 | Default string `gorm:"size:8;" json:"default"` //
14 | Remark string `gorm:"size:255;" json:"remark"` //备注
15 | ControlBy
16 | ModelTime
17 | }
18 |
19 | func (DictData) TableName() string {
20 | return "sys_dict_data"
21 | }
22 |
--------------------------------------------------------------------------------
/template/v4/js.go.template:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | // 查询{{.ClassName}}列表
4 | export function list{{.ClassName}}(query) {
5 | return request({
6 | url: '/api/v1/{{.ModuleName}}',
7 | method: 'get',
8 | params: query
9 | })
10 | }
11 |
12 | // 查询{{.ClassName}}详细
13 | export function get{{.ClassName}} ({{.PkJsonField}}) {
14 | return request({
15 | url: '/api/v1/{{.ModuleName}}/' + {{.PkJsonField}},
16 | method: 'get'
17 | })
18 | }
19 |
20 |
21 | // 新增{{.ClassName}}
22 | export function add{{.ClassName}}(data) {
23 | return request({
24 | url: '/api/v1/{{.ModuleName}}',
25 | method: 'post',
26 | data: data
27 | })
28 | }
29 |
30 | // 修改{{.ClassName}}
31 | export function update{{.ClassName}}(data) {
32 | return request({
33 | url: '/api/v1/{{.ModuleName}}/'+data.{{.PkJsonField}},
34 | method: 'put',
35 | data: data
36 | })
37 | }
38 |
39 | // 删除{{.ClassName}}
40 | export function del{{.ClassName}}(data) {
41 | return request({
42 | url: '/api/v1/{{.ModuleName}}',
43 | method: 'delete',
44 | data: data
45 | })
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_login_log.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type SysLoginLog struct {
8 | Model
9 | Username string `json:"username" gorm:"type:varchar(128);comment:用户名"`
10 | Status string `json:"status" gorm:"type:varchar(4);comment:状态"`
11 | Ipaddr string `json:"ipaddr" gorm:"type:varchar(255);comment:ip地址"`
12 | LoginLocation string `json:"loginLocation" gorm:"type:varchar(255);comment:归属地"`
13 | Browser string `json:"browser" gorm:"type:varchar(255);comment:浏览器"`
14 | Os string `json:"os" gorm:"type:varchar(255);comment:系统"`
15 | Platform string `json:"platform" gorm:"type:varchar(255);comment:固件"`
16 | LoginTime time.Time `json:"loginTime" gorm:"type:timestamp;comment:登录时间"`
17 | Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
18 | Msg string `json:"msg" gorm:"type:varchar(255);comment:信息"`
19 | CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"`
20 | UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"`
21 | ControlBy
22 | }
23 |
24 | func (SysLoginLog) TableName() string {
25 | return "sys_login_log"
26 | }
27 |
--------------------------------------------------------------------------------
/common/file_store/initialize.go:
--------------------------------------------------------------------------------
1 | package file_store
2 |
3 | import "fmt"
4 |
5 | type OXS struct {
6 | // Endpoint 访问域名
7 | Endpoint string
8 | // AccessKeyID AK
9 | AccessKeyID string
10 | // AccessKeySecret AKS
11 | AccessKeySecret string
12 | // BucketName 桶名称
13 | BucketName string
14 | }
15 |
16 | // Setup 配置文件存储driver
17 | func (e *OXS) Setup(driver DriverType, options ...ClientOption) FileStoreType {
18 | fileStoreType := driver
19 | var fileStore FileStoreType
20 | switch fileStoreType {
21 | case AliYunOSS:
22 | fileStore = new(ALiYunOSS)
23 | err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName)
24 | if err != nil {
25 | fmt.Println(err)
26 | }
27 | return fileStore
28 | case HuaweiOBS:
29 | fileStore = new(HuaWeiOBS)
30 | err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName)
31 | if err != nil {
32 | fmt.Println(err)
33 | }
34 | return fileStore
35 | case QiNiuKodo:
36 | fileStore = new(QiNiuKODO)
37 | err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName)
38 | if err != nil {
39 | fmt.Println(err)
40 | }
41 | return fileStore
42 | }
43 |
44 | return nil
45 | }
46 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_menu.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysMenu struct {
4 | MenuId int `json:"menuId" gorm:"primaryKey;autoIncrement"`
5 | MenuName string `json:"menuName" gorm:"size:128;"`
6 | Title string `json:"title" gorm:"size:128;"`
7 | Icon string `json:"icon" gorm:"size:128;"`
8 | Path string `json:"path" gorm:"size:128;"`
9 | Paths string `json:"paths" gorm:"size:128;"`
10 | MenuType string `json:"menuType" gorm:"size:1;"`
11 | Action string `json:"action" gorm:"size:16;"`
12 | Permission string `json:"permission" gorm:"size:255;"`
13 | ParentId int `json:"parentId" gorm:"size:11;"`
14 | NoCache bool `json:"noCache" gorm:"size:8;"`
15 | Breadcrumb string `json:"breadcrumb" gorm:"size:255;"`
16 | Component string `json:"component" gorm:"size:255;"`
17 | Sort int `json:"sort" gorm:"size:4;"`
18 | Visible string `json:"visible" gorm:"size:1;"`
19 | IsFrame string `json:"isFrame" gorm:"size:1;DEFAULT:0;"`
20 | SysApi []SysApi `json:"sysApi" gorm:"many2many:sys_menu_api_rule"`
21 | ControlBy
22 | ModelTime
23 | }
24 |
25 | func (SysMenu) TableName() string {
26 | return "sys_menu"
27 | }
--------------------------------------------------------------------------------
/common/models/user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "gorm.io/gorm"
5 |
6 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
7 | )
8 |
9 | // BaseUser 密码登录基础用户
10 | type BaseUser struct {
11 | Username string `json:"username" gorm:"type:varchar(100);comment:用户名"`
12 | Salt string `json:"-" gorm:"type:varchar(255);comment:加盐;<-"`
13 | PasswordHash string `json:"-" gorm:"type:varchar(128);comment:密码hash;<-"`
14 | Password string `json:"password" gorm:"-"`
15 | }
16 |
17 | // SetPassword 设置密码
18 | func (u *BaseUser) SetPassword(value string) {
19 | u.Password = value
20 | u.generateSalt()
21 | u.PasswordHash = u.GetPasswordHash()
22 | }
23 |
24 | // GetPasswordHash 获取密码hash
25 | func (u *BaseUser) GetPasswordHash() string {
26 | passwordHash, err := pkg.SetPassword(u.Password, u.Salt)
27 | if err != nil {
28 | return ""
29 | }
30 | return passwordHash
31 | }
32 |
33 | // generateSalt 生成加盐值
34 | func (u *BaseUser) generateSalt() {
35 | u.Salt = pkg.GenerateRandomKey16()
36 | }
37 |
38 | // Verify 验证密码
39 | func (u *BaseUser) Verify(db *gorm.DB, tableName string) bool {
40 | db.Table(tableName).Where("username = ?", u.Username).First(u)
41 | return u.GetPasswordHash() == u.PasswordHash
42 | }
43 |
--------------------------------------------------------------------------------
/app/admin/models/sys_dept.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "go-admin/common/models"
4 |
5 | type SysDept struct {
6 | DeptId int `json:"deptId" gorm:"primaryKey;autoIncrement;"` //部门编码
7 | ParentId int `json:"parentId" gorm:""` //上级部门
8 | DeptPath string `json:"deptPath" gorm:"size:255;"` //
9 | DeptName string `json:"deptName" gorm:"size:128;"` //部门名称
10 | Sort int `json:"sort" gorm:"size:4;"` //排序
11 | Leader string `json:"leader" gorm:"size:128;"` //负责人
12 | Phone string `json:"phone" gorm:"size:11;"` //手机
13 | Email string `json:"email" gorm:"size:64;"` //邮箱
14 | Status int `json:"status" gorm:"size:4;"` //状态
15 | models.ControlBy
16 | models.ModelTime
17 | DataScope string `json:"dataScope" gorm:"-"`
18 | Params string `json:"params" gorm:"-"`
19 | Children []SysDept `json:"children" gorm:"-"`
20 | }
21 |
22 | func (*SysDept) TableName() string {
23 | return "sys_dept"
24 | }
25 |
26 | func (e *SysDept) Generate() models.ActiveRecord {
27 | o := *e
28 | return &o
29 | }
30 |
31 | func (e *SysDept) GetId() interface{} {
32 | return e.DeptId
33 | }
34 |
--------------------------------------------------------------------------------
/common/storage/initialize.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: zhangwenjian
3 | * @Date: 2025/04/13 22:03
4 | * @Last Modified by: zhangwenjian
5 | * @Last Modified time: 2025/04/13 22:03
6 | */
7 |
8 | package storage
9 |
10 | import (
11 | "log"
12 |
13 | "github.com/go-admin-team/go-admin-core/sdk"
14 | "github.com/go-admin-team/go-admin-core/sdk/config"
15 | "github.com/go-admin-team/go-admin-core/sdk/pkg/captcha"
16 | )
17 |
18 | // Setup 配置storage组件
19 | func Setup() {
20 | setupCache()
21 | setupCaptcha()
22 | setupQueue()
23 | }
24 |
25 | func setupCache() {
26 | cacheAdapter, err := config.CacheConfig.Setup()
27 | if err != nil {
28 | log.Fatalf("cache setup error, %s\n", err.Error())
29 | }
30 | sdk.Runtime.SetCacheAdapter(cacheAdapter)
31 | }
32 |
33 | func setupCaptcha() {
34 | captcha.SetStore(captcha.NewCacheStore(sdk.Runtime.GetCacheAdapter(), 600))
35 | }
36 |
37 | func setupQueue() {
38 | if config.QueueConfig.Empty() {
39 | return
40 | }
41 | if q := sdk.Runtime.GetQueueAdapter(); q != nil {
42 | q.Shutdown()
43 | }
44 | queueAdapter, err := config.QueueConfig.Setup()
45 | if err != nil {
46 | log.Fatalf("queue setup error, %s\n", err.Error())
47 | }
48 | sdk.Runtime.SetQueueAdapter(queueAdapter)
49 | go queueAdapter.Run()
50 | }
51 |
--------------------------------------------------------------------------------
/app/admin/models/sys_dict_data.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "go-admin/common/models"
5 | )
6 |
7 | type SysDictData struct {
8 | DictCode int `json:"dictCode" gorm:"primaryKey;column:dict_code;autoIncrement;comment:主键编码"`
9 | DictSort int `json:"dictSort" gorm:"size:20;comment:DictSort"`
10 | DictLabel string `json:"dictLabel" gorm:"size:128;comment:DictLabel"`
11 | DictValue string `json:"dictValue" gorm:"size:255;comment:DictValue"`
12 | DictType string `json:"dictType" gorm:"size:64;comment:DictType"`
13 | CssClass string `json:"cssClass" gorm:"size:128;comment:CssClass"`
14 | ListClass string `json:"listClass" gorm:"size:128;comment:ListClass"`
15 | IsDefault string `json:"isDefault" gorm:"size:8;comment:IsDefault"`
16 | Status int `json:"status" gorm:"size:4;comment:Status"`
17 | Default string `json:"default" gorm:"size:8;comment:Default"`
18 | Remark string `json:"remark" gorm:"size:255;comment:Remark"`
19 | models.ControlBy
20 | models.ModelTime
21 | }
22 |
23 | func (*SysDictData) TableName() string {
24 | return "sys_dict_data"
25 | }
26 |
27 | func (e *SysDictData) Generate() models.ActiveRecord {
28 | o := *e
29 | return &o
30 | }
31 |
32 | func (e *SysDictData) GetId() interface{} {
33 | return e.DictCode
34 | }
35 |
--------------------------------------------------------------------------------
/app/admin/router/sys_user.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/admin/apis"
7 | "go-admin/common/actions"
8 | "go-admin/common/middleware"
9 | )
10 |
11 | func init() {
12 | routerCheckRole = append(routerCheckRole, registerSysUserRouter)
13 | }
14 |
15 | // 需认证的路由代码
16 | func registerSysUserRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
17 | api := apis.SysUser{}
18 | r := v1.Group("/sys-user").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()).Use(actions.PermissionAction())
19 | {
20 | r.GET("", api.GetPage)
21 | r.GET("/:id", api.Get)
22 | r.POST("", api.Insert)
23 | r.PUT("", api.Update)
24 | r.DELETE("", api.Delete)
25 | }
26 |
27 | user := v1.Group("/user").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()).Use(actions.PermissionAction())
28 | {
29 | user.GET("/profile", api.GetProfile)
30 | user.POST("/avatar", api.InsetAvatar)
31 | user.PUT("/pwd/set", api.UpdatePwd)
32 | user.PUT("/pwd/reset", api.ResetPwd)
33 | user.PUT("/status", api.UpdateStatus)
34 | }
35 | v1auth := v1.Group("").Use(authMiddleware.MiddlewareFunc())
36 | {
37 | v1auth.GET("/getinfo", api.GetInfo)
38 | }
39 | }
--------------------------------------------------------------------------------
/app/admin/router/sys_dict.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/admin/apis"
7 | "go-admin/common/middleware"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, registerDictRouter)
12 | }
13 |
14 | func registerDictRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
15 | dictApi := apis.SysDictType{}
16 | dataApi := apis.SysDictData{}
17 | dicts := v1.Group("/dict").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
18 | {
19 |
20 | dicts.GET("/data", dataApi.GetPage)
21 | dicts.GET("/data/:dictCode", dataApi.Get)
22 | dicts.POST("/data", dataApi.Insert)
23 | dicts.PUT("/data/:dictCode", dataApi.Update)
24 | dicts.DELETE("/data", dataApi.Delete)
25 |
26 | dicts.GET("/type-option-select", dictApi.GetAll)
27 | dicts.GET("/type", dictApi.GetPage)
28 | dicts.GET("/type/:id", dictApi.Get)
29 | dicts.POST("/type", dictApi.Insert)
30 | dicts.PUT("/type/:id", dictApi.Update)
31 | dicts.DELETE("/type", dictApi.Delete)
32 | }
33 | opSelect := v1.Group("/dict-data").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
34 | {
35 | opSelect.GET("/option-select", dataApi.GetAll)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/common/actions/create.go:
--------------------------------------------------------------------------------
1 | package actions
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | "github.com/go-admin-team/go-admin-core/sdk/api"
8 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
9 | "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
10 | "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
11 |
12 | "go-admin/common/dto"
13 | "go-admin/common/models"
14 | )
15 |
16 | // CreateAction 通用新增动作
17 | func CreateAction(control dto.Control) gin.HandlerFunc {
18 | return func(c *gin.Context) {
19 | log := api.GetRequestLogger(c)
20 | db, err := pkg.GetOrm(c)
21 | if err != nil {
22 | log.Error(err)
23 | return
24 | }
25 |
26 | //新增操作
27 | req := control.Generate()
28 | err = req.Bind(c)
29 | if err != nil {
30 | response.Error(c, http.StatusUnprocessableEntity, err, err.Error())
31 | return
32 | }
33 | var object models.ActiveRecord
34 | object, err = req.GenerateM()
35 | if err != nil {
36 | response.Error(c, 500, err, "模型生成失败")
37 | return
38 | }
39 | object.SetCreateBy(user.GetUserId(c))
40 | err = db.WithContext(c).Create(object).Error
41 | if err != nil {
42 | log.Errorf("Create error: %s", err)
43 | response.Error(c, 500, err, "创建失败")
44 | return
45 | }
46 | response.OK(c, object.GetId(), "创建成功")
47 | c.Next()
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/common/middleware/customerror.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | "runtime"
7 | "strconv"
8 | "strings"
9 | "time"
10 |
11 | "github.com/gin-gonic/gin"
12 | )
13 |
14 | func CustomError(c *gin.Context) {
15 | defer func() {
16 | if err := recover(); err != nil {
17 |
18 | if c.IsAborted() {
19 | c.Status(200)
20 | }
21 | switch errStr := err.(type) {
22 | case string:
23 | p := strings.Split(errStr, "#")
24 | if len(p) == 3 && p[0] == "CustomError" {
25 | statusCode, e := strconv.Atoi(p[1])
26 | if e != nil {
27 | break
28 | }
29 | c.Status(statusCode)
30 | fmt.Println(
31 | time.Now().Format("2006-01-02 15:04:05"),
32 | "[ERROR]",
33 | c.Request.Method,
34 | c.Request.URL,
35 | statusCode,
36 | c.Request.RequestURI,
37 | c.ClientIP(),
38 | p[2],
39 | )
40 | c.JSON(http.StatusOK, gin.H{
41 | "code": statusCode,
42 | "msg": p[2],
43 | })
44 | } else {
45 | c.JSON(http.StatusOK, gin.H{
46 | "code": 500,
47 | "msg": errStr,
48 | })
49 | }
50 | case runtime.Error:
51 | c.JSON(http.StatusOK, gin.H{
52 | "code": 500,
53 | "msg": errStr.Error(),
54 | })
55 | default:
56 | panic(err)
57 | }
58 | }
59 | }()
60 | c.Next()
61 | }
62 |
--------------------------------------------------------------------------------
/scripts/k8s/deploy.yml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: go-admin
6 | labels:
7 | app: go-admin
8 | service: go-admin
9 | spec:
10 | ports:
11 | - port: 8000
12 | name: http
13 | protocol: TCP
14 | selector:
15 | app: go-admin
16 | ---
17 | apiVersion: apps/v1
18 | kind: Deployment
19 | metadata:
20 | name: go-admin-v1
21 | labels:
22 | app: go-admin
23 | version: v1
24 | spec:
25 | replicas: 1
26 | selector:
27 | matchLabels:
28 | app: go-admin
29 | version: v1
30 | template:
31 | metadata:
32 | labels:
33 | app: go-admin
34 | version: v1
35 | spec:
36 | containers:
37 | - name: go-admin
38 | image: registry.cn-shanghai.aliyuncs.com/go-admin-team/go-admin
39 | imagePullPolicy: IfNotPresent
40 | ports:
41 | - containerPort: 8000
42 | volumeMounts:
43 | - name: go-admin
44 | mountPath: /temp
45 | - name: go-admin
46 | mountPath: /static
47 | - name: go-admin-config
48 | mountPath: /config/
49 | readOnly: true
50 | volumes:
51 | - name: go-admin
52 | persistentVolumeClaim:
53 | claimName: go-admin
54 | - name: go-admin-config
55 | configMap:
56 | name: settings-admin
57 | ---
58 |
--------------------------------------------------------------------------------
/common/file_store/oss.go:
--------------------------------------------------------------------------------
1 | package file_store
2 |
3 | import (
4 | "github.com/aliyun/aliyun-oss-go-sdk/oss"
5 | "log"
6 | )
7 |
8 | type ALiYunOSS struct {
9 | Client interface{}
10 | BucketName string
11 | }
12 |
13 | //Setup 装载
14 | //endpoint sss
15 | func (e *ALiYunOSS) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error {
16 | client, err := oss.New(endpoint, accessKeyID, accessKeySecret)
17 | if err != nil {
18 | log.Println("Error:", err)
19 | return err
20 | }
21 | e.Client = client
22 | e.BucketName = BucketName
23 |
24 | return nil
25 | }
26 |
27 | // UpLoad 文件上传
28 | func (e *ALiYunOSS) UpLoad(yourObjectName string, localFile interface{}) error {
29 | // 获取存储空间。
30 | bucket, err := e.Client.(*oss.Client).Bucket(e.BucketName)
31 | if err != nil {
32 | log.Println("Error:", err)
33 | return err
34 | }
35 | // 设置分片大小为100 KB,指定分片上传并发数为3,并开启断点续传上传。
36 | // 其中与objectKey是同一概念,表示断点续传上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
37 | // "LocalFile"为filePath,100*1024为partSize。
38 | err = bucket.UploadFile(yourObjectName, localFile.(string), 100*1024, oss.Routines(3), oss.Checkpoint(true, ""))
39 | if err != nil {
40 | log.Println("Error:", err)
41 | return err
42 | }
43 | return nil
44 | }
45 |
46 | func (e *ALiYunOSS) GetTempToken() (string, error) {
47 | return "", nil
48 | }
49 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/version/1653638869132_migrate.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "go-admin/cmd/migrate/migration/models"
5 | common "go-admin/common/models"
6 | "gorm.io/gorm"
7 | "runtime"
8 | "strconv"
9 |
10 | "go-admin/cmd/migrate/migration"
11 | )
12 |
13 | func init() {
14 | _, fileName, _, _ := runtime.Caller(0)
15 | migration.Migrate.SetVersion(migration.GetFilename(fileName), _1653638869132Test)
16 | }
17 |
18 | func _1653638869132Test(db *gorm.DB, version string) error {
19 | return db.Transaction(func(tx *gorm.DB) error {
20 | var list []models.SysMenu
21 | err := tx.Model(&models.SysMenu{}).Order("parent_id,menu_id").Find(&list).Error
22 | if err != nil {
23 | return err
24 | }
25 | for _, v := range list {
26 | if v.ParentId == 0 {
27 | v.Paths = "/0/" + strconv.Itoa(v.MenuId)
28 | } else {
29 | var e models.SysMenu
30 | err = tx.Model(&models.SysMenu{}).Where("menu_id=?", v.ParentId).First(&e).Error
31 | if err != nil {
32 | if err == gorm.ErrRecordNotFound {
33 | continue
34 | }
35 | return err
36 | }
37 | v.Paths = e.Paths + "/" + strconv.Itoa(v.MenuId)
38 | }
39 | err = tx.Model(&v).Update("paths", v.Paths).Error
40 | if err != nil {
41 | return err
42 | }
43 | }
44 | return tx.Create(&common.Migration{
45 | Version: version,
46 | }).Error
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/template/v4/actions/router_check_role.go.template:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 |
7 | "go-admin/app/{{.PackageName}}/models"
8 | "go-admin/app/{{.PackageName}}/service/dto"
9 | "go-admin/common/actions"
10 | "go-admin/common/middleware"
11 | )
12 |
13 | func init() {
14 | routerCheckRole = append(routerCheckRole, register{{.ClassName}}Router)
15 | }
16 |
17 | // 需认证的路由代码
18 | func register{{.ClassName}}Router(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
19 | r := v1.Group("/{{.ModuleName}}").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
20 | {
21 | model := &models.{{.ClassName}}{}
22 | r.GET("", actions.PermissionAction(), actions.IndexAction(model, new(dto.{{.ClassName}}Search), func() interface{} {
23 | list := make([]models.{{.ClassName}}, 0)
24 | return &list
25 | }))
26 | r.GET("/:id", actions.PermissionAction(), actions.ViewAction(new(dto.{{.ClassName}}ById), nil))
27 | r.POST("", actions.CreateAction(new(dto.{{.ClassName}}Control)))
28 | r.PUT("/:id", actions.PermissionAction(), actions.UpdateAction(new(dto.{{.ClassName}}Control)))
29 | r.DELETE("", actions.PermissionAction(), actions.DeleteAction(new(dto.{{.ClassName}}ById)))
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/jobs/router/sys_job.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/jobs/apis"
7 | models2 "go-admin/app/jobs/models"
8 | dto2 "go-admin/app/jobs/service/dto"
9 | "go-admin/common/actions"
10 | "go-admin/common/middleware"
11 | )
12 |
13 | func init() {
14 | routerCheckRole = append(routerCheckRole, registerSysJobRouter)
15 | }
16 |
17 | // 需认证的路由代码
18 | func registerSysJobRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
19 |
20 | r := v1.Group("/sysjob").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
21 | {
22 | sysJob := &models2.SysJob{}
23 | r.GET("", actions.PermissionAction(), actions.IndexAction(sysJob, new(dto2.SysJobSearch), func() interface{} {
24 | list := make([]models2.SysJob, 0)
25 | return &list
26 | }))
27 | r.GET("/:id", actions.PermissionAction(), actions.ViewAction(new(dto2.SysJobById), func() interface{} {
28 | return &dto2.SysJobItem{}
29 | }))
30 | r.POST("", actions.CreateAction(new(dto2.SysJobControl)))
31 | r.PUT("", actions.PermissionAction(), actions.UpdateAction(new(dto2.SysJobControl)))
32 | r.DELETE("", actions.PermissionAction(), actions.DeleteAction(new(dto2.SysJobById)))
33 | }
34 | sysJob := apis.SysJob{}
35 |
36 | v1.GET("/job/remove/:id", sysJob.RemoveJobForService)
37 | v1.GET("/job/start/:id", sysJob.StartJobForService)
38 | }
39 |
--------------------------------------------------------------------------------
/static/form-generator/preview.html:
--------------------------------------------------------------------------------
1 | form-generator-preview
--------------------------------------------------------------------------------
/cmd/cobra.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
7 | "go-admin/cmd/app"
8 | "go-admin/common/global"
9 | "os"
10 |
11 | "github.com/spf13/cobra"
12 |
13 | "go-admin/cmd/api"
14 | "go-admin/cmd/config"
15 | "go-admin/cmd/migrate"
16 | "go-admin/cmd/version"
17 | )
18 |
19 | var rootCmd = &cobra.Command{
20 | Use: "go-admin",
21 | Short: "go-admin",
22 | SilenceUsage: true,
23 | Long: `go-admin`,
24 | Args: func(cmd *cobra.Command, args []string) error {
25 | if len(args) < 1 {
26 | tip()
27 | return errors.New(pkg.Red("requires at least one arg"))
28 | }
29 | return nil
30 | },
31 | PersistentPreRunE: func(*cobra.Command, []string) error { return nil },
32 | Run: func(cmd *cobra.Command, args []string) {
33 | tip()
34 | },
35 | }
36 |
37 | func tip() {
38 | usageStr := `欢迎使用 ` + pkg.Green(`go-admin `+global.Version) + ` 可以使用 ` + pkg.Red(`-h`) + ` 查看命令`
39 | usageStr1 := `也可以参考 https://doc.go-admin.dev/guide/ksks 的相关内容`
40 | fmt.Printf("%s\n", usageStr)
41 | fmt.Printf("%s\n", usageStr1)
42 | }
43 |
44 | func init() {
45 | rootCmd.AddCommand(api.StartCmd)
46 | rootCmd.AddCommand(migrate.StartCmd)
47 | rootCmd.AddCommand(version.StartCmd)
48 | rootCmd.AddCommand(config.StartCmd)
49 | rootCmd.AddCommand(app.StartCmd)
50 | }
51 |
52 | //Execute : apply commands
53 | func Execute() {
54 | if err := rootCmd.Execute(); err != nil {
55 | os.Exit(-1)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/init.go:
--------------------------------------------------------------------------------
1 | package migration
2 |
3 | import (
4 | "log"
5 | "path/filepath"
6 | "sort"
7 | "sync"
8 |
9 | "gorm.io/gorm"
10 | )
11 |
12 | var Migrate = &Migration{
13 | version: make(map[string]func(db *gorm.DB, version string) error),
14 | }
15 |
16 | type Migration struct {
17 | db *gorm.DB
18 | version map[string]func(db *gorm.DB, version string) error
19 | mutex sync.Mutex
20 | }
21 |
22 | func (e *Migration) GetDb() *gorm.DB {
23 | return e.db
24 | }
25 |
26 | func (e *Migration) SetDb(db *gorm.DB) {
27 | e.db = db
28 | }
29 |
30 | func (e *Migration) SetVersion(k string, f func(db *gorm.DB, version string) error) {
31 | e.mutex.Lock()
32 | defer e.mutex.Unlock()
33 | e.version[k] = f
34 | }
35 |
36 | func (e *Migration) Migrate() {
37 | versions := make([]string, 0)
38 | for k := range e.version {
39 | versions = append(versions, k)
40 | }
41 | if !sort.StringsAreSorted(versions) {
42 | sort.Strings(versions)
43 | }
44 | var err error
45 | var count int64
46 | for _, v := range versions {
47 | err = e.db.Table("sys_migration").Where("version = ?", v).Count(&count).Error
48 | if err != nil {
49 | log.Fatalln(err)
50 | }
51 | if count > 0 {
52 | log.Println(count)
53 | count = 0
54 | continue
55 | }
56 | err = (e.version[v])(e.db.Debug(), v)
57 | if err != nil {
58 | log.Fatalln(err)
59 | }
60 | }
61 | }
62 |
63 | func GetFilename(s string) string {
64 | s = filepath.Base(s)
65 | return s[:13]
66 | }
67 |
--------------------------------------------------------------------------------
/common/file_store/obs.go:
--------------------------------------------------------------------------------
1 | package file_store
2 |
3 | import (
4 | "fmt"
5 | "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs"
6 | "log"
7 | )
8 |
9 | type HuaWeiOBS struct {
10 | Client interface{}
11 | BucketName string
12 | }
13 |
14 | func (e *HuaWeiOBS) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error {
15 | // 创建ObsClient结构体
16 | client, err := obs.New(accessKeyID, accessKeySecret, endpoint)
17 | if err != nil {
18 | log.Println("Error:", err)
19 | return err
20 | }
21 | e.Client = client
22 | e.BucketName = BucketName
23 | return nil
24 | }
25 |
26 | // UpLoad 文件上传
27 | // yourObjectName 文件路径名称,与objectKey是同一概念,表示断点续传上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
28 | func (e *HuaWeiOBS) UpLoad(yourObjectName string, localFile interface{}) error {
29 | // 获取存储空间。
30 | input := &obs.PutFileInput{}
31 | input.Bucket = e.BucketName
32 | input.Key = yourObjectName
33 | input.SourceFile = localFile.(string)
34 | output, err := e.Client.(*obs.ObsClient).PutFile(input)
35 |
36 | if err == nil {
37 | fmt.Printf("RequestId:%s\n", output.RequestId)
38 | fmt.Printf("ETag:%s, StorageClass:%s\n", output.ETag, output.StorageClass)
39 | } else {
40 | if obsError, ok := err.(obs.ObsError); ok {
41 | fmt.Println(obsError.Code)
42 | fmt.Println(obsError.Message)
43 | } else {
44 | fmt.Println(err)
45 | }
46 | }
47 | return nil
48 | }
49 |
50 | func (e *HuaWeiOBS) GetTempToken() (string, error) {
51 | return "", nil
52 | }
53 |
--------------------------------------------------------------------------------
/app/admin/models/initdb.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "fmt"
5 | "go-admin/common/global"
6 | "gorm.io/gorm"
7 | "io/ioutil"
8 | "log"
9 | "strings"
10 | )
11 |
12 | func InitDb(db *gorm.DB) (err error) {
13 | filePath := "config/db.sql"
14 | err = ExecSql(db, filePath)
15 | if global.Driver == "postgres" {
16 | filePath = "config/pg.sql"
17 | err = ExecSql(db, filePath)
18 | }
19 | return err
20 | }
21 |
22 | func ExecSql(db *gorm.DB, filePath string) error {
23 | sql, err := Ioutil(filePath)
24 | if err != nil {
25 | fmt.Println("数据库基础数据初始化脚本读取失败!原因:", err.Error())
26 | return err
27 | }
28 | sqlList := strings.Split(sql, ";")
29 | for i := 0; i < len(sqlList)-1; i++ {
30 | if strings.Contains(sqlList[i], "--") {
31 | fmt.Println(sqlList[i])
32 | continue
33 | }
34 | sql := strings.Replace(sqlList[i]+";", "\n", "", -1)
35 | sql = strings.TrimSpace(sql)
36 | if err = db.Exec(sql).Error; err != nil {
37 | log.Printf("error sql: %s", sql)
38 | if !strings.Contains(err.Error(), "Query was empty") {
39 | return err
40 | }
41 | }
42 | }
43 | return nil
44 | }
45 |
46 | func Ioutil(filePath string) (string, error) {
47 | if contents, err := ioutil.ReadFile(filePath); err == nil {
48 | //因为contents是[]byte类型,直接转换成string类型后会多一行空格,需要使用strings.Replace替换换行符
49 | result := strings.Replace(string(contents), "\n", "", 1)
50 | fmt.Println("Use ioutil.ReadFile to read a file:", result)
51 | return result, nil
52 | } else {
53 | return "", err
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/version/1599190683659_tables.go:
--------------------------------------------------------------------------------
1 | package version
2 |
3 | import (
4 | "github.com/go-admin-team/go-admin-core/sdk/config"
5 | "runtime"
6 |
7 | "go-admin/cmd/migrate/migration"
8 | "go-admin/cmd/migrate/migration/models"
9 | common "go-admin/common/models"
10 |
11 | "gorm.io/gorm"
12 | )
13 |
14 | func init() {
15 | _, fileName, _, _ := runtime.Caller(0)
16 | migration.Migrate.SetVersion(migration.GetFilename(fileName), _1599190683659Tables)
17 | }
18 |
19 | func _1599190683659Tables(db *gorm.DB, version string) error {
20 | return db.Transaction(func(tx *gorm.DB) error {
21 | if config.DatabaseConfig.Driver == "mysql" {
22 | tx = tx.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4")
23 | }
24 | err := tx.Migrator().AutoMigrate(
25 | new(models.SysDept),
26 | new(models.SysConfig),
27 | new(models.SysTables),
28 | new(models.SysColumns),
29 | new(models.SysMenu),
30 | new(models.SysLoginLog),
31 | new(models.SysOperaLog),
32 | new(models.SysRoleDept),
33 | new(models.SysUser),
34 | new(models.SysRole),
35 | new(models.SysPost),
36 | new(models.DictData),
37 | new(models.DictType),
38 | new(models.SysJob),
39 | new(models.SysConfig),
40 | new(models.SysApi),
41 | new(models.TbDemo),
42 | )
43 | if err != nil {
44 | return err
45 | }
46 | if err := models.InitDb(tx); err != nil {
47 | return err
48 | }
49 | return tx.Create(&common.Migration{
50 | Version: version,
51 | }).Error
52 | })
53 | }
54 |
--------------------------------------------------------------------------------
/common/middleware/handler/user.go:
--------------------------------------------------------------------------------
1 | package handler
2 |
3 | import (
4 | "go-admin/common/models"
5 | "gorm.io/gorm"
6 | )
7 |
8 | type SysUser struct {
9 | UserId int `gorm:"primaryKey;autoIncrement;comment:编码" json:"userId"`
10 | Username string `json:"username" gorm:"size:64;comment:用户名"`
11 | Password string `json:"-" gorm:"size:128;comment:密码"`
12 | NickName string `json:"nickName" gorm:"size:128;comment:昵称"`
13 | Phone string `json:"phone" gorm:"size:11;comment:手机号"`
14 | RoleId int `json:"roleId" gorm:"size:20;comment:角色ID"`
15 | Salt string `json:"-" gorm:"size:255;comment:加盐"`
16 | Avatar string `json:"avatar" gorm:"size:255;comment:头像"`
17 | Sex string `json:"sex" gorm:"size:255;comment:性别"`
18 | Email string `json:"email" gorm:"size:128;comment:邮箱"`
19 | DeptId int `json:"deptId" gorm:"size:20;comment:部门"`
20 | PostId int `json:"postId" gorm:"size:20;comment:岗位"`
21 | Remark string `json:"remark" gorm:"size:255;comment:备注"`
22 | Status string `json:"status" gorm:"size:4;comment:状态"`
23 | DeptIds []int `json:"deptIds" gorm:"-"`
24 | PostIds []int `json:"postIds" gorm:"-"`
25 | RoleIds []int `json:"roleIds" gorm:"-"`
26 | //Dept *SysDept `json:"dept"`
27 | models.ControlBy
28 | models.ModelTime
29 | }
30 |
31 | func (*SysUser) TableName() string {
32 | return "sys_user"
33 | }
34 |
35 | func (e *SysUser) AfterFind(_ *gorm.DB) error {
36 | e.DeptIds = []int{e.DeptId}
37 | e.PostIds = []int{e.PostId}
38 | e.RoleIds = []int{e.RoleId}
39 | return nil
40 | }
41 |
--------------------------------------------------------------------------------
/app/admin/models/sys_role.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "go-admin/common/models"
4 |
5 | type SysRole struct {
6 | RoleId int `json:"roleId" gorm:"primaryKey;autoIncrement"` // 角色编码
7 | RoleName string `json:"roleName" gorm:"size:128;"` // 角色名称
8 | Status string `json:"status" gorm:"size:4;"` // 状态 1禁用 2正常
9 | RoleKey string `json:"roleKey" gorm:"size:128;"` //角色代码
10 | RoleSort int `json:"roleSort" gorm:""` //角色排序
11 | Flag string `json:"flag" gorm:"size:128;"` //
12 | Remark string `json:"remark" gorm:"size:255;"` //备注
13 | Admin bool `json:"admin" gorm:"size:4;"`
14 | DataScope string `json:"dataScope" gorm:"size:128;"`
15 | Params string `json:"params" gorm:"-"`
16 | MenuIds []int `json:"menuIds" gorm:"-"`
17 | DeptIds []int `json:"deptIds" gorm:"-"`
18 | SysDept []SysDept `json:"sysDept" gorm:"many2many:sys_role_dept;foreignKey:RoleId;joinForeignKey:role_id;references:DeptId;joinReferences:dept_id;"`
19 | SysMenu *[]SysMenu `json:"sysMenu" gorm:"many2many:sys_role_menu;foreignKey:RoleId;joinForeignKey:role_id;references:MenuId;joinReferences:menu_id;"`
20 | models.ControlBy
21 | models.ModelTime
22 | }
23 |
24 | func (*SysRole) TableName() string {
25 | return "sys_role"
26 | }
27 |
28 | func (e *SysRole) Generate() models.ActiveRecord {
29 | o := *e
30 | return &o
31 | }
32 |
33 | func (e *SysRole) GetId() interface{} {
34 | return e.RoleId
35 | }
36 |
--------------------------------------------------------------------------------
/common/actions/index.go:
--------------------------------------------------------------------------------
1 | package actions
2 |
3 | import (
4 | "errors"
5 | "net/http"
6 |
7 | "github.com/gin-gonic/gin"
8 | log "github.com/go-admin-team/go-admin-core/logger"
9 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
10 | "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
11 | "gorm.io/gorm"
12 |
13 | "go-admin/common/dto"
14 | "go-admin/common/models"
15 | )
16 |
17 | // IndexAction 通用查询动作
18 | func IndexAction(m models.ActiveRecord, d dto.Index, f func() interface{}) gin.HandlerFunc {
19 | return func(c *gin.Context) {
20 | db, err := pkg.GetOrm(c)
21 | if err != nil {
22 | log.Error(err)
23 | return
24 | }
25 |
26 | msgID := pkg.GenerateMsgIDFromContext(c)
27 | list := f()
28 | object := m.Generate()
29 | req := d.Generate()
30 | var count int64
31 |
32 | //查询列表
33 | err = req.Bind(c)
34 | if err != nil {
35 | response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
36 | return
37 | }
38 |
39 | //数据权限检查
40 | p := GetPermissionFromContext(c)
41 |
42 | err = db.WithContext(c).Model(object).
43 | Scopes(
44 | dto.MakeCondition(req.GetNeedSearch()),
45 | dto.Paginate(req.GetPageSize(), req.GetPageIndex()),
46 | Permission(object.TableName(), p),
47 | ).
48 | Find(list).Limit(-1).Offset(-1).
49 | Count(&count).Error
50 | if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
51 | log.Errorf("MsgID[%s] Index error: %s", msgID, err)
52 | response.Error(c, 500, err, "查询失败")
53 | return
54 | }
55 | response.PageOK(c, list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
56 | c.Next()
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/template/v4/model.go.template:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | {{- $bb := false -}}
5 | {{- range .Columns -}}
6 | {{- $z := .IsQuery -}}
7 | {{- if ($z) -}}
8 | {{- if eq .GoType "time.Time" -}}{{- $bb = true -}}{{- end -}}
9 | {{- end -}}
10 | {{- end -}}
11 | {{- range .Columns -}}
12 | {{- if eq .GoField "CreatedAt" -}}
13 | {{- else if eq .GoField "UpdatedAt" -}}
14 | {{- else if eq .GoField "DeletedAt" -}}
15 | {{- else -}}
16 | {{- if eq .GoType "time.Time" -}}{{- $bb = true -}}{{- end -}}
17 | {{- end -}}
18 | {{- end -}}
19 | {{- if eq $bb true }}
20 | "time"
21 | {{- end }}
22 |
23 | "go-admin/common/models"
24 |
25 | )
26 |
27 | type {{.ClassName}} struct {
28 | models.Model
29 | {{ range .Columns -}}
30 | {{$x := .Pk}}
31 | {{- if ($x) }}
32 | {{- else if eq .GoField "CreatedAt" -}}
33 | {{- else if eq .GoField "UpdatedAt" -}}
34 | {{- else if eq .GoField "DeletedAt" -}}
35 | {{- else if eq .GoField "CreateBy" -}}
36 | {{- else if eq .GoField "UpdateBy" -}}
37 | {{- else }}
38 | {{.GoField}} {{.GoType}} `json:"{{.JsonField}}" gorm:"type:{{.ColumnType}};comment:{{- if eq .ColumnComment "" -}}{{.GoField}}{{- else -}}{{.ColumnComment}}{{end -}}"` {{end -}}
39 | {{- end }}
40 | models.ModelTime
41 | models.ControlBy
42 | }
43 |
44 | func ({{.ClassName}}) TableName() string {
45 | return "{{.TBName}}"
46 | }
47 |
48 | func (e *{{.ClassName}}) Generate() models.ActiveRecord {
49 | o := *e
50 | return &o
51 | }
52 |
53 | func (e *{{.ClassName}}) GetId() interface{} {
54 | return e.{{.PkGoField}}
55 | }
--------------------------------------------------------------------------------
/common/actions/update.go:
--------------------------------------------------------------------------------
1 | package actions
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | log "github.com/go-admin-team/go-admin-core/logger"
8 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
9 | "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
10 | "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
11 |
12 | "go-admin/common/dto"
13 | "go-admin/common/models"
14 | )
15 |
16 | // UpdateAction 通用更新动作
17 | func UpdateAction(control dto.Control) gin.HandlerFunc {
18 | return func(c *gin.Context) {
19 | db, err := pkg.GetOrm(c)
20 | if err != nil {
21 | log.Error(err)
22 | return
23 | }
24 |
25 | msgID := pkg.GenerateMsgIDFromContext(c)
26 | req := control.Generate()
27 | //更新操作
28 | err = req.Bind(c)
29 | if err != nil {
30 | response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
31 | return
32 | }
33 | var object models.ActiveRecord
34 | object, err = req.GenerateM()
35 | if err != nil {
36 | response.Error(c, 500, err, "模型生成失败")
37 | return
38 | }
39 | object.SetUpdateBy(user.GetUserId(c))
40 |
41 | //数据权限检查
42 | p := GetPermissionFromContext(c)
43 |
44 | db = db.WithContext(c).Scopes(
45 | Permission(object.TableName(), p),
46 | ).Where(req.GetId()).Updates(object)
47 | if err = db.Error; err != nil {
48 | log.Errorf("MsgID[%s] Update error: %s", msgID, err)
49 | response.Error(c, 500, err, "更新失败")
50 | return
51 | }
52 | if db.RowsAffected == 0 {
53 | response.Error(c, http.StatusForbidden, nil, "无权更新该数据")
54 | return
55 | }
56 | response.OK(c, object.GetId(), "更新成功")
57 | c.Next()
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/jobs/apis/sys_job.go:
--------------------------------------------------------------------------------
1 | package apis
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | "github.com/go-admin-team/go-admin-core/sdk"
8 | "github.com/go-admin-team/go-admin-core/sdk/api"
9 |
10 | "go-admin/app/jobs/service"
11 | "go-admin/common/dto"
12 | )
13 |
14 | type SysJob struct {
15 | api.Api
16 | }
17 |
18 | // RemoveJobForService 调用service实现
19 | func (e SysJob) RemoveJobForService(c *gin.Context) {
20 | v := dto.GeneralDelDto{}
21 | s := service.SysJob{}
22 | err := e.MakeContext(c).
23 | MakeOrm().
24 | Bind(&v).
25 | MakeService(&s.Service).
26 | Errors
27 | if err != nil {
28 | e.Logger.Error(err)
29 | return
30 | }
31 |
32 | s.Cron = sdk.Runtime.GetCrontabKey(c.Request.Host)
33 | err = s.RemoveJob(&v)
34 | if err != nil {
35 | e.Logger.Errorf("RemoveJob error, %s", err.Error())
36 | e.Error(500, err, "")
37 | return
38 | }
39 | e.OK(nil, s.Msg)
40 | }
41 |
42 | // StartJobForService 启动job service实现
43 | func (e SysJob) StartJobForService(c *gin.Context) {
44 | e.MakeContext(c)
45 | log := e.GetLogger()
46 | db, err := e.GetOrm()
47 | if err != nil {
48 | log.Error(err)
49 | return
50 | }
51 | var v dto.GeneralGetDto
52 | err = c.BindUri(&v)
53 | if err != nil {
54 | log.Warnf("参数验证错误, error: %s", err)
55 | e.Error(http.StatusUnprocessableEntity, err, "参数验证失败")
56 | return
57 | }
58 | s := service.SysJob{}
59 | s.Orm = db
60 | s.Log = log
61 | s.Cron = sdk.Runtime.GetCrontabKey(c.Request.Host)
62 | err = s.StartJob(&v)
63 | if err != nil {
64 | log.Errorf("GetCrontabKey error, %s", err.Error())
65 | e.Error(500, err, err.Error())
66 | return
67 | }
68 | e.OK(nil, s.Msg)
69 | }
70 |
--------------------------------------------------------------------------------
/config/settings.full.yml:
--------------------------------------------------------------------------------
1 | settings:
2 | application:
3 | # dev开发环境 test测试环境 prod线上环境
4 | mode: dev
5 | # 服务器ip,默认使用 0.0.0.0
6 | host: 0.0.0.0
7 | # 服务名称
8 | name: testApp
9 | # 端口号
10 | port: 8000 # 服务端口号
11 | readtimeout: 1
12 | writertimeout: 2
13 | # 数据权限功能开关
14 | enabledp: false
15 | ssl:
16 | # https对应的域名
17 | domain: localhost:8000
18 | # https开关
19 | enable: false
20 | # ssl 证书key
21 | key: keystring
22 | # ssl 证书路径
23 | pem: temp/pem.pem
24 | logger:
25 | # 日志存放路径
26 | path: temp/logs
27 | # 日志输出,file:文件,default:命令行,其他:命令行
28 | stdout: '' #控制台日志,启用后,不输出到文件
29 | # 日志等级, trace, debug, info, warn, error, fatal
30 | level: trace
31 | # 数据库日志开关
32 | enableddb: false
33 | jwt:
34 | # token 密钥,生产环境时及的修改
35 | secret: go-admin
36 | # token 过期时间 单位:秒
37 | timeout: 3600
38 | database:
39 | # 数据库类型 mysql,sqlite3, postgres
40 | driver: mysql
41 | # 数据库连接字符串 mysql 缺省信息 charset=utf8&parseTime=True&loc=Local&timeout=1000ms
42 | source: user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms
43 | # source: sqlite3.db
44 | # source: host=myhost port=myport user=gorm dbname=gorm password=mypassword
45 | registers:
46 | - sources:
47 | - user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms
48 | gen:
49 | # 代码生成读取的数据库名称
50 | dbname: dbname
51 | # 代码生成是使用前端代码存放位置,需要指定到src文件夹,相对路径
52 | frontpath: ../go-admin-ui/src
53 | queue:
54 | memory:
55 | poolSize: 100
56 | extend: # 扩展项使用说明
57 | demo:
58 | name: data
59 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "golang.org/x/crypto/bcrypt"
5 | "gorm.io/gorm"
6 | )
7 |
8 | type SysUser struct {
9 | UserId int `gorm:"primaryKey;autoIncrement;comment:编码" json:"userId"`
10 | Username string `json:"username" gorm:"type:varchar(64);comment:用户名"`
11 | Password string `json:"-" gorm:"type:varchar(128);comment:密码"`
12 | NickName string `json:"nickName" gorm:"type:varchar(128);comment:昵称"`
13 | Phone string `json:"phone" gorm:"type:varchar(11);comment:手机号"`
14 | RoleId int `json:"roleId" gorm:"type:bigint;comment:角色ID"`
15 | Salt string `json:"-" gorm:"type:varchar(255);comment:加盐"`
16 | Avatar string `json:"avatar" gorm:"type:varchar(255);comment:头像"`
17 | Sex string `json:"sex" gorm:"type:varchar(255);comment:性别"`
18 | Email string `json:"email" gorm:"type:varchar(128);comment:邮箱"`
19 | DeptId int `json:"deptId" gorm:"type:bigint;comment:部门"`
20 | PostId int `json:"postId" gorm:"type:bigint;comment:岗位"`
21 | Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
22 | Status string `json:"status" gorm:"type:varchar(4);comment:状态"`
23 | ControlBy
24 | ModelTime
25 | }
26 |
27 | func (*SysUser) TableName() string {
28 | return "sys_user"
29 | }
30 |
31 | // Encrypt 加密
32 | func (e *SysUser) Encrypt() (err error) {
33 | if e.Password == "" {
34 | return
35 | }
36 |
37 | var hash []byte
38 | if hash, err = bcrypt.GenerateFromPassword([]byte(e.Password), bcrypt.DefaultCost); err != nil {
39 | return
40 | } else {
41 | e.Password = string(hash)
42 | return
43 | }
44 | }
45 |
46 | func (e *SysUser) BeforeCreate(_ *gorm.DB) error {
47 | return e.Encrypt()
48 | }
49 |
--------------------------------------------------------------------------------
/common/actions/delete.go:
--------------------------------------------------------------------------------
1 | package actions
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/gin-gonic/gin"
7 | log "github.com/go-admin-team/go-admin-core/logger"
8 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
9 | "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
10 | "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
11 |
12 | "go-admin/common/dto"
13 | "go-admin/common/models"
14 | )
15 |
16 | // DeleteAction 通用删除动作
17 | func DeleteAction(control dto.Control) gin.HandlerFunc {
18 | return func(c *gin.Context) {
19 | db, err := pkg.GetOrm(c)
20 | if err != nil {
21 | log.Error(err)
22 | return
23 | }
24 |
25 | msgID := pkg.GenerateMsgIDFromContext(c)
26 | //删除操作
27 | req := control.Generate()
28 | err = req.Bind(c)
29 | if err != nil {
30 | log.Errorf("MsgID[%s] Bind error: %s", msgID, err)
31 | response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
32 | return
33 | }
34 | var object models.ActiveRecord
35 | object, err = req.GenerateM()
36 | if err != nil {
37 | response.Error(c, 500, err, "模型生成失败")
38 | return
39 | }
40 |
41 | object.SetUpdateBy(user.GetUserId(c))
42 |
43 | //数据权限检查
44 | p := GetPermissionFromContext(c)
45 |
46 | db = db.WithContext(c).Scopes(
47 | Permission(object.TableName(), p),
48 | ).Where(req.GetId()).Delete(object)
49 | if err = db.Error; err != nil {
50 | log.Errorf("MsgID[%s] Delete error: %s", msgID, err)
51 | response.Error(c, 500, err, "删除失败")
52 | return
53 | }
54 | if db.RowsAffected == 0 {
55 | response.Error(c, http.StatusForbidden, nil, "无权删除该数据")
56 | return
57 | }
58 | response.OK(c, object.GetId(), "删除成功")
59 | c.Next()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/other/apis/tools/db_columns.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
6 | _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
7 |
8 | "go-admin/app/other/models/tools"
9 | )
10 |
11 | // GetDBColumnList 分页列表数据
12 | // @Summary 分页列表数据 / page list data
13 | // @Description 数据库表列分页列表 / database table column page list
14 | // @Tags 工具 / 生成工具
15 | // @Param tableName query string false "tableName / 数据表名称"
16 | // @Param pageSize query int false "pageSize / 页条数"
17 | // @Param pageIndex query int false "pageIndex / 页码"
18 | // @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
19 | // @Router /api/v1/db/columns/page [get]
20 | func (e Gen) GetDBColumnList(c *gin.Context) {
21 | e.Context = c
22 | log := e.GetLogger()
23 | var data tools.DBColumns
24 | var err error
25 | var pageSize = 10
26 | var pageIndex = 1
27 |
28 | if size := c.Request.FormValue("pageSize"); size != "" {
29 | pageSize, err = pkg.StringToInt(size)
30 | }
31 |
32 | if index := c.Request.FormValue("pageIndex"); index != "" {
33 | pageIndex, err = pkg.StringToInt(index)
34 | }
35 |
36 | db, err := pkg.GetOrm(c)
37 | if err != nil {
38 | log.Errorf("get db connection error, %s", err.Error())
39 | e.Error(500, err, "数据库连接获取失败")
40 | return
41 | }
42 |
43 | data.TableName = c.Request.FormValue("tableName")
44 | pkg.Assert(data.TableName == "", "table name cannot be empty!", 500)
45 | result, count, err := data.GetPage(db, pageSize, pageIndex)
46 | if err != nil {
47 | log.Errorf("GetPage error, %s", err.Error())
48 | e.Error(500, err, "")
49 | return
50 | }
51 | e.PageOK(result, count, pageIndex, pageSize, "查询成功")
52 | }
53 |
--------------------------------------------------------------------------------
/common/actions/view.go:
--------------------------------------------------------------------------------
1 | package actions
2 |
3 | import (
4 | "errors"
5 | "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
6 | "net/http"
7 |
8 | "github.com/gin-gonic/gin"
9 | log "github.com/go-admin-team/go-admin-core/logger"
10 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
11 | "gorm.io/gorm"
12 |
13 | "go-admin/common/dto"
14 | "go-admin/common/models"
15 | )
16 |
17 | // ViewAction 通用详情动作
18 | func ViewAction(control dto.Control, f func() interface{}) gin.HandlerFunc {
19 | return func(c *gin.Context) {
20 | db, err := pkg.GetOrm(c)
21 | if err != nil {
22 | log.Error(err)
23 | return
24 | }
25 |
26 | msgID := pkg.GenerateMsgIDFromContext(c)
27 | //查看详情
28 | req := control.Generate()
29 | err = req.Bind(c)
30 | if err != nil {
31 | response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
32 | return
33 | }
34 | var object models.ActiveRecord
35 | object, err = req.GenerateM()
36 | if err != nil {
37 | response.Error(c, 500, err, "模型生成失败")
38 | return
39 | }
40 |
41 | var rsp interface{}
42 | if f != nil {
43 | rsp = f()
44 | } else {
45 | rsp, _ = req.GenerateM()
46 | }
47 |
48 | //数据权限检查
49 | p := GetPermissionFromContext(c)
50 |
51 | err = db.Model(object).WithContext(c).Scopes(
52 | Permission(object.TableName(), p),
53 | ).Where(req.GetId()).First(rsp).Error
54 |
55 | if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
56 | response.Error(c, http.StatusNotFound, nil, "查看对象不存在或无权查看")
57 | return
58 | }
59 | if err != nil {
60 | log.Errorf("MsgID[%s] View error: %s", msgID, err)
61 | response.Error(c, 500, err, "查看失败")
62 | return
63 | }
64 | response.OK(c, rsp, "查询成功")
65 | c.Next()
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | PROJECT:=go-admin
2 |
3 | .PHONY: build
4 | build:
5 | CGO_ENABLED=0 go build -ldflags="-w -s" -a -installsuffix "" -o go-admin .
6 |
7 | # make build-linux
8 | build-linux:
9 | @docker build -t go-admin:latest .
10 | @echo "build successful"
11 |
12 | build-sqlite:
13 | go build -tags sqlite3 -ldflags="-w -s" -a -installsuffix -o go-admin .
14 |
15 | # make run
16 | run:
17 | # delete go-admin-api container
18 | @if [ $(shell docker ps -aq --filter name=go-admin --filter publish=8000) ]; then docker rm -f go-admin; fi
19 |
20 | # 启动方法一 run go-admin-api container docker-compose 启动方式
21 | # 进入到项目根目录 执行 make run 命令
22 | @docker-compose up -d
23 |
24 | # 启动方式二 docker run 这里注意-v挂载的宿主机的地址改为部署时的实际决对路径
25 | #@docker run --name=go-admin -p 8000:8000 -v /home/code/go/src/go-admin/go-admin/config:/go-admin-api/config -v /home/code/go/src/go-admin/go-admin-api/static:/go-admin/static -v /home/code/go/src/go-admin/go-admin/temp:/go-admin-api/temp -d --restart=always go-admin:latest
26 |
27 | @echo "go-admin service is running..."
28 |
29 | # delete Tag= 的镜像
30 | @docker image prune -f
31 | @docker ps -a | grep "go-admin"
32 |
33 | stop:
34 | # delete go-admin-api container
35 | @if [ $(shell docker ps -aq --filter name=go-admin --filter publish=8000) ]; then docker-compose down; fi
36 | #@if [ $(shell docker ps -aq --filter name=go-admin --filter publish=8000) ]; then docker rm -f go-admin; fi
37 | #@echo "go-admin stop success"
38 |
39 |
40 | #.PHONY: test
41 | #test:
42 | # go test -v ./... -cover
43 |
44 | #.PHONY: docker
45 | #docker:
46 | # docker build . -t go-admin:latest
47 |
48 | # make deploy
49 | deploy:
50 |
51 | #@git checkout master
52 | #@git pull origin master
53 | make build-linux
54 | make run
55 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches: [ master, dev ]
6 | pull_request:
7 | branches: [ master ]
8 | env:
9 | REGISTRY: ghcr.io
10 | IMAGE_NAME: ${{ github.repository }}
11 |
12 | jobs:
13 |
14 | build:
15 | name: Build
16 | runs-on: ubuntu-latest
17 | steps:
18 |
19 | - name: Set up Go 1.18
20 | uses: actions/setup-go@v3
21 | with:
22 | go-version: 1.18
23 | id: go
24 |
25 | - name: Check out code into the Go module directory
26 | uses: actions/checkout@v3
27 |
28 | - name: Get dependencies
29 | run: go mod tidy
30 | - name: Build
31 | run: make build
32 |
33 | - name: Log in to the Container registry
34 | uses: docker/login-action@v2
35 | if: startsWith(${{github.ref}}, 'refs/tags/')
36 | with:
37 | registry: ${{ env.REGISTRY }}
38 | username: ${{ github.actor }}
39 | password: ${{ secrets.GITHUB_TOKEN }}
40 |
41 | - name: Extract metadata (tags, labels) for Docker
42 | id: meta
43 | if: startsWith(${{github.ref}}, 'refs/tags/')
44 | uses: docker/metadata-action@v4
45 | with:
46 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
47 | flavor: |
48 | latest=auto
49 | tags: |
50 | type=schedule
51 | type=ref,event=tag
52 | type=sha,prefix=,format=long,enable=true,priority=100
53 |
54 | - name: Build and push Docker image
55 | uses: docker/build-push-action@v3
56 | if: startsWith(${{github.ref}}, 'refs/tags/')
57 | with:
58 | context: .
59 | file: scripts/Dockerfile
60 | push: true
61 | tags: ${{ steps.meta.outputs.tags }}
62 | labels: ${{ steps.meta.outputs.labels }}
63 |
--------------------------------------------------------------------------------
/common/middleware/header.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "net/http"
5 | "time"
6 |
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | // NoCache is a middleware function that appends headers
11 | // to prevent the client from caching the HTTP response.
12 | func NoCache(c *gin.Context) {
13 | c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
14 | c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
15 | c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
16 | c.Next()
17 | }
18 |
19 | // Options is a middleware function that appends headers
20 | // for options requests and aborts then exits the middleware
21 | // chain and ends the request.
22 | func Options(c *gin.Context) {
23 | if c.Request.Method != "OPTIONS" {
24 | c.Next()
25 | } else {
26 | c.Header("Access-Control-Allow-Origin", "*")
27 | c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
28 | c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
29 | c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS")
30 | c.Header("Content-Type", "application/json")
31 | c.AbortWithStatus(200)
32 | }
33 | }
34 |
35 | // Secure is a middleware function that appends security
36 | // and resource access headers.
37 | func Secure(c *gin.Context) {
38 | c.Header("Access-Control-Allow-Origin", "*")
39 | //c.Header("X-Frame-Options", "DENY")
40 | c.Header("X-Content-Type-Options", "nosniff")
41 | c.Header("X-XSS-Protection", "1; mode=block")
42 | if c.Request.TLS != nil {
43 | c.Header("Strict-Transport-Security", "max-age=31536000")
44 | }
45 |
46 | // Also consider adding Content-Security-Policy headers
47 | // c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com")
48 | }
49 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [ master ]
9 |
10 | jobs:
11 | analyze:
12 | name: Analyze
13 | runs-on: ubuntu-latest
14 |
15 | strategy:
16 | fail-fast: false
17 | matrix:
18 | language: [ 'go' ]
19 |
20 | steps:
21 | - name: Checkout repository
22 | uses: actions/checkout@v2
23 |
24 | # Initializes the CodeQL tools for scanning.
25 | - name: Initialize CodeQL
26 | uses: github/codeql-action/init@v1
27 | with:
28 | languages: ${{ matrix.language }}
29 | # If you wish to specify custom queries, you can do so here or in a config file.
30 | # By default, queries listed here will override any specified in a config file.
31 | # Prefix the list here with "+" to use these queries and those in the config file.
32 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
33 |
34 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
35 | # If this step fails, then you should remove it and run the build manually (see below)
36 | - name: Autobuild
37 | uses: github/codeql-action/autobuild@v1
38 |
39 | # ℹ️ Command-line programs to run using the OS shell.
40 | # 📚 https://git.io/JvXDl
41 |
42 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
43 | # and modify them (or add more) to build your code if your project
44 | # uses a compiled language
45 |
46 | #- run: |
47 | # make bootstrap
48 | # make release
49 |
50 | - name: Perform CodeQL Analysis
51 | uses: github/codeql-action/analyze@v1
52 |
--------------------------------------------------------------------------------
/app/admin/service/sys_login_log.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/go-admin-team/go-admin-core/sdk/service"
7 | "gorm.io/gorm"
8 |
9 | "go-admin/app/admin/models"
10 | "go-admin/app/admin/service/dto"
11 | cDto "go-admin/common/dto"
12 | )
13 |
14 | type SysLoginLog struct {
15 | service.Service
16 | }
17 |
18 | // GetPage 获取SysLoginLog列表
19 | func (e *SysLoginLog) GetPage(c *dto.SysLoginLogGetPageReq, list *[]models.SysLoginLog, count *int64) error {
20 | var err error
21 | var data models.SysLoginLog
22 |
23 | err = e.Orm.Model(&data).
24 | Scopes(
25 | cDto.MakeCondition(c.GetNeedSearch()),
26 | cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
27 | ).
28 | Find(list).Limit(-1).Offset(-1).
29 | Count(count).Error
30 | if err != nil {
31 | e.Log.Errorf("db error:%s", err)
32 | return err
33 | }
34 | return nil
35 | }
36 |
37 | // Get 获取SysLoginLog对象
38 | func (e *SysLoginLog) Get(d *dto.SysLoginLogGetReq, model *models.SysLoginLog) error {
39 | var err error
40 | db := e.Orm.First(model, d.GetId())
41 | err = db.Error
42 | if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
43 | err = errors.New("查看对象不存在或无权查看")
44 | e.Log.Errorf("db error:%s", err)
45 | return err
46 | }
47 | if err = db.Error; err != nil {
48 | e.Log.Errorf("db error:%s", err)
49 | return err
50 | }
51 | return nil
52 | }
53 |
54 | // Remove 删除SysLoginLog
55 | func (e *SysLoginLog) Remove(c *dto.SysLoginLogDeleteReq) error {
56 | var err error
57 | var data models.SysLoginLog
58 |
59 | db := e.Orm.Delete(&data, c.GetId())
60 | if err = db.Error; err != nil {
61 | e.Log.Errorf("Delete error: %s", err)
62 | return err
63 | }
64 | if db.RowsAffected == 0 {
65 | err = errors.New("无权删除该数据")
66 | return err
67 | }
68 | return nil
69 | }
70 |
--------------------------------------------------------------------------------
/cmd/config/server.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 |
7 | "github.com/go-admin-team/go-admin-core/config/source/file"
8 | "github.com/spf13/cobra"
9 |
10 | "github.com/go-admin-team/go-admin-core/sdk/config"
11 | )
12 |
13 | var (
14 | configYml string
15 | StartCmd = &cobra.Command{
16 | Use: "config",
17 | Short: "Get Application config info",
18 | Example: "go-admin config -c config/settings.yml",
19 | Run: func(cmd *cobra.Command, args []string) {
20 | run()
21 | },
22 | }
23 | )
24 |
25 | func init() {
26 | StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file")
27 | }
28 |
29 | func run() {
30 | config.Setup(file.NewSource(file.WithPath(configYml)))
31 |
32 | application, errs := json.MarshalIndent(config.ApplicationConfig, "", " ") //转换成JSON返回的是byte[]
33 | if errs != nil {
34 | fmt.Println(errs.Error())
35 | }
36 | fmt.Println("application:", string(application))
37 |
38 | jwt, errs := json.MarshalIndent(config.JwtConfig, "", " ") //转换成JSON返回的是byte[]
39 | if errs != nil {
40 | fmt.Println(errs.Error())
41 | }
42 | fmt.Println("jwt:", string(jwt))
43 |
44 | // todo 需要兼容
45 | database, errs := json.MarshalIndent(config.DatabasesConfig, "", " ") //转换成JSON返回的是byte[]
46 | if errs != nil {
47 | fmt.Println(errs.Error())
48 | }
49 | fmt.Println("database:", string(database))
50 |
51 | gen, errs := json.MarshalIndent(config.GenConfig, "", " ") //转换成JSON返回的是byte[]
52 | if errs != nil {
53 | fmt.Println(errs.Error())
54 | }
55 | fmt.Println("gen:", string(gen))
56 |
57 | loggerConfig, errs := json.MarshalIndent(config.LoggerConfig, "", " ") //转换成JSON返回的是byte[]
58 | if errs != nil {
59 | fmt.Println(errs.Error())
60 | }
61 | fmt.Println("logger:", string(loggerConfig))
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/common/middleware/settings.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | type UrlInfo struct {
4 | Url string
5 | Method string
6 | }
7 |
8 | // CasbinExclude casbin 排除的路由列表
9 | var CasbinExclude = []UrlInfo{
10 | {Url: "/api/v1/dict/type-option-select", Method: "GET"},
11 | {Url: "/api/v1/dict-data/option-select", Method: "GET"},
12 | {Url: "/api/v1/deptTree", Method: "GET"},
13 | {Url: "/api/v1/db/tables/page", Method: "GET"},
14 | {Url: "/api/v1/db/columns/page", Method: "GET"},
15 | {Url: "/api/v1/gen/toproject/:tableId", Method: "GET"},
16 | {Url: "/api/v1/gen/todb/:tableId", Method: "GET"},
17 | {Url: "/api/v1/gen/tabletree", Method: "GET"},
18 | {Url: "/api/v1/gen/preview/:tableId", Method: "GET"},
19 | {Url: "/api/v1/gen/apitofile/:tableId", Method: "GET"},
20 | {Url: "/api/v1/getCaptcha", Method: "GET"},
21 | {Url: "/api/v1/getinfo", Method: "GET"},
22 | {Url: "/api/v1/menuTreeselect", Method: "GET"},
23 | {Url: "/api/v1/menurole", Method: "GET"},
24 | {Url: "/api/v1/menuids", Method: "GET"},
25 | {Url: "/api/v1/roleMenuTreeselect/:roleId", Method: "GET"},
26 | {Url: "/api/v1/roleDeptTreeselect/:roleId", Method: "GET"},
27 | {Url: "/api/v1/refresh_token", Method: "GET"},
28 | {Url: "/api/v1/configKey/:configKey", Method: "GET"},
29 | {Url: "/api/v1/app-config", Method: "GET"},
30 | {Url: "/api/v1/user/profile", Method: "GET"},
31 | {Url: "/info", Method: "GET"},
32 | {Url: "/api/v1/login", Method: "POST"},
33 | {Url: "/api/v1/logout", Method: "POST"},
34 | {Url: "/api/v1/user/avatar", Method: "POST"},
35 | {Url: "/api/v1/user/pwd", Method: "PUT"},
36 | {Url: "/api/v1/metrics", Method: "GET"},
37 | {Url: "/api/v1/health", Method: "GET"},
38 | {Url: "/", Method: "GET"},
39 | {Url: "/api/v1/server-monitor", Method: "GET"},
40 | {Url: "/api/v1/public/uploadFile", Method: "POST"},
41 | {Url: "/api/v1/user/pwd/set", Method: "PUT"},
42 | {Url: "/api/v1/sys-user", Method: "PUT"},
43 | }
44 |
--------------------------------------------------------------------------------
/app/other/router/gen_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
6 | "go-admin/app/admin/apis"
7 | "go-admin/app/other/apis/tools"
8 | )
9 |
10 | func init() {
11 | routerCheckRole = append(routerCheckRole, sysNoCheckRoleRouter, registerDBRouter, registerSysTableRouter)
12 | }
13 |
14 | func sysNoCheckRoleRouter(v1 *gin.RouterGroup ,authMiddleware *jwt.GinJWTMiddleware) {
15 | r1 := v1.Group("")
16 | {
17 | sys := apis.System{}
18 | r1.GET("/captcha", sys.GenerateCaptchaHandler)
19 | }
20 |
21 | r := v1.Group("").Use(authMiddleware.MiddlewareFunc())
22 | {
23 | gen := tools.Gen{}
24 | r.GET("/gen/preview/:tableId", gen.Preview)
25 | r.GET("/gen/toproject/:tableId", gen.GenCode)
26 | r.GET("/gen/apitofile/:tableId", gen.GenApiToFile)
27 | r.GET("/gen/todb/:tableId", gen.GenMenuAndApi)
28 | sysTable := tools.SysTable{}
29 | r.GET("/gen/tabletree", sysTable.GetSysTablesTree)
30 | }
31 | }
32 |
33 | func registerDBRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
34 | db := v1.Group("/db").Use(authMiddleware.MiddlewareFunc())
35 | {
36 | gen := tools.Gen{}
37 | db.GET("/tables/page", gen.GetDBTableList)
38 | db.GET("/columns/page", gen.GetDBColumnList)
39 | }
40 | }
41 |
42 | func registerSysTableRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
43 | tables := v1.Group("/sys/tables")
44 | {
45 | sysTable := tools.SysTable{}
46 | tables.Group("").Use(authMiddleware.MiddlewareFunc()).GET("/page", sysTable.GetPage)
47 | tablesInfo := tables.Group("/info").Use(authMiddleware.MiddlewareFunc())
48 | {
49 | tablesInfo.POST("", sysTable.Insert)
50 | tablesInfo.PUT("", sysTable.Update)
51 | tablesInfo.DELETE("/:tableId", sysTable.Delete)
52 | tablesInfo.GET("/:tableId", sysTable.Get)
53 | tablesInfo.GET("", sysTable.GetSysTablesInfo)
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_opera_log.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type SysOperaLog struct {
8 | Model
9 | Title string `json:"title" gorm:"type:varchar(255);comment:操作模块"`
10 | BusinessType string `json:"businessType" gorm:"type:varchar(128);comment:操作类型"`
11 | BusinessTypes string `json:"businessTypes" gorm:"type:varchar(128);comment:BusinessTypes"`
12 | Method string `json:"method" gorm:"type:varchar(128);comment:函数"`
13 | RequestMethod string `json:"requestMethod" gorm:"type:varchar(128);comment:请求方式: GET POST PUT DELETE"`
14 | OperatorType string `json:"operatorType" gorm:"type:varchar(128);comment:操作类型"`
15 | OperName string `json:"operName" gorm:"type:varchar(128);comment:操作者"`
16 | DeptName string `json:"deptName" gorm:"type:varchar(128);comment:部门名称"`
17 | OperUrl string `json:"operUrl" gorm:"type:varchar(255);comment:访问地址"`
18 | OperIp string `json:"operIp" gorm:"type:varchar(128);comment:客户端ip"`
19 | OperLocation string `json:"operLocation" gorm:"type:varchar(128);comment:访问位置"`
20 | OperParam string `json:"operParam" gorm:"type:text;comment:请求参数"`
21 | Status string `json:"status" gorm:"type:varchar(4);comment:操作状态 1:正常 2:关闭"`
22 | OperTime time.Time `json:"operTime" gorm:"type:timestamp;comment:操作时间"`
23 | JsonResult string `json:"jsonResult" gorm:"type:varchar(255);comment:返回数据"`
24 | Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"`
25 | LatencyTime string `json:"latencyTime" gorm:"type:varchar(128);comment:耗时"`
26 | UserAgent string `json:"userAgent" gorm:"type:varchar(255);comment:ua"`
27 | CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"`
28 | UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"`
29 | ControlBy
30 | }
31 |
32 | func (SysOperaLog) TableName() string {
33 | return "sys_opera_log"
34 | }
35 |
--------------------------------------------------------------------------------
/template/router.template:
--------------------------------------------------------------------------------
1 | package router
2 |
3 |
4 | import (
5 | "github.com/gin-gonic/gin"
6 | _ "github.com/gin-gonic/gin"
7 | log "github.com/go-admin-team/go-admin-core/logger"
8 | "github.com/go-admin-team/go-admin-core/sdk"
9 | // "github.com/go-admin-team/go-admin-core/sdk/pkg"
10 | "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
11 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
12 | common "go-admin/common/middleware"
13 | "os"
14 | )
15 |
16 | var (
17 | routerNoCheckRole = make([]func(*gin.RouterGroup), 0)
18 | routerCheckRole = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0)
19 | )
20 |
21 | // InitRouter 路由初始化
22 | func InitRouter() {
23 | var r *gin.Engine
24 | h := sdk.Runtime.GetEngine()
25 | if h == nil {
26 | h = gin.New()
27 | sdk.Runtime.SetEngine(h)
28 | }
29 | switch h.(type) {
30 | case *gin.Engine:
31 | r = h.(*gin.Engine)
32 | default:
33 | log.Fatal("not support other engine")
34 | os.Exit(-1)
35 | }
36 |
37 | // the jwt middleware
38 | authMiddleware, err := common.AuthInit()
39 | if err != nil {
40 | log.Fatalf("JWT Init Error, %s", err.Error())
41 | }
42 |
43 | // 注册业务路由
44 | InitBusinessRouter(r, authMiddleware)
45 | }
46 |
47 | func InitBusinessRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine {
48 |
49 | // 无需认证的路由
50 | noCheckRoleRouter(r)
51 | // 需要认证的路由
52 | checkRoleRouter(r, authMiddleware)
53 |
54 | return r
55 | }
56 |
57 | // noCheckRoleRouter 无需认证的路由
58 | func noCheckRoleRouter(r *gin.Engine) {
59 | // 可根据业务需求来设置接口版本
60 | v := r.Group("/api/v1")
61 |
62 | for _, f := range routerNoCheckRole {
63 | f(v)
64 | }
65 | }
66 |
67 | // checkRoleRouter 需要认证的路由
68 | func checkRoleRouter(r *gin.Engine, authMiddleware *jwtauth.GinJWTMiddleware) {
69 | // 可根据业务需求来设置接口版本
70 | v := r.Group("/api/v1")
71 |
72 | for _, f := range routerCheckRole {
73 | f(v, authMiddleware)
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/common/middleware/permission.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/casbin/casbin/v2/util"
5 | "net/http"
6 |
7 | "github.com/gin-gonic/gin"
8 | "github.com/go-admin-team/go-admin-core/sdk"
9 | "github.com/go-admin-team/go-admin-core/sdk/api"
10 | "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
11 | "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
12 | )
13 |
14 | // AuthCheckRole 权限检查中间件
15 | func AuthCheckRole() gin.HandlerFunc {
16 | return func(c *gin.Context) {
17 | log := api.GetRequestLogger(c)
18 | data, _ := c.Get(jwtauth.JwtPayloadKey)
19 | v := data.(jwtauth.MapClaims)
20 | e := sdk.Runtime.GetCasbinKey(c.Request.Host)
21 | var res, casbinExclude bool
22 | var err error
23 | //检查权限
24 | if v["rolekey"] == "admin" {
25 | res = true
26 | c.Next()
27 | return
28 | }
29 | for _, i := range CasbinExclude {
30 | if util.KeyMatch2(c.Request.URL.Path, i.Url) && c.Request.Method == i.Method {
31 | casbinExclude = true
32 | break
33 | }
34 | }
35 | if casbinExclude {
36 | log.Infof("Casbin exclusion, no validation method:%s path:%s", c.Request.Method, c.Request.URL.Path)
37 | c.Next()
38 | return
39 | }
40 | res, err = e.Enforce(v["rolekey"], c.Request.URL.Path, c.Request.Method)
41 | if err != nil {
42 | log.Errorf("AuthCheckRole error:%s method:%s path:%s", err, c.Request.Method, c.Request.URL.Path)
43 | response.Error(c, 500, err, "")
44 | return
45 | }
46 |
47 | if res {
48 | log.Infof("isTrue: %v role: %s method: %s path: %s", res, v["rolekey"], c.Request.Method, c.Request.URL.Path)
49 | c.Next()
50 | } else {
51 | log.Warnf("isTrue: %v role: %s method: %s path: %s message: %s", res, v["rolekey"], c.Request.Method, c.Request.URL.Path, "当前request无权限,请管理员确认!")
52 | c.JSON(http.StatusOK, gin.H{
53 | "code": 403,
54 | "msg": "对不起,您没有该接口访问权限,请联系管理员",
55 | })
56 | c.Abort()
57 | return
58 | }
59 |
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/other/apis/tools/db_tables.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "errors"
5 | "github.com/gin-gonic/gin"
6 | "github.com/go-admin-team/go-admin-core/sdk/config"
7 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
8 | _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response"
9 |
10 | "go-admin/app/other/models/tools"
11 | )
12 |
13 | // GetDBTableList 分页列表数据
14 | // @Summary 分页列表数据 / page list data
15 | // @Description 数据库表分页列表 / database table page list
16 | // @Tags 工具 / 生成工具
17 | // @Param tableName query string false "tableName / 数据表名称"
18 | // @Param pageSize query int false "pageSize / 页条数"
19 | // @Param pageIndex query int false "pageIndex / 页码"
20 | // @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
21 | // @Router /api/v1/db/tables/page [get]
22 | func (e Gen) GetDBTableList(c *gin.Context) {
23 | //var res response.Response
24 | var data tools.DBTables
25 | var err error
26 | var pageSize = 10
27 | var pageIndex = 1
28 | e.Context = c
29 | log := e.GetLogger()
30 | if config.DatabaseConfig.Driver == "sqlite3" || config.DatabaseConfig.Driver == "postgres" {
31 | err = errors.New("对不起,sqlite3 或 postgres 不支持代码生成!")
32 | log.Warn(err)
33 | e.Error(403, err, "")
34 | return
35 | }
36 |
37 | if size := c.Request.FormValue("pageSize"); size != "" {
38 | pageSize, err = pkg.StringToInt(size)
39 | }
40 |
41 | if index := c.Request.FormValue("pageIndex"); index != "" {
42 | pageIndex, err = pkg.StringToInt(index)
43 | }
44 |
45 | db, err := pkg.GetOrm(c)
46 | if err != nil {
47 | log.Errorf("get db connection error, %s", err.Error())
48 | e.Error(500, err, "数据库连接获取失败")
49 | return
50 | }
51 |
52 | data.TableName = c.Request.FormValue("tableName")
53 | result, count, err := data.GetPage(db, pageSize, pageIndex)
54 | if err != nil {
55 | log.Errorf("GetPage error, %s", err.Error())
56 | e.Error(500, err, "")
57 | return
58 | }
59 | e.PageOK(result, count, pageIndex, pageSize, "查询成功")
60 | }
61 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/initdb.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "fmt"
5 | "go-admin/common/global"
6 | "io/ioutil"
7 | "log"
8 | "strings"
9 |
10 | "gorm.io/gorm"
11 | )
12 |
13 | func InitDb(db *gorm.DB) (err error) {
14 | filePath := "config/db.sql"
15 | if global.Driver == "postgres" {
16 | filePath := "config/db.sql"
17 | if err = ExecSql(db, filePath); err != nil {
18 | return err
19 | }
20 | filePath = "config/pg.sql"
21 | err = ExecSql(db, filePath)
22 | } else if global.Driver == "mysql" {
23 | filePath = "config/db-begin-mysql.sql"
24 | if err = ExecSql(db, filePath); err != nil {
25 | return err
26 | }
27 | filePath = "config/db.sql"
28 | if err = ExecSql(db, filePath); err != nil {
29 | return err
30 | }
31 | filePath = "config/db-end-mysql.sql"
32 | err = ExecSql(db, filePath)
33 | } else {
34 | err = ExecSql(db, filePath)
35 | }
36 | return err
37 | }
38 |
39 | func ExecSql(db *gorm.DB, filePath string) error {
40 | sql, err := Ioutil(filePath)
41 | if err != nil {
42 | fmt.Println("数据库基础数据初始化脚本读取失败!原因:", err.Error())
43 | return err
44 | }
45 | sqlList := strings.Split(sql, ";")
46 | for i := 0; i < len(sqlList)-1; i++ {
47 | if strings.Contains(sqlList[i], "--") {
48 | fmt.Println(sqlList[i])
49 | continue
50 | }
51 | sql := strings.Replace(sqlList[i]+";", "\n", "", -1)
52 | sql = strings.TrimSpace(sql)
53 | if err = db.Exec(sql).Error; err != nil {
54 | log.Printf("error sql: %s", sql)
55 | if !strings.Contains(err.Error(), "Query was empty") {
56 | return err
57 | }
58 | }
59 | }
60 | return nil
61 | }
62 |
63 | func Ioutil(filePath string) (string, error) {
64 | if contents, err := ioutil.ReadFile(filePath); err == nil {
65 | //因为contents是[]byte类型,直接转换成string类型后会多一行空格,需要使用strings.Replace替换换行符
66 | result := strings.Replace(string(contents), "\n", "", 1)
67 | fmt.Println("Use ioutil.ReadFile to read a file:", result)
68 | return result, nil
69 | } else {
70 | return "", err
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/admin/models/sys_menu.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import "go-admin/common/models"
4 |
5 | type SysMenu struct {
6 | MenuId int `json:"menuId" gorm:"primaryKey;autoIncrement"`
7 | MenuName string `json:"menuName" gorm:"size:128;"`
8 | Title string `json:"title" gorm:"size:128;"`
9 | Icon string `json:"icon" gorm:"size:128;"`
10 | Path string `json:"path" gorm:"size:128;"`
11 | Paths string `json:"paths" gorm:"size:128;"`
12 | MenuType string `json:"menuType" gorm:"size:1;"`
13 | Action string `json:"action" gorm:"size:16;"`
14 | Permission string `json:"permission" gorm:"size:255;"`
15 | ParentId int `json:"parentId" gorm:"size:11;"`
16 | NoCache bool `json:"noCache" gorm:"size:8;"`
17 | Breadcrumb string `json:"breadcrumb" gorm:"size:255;"`
18 | Component string `json:"component" gorm:"size:255;"`
19 | Sort int `json:"sort" gorm:"size:4;"`
20 | Visible string `json:"visible" gorm:"size:1;"`
21 | IsFrame string `json:"isFrame" gorm:"size:1;DEFAULT:0;"`
22 | SysApi []SysApi `json:"sysApi" gorm:"many2many:sys_menu_api_rule"`
23 | Apis []int `json:"apis" gorm:"-"`
24 | DataScope string `json:"dataScope" gorm:"-"`
25 | Params string `json:"params" gorm:"-"`
26 | RoleId int `gorm:"-"`
27 | Children []SysMenu `json:"children,omitempty" gorm:"-"`
28 | IsSelect bool `json:"is_select" gorm:"-"`
29 | models.ControlBy
30 | models.ModelTime
31 | }
32 |
33 | type SysMenuSlice []SysMenu
34 |
35 | func (x SysMenuSlice) Len() int { return len(x) }
36 | func (x SysMenuSlice) Less(i, j int) bool { return x[i].Sort < x[j].Sort }
37 | func (x SysMenuSlice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
38 |
39 | func (*SysMenu) TableName() string {
40 | return "sys_menu"
41 | }
42 |
43 | func (e *SysMenu) Generate() models.ActiveRecord {
44 | o := *e
45 | return &o
46 | }
47 |
48 | func (e *SysMenu) GetId() interface{} {
49 | return e.MenuId
50 | }
51 |
--------------------------------------------------------------------------------
/common/dto/search.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "github.com/go-admin-team/go-admin-core/tools/search"
5 | "go-admin/common/global"
6 | "gorm.io/gorm"
7 | )
8 |
9 | type GeneralDelDto struct {
10 | Id int `uri:"id" json:"id" validate:"required"`
11 | Ids []int `json:"ids"`
12 | }
13 |
14 | func (g GeneralDelDto) GetIds() []int {
15 | ids := make([]int, 0)
16 | if g.Id != 0 {
17 | ids = append(ids, g.Id)
18 | }
19 | if len(g.Ids) > 0 {
20 | for _, id := range g.Ids {
21 | if id > 0 {
22 | ids = append(ids, id)
23 | }
24 | }
25 | } else {
26 | if g.Id > 0 {
27 | ids = append(ids, g.Id)
28 | }
29 | }
30 | if len(ids) <= 0 {
31 | //方式全部删除
32 | ids = append(ids, 0)
33 | }
34 | return ids
35 | }
36 |
37 | type GeneralGetDto struct {
38 | Id int `uri:"id" json:"id" validate:"required"`
39 | }
40 |
41 | func MakeCondition(q interface{}) func(db *gorm.DB) *gorm.DB {
42 | return func(db *gorm.DB) *gorm.DB {
43 | condition := &search.GormCondition{
44 | GormPublic: search.GormPublic{},
45 | Join: make([]*search.GormJoin, 0),
46 | }
47 | search.ResolveSearchQuery(global.Driver, q, condition)
48 | for _, join := range condition.Join {
49 | if join == nil {
50 | continue
51 | }
52 | db = db.Joins(join.JoinOn)
53 | for k, v := range join.Where {
54 | db = db.Where(k, v...)
55 | }
56 | for k, v := range join.Or {
57 | db = db.Or(k, v...)
58 | }
59 | for _, o := range join.Order {
60 | db = db.Order(o)
61 | }
62 | }
63 | for k, v := range condition.Where {
64 | db = db.Where(k, v...)
65 | }
66 | for k, v := range condition.Or {
67 | db = db.Or(k, v...)
68 | }
69 | for _, o := range condition.Order {
70 | db = db.Order(o)
71 | }
72 | return db
73 | }
74 | }
75 |
76 | func Paginate(pageSize, pageIndex int) func(db *gorm.DB) *gorm.DB {
77 | return func(db *gorm.DB) *gorm.DB {
78 | offset := (pageIndex - 1) * pageSize
79 | if offset < 0 {
80 | offset = 0
81 | }
82 | return db.Offset(offset).Limit(pageSize)
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
13 |
14 | [[中文版模板 / Chinese template](https://github.com/go-admin-team/go-admin/blob/master/.github/PULL_REQUEST_TEMPLATE/pr_cn.md)]
15 |
16 | ### 🤔 This is a ...
17 |
18 | - [ ] New feature
19 | - [ ] Bug fix
20 | - [ ] Site / documentation update
21 | - [ ] Demo update
22 | - [ ] Component style update
23 | - [ ] TypeScript definition update
24 | - [ ] Bundle size optimization
25 | - [ ] Performance optimization
26 | - [ ] Enhancement feature
27 | - [ ] Internationalization
28 | - [ ] Refactoring
29 | - [ ] Code style optimization
30 | - [ ] Test Case
31 | - [ ] Branch merge
32 | - [ ] Other (about what?)
33 |
34 | ### 🔗 Related issue link
35 |
36 |
39 |
40 | ### 💡 Background and solution
41 |
42 |
47 |
48 | ### 📝 Changelog
49 |
50 |
53 |
54 | | Language | Changelog |
55 | | ---------- | --------- |
56 | | 🇺🇸 English | |
57 | | 🇨🇳 Chinese | |
58 |
59 | ### ☑️ Self-Check before Merge
60 |
61 | ⚠️ Please check all items below before review. ⚠️
62 |
63 | - [ ] Doc is updated/provided or not needed
64 | - [ ] Demo is updated/provided or not needed
65 | - [ ] TypeScript's definition is updated/provided or not needed
66 | - [ ] Changelog is provided or not needed
67 |
--------------------------------------------------------------------------------
/common/database/initialize.go:
--------------------------------------------------------------------------------
1 | package database
2 |
3 | import (
4 | "time"
5 |
6 | log "github.com/go-admin-team/go-admin-core/logger"
7 | "github.com/go-admin-team/go-admin-core/sdk"
8 | toolsConfig "github.com/go-admin-team/go-admin-core/sdk/config"
9 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
10 | mycasbin "github.com/go-admin-team/go-admin-core/sdk/pkg/casbin"
11 | toolsDB "github.com/go-admin-team/go-admin-core/tools/database"
12 | . "github.com/go-admin-team/go-admin-core/tools/gorm/logger"
13 | "gorm.io/gorm"
14 | "gorm.io/gorm/logger"
15 | "gorm.io/gorm/schema"
16 |
17 | "go-admin/common/global"
18 | )
19 |
20 | // Setup 配置数据库
21 | func Setup() {
22 | for k := range toolsConfig.DatabasesConfig {
23 | setupSimpleDatabase(k, toolsConfig.DatabasesConfig[k])
24 | }
25 | }
26 |
27 | func setupSimpleDatabase(host string, c *toolsConfig.Database) {
28 | if global.Driver == "" {
29 | global.Driver = c.Driver
30 | }
31 | log.Infof("%s => %s", host, pkg.Green(c.Source))
32 | registers := make([]toolsDB.ResolverConfigure, len(c.Registers))
33 | for i := range c.Registers {
34 | registers[i] = toolsDB.NewResolverConfigure(
35 | c.Registers[i].Sources,
36 | c.Registers[i].Replicas,
37 | c.Registers[i].Policy,
38 | c.Registers[i].Tables)
39 | }
40 | resolverConfig := toolsDB.NewConfigure(c.Source, c.MaxIdleConns, c.MaxOpenConns, c.ConnMaxIdleTime, c.ConnMaxLifeTime, registers)
41 | db, err := resolverConfig.Init(&gorm.Config{
42 | NamingStrategy: schema.NamingStrategy{
43 | SingularTable: true,
44 | },
45 | Logger: New(
46 | logger.Config{
47 | SlowThreshold: time.Second,
48 | Colorful: true,
49 | LogLevel: logger.LogLevel(
50 | log.DefaultLogger.Options().Level.LevelForGorm()),
51 | },
52 | ),
53 | }, opens[c.Driver])
54 |
55 | if err != nil {
56 | log.Fatal(pkg.Red(c.Driver+" connect error :"), err)
57 | } else {
58 | log.Info(pkg.Green(c.Driver + " connect success !"))
59 | }
60 |
61 | e := mycasbin.Setup(db, "")
62 |
63 | sdk.Runtime.SetDb(host, db)
64 | sdk.Runtime.SetCasbin(host, e)
65 | }
66 |
--------------------------------------------------------------------------------
/app/jobs/models/sys_job.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "go-admin/common/models"
5 | "gorm.io/gorm"
6 | )
7 |
8 | type SysJob struct {
9 | JobId int `json:"jobId" gorm:"primaryKey;autoIncrement"` // 编码
10 | JobName string `json:"jobName" gorm:"size:255;"` // 名称
11 | JobGroup string `json:"jobGroup" gorm:"size:255;"` // 任务分组
12 | JobType int `json:"jobType" gorm:"size:1;"` // 任务类型
13 | CronExpression string `json:"cronExpression" gorm:"size:255;"` // cron表达式
14 | InvokeTarget string `json:"invokeTarget" gorm:"size:255;"` // 调用目标
15 | Args string `json:"args" gorm:"size:255;"` // 目标参数
16 | MisfirePolicy int `json:"misfirePolicy" gorm:"size:255;"` // 执行策略
17 | Concurrent int `json:"concurrent" gorm:"size:1;"` // 是否并发
18 | Status int `json:"status" gorm:"size:1;"` // 状态
19 | EntryId int `json:"entry_id" gorm:"size:11;"` // job启动时返回的id
20 | models.ControlBy
21 | models.ModelTime
22 |
23 | DataScope string `json:"dataScope" gorm:"-"`
24 | }
25 |
26 | func (*SysJob) TableName() string {
27 | return "sys_job"
28 | }
29 |
30 | func (e *SysJob) Generate() models.ActiveRecord {
31 | o := *e
32 | return &o
33 | }
34 |
35 | func (e *SysJob) GetId() interface{} {
36 | return e.JobId
37 | }
38 |
39 | func (e *SysJob) SetCreateBy(createBy int) {
40 | e.CreateBy = createBy
41 | }
42 |
43 | func (e *SysJob) SetUpdateBy(updateBy int) {
44 | e.UpdateBy = updateBy
45 | }
46 |
47 | func (e *SysJob) GetList(tx *gorm.DB, list interface{}) (err error) {
48 | return tx.Table(e.TableName()).Where("status = ?", 2).Find(list).Error
49 | }
50 |
51 | // Update 更新SysJob
52 | func (e *SysJob) Update(tx *gorm.DB, id interface{}) (err error) {
53 | return tx.Table(e.TableName()).Where(id).Updates(&e).Error
54 | }
55 |
56 | func (e *SysJob) RemoveAllEntryID(tx *gorm.DB) (update SysJob, err error) {
57 | if err = tx.Table(e.TableName()).Where("entry_id > ?", 0).Update("entry_id", 0).Error; err != nil {
58 | return
59 | }
60 | return
61 | }
62 |
--------------------------------------------------------------------------------
/app/admin/service/dto/sys_login_log.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "time"
5 |
6 | "go-admin/common/dto"
7 | )
8 |
9 | type SysLoginLogGetPageReq struct {
10 | dto.Pagination `search:"-"`
11 | Username string `form:"username" search:"type:exact;column:username;table:sys_login_log" comment:"用户名"`
12 | Status string `form:"status" search:"type:exact;column:status;table:sys_login_log" comment:"状态"`
13 | Ipaddr string `form:"ipaddr" search:"type:exact;column:ipaddr;table:sys_login_log" comment:"ip地址"`
14 | LoginLocation string `form:"loginLocation" search:"type:exact;column:login_location;table:sys_login_log" comment:"归属地"`
15 | BeginTime string `form:"beginTime" search:"type:gte;column:ctime;table:sys_login_log" comment:"创建时间"`
16 | EndTime string `form:"endTime" search:"type:lte;column:ctime;table:sys_login_log" comment:"创建时间"`
17 | SysLoginLogOrder
18 | }
19 |
20 | type SysLoginLogOrder struct {
21 | CreatedAtOrder string `search:"type:order;column:created_at;table:sys_login_log" form:"createdAtOrder"`
22 | }
23 |
24 | func (m *SysLoginLogGetPageReq) GetNeedSearch() interface{} {
25 | return *m
26 | }
27 |
28 | type SysLoginLogControl struct {
29 | ID int `uri:"Id" comment:"主键"` // 主键
30 | Username string `json:"username" comment:"用户名"`
31 | Status string `json:"status" comment:"状态"`
32 | Ipaddr string `json:"ipaddr" comment:"ip地址"`
33 | LoginLocation string `json:"loginLocation" comment:"归属地"`
34 | Browser string `json:"browser" comment:"浏览器"`
35 | Os string `json:"os" comment:"系统"`
36 | Platform string `json:"platform" comment:"固件"`
37 | LoginTime time.Time `json:"loginTime" comment:"登录时间"`
38 | Remark string `json:"remark" comment:"备注"`
39 | Msg string `json:"msg" comment:"信息"`
40 | }
41 |
42 | type SysLoginLogGetReq struct {
43 | Id int `uri:"id"`
44 | }
45 |
46 | func (s *SysLoginLogGetReq) GetId() interface{} {
47 | return s.Id
48 | }
49 |
50 | // SysLoginLogDeleteReq 功能删除请求参数
51 | type SysLoginLogDeleteReq struct {
52 | Ids []int `json:"ids"`
53 | }
54 |
55 | func (s *SysLoginLogDeleteReq) GetId() interface{} {
56 | return s.Ids
57 | }
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | env:
10 | IMAGE_NAME: registry.ap-northeast-1.aliyuncs.com/go-admin/go-admin-api # 镜像名称
11 | TAG: ${{ github.sha }}
12 | IMAGE_NAME_TAG: registry.ap-northeast-1.aliyuncs.com/go-admin/go-admin-api:${{ github.sha }}
13 |
14 | jobs:
15 |
16 | build:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: actions/checkout@v3
20 |
21 | - name: Set up Go
22 | uses: actions/setup-go@v3
23 | with:
24 | go-version: 1.24
25 |
26 | - name: Tidy
27 | run: go mod tidy
28 |
29 | - name: Build
30 | run: env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -tags "sqlite3,json1" --ldflags "-extldflags -static" -o main .
31 |
32 | - name: Build the Docker image and push
33 | run: |
34 | docker login --username=${{ secrets.DOCKER_USERNAME }} registry.ap-northeast-1.aliyuncs.com --password=${{ secrets.DOCKER_PASSWORD }}
35 | echo "************ docker login end"
36 | docker build -t go-admin-api:latest .
37 | echo "************ docker build end"
38 | docker tag go-admin-api ${{ env.IMAGE_NAME_TAG }}
39 | echo "************ docker tag end"
40 | docker images
41 | echo "************ docker images end"
42 | docker push ${{ env.IMAGE_NAME_TAG }} # 推送
43 | echo "************ docker push end"
44 |
45 | - name: Restart server # 第五步,重启服务
46 | uses: appleboy/ssh-action@master
47 | env:
48 | GITHUB_SHA_X: ${GITHUB_SHA}
49 | with:
50 | host: ${{ secrets.SSH_HOST }} # 下面三个配置与上一步类似
51 | username: ${{ secrets.SSH_USERNAME }}
52 | key: ${{ secrets.DEPLOY_KEY }}
53 | # 重启的脚本,根据自身情况做相应改动,一般要做的是migrate数据库以及重启服务器
54 | script: |
55 | sudo docker rm -f go-admin-api
56 | sudo docker login --username=${{ secrets.DOCKER_USERNAME }} registry.ap-northeast-1.aliyuncs.com --password=${{ secrets.DOCKER_PASSWORD }}
57 | sudo docker run -d -p 8000:8000 --name go-admin-api ${{ env.IMAGE_NAME_TAG }}
58 |
--------------------------------------------------------------------------------
/config/settings.yml:
--------------------------------------------------------------------------------
1 | settings:
2 | application:
3 | # dev开发环境 test测试环境 prod线上环境
4 | mode: dev
5 | # 服务器ip,默认使用 0.0.0.0
6 | host: 0.0.0.0
7 | # 服务名称
8 | name: testApp
9 | # 端口号
10 | port: 8000 # 服务端口号
11 | readtimeout: 1
12 | writertimeout: 2
13 | # 数据权限功能开关
14 | enabledp: false
15 | logger:
16 | # 日志存放路径
17 | path: temp/logs
18 | # 日志输出,file:文件,default:命令行,其他:命令行
19 | stdout: '' #控制台日志,启用后,不输出到文件
20 | # 日志等级, trace, debug, info, warn, error, fatal
21 | level: trace
22 | # 数据库日志开关
23 | enableddb: false
24 | jwt:
25 | # token 密钥,生产环境时及的修改
26 | secret: go-admin
27 | # token 过期时间 单位:秒
28 | timeout: 3600
29 | database:
30 | # 数据库类型 mysql, sqlite3, postgres, sqlserver
31 | # sqlserver: sqlserver://用户名:密码@地址?database=数据库名
32 | driver: mysql
33 | # 数据库连接字符串 mysql 缺省信息 charset=utf8&parseTime=True&loc=Local&timeout=1000ms
34 | source: user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms
35 | # databases:
36 | # 'locaohost:8000':
37 | # driver: mysql
38 | # # 数据库连接字符串 mysql 缺省信息 charset=utf8&parseTime=True&loc=Local&timeout=1000ms
39 | # source: user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms
40 | # registers:
41 | # - sources:
42 | # - user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local&timeout=1000ms
43 | gen:
44 | # 代码生成读取的数据库名称
45 | dbname: dbname
46 | # 代码生成是使用前端代码存放位置,需要指定到src文件夹,相对路径
47 | frontpath: ../go-admin-ui/src
48 | extend: # 扩展项使用说明
49 | demo:
50 | name: data
51 | cache:
52 | # redis:
53 | # addr: 127.0.0.1:6379
54 | # password: xxxxxx
55 | # db: 2
56 | # key存在即可
57 | memory: ''
58 | queue:
59 | memory:
60 | poolSize: 100
61 | # redis:
62 | # addr: 127.0.0.1:6379
63 | # password: xxxxxx
64 | # producer:
65 | # streamMaxLength: 100
66 | # approximateMaxLength: true
67 | # consumer:
68 | # visibilityTimeout: 60
69 | # bufferSize: 100
70 | # concurrency: 10
71 | # blockingTimeout: 5
72 | # reclaimInterval: 1
73 | locker:
74 | redis:
--------------------------------------------------------------------------------
/app/other/models/tools/db_tables.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "errors"
5 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
6 |
7 | "gorm.io/gorm"
8 |
9 | config2 "github.com/go-admin-team/go-admin-core/sdk/config"
10 | )
11 |
12 | type DBTables struct {
13 | TableName string `gorm:"column:TABLE_NAME" json:"tableName"`
14 | Engine string `gorm:"column:ENGINE" json:"engine"`
15 | TableRows string `gorm:"column:TABLE_ROWS" json:"tableRows"`
16 | TableCollation string `gorm:"column:TABLE_COLLATION" json:"tableCollation"`
17 | CreateTime string `gorm:"column:CREATE_TIME" json:"createTime"`
18 | UpdateTime string `gorm:"column:UPDATE_TIME" json:"updateTime"`
19 | TableComment string `gorm:"column:TABLE_COMMENT" json:"tableComment"`
20 | }
21 |
22 | func (e *DBTables) GetPage(tx *gorm.DB, pageSize int, pageIndex int) ([]DBTables, int, error) {
23 | var doc []DBTables
24 | table := new(gorm.DB)
25 | var count int64
26 |
27 | if config2.DatabaseConfig.Driver == "mysql" {
28 | table = tx.Table("information_schema.tables")
29 | table = table.Where("TABLE_NAME not in (select table_name from `" + config2.GenConfig.DBName + "`.sys_tables) ")
30 | table = table.Where("table_schema= ? ", config2.GenConfig.DBName)
31 |
32 | if e.TableName != "" {
33 | table = table.Where("TABLE_NAME = ?", e.TableName)
34 | }
35 | if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Offset(-1).Limit(-1).Count(&count).Error; err != nil {
36 | return nil, 0, err
37 | }
38 | } else {
39 | pkg.Assert(true, "目前只支持mysql数据库", 500)
40 | }
41 |
42 | //table.Count(&count)
43 | return doc, int(count), nil
44 | }
45 |
46 | func (e *DBTables) Get(tx *gorm.DB) (DBTables, error) {
47 | var doc DBTables
48 | if config2.DatabaseConfig.Driver == "mysql" {
49 | table := tx.Table("information_schema.tables")
50 | table = table.Where("table_schema= ? ", config2.GenConfig.DBName)
51 | if e.TableName == "" {
52 | return doc, errors.New("table name cannot be empty!")
53 | }
54 | table = table.Where("TABLE_NAME = ?", e.TableName)
55 | if err := table.First(&doc).Error; err != nil {
56 | return doc, err
57 | }
58 | } else {
59 | pkg.Assert(true, "目前只支持mysql数据库", 500)
60 | }
61 | return doc, nil
62 | }
63 |
--------------------------------------------------------------------------------
/cmd/app/server.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "bytes"
5 | "errors"
6 | "fmt"
7 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
8 | "github.com/go-admin-team/go-admin-core/sdk/pkg/utils"
9 | "github.com/spf13/cobra"
10 | "text/template"
11 | )
12 |
13 | var (
14 | appName string
15 | StartCmd = &cobra.Command{
16 | Use: "app",
17 | Short: "Create a new app",
18 | Long: "Use when you need to create a new app",
19 | Example: "go-admin app -n admin",
20 | Run: func(cmd *cobra.Command, args []string) {
21 | run()
22 | },
23 | }
24 | )
25 |
26 | func init() {
27 | StartCmd.PersistentFlags().StringVarP(&appName, "name", "n", "", "Start server with provided configuration file")
28 | }
29 |
30 | func run() {
31 |
32 | fmt.Println(`start init`)
33 | //1. 读取配置
34 |
35 | fmt.Println(`generate migration file`)
36 | _ = genFile()
37 |
38 | }
39 |
40 | func genFile() error {
41 | if appName == "" {
42 | return errors.New("arg `name` invalid :name is empty")
43 | }
44 | path := "app/"
45 | appPath := path + appName
46 | err := utils.IsNotExistMkDir(appPath)
47 | if err != nil {
48 | return err
49 | }
50 | apiPath := appPath + "/apis/"
51 | err = utils.IsNotExistMkDir(apiPath)
52 | if err != nil {
53 | return err
54 | }
55 | modelsPath := appPath + "/models/"
56 | err = utils.IsNotExistMkDir(modelsPath)
57 | if err != nil {
58 | return err
59 | }
60 | routerPath := appPath + "/router/"
61 | err = utils.IsNotExistMkDir(routerPath)
62 | if err != nil {
63 | return err
64 | }
65 | servicePath := appPath + "/service/"
66 | err = utils.IsNotExistMkDir(servicePath)
67 | if err != nil {
68 | return err
69 | }
70 | dtoPath := appPath + "/service/dto/"
71 | err = utils.IsNotExistMkDir(dtoPath)
72 | if err != nil {
73 | return err
74 | }
75 |
76 | t1, err := template.ParseFiles("template/cmd_api.template")
77 | if err != nil {
78 | return err
79 | }
80 | m := map[string]string{}
81 | m["appName"] = appName
82 | var b1 bytes.Buffer
83 | err = t1.Execute(&b1, m)
84 | pkg.FileCreate(b1, "./cmd/api/"+appName+".go")
85 | t2, err := template.ParseFiles("template/router.template")
86 | var b2 bytes.Buffer
87 | err = t2.Execute(&b2, nil)
88 | pkg.FileCreate(b2, appPath+"/router/router.go")
89 | return nil
90 | }
91 |
--------------------------------------------------------------------------------
/app/admin/service/sys_opera_log.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "errors"
5 |
6 | "go-admin/app/admin/models"
7 | "go-admin/app/admin/service/dto"
8 | cDto "go-admin/common/dto"
9 |
10 | "github.com/go-admin-team/go-admin-core/sdk/service"
11 | "gorm.io/gorm"
12 | )
13 |
14 | type SysOperaLog struct {
15 | service.Service
16 | }
17 |
18 | // GetPage 获取SysOperaLog列表
19 | func (e *SysOperaLog) GetPage(c *dto.SysOperaLogGetPageReq, list *[]models.SysOperaLog, count *int64) error {
20 | var err error
21 | var data models.SysOperaLog
22 |
23 | err = e.Orm.Model(&data).
24 | Scopes(
25 | cDto.MakeCondition(c.GetNeedSearch()),
26 | cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
27 | ).
28 | Find(list).Limit(-1).Offset(-1).
29 | Count(count).Error
30 | if err != nil {
31 | e.Log.Errorf("Service GetSysOperaLogPage error:%s", err.Error())
32 | return err
33 | }
34 | return nil
35 | }
36 |
37 | // Get 获取SysOperaLog对象
38 | func (e *SysOperaLog) Get(d *dto.SysOperaLogGetReq, model *models.SysOperaLog) error {
39 | var data models.SysOperaLog
40 |
41 | err := e.Orm.Model(&data).
42 | First(model, d.GetId()).Error
43 | if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
44 | err = errors.New("查看对象不存在或无权查看")
45 | e.Log.Errorf("Service GetSysOperaLog error:%s", err.Error())
46 | return err
47 | }
48 | if err != nil {
49 | e.Log.Errorf("Service GetSysOperaLog error:%s", err.Error())
50 | return err
51 | }
52 | return nil
53 | }
54 |
55 | // Insert 创建SysOperaLog对象
56 | func (e *SysOperaLog) Insert(model *models.SysOperaLog) error {
57 | var err error
58 | var data models.SysOperaLog
59 |
60 | err = e.Orm.Model(&data).
61 | Create(model).Error
62 | if err != nil {
63 | e.Log.Errorf("Service InsertSysOperaLog error:%s", err.Error())
64 | return err
65 | }
66 | return nil
67 | }
68 |
69 | // Remove 删除SysOperaLog
70 | func (e *SysOperaLog) Remove(d *dto.SysOperaLogDeleteReq) error {
71 | var err error
72 | var data models.SysOperaLog
73 |
74 | db := e.Orm.Model(&data).Delete(&data, d.GetId())
75 | if err = db.Error; err != nil {
76 | e.Log.Errorf("Service RemoveSysOperaLog error:%s", err.Error())
77 | return err
78 | }
79 | if db.RowsAffected == 0 {
80 | return errors.New("无权删除该数据")
81 | }
82 | return nil
83 | }
84 |
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_tables.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysTables struct {
4 | TableId int `gorm:"primaryKey;autoIncrement" json:"tableId"` //表编码
5 | TBName string `gorm:"column:table_name;size:255;" json:"tableName"` //表名称
6 | TableComment string `gorm:"size:255;" json:"tableComment"` //表备注
7 | ClassName string `gorm:"size:255;" json:"className"` //类名
8 | TplCategory string `gorm:"size:255;" json:"tplCategory"` //
9 | PackageName string `gorm:"size:255;" json:"packageName"` //包名
10 | ModuleName string `gorm:"size:255;" json:"moduleName"` //go文件名
11 | ModuleFrontName string `gorm:"size:255;comment:前端文件名;" json:"moduleFrontName"` //前端文件名
12 | BusinessName string `gorm:"size:255;" json:"businessName"` //
13 | FunctionName string `gorm:"size:255;" json:"functionName"` //功能名称
14 | FunctionAuthor string `gorm:"size:255;" json:"functionAuthor"` //功能作者
15 | PkColumn string `gorm:"size:255;" json:"pkColumn"`
16 | PkGoField string `gorm:"size:255;" json:"pkGoField"`
17 | PkJsonField string `gorm:"size:255;" json:"pkJsonField"`
18 | Options string `gorm:"size:255;" json:"options"`
19 | TreeCode string `gorm:"size:255;" json:"treeCode"`
20 | TreeParentCode string `gorm:"size:255;" json:"treeParentCode"`
21 | TreeName string `gorm:"size:255;" json:"treeName"`
22 | Tree bool `gorm:"size:1;default:0;" json:"tree"`
23 | Crud bool `gorm:"size:1;default:1;" json:"crud"`
24 | Remark string `gorm:"size:255;" json:"remark"`
25 | IsDataScope int `gorm:"size:1;" json:"isDataScope"`
26 | IsActions int `gorm:"size:1;" json:"isActions"`
27 | IsAuth int `gorm:"size:1;" json:"isAuth"`
28 | IsLogicalDelete string `gorm:"size:1;" json:"isLogicalDelete"`
29 | LogicalDelete bool `gorm:"size:1;" json:"logicalDelete"`
30 | LogicalDeleteColumn string `gorm:"size:128;" json:"logicalDeleteColumn"`
31 | ModelTime
32 | ControlBy
33 | }
34 |
35 | func (SysTables) TableName() string {
36 | return "sys_tables"
37 | }
38 |
--------------------------------------------------------------------------------
/app/admin/models/sys_login_log.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "time"
7 |
8 | log "github.com/go-admin-team/go-admin-core/logger"
9 | "github.com/go-admin-team/go-admin-core/sdk"
10 | "github.com/go-admin-team/go-admin-core/storage"
11 |
12 | "go-admin/common/models"
13 | )
14 |
15 | type SysLoginLog struct {
16 | models.Model
17 | Username string `json:"username" gorm:"size:128;comment:用户名"`
18 | Status string `json:"status" gorm:"size:4;comment:状态"`
19 | Ipaddr string `json:"ipaddr" gorm:"size:255;comment:ip地址"`
20 | LoginLocation string `json:"loginLocation" gorm:"size:255;comment:归属地"`
21 | Browser string `json:"browser" gorm:"size:255;comment:浏览器"`
22 | Os string `json:"os" gorm:"size:255;comment:系统"`
23 | Platform string `json:"platform" gorm:"size:255;comment:固件"`
24 | LoginTime time.Time `json:"loginTime" gorm:"comment:登录时间"`
25 | Remark string `json:"remark" gorm:"size:255;comment:备注"`
26 | Msg string `json:"msg" gorm:"size:255;comment:信息"`
27 | CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"`
28 | UpdatedAt time.Time `json:"updatedAt" gorm:"comment:最后更新时间"`
29 | models.ControlBy
30 | }
31 |
32 | func (*SysLoginLog) TableName() string {
33 | return "sys_login_log"
34 | }
35 |
36 | func (e *SysLoginLog) Generate() models.ActiveRecord {
37 | o := *e
38 | return &o
39 | }
40 |
41 | func (e *SysLoginLog) GetId() interface{} {
42 | return e.Id
43 | }
44 |
45 | // SaveLoginLog 从队列中获取登录日志
46 | func SaveLoginLog(message storage.Messager) (err error) {
47 | //准备db
48 | db := sdk.Runtime.GetDbByKey(message.GetPrefix())
49 | if db == nil {
50 | err = errors.New("db not exist")
51 | log.Errorf("host[%s]'s %s", message.GetPrefix(), err.Error())
52 | return err
53 | }
54 | var rb []byte
55 | rb, err = json.Marshal(message.GetValues())
56 | if err != nil {
57 | log.Errorf("json Marshal error, %s", err.Error())
58 | return err
59 | }
60 | var l SysLoginLog
61 | err = json.Unmarshal(rb, &l)
62 | if err != nil {
63 | log.Errorf("json Unmarshal error, %s", err.Error())
64 | return err
65 | }
66 | err = db.Create(&l).Error
67 | if err != nil {
68 | log.Errorf("db create error, %s", err.Error())
69 | return err
70 | }
71 | return nil
72 | }
73 |
--------------------------------------------------------------------------------
/app/admin/models/sys_user.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "go-admin/common/models"
5 | "golang.org/x/crypto/bcrypt"
6 | "gorm.io/gorm"
7 | )
8 |
9 | type SysUser struct {
10 | UserId int `gorm:"primaryKey;autoIncrement;comment:编码" json:"userId"`
11 | Username string `json:"username" gorm:"size:64;comment:用户名"`
12 | Password string `json:"-" gorm:"size:128;comment:密码"`
13 | NickName string `json:"nickName" gorm:"size:128;comment:昵称"`
14 | Phone string `json:"phone" gorm:"size:11;comment:手机号"`
15 | RoleId int `json:"roleId" gorm:"size:20;comment:角色ID"`
16 | Salt string `json:"-" gorm:"size:255;comment:加盐"`
17 | Avatar string `json:"avatar" gorm:"size:255;comment:头像"`
18 | Sex string `json:"sex" gorm:"size:255;comment:性别"`
19 | Email string `json:"email" gorm:"size:128;comment:邮箱"`
20 | DeptId int `json:"deptId" gorm:"size:20;comment:部门"`
21 | PostId int `json:"postId" gorm:"size:20;comment:岗位"`
22 | Remark string `json:"remark" gorm:"size:255;comment:备注"`
23 | Status string `json:"status" gorm:"size:4;comment:状态"`
24 | DeptIds []int `json:"deptIds" gorm:"-"`
25 | PostIds []int `json:"postIds" gorm:"-"`
26 | RoleIds []int `json:"roleIds" gorm:"-"`
27 | Dept *SysDept `json:"dept"`
28 | models.ControlBy
29 | models.ModelTime
30 | }
31 |
32 | func (*SysUser) TableName() string {
33 | return "sys_user"
34 | }
35 |
36 | func (e *SysUser) Generate() models.ActiveRecord {
37 | o := *e
38 | return &o
39 | }
40 |
41 | func (e *SysUser) GetId() interface{} {
42 | return e.UserId
43 | }
44 |
45 | // Encrypt 加密
46 | func (e *SysUser) Encrypt() (err error) {
47 | if e.Password == "" {
48 | return
49 | }
50 |
51 | var hash []byte
52 | if hash, err = bcrypt.GenerateFromPassword([]byte(e.Password), bcrypt.DefaultCost); err != nil {
53 | return
54 | } else {
55 | e.Password = string(hash)
56 | return
57 | }
58 | }
59 |
60 | func (e *SysUser) BeforeCreate(_ *gorm.DB) error {
61 | return e.Encrypt()
62 | }
63 |
64 | func (e *SysUser) BeforeUpdate(_ *gorm.DB) error {
65 | var err error
66 | if e.Password != "" {
67 | err = e.Encrypt()
68 | }
69 | return err
70 | }
71 |
72 | func (e *SysUser) AfterFind(_ *gorm.DB) error {
73 | e.DeptIds = []int{e.DeptId}
74 | e.PostIds = []int{e.PostId}
75 | e.RoleIds = []int{e.RoleId}
76 | return nil
77 | }
78 |
--------------------------------------------------------------------------------
/app/jobs/service/sys_job.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "errors"
5 | "time"
6 |
7 | "github.com/go-admin-team/go-admin-core/sdk/service"
8 | "github.com/robfig/cron/v3"
9 |
10 | "go-admin/app/jobs"
11 | "go-admin/app/jobs/models"
12 | "go-admin/common/dto"
13 | )
14 |
15 | type SysJob struct {
16 | service.Service
17 | Cron *cron.Cron
18 | }
19 |
20 | // RemoveJob 删除job
21 | func (e *SysJob) RemoveJob(c *dto.GeneralDelDto) error {
22 | var err error
23 | var data models.SysJob
24 | err = e.Orm.Table(data.TableName()).First(&data, c.Id).Error
25 | if err != nil {
26 | e.Log.Errorf("db error: %s", err)
27 | return err
28 | }
29 | cn := jobs.Remove(e.Cron, data.EntryId)
30 |
31 | select {
32 | case res := <-cn:
33 | if res {
34 | err = e.Orm.Table(data.TableName()).Where("entry_id = ?", data.EntryId).Update("entry_id", 0).Error
35 | if err != nil {
36 | e.Log.Errorf("db error: %s", err)
37 | }
38 | return err
39 | }
40 | case <-time.After(time.Second * 1):
41 | e.Msg = "操作超时!"
42 | return nil
43 | }
44 | return nil
45 | }
46 |
47 | // StartJob 启动任务
48 | func (e *SysJob) StartJob(c *dto.GeneralGetDto) error {
49 | var data models.SysJob
50 | var err error
51 | err = e.Orm.Table(data.TableName()).First(&data, c.Id).Error
52 | if err != nil {
53 | e.Log.Errorf("db error: %s", err)
54 | return err
55 | }
56 |
57 | if data.Status == 1 {
58 | err = errors.New("当前Job是关闭状态不能被启动,请先启用。")
59 | return err
60 | }
61 |
62 | if data.JobType == 1 {
63 | var j = &jobs.HttpJob{}
64 | j.InvokeTarget = data.InvokeTarget
65 | j.CronExpression = data.CronExpression
66 | j.JobId = data.JobId
67 | j.Name = data.JobName
68 | data.EntryId, err = jobs.AddJob(e.Cron, j)
69 | if err != nil {
70 | e.Log.Errorf("jobs AddJob[HttpJob] error: %s", err)
71 | }
72 | } else {
73 | var j = &jobs.ExecJob{}
74 | j.InvokeTarget = data.InvokeTarget
75 | j.CronExpression = data.CronExpression
76 | j.JobId = data.JobId
77 | j.Name = data.JobName
78 | j.Args = data.Args
79 | data.EntryId, err = jobs.AddJob(e.Cron, j)
80 | if err != nil {
81 | e.Log.Errorf("jobs AddJob[ExecJob] error: %s", err)
82 | }
83 | }
84 | if err != nil {
85 | return err
86 | }
87 |
88 | err = e.Orm.Table(data.TableName()).Where(c.Id).Updates(&data).Error
89 | if err != nil {
90 | e.Log.Errorf("db error: %s", err)
91 | }
92 | return err
93 | }
94 |
--------------------------------------------------------------------------------
/app/admin/service/dto/sys_dict_type.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "go-admin/app/admin/models"
5 |
6 | "go-admin/common/dto"
7 | common "go-admin/common/models"
8 | )
9 |
10 | type SysDictTypeGetPageReq struct {
11 | dto.Pagination `search:"-"`
12 | DictId []int `form:"dictId" search:"type:in;column:dict_id;table:sys_dict_type"`
13 | DictName string `form:"dictName" search:"type:icontains;column:dict_name;table:sys_dict_type"`
14 | DictType string `form:"dictType" search:"type:icontains;column:dict_type;table:sys_dict_type"`
15 | Status int `form:"status" search:"type:exact;column:status;table:sys_dict_type"`
16 | }
17 |
18 | type SysDictTypeOrder struct {
19 | DictIdOrder string `search:"type:order;column:dict_id;table:sys_dict_type" form:"dictIdOrder"`
20 | }
21 |
22 | func (m *SysDictTypeGetPageReq) GetNeedSearch() interface{} {
23 | return *m
24 | }
25 |
26 | type SysDictTypeInsertReq struct {
27 | Id int `uri:"id"`
28 | DictName string `json:"dictName"`
29 | DictType string `json:"dictType"`
30 | Status int `json:"status"`
31 | Remark string `json:"remark"`
32 | common.ControlBy
33 | }
34 |
35 | func (s *SysDictTypeInsertReq) Generate(model *models.SysDictType) {
36 | if s.Id != 0 {
37 | model.ID = s.Id
38 | }
39 | model.DictName = s.DictName
40 | model.DictType = s.DictType
41 | model.Status = s.Status
42 | model.Remark = s.Remark
43 |
44 | }
45 |
46 | func (s *SysDictTypeInsertReq) GetId() interface{} {
47 | return s.Id
48 | }
49 |
50 | type SysDictTypeUpdateReq struct {
51 | Id int `uri:"id"`
52 | DictName string `json:"dictName"`
53 | DictType string `json:"dictType"`
54 | Status int `json:"status"`
55 | Remark string `json:"remark"`
56 | common.ControlBy
57 | }
58 |
59 | func (s *SysDictTypeUpdateReq) Generate(model *models.SysDictType) {
60 | if s.Id != 0 {
61 | model.ID = s.Id
62 | }
63 | model.DictName = s.DictName
64 | model.DictType = s.DictType
65 | model.Status = s.Status
66 | model.Remark = s.Remark
67 |
68 | }
69 |
70 | func (s *SysDictTypeUpdateReq) GetId() interface{} {
71 | return s.Id
72 | }
73 |
74 | type SysDictTypeGetReq struct {
75 | Id int `uri:"id"`
76 | }
77 |
78 | func (s *SysDictTypeGetReq) GetId() interface{} {
79 | return s.Id
80 | }
81 |
82 | type SysDictTypeDeleteReq struct {
83 | Ids []int `json:"ids"`
84 | common.ControlBy
85 | }
86 |
87 | func (s *SysDictTypeDeleteReq) GetId() interface{} {
88 | return s.Ids
89 | }
90 |
--------------------------------------------------------------------------------
/common/dto/generate.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | vd "github.com/bytedance/go-tagexpr/v2/validator"
5 | "net/http"
6 |
7 | "github.com/gin-gonic/gin"
8 | "github.com/go-admin-team/go-admin-core/sdk/api"
9 | )
10 |
11 | type ObjectById struct {
12 | Id int `uri:"id"`
13 | Ids []int `json:"ids"`
14 | }
15 |
16 | func (s *ObjectById) Bind(ctx *gin.Context) error {
17 | var err error
18 | log := api.GetRequestLogger(ctx)
19 | err = ctx.ShouldBindUri(s)
20 | if err != nil {
21 | log.Warnf("ShouldBindUri error: %s", err.Error())
22 | return err
23 | }
24 | if ctx.Request.Method == http.MethodDelete {
25 | err = ctx.ShouldBind(&s)
26 | if err != nil {
27 | log.Warnf("ShouldBind error: %s", err.Error())
28 | return err
29 | }
30 | if len(s.Ids) > 0 {
31 | return nil
32 | }
33 | if s.Ids == nil {
34 | s.Ids = make([]int, 0)
35 | }
36 | if s.Id != 0 {
37 | s.Ids = append(s.Ids, s.Id)
38 | }
39 | }
40 | if err = vd.Validate(s); err != nil {
41 | log.Errorf("Validate error: %s", err.Error())
42 | return err
43 | }
44 | return err
45 | }
46 |
47 | func (s *ObjectById) GetId() interface{} {
48 | if len(s.Ids) > 0 {
49 | s.Ids = append(s.Ids, s.Id)
50 | return s.Ids
51 | }
52 | return s.Id
53 | }
54 |
55 | type ObjectGetReq struct {
56 | Id int `uri:"id"`
57 | }
58 |
59 | func (s *ObjectGetReq) Bind(ctx *gin.Context) error {
60 | var err error
61 | log := api.GetRequestLogger(ctx)
62 | err = ctx.ShouldBindUri(s)
63 | if err != nil {
64 | log.Warnf("ShouldBindUri error: %s", err.Error())
65 | return err
66 | }
67 | if err = vd.Validate(s); err != nil {
68 | log.Errorf("Validate error: %s", err.Error())
69 | return err
70 | }
71 | return err
72 | }
73 |
74 | func (s *ObjectGetReq) GetId() interface{} {
75 | return s.Id
76 | }
77 |
78 | type ObjectDeleteReq struct {
79 | Ids []int `json:"ids"`
80 | }
81 |
82 | func (s *ObjectDeleteReq) Bind(ctx *gin.Context) error {
83 | var err error
84 | log := api.GetRequestLogger(ctx)
85 | err = ctx.ShouldBind(&s)
86 | if err != nil {
87 | log.Warnf("ShouldBind error: %s", err.Error())
88 | return err
89 | }
90 | if len(s.Ids) > 0 {
91 | return nil
92 | }
93 | if s.Ids == nil {
94 | s.Ids = make([]int, 0)
95 | }
96 |
97 | if err = vd.Validate(s); err != nil {
98 | log.Errorf("Validate error: %s", err.Error())
99 | return err
100 | }
101 | return err
102 | }
103 |
104 | func (s *ObjectDeleteReq) GetId() interface{} {
105 | return s.Ids
106 | }
107 |
--------------------------------------------------------------------------------
/common/response/binding.go:
--------------------------------------------------------------------------------
1 | package response
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin/binding"
6 | "reflect"
7 | "strings"
8 | "sync"
9 | )
10 |
11 | const (
12 | _ uint8 = iota
13 | json
14 | xml
15 | yaml
16 | form
17 | query
18 | )
19 |
20 | //var constructor = &bindConstructor{}
21 |
22 | type bindConstructor struct {
23 | cache map[string][]uint8
24 | mux sync.Mutex
25 | }
26 |
27 | func (e *bindConstructor) GetBindingForGin(d interface{}) []binding.Binding {
28 | bs := e.getBinding(reflect.TypeOf(d).String())
29 | if bs == nil {
30 | //重新构建
31 | bs = e.resolve(d)
32 | }
33 | gbs := make([]binding.Binding, len(bs))
34 | for i, b := range bs {
35 | switch b {
36 | case json:
37 | gbs[i] = binding.JSON
38 | case xml:
39 | gbs[i] = binding.XML
40 | case yaml:
41 | gbs[i] = binding.YAML
42 | case form:
43 | gbs[i] = binding.Form
44 | case query:
45 | gbs[i] = binding.Query
46 | default:
47 | gbs[i] = nil
48 | }
49 | }
50 | return gbs
51 | }
52 |
53 | func (e *bindConstructor) resolve(d interface{}) []uint8 {
54 | bs := make([]uint8, 0)
55 | qType := reflect.TypeOf(d).Elem()
56 | var tag reflect.StructTag
57 | var ok bool
58 | fmt.Println(qType.Kind())
59 | for i := 0; i < qType.NumField(); i++ {
60 | tag = qType.Field(i).Tag
61 | if _, ok = tag.Lookup("json"); ok {
62 | bs = append(bs, json)
63 | }
64 | if _, ok = tag.Lookup("xml"); ok {
65 | bs = append(bs, xml)
66 | }
67 | if _, ok = tag.Lookup("yaml"); ok {
68 | bs = append(bs, yaml)
69 | }
70 | if _, ok = tag.Lookup("form"); ok {
71 | bs = append(bs, form)
72 | }
73 | if _, ok = tag.Lookup("query"); ok {
74 | bs = append(bs, query)
75 | }
76 | if _, ok = tag.Lookup("uri"); ok {
77 | bs = append(bs, 0)
78 | }
79 | if t, ok := tag.Lookup("binding"); ok && strings.Index(t, "dive") > -1 {
80 | qValue := reflect.ValueOf(d)
81 | bs = append(bs, e.resolve(qValue.Field(i))...)
82 | continue
83 | }
84 | if t, ok := tag.Lookup("validate"); ok && strings.Index(t, "dive") > -1 {
85 | qValue := reflect.ValueOf(d)
86 | bs = append(bs, e.resolve(qValue.Field(i))...)
87 | }
88 | }
89 | return bs
90 | }
91 |
92 | func (e *bindConstructor) getBinding(name string) []uint8 {
93 | e.mux.Lock()
94 | defer e.mux.Unlock()
95 | return e.cache[name]
96 | }
97 |
98 | func (e *bindConstructor) setBinding(name string, bs []uint8) {
99 | e.mux.Lock()
100 | defer e.mux.Unlock()
101 | if e.cache == nil {
102 | e.cache = make(map[string][]uint8)
103 | }
104 | e.cache[name] = bs
105 | }
106 |
--------------------------------------------------------------------------------
/app/admin/service/sys_post.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/go-admin-team/go-admin-core/sdk/service"
7 | "gorm.io/gorm"
8 |
9 | "go-admin/app/admin/models"
10 | "go-admin/app/admin/service/dto"
11 | cDto "go-admin/common/dto"
12 | )
13 |
14 | type SysPost struct {
15 | service.Service
16 | }
17 |
18 | // GetPage 获取SysPost列表
19 | func (e *SysPost) GetPage(c *dto.SysPostPageReq, list *[]models.SysPost, count *int64) error {
20 | var err error
21 | var data models.SysPost
22 |
23 | err = e.Orm.Model(&data).
24 | Scopes(
25 | cDto.MakeCondition(c.GetNeedSearch()),
26 | cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
27 | ).
28 | Find(list).Limit(-1).Offset(-1).
29 | Count(count).Error
30 | if err != nil {
31 | e.Log.Errorf("db error:%s \r", err)
32 | return err
33 | }
34 | return nil
35 | }
36 |
37 | // Get 获取SysPost对象
38 | func (e *SysPost) Get(d *dto.SysPostGetReq, model *models.SysPost) error {
39 | var err error
40 | var data models.SysPost
41 |
42 | db := e.Orm.Model(&data).
43 | First(model, d.GetId())
44 | err = db.Error
45 | if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
46 | err = errors.New("查看对象不存在或无权查看")
47 | e.Log.Errorf("db error:%s", err)
48 | return err
49 | }
50 | if err != nil {
51 | e.Log.Errorf("db error:%s", err)
52 | return err
53 | }
54 | return nil
55 | }
56 |
57 | // Insert 创建SysPost对象
58 | func (e *SysPost) Insert(c *dto.SysPostInsertReq) error {
59 | var err error
60 | var data models.SysPost
61 | c.Generate(&data)
62 | err = e.Orm.Create(&data).Error
63 | if err != nil {
64 | e.Log.Errorf("db error:%s", err)
65 | return err
66 | }
67 | return nil
68 | }
69 |
70 | // Update 修改SysPost对象
71 | func (e *SysPost) Update(c *dto.SysPostUpdateReq) error {
72 | var err error
73 | var model = models.SysPost{}
74 | e.Orm.First(&model, c.GetId())
75 | c.Generate(&model)
76 |
77 | db := e.Orm.Save(&model)
78 | if err = db.Error; err != nil {
79 | e.Log.Errorf("db error:%s", err)
80 | return err
81 | }
82 | if db.RowsAffected == 0 {
83 | return errors.New("无权更新该数据")
84 |
85 | }
86 | return nil
87 | }
88 |
89 | // Remove 删除SysPost
90 | func (e *SysPost) Remove(d *dto.SysPostDeleteReq) error {
91 | var err error
92 | var data models.SysPost
93 |
94 | db := e.Orm.Model(&data).Delete(&data, d.GetId())
95 | if err = db.Error; err != nil {
96 | e.Log.Errorf("Delete error: %s", err)
97 | return err
98 | }
99 | if db.RowsAffected == 0 {
100 | err = errors.New("无权删除该数据")
101 | return err
102 | }
103 | return nil
104 | }
105 |
--------------------------------------------------------------------------------
/app/other/models/tools/db_columns.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/go-admin-team/go-admin-core/sdk/config"
7 | "github.com/go-admin-team/go-admin-core/sdk/pkg"
8 | "gorm.io/gorm"
9 | )
10 |
11 | type DBColumns struct {
12 | TableSchema string `gorm:"column:TABLE_SCHEMA" json:"tableSchema"`
13 | TableName string `gorm:"column:TABLE_NAME" json:"tableName"`
14 | ColumnName string `gorm:"column:COLUMN_NAME" json:"columnName"`
15 | ColumnDefault string `gorm:"column:COLUMN_DEFAULT" json:"columnDefault"`
16 | IsNullable string `gorm:"column:IS_NULLABLE" json:"isNullable"`
17 | DataType string `gorm:"column:DATA_TYPE" json:"dataType"`
18 | CharacterMaximumLength string `gorm:"column:CHARACTER_MAXIMUM_LENGTH" json:"characterMaximumLength"`
19 | CharacterSetName string `gorm:"column:CHARACTER_SET_NAME" json:"characterSetName"`
20 | ColumnType string `gorm:"column:COLUMN_TYPE" json:"columnType"`
21 | ColumnKey string `gorm:"column:COLUMN_KEY" json:"columnKey"`
22 | Extra string `gorm:"column:EXTRA" json:"extra"`
23 | ColumnComment string `gorm:"column:COLUMN_COMMENT" json:"columnComment"`
24 | }
25 |
26 | func (e *DBColumns) GetPage(tx *gorm.DB, pageSize int, pageIndex int) ([]DBColumns, int, error) {
27 | var doc []DBColumns
28 | var count int64
29 | table := new(gorm.DB)
30 |
31 | if config.DatabaseConfig.Driver == "mysql" {
32 | table = tx.Table("information_schema.`COLUMNS`")
33 | table = table.Where("table_schema= ? ", config.GenConfig.DBName)
34 |
35 | if e.TableName != "" {
36 | return nil, 0, errors.New("table name cannot be empty!")
37 | }
38 |
39 | table = table.Where("TABLE_NAME = ?", e.TableName)
40 | }
41 |
42 | if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Offset(-1).Limit(-1).Count(&count).Error; err != nil {
43 | return nil, 0, err
44 | }
45 | //table.Count(&count)
46 | return doc, int(count), nil
47 |
48 | }
49 |
50 | func (e *DBColumns) GetList(tx *gorm.DB) ([]DBColumns, error) {
51 | var doc []DBColumns
52 | table := new(gorm.DB)
53 |
54 | if e.TableName == "" {
55 | return nil, errors.New("table name cannot be empty!")
56 | }
57 |
58 | if config.DatabaseConfig.Driver == "mysql" {
59 | table = tx.Table("information_schema.columns")
60 | table = table.Where("table_schema= ? ", config.GenConfig.DBName)
61 |
62 | table = table.Where("TABLE_NAME = ?", e.TableName).Order("ORDINAL_POSITION asc")
63 | } else {
64 | pkg.Assert(true, "目前只支持mysql数据库", 500)
65 | }
66 | if err := table.Find(&doc).Error; err != nil {
67 | return doc, err
68 | }
69 | return doc, nil
70 | }
--------------------------------------------------------------------------------
/cmd/migrate/migration/models/sys_columns.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | type SysColumns struct {
4 | ColumnId int `gorm:"primaryKey;autoIncrement" json:"columnId"`
5 | TableId int `gorm:"" json:"tableId"`
6 | ColumnName string `gorm:"size:128;" json:"columnName"`
7 | ColumnComment string `gorm:"column:column_comment;size:128;" json:"columnComment"`
8 | ColumnType string `gorm:"column:column_type;size:128;" json:"columnType"`
9 | GoType string `gorm:"column:go_type;size:128;" json:"goType"`
10 | GoField string `gorm:"column:go_field;size:128;" json:"goField"`
11 | JsonField string `gorm:"column:json_field;size:128;" json:"jsonField"`
12 | IsPk string `gorm:"column:is_pk;size:4;" json:"isPk"`
13 | IsIncrement string `gorm:"column:is_increment;size:4;" json:"isIncrement"`
14 | IsRequired string `gorm:"column:is_required;size:4;" json:"isRequired"`
15 | IsInsert string `gorm:"column:is_insert;size:4;" json:"isInsert"`
16 | IsEdit string `gorm:"column:is_edit;size:4;" json:"isEdit"`
17 | IsList string `gorm:"column:is_list;size:4;" json:"isList"`
18 | IsQuery string `gorm:"column:is_query;size:4;" json:"isQuery"`
19 | QueryType string `gorm:"column:query_type;size:128;" json:"queryType"`
20 | HtmlType string `gorm:"column:html_type;size:128;" json:"htmlType"`
21 | DictType string `gorm:"column:dict_type;size:128;" json:"dictType"`
22 | Sort int `gorm:"column:sort;" json:"sort"`
23 | List string `gorm:"column:list;size:1;" json:"list"`
24 | Pk bool `gorm:"column:pk;size:1;" json:"pk"`
25 | Required bool `gorm:"column:required;size:1;" json:"required"`
26 | SuperColumn bool `gorm:"column:super_column;size:1;" json:"superColumn"`
27 | UsableColumn bool `gorm:"column:usable_column;size:1;" json:"usableColumn"`
28 | Increment bool `gorm:"column:increment;size:1;" json:"increment"`
29 | Insert bool `gorm:"column:insert;size:1;" json:"insert"`
30 | Edit bool `gorm:"column:edit;size:1;" json:"edit"`
31 | Query bool `gorm:"column:query;size:1;" json:"query"`
32 | Remark string `gorm:"column:remark;size:255;" json:"remark"`
33 | FkTableName string `gorm:"" json:"fkTableName"`
34 | FkTableNameClass string `gorm:"" json:"fkTableNameClass"`
35 | FkTableNamePackage string `gorm:"" json:"fkTableNamePackage"`
36 | FkLabelId string `gorm:"" json:"fkLabelId"`
37 | FkLabelName string `gorm:"size:255;" json:"fkLabelName"`
38 | ModelTime
39 | ControlBy
40 | }
41 |
42 | func (SysColumns) TableName() string {
43 | return "sys_columns"
44 | }
45 |
--------------------------------------------------------------------------------
/app/admin/router/sys_router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "go-admin/app/admin/apis"
5 | "mime"
6 |
7 | "github.com/go-admin-team/go-admin-core/sdk/config"
8 |
9 | "github.com/gin-gonic/gin"
10 | jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth"
11 | "github.com/go-admin-team/go-admin-core/sdk/pkg/ws"
12 | ginSwagger "github.com/swaggo/gin-swagger"
13 |
14 | swaggerfiles "github.com/swaggo/files"
15 |
16 | "go-admin/common/middleware"
17 | "go-admin/common/middleware/handler"
18 | _ "go-admin/docs/admin"
19 | )
20 |
21 | func InitSysRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.RouterGroup {
22 | g := r.Group("")
23 | sysBaseRouter(g)
24 | // 静态文件
25 | sysStaticFileRouter(g)
26 | // swagger;注意:生产环境可以注释掉
27 | if config.ApplicationConfig.Mode != "prod" {
28 | sysSwaggerRouter(g)
29 | }
30 | // 需要认证
31 | sysCheckRoleRouterInit(g, authMiddleware)
32 | return g
33 | }
34 |
35 | func sysBaseRouter(r *gin.RouterGroup) {
36 |
37 | go ws.WebsocketManager.Start()
38 | go ws.WebsocketManager.SendService()
39 | go ws.WebsocketManager.SendAllService()
40 |
41 | if config.ApplicationConfig.Mode != "prod" {
42 | r.GET("/", apis.GoAdmin)
43 | }
44 | r.GET("/info", handler.Ping)
45 | }
46 |
47 | func sysStaticFileRouter(r *gin.RouterGroup) {
48 | err := mime.AddExtensionType(".js", "application/javascript")
49 | if err != nil {
50 | return
51 | }
52 | r.Static("/static", "./static")
53 | if config.ApplicationConfig.Mode != "prod" {
54 | r.Static("/form-generator", "./static/form-generator")
55 | }
56 | }
57 |
58 | func sysSwaggerRouter(r *gin.RouterGroup) {
59 | r.GET("/swagger/admin/*any", ginSwagger.WrapHandler(swaggerfiles.NewHandler(), ginSwagger.InstanceName("admin")))
60 | }
61 |
62 | func sysCheckRoleRouterInit(r *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
63 | wss := r.Group("").Use(authMiddleware.MiddlewareFunc())
64 | {
65 | wss.GET("/ws/:id/:channel", ws.WebsocketManager.WsClient)
66 | wss.GET("/wslogout/:id/:channel", ws.WebsocketManager.UnWsClient)
67 | }
68 |
69 | v1 := r.Group("/api/v1")
70 | {
71 | v1.POST("/login", authMiddleware.LoginHandler)
72 | // Refresh time can be longer than token timeout
73 | v1.GET("/refresh_token", authMiddleware.RefreshHandler)
74 | }
75 | registerBaseRouter(v1, authMiddleware)
76 | }
77 |
78 | func registerBaseRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
79 | api := apis.SysMenu{}
80 | api2 := apis.SysDept{}
81 | v1auth := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
82 | {
83 | v1auth.GET("/roleMenuTreeselect/:roleId", api.GetMenuTreeSelect)
84 | //v1.GET("/menuTreeselect", api.GetMenuTreeSelect)
85 | v1auth.GET("/roleDeptTreeselect/:roleId", api2.GetDeptTreeRoleSelect)
86 | v1auth.POST("/logout", handler.LogOut)
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/admin/models/sys_api.go:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "fmt"
7 | "io/ioutil"
8 | "regexp"
9 | "strings"
10 |
11 | "github.com/bitly/go-simplejson"
12 | "github.com/go-admin-team/go-admin-core/sdk"
13 | "github.com/go-admin-team/go-admin-core/sdk/runtime"
14 | "github.com/go-admin-team/go-admin-core/storage"
15 |
16 | "go-admin/common/models"
17 | )
18 |
19 | type SysApi struct {
20 | Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"`
21 | Handle string `json:"handle" gorm:"size:128;comment:handle"`
22 | Title string `json:"title" gorm:"size:128;comment:标题"`
23 | Path string `json:"path" gorm:"size:128;comment:地址"`
24 | Action string `json:"action" gorm:"size:16;comment:请求类型"`
25 | Type string `json:"type" gorm:"size:16;comment:接口类型"`
26 | models.ModelTime
27 | models.ControlBy
28 | }
29 |
30 | func (*SysApi) TableName() string {
31 | return "sys_api"
32 | }
33 |
34 | func (e *SysApi) Generate() models.ActiveRecord {
35 | o := *e
36 | return &o
37 | }
38 |
39 | func (e *SysApi) GetId() interface{} {
40 | return e.Id
41 | }
42 |
43 | func SaveSysApi(message storage.Messager) (err error) {
44 | var rb []byte
45 | rb, err = json.Marshal(message.GetValues())
46 | if err != nil {
47 | err = fmt.Errorf("json Marshal error, %v", err.Error())
48 | return err
49 | }
50 |
51 | var l runtime.Routers
52 | err = json.Unmarshal(rb, &l)
53 | if err != nil {
54 | err = fmt.Errorf("json Unmarshal error, %s", err.Error())
55 | return err
56 | }
57 | dbList := sdk.Runtime.GetDb()
58 | for _, d := range dbList {
59 | for _, v := range l.List {
60 | if v.HttpMethod != "HEAD" ||
61 | strings.Contains(v.RelativePath, "/swagger/") ||
62 | strings.Contains(v.RelativePath, "/static/") ||
63 | strings.Contains(v.RelativePath, "/form-generator/") ||
64 | strings.Contains(v.RelativePath, "/sys/tables") {
65 |
66 | // 根据接口方法注释里的@Summary填充接口名称,适用于代码生成器
67 | // 可在此处增加配置路径前缀的if判断,只对代码生成的自建应用进行定向的接口名称填充
68 | jsonFile, _ := ioutil.ReadFile("docs/swagger.json")
69 | jsonData, _ := simplejson.NewFromReader(bytes.NewReader(jsonFile))
70 | urlPath := v.RelativePath
71 | idPatten := "(.*)/:(\\w+)" // 正则替换,把:id换成{id}
72 | reg, _ := regexp.Compile(idPatten)
73 | if reg.MatchString(urlPath) {
74 | urlPath = reg.ReplaceAllString(v.RelativePath, "${1}/{${2}}") // 把:id换成{id}
75 | }
76 | apiTitle, _ := jsonData.Get("paths").Get(urlPath).Get(strings.ToLower(v.HttpMethod)).Get("summary").String()
77 |
78 | err := d.Debug().Where(SysApi{Path: v.RelativePath, Action: v.HttpMethod}).
79 | Attrs(SysApi{Handle: v.Handler, Title: apiTitle}).
80 | FirstOrCreate(&SysApi{}).
81 | //Update("handle", v.Handler).
82 | Error
83 | if err != nil {
84 | err := fmt.Errorf("Models SaveSysApi error: %s \r\n ", err.Error())
85 | return err
86 | }
87 | }
88 | }
89 | }
90 | return nil
91 | }
92 |
--------------------------------------------------------------------------------
/app/admin/service/dto/sys_api.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "go-admin/app/admin/models"
5 | "go-admin/common/dto"
6 | common "go-admin/common/models"
7 | )
8 |
9 | // SysApiGetPageReq 功能列表请求参数
10 | type SysApiGetPageReq struct {
11 | dto.Pagination `search:"-"`
12 | Title string `form:"title" search:"type:contains;column:title;table:sys_api" comment:"标题"`
13 | Path string `form:"path" search:"type:contains;column:path;table:sys_api" comment:"地址"`
14 | Action string `form:"action" search:"type:exact;column:action;table:sys_api" comment:"请求方式"`
15 | ParentId string `form:"parentId" search:"type:exact;column:parent_id;table:sys_api" comment:"按钮id"`
16 | Type string `form:"type" search:"-" comment:"类型"`
17 | SysApiOrder
18 | }
19 |
20 | type SysApiOrder struct {
21 | TitleOrder string `search:"type:order;column:title;table:sys_api" form:"titleOrder"`
22 | PathOrder string `search:"type:order;column:path;table:sys_api" form:"pathOrder"`
23 | CreatedAtOrder string `search:"type:order;column:created_at;table:sys_api" form:"createdAtOrder"`
24 | }
25 |
26 | func (m *SysApiGetPageReq) GetNeedSearch() interface{} {
27 | return *m
28 | }
29 |
30 | // SysApiInsertReq 功能创建请求参数
31 | type SysApiInsertReq struct {
32 | Id int `json:"-" comment:"编码"` // 编码
33 | Handle string `json:"handle" comment:"handle"`
34 | Title string `json:"title" comment:"标题"`
35 | Path string `json:"path" comment:"地址"`
36 | Type string `json:"type" comment:""`
37 | Action string `json:"action" comment:"类型"`
38 | common.ControlBy
39 | }
40 |
41 | func (s *SysApiInsertReq) Generate(model *models.SysApi) {
42 | model.Handle = s.Handle
43 | model.Title = s.Title
44 | model.Path = s.Path
45 | model.Type = s.Type
46 | model.Action = s.Action
47 | }
48 |
49 | func (s *SysApiInsertReq) GetId() interface{} {
50 | return s.Id
51 | }
52 |
53 | // SysApiUpdateReq 功能更新请求参数
54 | type SysApiUpdateReq struct {
55 | Id int `uri:"id" comment:"编码"` // 编码
56 | Handle string `json:"handle" comment:"handle"`
57 | Title string `json:"title" comment:"标题"`
58 | Path string `json:"path" comment:"地址"`
59 | Type string `json:"type" comment:""`
60 | Action string `json:"action" comment:"类型"`
61 | common.ControlBy
62 | }
63 |
64 | func (s *SysApiUpdateReq) Generate(model *models.SysApi) {
65 | if s.Id != 0 {
66 | model.Id = s.Id
67 | }
68 | model.Handle = s.Handle
69 | model.Title = s.Title
70 | model.Path = s.Path
71 | model.Type = s.Type
72 | model.Action = s.Action
73 | }
74 |
75 | func (s *SysApiUpdateReq) GetId() interface{} {
76 | return s.Id
77 | }
78 |
79 | // SysApiGetReq 功能获取请求参数
80 | type SysApiGetReq struct {
81 | Id int `uri:"id"`
82 | }
83 |
84 | func (s *SysApiGetReq) GetId() interface{} {
85 | return s.Id
86 | }
87 |
88 | // SysApiDeleteReq 功能删除请求参数
89 | type SysApiDeleteReq struct {
90 | Ids []int `json:"ids"`
91 | }
92 |
93 | func (s *SysApiDeleteReq) GetId() interface{} {
94 | return s.Ids
95 | }
96 |
--------------------------------------------------------------------------------
/common/file_store/kodo.go:
--------------------------------------------------------------------------------
1 | package file_store
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/qiniu/go-sdk/v7/auth/qbox"
7 | "github.com/qiniu/go-sdk/v7/storage"
8 | )
9 |
10 | type Zone string
11 |
12 | const (
13 | // HuaDong 华东
14 | HuaDong Zone = "HuaDong"
15 | // HuaBei 华北
16 | HuaBei Zone = "HuaBei"
17 | // HuaNan 华南
18 | HuaNan Zone = "HuaNan"
19 | // BeiMei 北美
20 | BeiMei Zone = "BeiMei"
21 | // XinJiaPo 新加坡
22 | XinJiaPo Zone = "XinJiaPo"
23 | )
24 |
25 | type QiNiuKODO struct {
26 | Client interface{}
27 | BucketName string
28 | cfg storage.Config
29 | options []ClientOption
30 | }
31 |
32 | func (e *QiNiuKODO) getToken() string {
33 | putPolicy := storage.PutPolicy{
34 | Scope: e.BucketName,
35 | }
36 | if len(e.options) > 0 && e.options[0]["Expires"] != nil {
37 | putPolicy.Expires = e.options[0]["Expires"].(uint64)
38 | }
39 | upToken := putPolicy.UploadToken(e.Client.(*qbox.Mac))
40 | return upToken
41 | }
42 |
43 | //Setup 装载
44 | //endpoint sss
45 | func (e *QiNiuKODO) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error {
46 |
47 | mac := qbox.NewMac(accessKeyID, accessKeySecret)
48 | // 获取存储空间。
49 | cfg := storage.Config{}
50 | // 空间对应的机房
51 | e.setZoneORDefault(cfg, options...)
52 | // 是否使用https域名
53 | cfg.UseHTTPS = true
54 | // 上传是否使用CDN上传加速
55 | cfg.UseCdnDomains = false
56 |
57 | e.Client = mac
58 | e.BucketName = BucketName
59 | e.cfg = cfg
60 | e.options = options
61 | return nil
62 | }
63 |
64 | // setZoneORDefault 设置Zone或者默认华东
65 | func (e *QiNiuKODO) setZoneORDefault(cfg storage.Config, options ...ClientOption) {
66 | if len(options) > 0 && options[0]["Zone"] != nil {
67 | if _, ok := options[0]["Zone"].(Zone); !ok {
68 | cfg.Zone = &storage.ZoneHuadong
69 | }
70 | switch options[0]["Zone"].(Zone) {
71 | case HuaDong:
72 | cfg.Zone = &storage.ZoneHuadong
73 | case HuaBei:
74 | cfg.Zone = &storage.ZoneHuabei
75 | case HuaNan:
76 | cfg.Zone = &storage.ZoneHuanan
77 | case BeiMei:
78 | cfg.Zone = &storage.ZoneBeimei
79 | case XinJiaPo:
80 | cfg.Zone = &storage.ZoneXinjiapo
81 | default:
82 | cfg.Zone = &storage.ZoneHuadong
83 | }
84 | }
85 | }
86 |
87 | // UpLoad 文件上传
88 | func (e *QiNiuKODO) UpLoad(yourObjectName string, localFile interface{}) error {
89 |
90 | // 构建表单上传的对象
91 | formUploader := storage.NewFormUploader(&e.cfg)
92 | ret := storage.PutRet{}
93 | // 可选配置
94 | putExtra := storage.PutExtra{
95 | Params: map[string]string{
96 | "x:name": "github logo",
97 | },
98 | }
99 | err := formUploader.PutFile(context.Background(), &ret, e.getToken(), yourObjectName, localFile.(string), &putExtra)
100 | if err != nil {
101 | fmt.Println(err)
102 | return err
103 | }
104 | fmt.Println(ret.Key, ret.Hash)
105 | return nil
106 | }
107 |
108 | func (e *QiNiuKODO) GetTempToken() (string, error) {
109 | token := e.getToken()
110 | return token, nil
111 | }
112 |
--------------------------------------------------------------------------------
/common/dto/auto_form.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | type AutoForm struct {
4 | Fields []Field `json:"fields"`
5 | FormRef string `json:"formRef"`
6 | FormModel string `json:"formModel"`
7 | Size string `json:"size"`
8 | LabelPosition string `json:"labelPosition"`
9 | LabelWidth int `json:"labelWidth"`
10 | FormRules string `json:"formRules"`
11 | Gutter int `json:"gutter"`
12 | Disabled bool `json:"disabled"`
13 | Span int `json:"span"`
14 | FormBtns bool `json:"formBtns"`
15 | }
16 |
17 | type Config struct {
18 | Label string `json:"label"`
19 | LabelWidth interface{} `json:"labelWidth"`
20 | ShowLabel bool `json:"showLabel"`
21 | ChangeTag bool `json:"changeTag"`
22 | Tag string `json:"tag"`
23 | TagIcon string `json:"tagIcon"`
24 | Required bool `json:"required"`
25 | Layout string `json:"layout"`
26 | Span int `json:"span"`
27 | Document string `json:"document"`
28 | RegList []interface{} `json:"regList"`
29 | FormId int `json:"formId"`
30 | RenderKey int64 `json:"renderKey"`
31 | DefaultValue interface{} `json:"defaultValue"`
32 | ShowTip bool `json:"showTip,omitempty"`
33 | ButtonText string `json:"buttonText,omitempty"`
34 | FileSize int `json:"fileSize,omitempty"`
35 | SizeUnit string `json:"sizeUnit,omitempty"`
36 | }
37 |
38 | type Option struct {
39 | Label string `json:"label"`
40 | Value string `json:"value"`
41 | }
42 |
43 | type Slot struct {
44 | Prepend string `json:"prepend,omitempty"`
45 | Append string `json:"append,omitempty"`
46 | ListType bool `json:"list-type,omitempty"`
47 | Options []Option `json:"options,omitempty"`
48 | }
49 |
50 | type Field struct {
51 | Config Config `json:"__config__"`
52 | Slot Slot `json:"__slot__"`
53 | Placeholder string `json:"placeholder,omitempty"`
54 | Style Style `json:"style,omitempty"`
55 | Clearable bool `json:"clearable,omitempty"`
56 | PrefixIcon string `json:"prefix-icon,omitempty"`
57 | SuffixIcon string `json:"suffix-icon,omitempty"`
58 | Maxlength interface{} `json:"maxlength"`
59 | ShowWordLimit bool `json:"show-word-limit,omitempty"`
60 | Readonly bool `json:"readonly,omitempty"`
61 | Disabled bool `json:"disabled"`
62 | VModel string `json:"__vModel__"`
63 | Action string `json:"action,omitempty"`
64 | Accept string `json:"accept,omitempty"`
65 | Name string `json:"name,omitempty"`
66 | AutoUpload bool `json:"auto-upload,omitempty"`
67 | ListType string `json:"list-type,omitempty"`
68 | Multiple bool `json:"multiple,omitempty"`
69 | Filterable bool `json:"filterable,omitempty"`
70 | }
71 |
72 | type Style struct {
73 | Width string `json:"width"`
74 | }
75 |
--------------------------------------------------------------------------------
/test/model.go.template:
--------------------------------------------------------------------------------
1 | package models
2 |
3 | import (
4 | orm "go-admin/global"
5 | "go-admin/utils"
6 | "time"
7 | )
8 |
9 | type {{.ClassName}} struct {
10 |
11 | {{ range .Columns -}}
12 | {{$x := .Pk}}
13 | // {{.ColumnComment}}
14 | {{if ($x)}}{{.GoField}} {{.GoType}} `json:"{{.JsonField}}" gorm:"column:{{.ColumnName}};primary_key"`{{else}}{{.GoField}} {{.GoType}} `json:"{{.JsonField}}" gorm:"column:{{.ColumnName}};"`{{end}}
15 | {{ end -}}
16 | }
17 |
18 | // 创建{{.ClassName}}
19 | func (e *{{.ClassName}}) Create() ({{.ClassName}}, error) {
20 | var doc {{.ClassName}}
21 | doc.IsDel = "0"
22 | e.CreateTime = time.Now().String()
23 | result := orm.Eloquent.Table("{{.TableName}}").Create(&e)
24 | if result.Error != nil {
25 | err := result.Error
26 | return doc, err
27 | }
28 | doc = *e
29 | return doc, nil
30 | }
31 |
32 | // 获取{{.ClassName}}
33 | func (e *{{.ClassName}}) Get() ({{.ClassName}}, error) {
34 | var doc {{.ClassName}}
35 |
36 | table := orm.Eloquent.Table("{{.TableName}}")
37 | {{ range .Columns -}}
38 | {{$z := .IsQuery}}
39 | {{- if ($z) -}}if e.{{.GoField}} != "" {
40 | table = table.Where("{{.ColumnName}} = ?", e.{{.GoField}})
41 | }
42 | {{ end }}
43 | {{- end -}}
44 |
45 | if err := table.First(&doc).Error; err != nil {
46 | return doc, err
47 | }
48 | return doc, nil
49 | }
50 |
51 | // 获取{{.ClassName}}带分页
52 | func (e *{{.ClassName}}) GetPage(pageSize int, pageIndex int) ([]{{.ClassName}}, int32, error) {
53 | var doc []{{.ClassName}}
54 |
55 | table := orm.Eloquent.Table("{{.TableName}}")
56 | {{ range .Columns -}}
57 | {{$z := .IsQuery}}
58 | {{- if ($z) -}}if e.{{.GoField}} != "" {
59 | table = table.Where("{{.ColumnName}} = ?", e.{{.GoField}})
60 | }
61 | {{ end }}
62 | {{- end -}}
63 |
64 | // 数据权限控制
65 | dataPermission := new(DataPermission)
66 | dataPermission.UserId, _ = utils.StringToInt(e.DataScope)
67 | table,err := dataPermission.GetDataScope("{{.TableName}}", table)
68 | if err != nil {
69 | return nil, 0, err
70 | }
71 | var count int32
72 | table = table.Offset((pageIndex - 1) * pageSize).Limit(pageSize)
73 | if err := table.Find(&doc).Offset(-1).Limit(-1).Count(&count).Error; err != nil {
74 | return nil, 0, err
75 | }
76 | return doc, count, nil
77 | }
78 |
79 | // 更新{{.ClassName}}
80 | func (e *{{.ClassName}}) Update(id int) (update {{.ClassName}}, err error) {
81 | if err = orm.Eloquent.Table("{{.TableName}}").Where("{{.PkColumn}} = ?", id).First(&update).Error; err != nil {
82 | return
83 | }
84 |
85 | //参数1:是要修改的数据
86 | //参数2:是修改的数据
87 | if err = orm.Eloquent.Table("{{.TableName}}").Model(&update).Updates(&e).Error; err != nil {
88 | return
89 | }
90 | return
91 | }
92 |
93 | // 删除{{.ClassName}}
94 | func (e *{{.ClassName}}) Delete(id int) (success bool, err error) {
95 |
96 | if err = orm.Eloquent.Table("{{.TableName}}").Where("{{.PkColumn}} = ?", id).Delete(&{{.ClassName}}{}).Error; err != nil {
97 | success = false
98 | return
99 | }
100 | success = true
101 | return
102 | }
103 |
104 |
--------------------------------------------------------------------------------