mirror of
https://github.com/quarkcloudio/quark-go.git
synced 2025-09-26 20:11:11 +08:00
first commit
This commit is contained in:
22
.editorconfig
Normal file
22
.editorconfig
Normal file
@@ -0,0 +1,22 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.go,Makefile,.gitmodules,go.mod,go.sum}]
|
||||
indent_style = tab
|
||||
|
||||
[*.md]
|
||||
indent_style = tab
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{js,jsx,ts,tsx,css,less,sass,scss,vue,py}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# Mac OS X files
|
||||
.DS_Store
|
||||
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
|
||||
# Air tool tmp file
|
||||
tmp/
|
||||
|
||||
# Install lock file
|
||||
install.lock
|
||||
|
||||
# examples web site static files
|
||||
examples/*/website/
|
1
LICENSE.md
Normal file
1
LICENSE.md
Normal file
@@ -0,0 +1 @@
|
||||
Hacker license!
|
31
README.md
Normal file
31
README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
## 介绍
|
||||
QuarkGO 是一个基于golang的低代码工具;它提供的丰富组件,能帮助您使用很少的代码就能搭建出功能完善的应用系统。
|
||||
|
||||
## 系统特性
|
||||
|
||||
**内置功能**
|
||||
* 管理员管理
|
||||
* 用户管理
|
||||
* 权限系统
|
||||
* 菜单管理
|
||||
* 系统配置
|
||||
* 操作日志
|
||||
* 附件管理
|
||||
|
||||
**内置组件**
|
||||
* Layout组件
|
||||
* Container组件
|
||||
* Card组件
|
||||
* Table组件
|
||||
* Form组件
|
||||
* Show组件
|
||||
* TabForm组件
|
||||
* ...
|
||||
|
||||
## 技术支持
|
||||
为了避免打扰作者日常工作,你可以在Github上提交 [Issues](https://github.com/quarkcms/quark-go/issues)
|
||||
|
||||
相关教程,你可以查看 [在线文档](http://www.quarkcms.com/quark-go/)
|
||||
|
||||
## License
|
||||
QuarkGo is licensed under The MIT License (MIT).
|
0
cmd/quark/.keep
Normal file
0
cmd/quark/.keep
Normal file
9
examples/fiberadmin/.air.toml
Normal file
9
examples/fiberadmin/.air.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
|
||||
|
||||
# Working directory
|
||||
# . or absolute path, please note that the directories following must be under root.
|
||||
root = "."
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
exclude_dir = ["assets", "tmp", "vendor", "website"]
|
35
examples/fiberadmin/main.go
Normal file
35
examples/fiberadmin/main.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/quarkcms/quark-go/pkg/adapter/fiberadapter"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
// 数据库配置信息
|
||||
dsn := "root:Bc5HQFJc4bLjZCcC@tcp(127.0.0.1:3306)/quarkgo?charset=utf8&parseTime=True&loc=Local"
|
||||
|
||||
// 配置资源
|
||||
config := &builder.Config{
|
||||
AppKey: "123456",
|
||||
Providers: admin.Providers,
|
||||
DBConfig: &builder.DBConfig{
|
||||
Dialector: mysql.Open(dsn),
|
||||
Opts: &gorm.Config{},
|
||||
},
|
||||
}
|
||||
|
||||
// 创建对象
|
||||
b := builder.New(config)
|
||||
|
||||
// 适配fiber
|
||||
fiberadapter.Adapter(b, app)
|
||||
|
||||
app.Listen(":3000")
|
||||
}
|
9
examples/ginadmin/.air.toml
Normal file
9
examples/ginadmin/.air.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
|
||||
|
||||
# Working directory
|
||||
# . or absolute path, please note that the directories following must be under root.
|
||||
root = "."
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
exclude_dir = ["assets", "tmp", "vendor", "website"]
|
9
examples/hertzadmin/.air.toml
Normal file
9
examples/hertzadmin/.air.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
|
||||
|
||||
# Working directory
|
||||
# . or absolute path, please note that the directories following must be under root.
|
||||
root = "."
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
exclude_dir = ["assets", "tmp", "vendor", "website"]
|
37
examples/hertzadmin/.gitignore
vendored
Normal file
37
examples/hertzadmin/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
_obj
|
||||
_test
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
_testmain.go
|
||||
*.exe
|
||||
*.exe~
|
||||
*.test
|
||||
*.prof
|
||||
*.rar
|
||||
*.zip
|
||||
*.gz
|
||||
*.psd
|
||||
*.bmd
|
||||
*.cfg
|
||||
*.pptx
|
||||
*.log
|
||||
*nohup.out
|
||||
*settings.pyc
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
!.gitkeep
|
||||
.DS_Store
|
||||
/.idea
|
||||
/.vscode
|
||||
/output
|
||||
*.local.yml
|
||||
dumped_hertz_remote_config.json
|
||||
|
3
examples/hertzadmin/.hz
Normal file
3
examples/hertzadmin/.hz
Normal file
@@ -0,0 +1,3 @@
|
||||
// Code generated by hz. DO NOT EDIT.
|
||||
|
||||
hz version: v0.4.0
|
10
examples/hertzadmin/biz/handler/providers.go
Normal file
10
examples/hertzadmin/biz/handler/providers.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/examples/hertzadmin/biz/handler/resources"
|
||||
)
|
||||
|
||||
// 注册服务
|
||||
var Providers = []interface{}{
|
||||
&resources.Demo{},
|
||||
}
|
37
examples/hertzadmin/biz/handler/resources/demo.go
Normal file
37
examples/hertzadmin/biz/handler/resources/demo.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
)
|
||||
|
||||
type Demo struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Demo) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *Demo) Fields(request *builder.Request) []interface{} {
|
||||
|
||||
return []interface{}{}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *Demo) Searches(request *builder.Request) []interface{} {
|
||||
|
||||
return []interface{}{}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *Demo) Actions(request *builder.Request) []interface{} {
|
||||
|
||||
return []interface{}{}
|
||||
}
|
12
examples/hertzadmin/biz/router/register.go
Normal file
12
examples/hertzadmin/biz/router/register.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// Code generated by hertz generator. DO NOT EDIT.
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/cloudwego/hertz/pkg/app/server"
|
||||
)
|
||||
|
||||
// GeneratedRegister registers routers generated by IDL.
|
||||
func GeneratedRegister(r *server.Hertz) {
|
||||
//INSERT_POINT: DO NOT DELETE THIS LINE!
|
||||
}
|
22
examples/hertzadmin/main.go
Normal file
22
examples/hertzadmin/main.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// Code generated by hertz generator.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/cloudwego/hertz/pkg/app"
|
||||
"github.com/cloudwego/hertz/pkg/app/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
h := server.Default(server.WithHostPorts(":3000"))
|
||||
|
||||
// 静态文件目录
|
||||
fs := &app.FS{Root: "/website", IndexNames: []string{"index.html"}}
|
||||
h.StaticFS("/", fs)
|
||||
|
||||
// 注册路由
|
||||
register(h)
|
||||
|
||||
// 启动服务
|
||||
h.Spin()
|
||||
}
|
44
examples/hertzadmin/router.go
Normal file
44
examples/hertzadmin/router.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// Code generated by hertz generator.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/cloudwego/hertz/pkg/app/server"
|
||||
"github.com/quarkcms/quark-go/examples/hertzadmin/biz/handler"
|
||||
"github.com/quarkcms/quark-go/pkg/adapter/hertzadapter"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin"
|
||||
"github.com/quarkcms/quark-go/pkg/app/install"
|
||||
"github.com/quarkcms/quark-go/pkg/app/middleware"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// customizeRegister registers customize routers.
|
||||
func customizedRegister(r *server.Hertz) {
|
||||
|
||||
// 数据库配置信息
|
||||
dsn := "root:Bc5HQFJc4bLjZCcC@tcp(127.0.0.1:3306)/quarkgo?charset=utf8&parseTime=True&loc=Local"
|
||||
|
||||
// 配置资源
|
||||
config := &builder.Config{
|
||||
AppKey: "123456",
|
||||
Providers: append(admin.Providers, handler.Providers...),
|
||||
DBConfig: &builder.DBConfig{
|
||||
Dialector: mysql.Open(dsn),
|
||||
Opts: &gorm.Config{},
|
||||
},
|
||||
}
|
||||
|
||||
// 创建对象
|
||||
b := builder.New(config)
|
||||
|
||||
// 初始化安装
|
||||
b.Use(install.Handle)
|
||||
|
||||
// 中间件
|
||||
b.Use(middleware.Handle)
|
||||
|
||||
// 适配hertz
|
||||
hertzadapter.Adapter(b, r)
|
||||
}
|
16
examples/hertzadmin/router_gen.go
Normal file
16
examples/hertzadmin/router_gen.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// Code generated by hertz generator. DO NOT EDIT.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/cloudwego/hertz/pkg/app/server"
|
||||
router "github.com/quarkcms/quark-go/examples/hertzadmin/biz/router"
|
||||
)
|
||||
|
||||
// register registers all routers.
|
||||
func register(r *server.Hertz) {
|
||||
|
||||
router.GeneratedRegister(r)
|
||||
|
||||
customizedRegister(r)
|
||||
}
|
93
go.mod
Normal file
93
go.mod
Normal file
@@ -0,0 +1,93 @@
|
||||
module github.com/quarkcms/quark-go
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1
|
||||
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18
|
||||
github.com/alibabacloud-go/tea v1.1.20
|
||||
github.com/alibabacloud-go/tea-utils v1.4.5
|
||||
github.com/go-basic/uuid v1.0.0
|
||||
github.com/gofiber/fiber/v2 v2.41.0
|
||||
github.com/parnurzeal/gorequest v0.2.16
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect
|
||||
github.com/bytedance/gopkg v0.0.0-20220531084716-665b4f21126f // indirect
|
||||
github.com/bytedance/sonic v1.5.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 // indirect
|
||||
github.com/cloudwego/netpoll v0.3.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/henrylee2cn/ameda v1.4.10 // indirect
|
||||
github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/nyaruka/phonenumbers v1.0.55 // indirect
|
||||
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.3 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/tidwall/gjson v1.13.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.43.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/arch v0.0.0-20220722155209-00200b7164a7 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 // indirect
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
|
||||
github.com/alibabacloud-go/openapi-util v0.0.11 // indirect
|
||||
github.com/alibabacloud-go/tea-xml v1.1.2 // indirect
|
||||
github.com/aliyun/credentials-go v1.1.2 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.5.6 // indirect
|
||||
github.com/cloudwego/hertz v0.4.2
|
||||
github.com/dchest/captcha v1.0.0
|
||||
github.com/derekstavis/go-qs v0.0.0-20180720192143-9eef69e6c4e7
|
||||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/gobeam/stringy v0.0.5
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||
github.com/xuri/excelize/v2 v2.6.1
|
||||
golang.org/x/crypto v0.5.0
|
||||
golang.org/x/net v0.5.0 // indirect
|
||||
gopkg.in/ini.v1 v1.56.0 // indirect
|
||||
gorm.io/driver/mysql v1.4.5
|
||||
gorm.io/gorm v1.24.3
|
||||
moul.io/http2curl v1.0.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/apache/thrift => github.com/apache/thrift v0.13.0
|
279
go.sum
Normal file
279
go.sum
Normal file
@@ -0,0 +1,279 @@
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.1.18/go.mod h1:PB4HffMhJVmAgNKNq3wYbTUlFvPgxJpTzd1F5pTuUsc=
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY=
|
||||
github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50=
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18 h1:hfZA4cgIl6frNdsRmAyj8sn9J1bihQpYbzIVv2T/+Cs=
|
||||
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18/go.mod h1:di54xjBFHvKiQQo7st3TUmiMy0ywne5TOHup786Rhes=
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
||||
github.com/alibabacloud-go/openapi-util v0.0.11 h1:iYnqOPR5hyEEnNZmebGyRMkkEJRWUEjDiiaOHZ5aNhA=
|
||||
github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
|
||||
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.1.20 h1:wFK4xEbvGYMtzTyHhIju9D7ecWxvSUdoLO6y4vDLFik=
|
||||
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||
github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY=
|
||||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I=
|
||||
github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM=
|
||||
github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q=
|
||||
github.com/bytedance/gopkg v0.0.0-20220531084716-665b4f21126f h1:2YCF3cgO6XCub0HIsLrA8ZGhmAPGZfOeSaGjT6Kx4Mc=
|
||||
github.com/bytedance/gopkg v0.0.0-20220531084716-665b4f21126f/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q=
|
||||
github.com/bytedance/sonic v1.5.0 h1:XWdTi8bwPgxIML+eNV1IwNuTROK6EUrQ65ey8yd6fRQ=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 h1:1sDoSuDPWzhkdzNVxCxtIaKiAe96ESVPv8coGwc1gZ4=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/clbanning/mxj/v2 v2.5.6 h1:Jm4VaCI/+Ug5Q57IzEoZbwx4iQFA6wkXv72juUSeK+g=
|
||||
github.com/clbanning/mxj/v2 v2.5.6/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/cloudwego/hertz v0.4.2 h1:Ntfs5MdPoKeFSbyStU2drM4CizOkEfYWsB9s1Q3taPY=
|
||||
github.com/cloudwego/hertz v0.4.2/go.mod h1:K1U0RlU07CDeBINfHNbafH/3j9uSgIW8otbjUys3OPY=
|
||||
github.com/cloudwego/netpoll v0.3.1 h1:xByoORmCLIyKZ8gS+da06WDo3j+jvmhaqS2KeKejtBk=
|
||||
github.com/cloudwego/netpoll v0.3.1/go.mod h1:1T2WVuQ+MQw6h6DpE45MohSvDTKdy2DlzCx2KsnPI4E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/captcha v1.0.0 h1:vw+bm/qMFvTgcjQlYVTuQBJkarm5R0YSsDKhm1HZI2o=
|
||||
github.com/dchest/captcha v1.0.0/go.mod h1:7zoElIawLp7GUMLcj54K9kbw+jEyvz2K0FDdRRYhvWo=
|
||||
github.com/derekstavis/go-qs v0.0.0-20180720192143-9eef69e6c4e7 h1:zmAiXR9h1TCVN/0yCMRYQNE91dNRORpSzMFiqfTTPOs=
|
||||
github.com/derekstavis/go-qs v0.0.0-20180720192143-9eef69e6c4e7/go.mod h1:Vgz4nKcG6+B7QcALsWZpmhyQTLSl7nwFGKSrbq2LxEo=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
|
||||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/go-basic/uuid v1.0.0 h1:Faqtetcr8uwOzR2qp8RSpkahQiv4+BnJhrpuXPOo63M=
|
||||
github.com/go-basic/uuid v1.0.0/go.mod h1:yVtVnsXcmaLc9F4Zw7hTV7R0+vtuQw00mdXi+F6tqco=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/gobeam/stringy v0.0.5 h1:TvxQGSAqr/qF0SBVxa8Q67WWIo7bCWS0bM101WOd52g=
|
||||
github.com/gobeam/stringy v0.0.5/go.mod h1:W3620X9dJHf2FSZF5fRnWekHcHQjwmCz8ZQ2d1qloqE=
|
||||
github.com/gofiber/fiber/v2 v2.41.0 h1:YhNoUS/OTjEz+/WLYuQ01xI7RXgKEFnGBKMagAu5f0M=
|
||||
github.com/gofiber/fiber/v2 v2.41.0/go.mod h1:RdebcCuCRFp4W6hr3968/XxwJVg0K+jr9/Ae0PFzZ0Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4=
|
||||
github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk=
|
||||
github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4=
|
||||
github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhYIrO6sdV/FPe0xQM6fNHkVQW2IAymfM0=
|
||||
github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ=
|
||||
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
|
||||
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
|
||||
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg=
|
||||
github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/parnurzeal/gorequest v0.2.16 h1:T/5x+/4BT+nj+3eSknXmCTnEVGSzFzPGdpqmUVVZXHQ=
|
||||
github.com/parnurzeal/gorequest v0.2.16/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
|
||||
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
|
||||
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
|
||||
github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
|
||||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M=
|
||||
github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
|
||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.43.0 h1:Gy4sb32C98fbzVWZlTM1oTMdLWGyvxR03VhM6cBIU4g=
|
||||
github.com/valyala/fasthttp v1.43.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 h1:6932x8ltq1w4utjmfMPVj09jdMlkY0aiA6+Skbtl3/c=
|
||||
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||
github.com/xuri/excelize/v2 v2.6.1 h1:ICBdtw803rmhLN3zfvyEGH3cwSmZv+kde7LhTDT659k=
|
||||
github.com/xuri/excelize/v2 v2.6.1/go.mod h1:tL+0m6DNwSXj/sILHbQTYsLi9IF4TW59H2EF3Yrx1AU=
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M=
|
||||
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.0.0-20220722155209-00200b7164a7 h1:VBQqJMNMRfQsWSiCTLgz9XjAfWlgnJAPv8nsp1HF8Tw=
|
||||
golang.org/x/arch v0.0.0-20220722155209-00200b7164a7/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE=
|
||||
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y=
|
||||
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.4.5 h1:u1lytId4+o9dDaNcPCFzNv7h6wvmc92UjNk3z8enSBU=
|
||||
gorm.io/driver/mysql v1.4.5/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc=
|
||||
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.24.3 h1:WL2ifUmzR/SLp85CSURAfybcHnGZ+yLSGSxgYXlFBHg=
|
||||
gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
106
internal/aliyunsms/aliyunsms.go
Normal file
106
internal/aliyunsms/aliyunsms.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package aliyunsms
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/client"
|
||||
dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v2/client"
|
||||
util "github.com/alibabacloud-go/tea-utils/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
)
|
||||
|
||||
// 配置
|
||||
type Config struct {
|
||||
AccessKeyId string
|
||||
AccessKeySecret string
|
||||
SignName string
|
||||
TemplateCode string
|
||||
}
|
||||
|
||||
// 结构体
|
||||
type App struct {
|
||||
Config *Config
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func New(config *Config) *App {
|
||||
|
||||
return &App{
|
||||
Config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// 发送短信
|
||||
func (p *App) SendSms(phone string, code string) (bool, string) {
|
||||
|
||||
// 匹配规则
|
||||
regRuler := "^1[345789]{1}\\d{9}$"
|
||||
|
||||
// 正则调用规则
|
||||
reg := regexp.MustCompile(regRuler)
|
||||
|
||||
// 返回 MatchString 是否匹配
|
||||
if !reg.MatchString(phone) {
|
||||
return false, "手机号格式错误!"
|
||||
}
|
||||
|
||||
client, _err := Client(tea.String(p.Config.AccessKeyId), tea.String(p.Config.AccessKeySecret))
|
||||
if _err != nil {
|
||||
return false, _err.Error()
|
||||
}
|
||||
|
||||
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||
PhoneNumbers: tea.String(phone),
|
||||
SignName: tea.String(p.Config.SignName),
|
||||
TemplateCode: tea.String(p.Config.TemplateCode),
|
||||
TemplateParam: tea.String("{\"code\":\"" + code + "\"}"),
|
||||
}
|
||||
runtime := &util.RuntimeOptions{}
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
_, _err = client.SendSmsWithOptions(sendSmsRequest, runtime)
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
var error = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
error = _t
|
||||
} else {
|
||||
error.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
// 如有需要,请打印 error
|
||||
util.AssertAsString(error.Message)
|
||||
}
|
||||
|
||||
if _err != nil {
|
||||
return false, _err.Error()
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// 使用AK&SK初始化账号Client
|
||||
func Client(accessKeyId *string, accessKeySecret *string) (_result *dysmsapi20170525.Client, _err error) {
|
||||
config := &openapi.Config{
|
||||
// 您的 AccessKey ID
|
||||
AccessKeyId: accessKeyId,
|
||||
// 您的 AccessKey Secret
|
||||
AccessKeySecret: accessKeySecret,
|
||||
}
|
||||
// 访问的域名
|
||||
config.Endpoint = tea.String("dysmsapi.aliyuncs.com")
|
||||
_result = &dysmsapi20170525.Client{}
|
||||
_result, _err = dysmsapi20170525.NewClient(config)
|
||||
|
||||
return _result, _err
|
||||
}
|
74
internal/sioosms/sioosms.go
Normal file
74
internal/sioosms/sioosms.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package aliyunsms
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/parnurzeal/gorequest"
|
||||
)
|
||||
|
||||
// 配置
|
||||
type Config struct {
|
||||
Uid string
|
||||
Password string
|
||||
}
|
||||
|
||||
// 结构体
|
||||
type App struct {
|
||||
Config *Config
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func New(config *Config) *App {
|
||||
|
||||
return &App{
|
||||
Config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// 发送短信
|
||||
func (p *App) SendSms(phone string, content string) (bool, string) {
|
||||
// 匹配规则
|
||||
regRuler := "^1[345789]{1}\\d{9}$"
|
||||
|
||||
// 正则调用规则
|
||||
reg := regexp.MustCompile(regRuler)
|
||||
|
||||
// 返回 MatchString 是否匹配
|
||||
if !reg.MatchString(phone) {
|
||||
return false, "手机号格式错误!"
|
||||
}
|
||||
|
||||
uid := p.Config.Uid
|
||||
password := p.Config.Password
|
||||
|
||||
if uid == "" || password == "" {
|
||||
return false, "接口配置错误!"
|
||||
}
|
||||
|
||||
md5Byte := md5.Sum([]byte(password))
|
||||
md5Password := fmt.Sprintf("%x", md5Byte)
|
||||
|
||||
// 接口url
|
||||
url := "https://submit.10690221.com/send/ordinarykv?uid=" + uid + "&password=" + md5Password + "&mobile=" + phone + "&msg=" + content
|
||||
|
||||
request := gorequest.New()
|
||||
_, body, _ := request.Get(url).End()
|
||||
|
||||
type Data struct {
|
||||
Msg string
|
||||
Code int
|
||||
MsgId string
|
||||
}
|
||||
|
||||
var data Data
|
||||
json.Unmarshal([]byte(body), &data)
|
||||
|
||||
if data.Code == 0 {
|
||||
return true, "发送成功"
|
||||
} else {
|
||||
return true, data.Msg
|
||||
}
|
||||
}
|
94
pkg/adapter/fiberadapter/fiberadapter.go
Normal file
94
pkg/adapter/fiberadapter/fiberadapter.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package fiberadapter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
)
|
||||
|
||||
const COMPONENT_RESPONSE = "component" // 组件类型响应
|
||||
const ACTION_RESPONSE = "action" // 行为类型响应
|
||||
const FILE_RESPONSE = "file" // 文件类型响应
|
||||
|
||||
// 将gofiber框架的Ctx转换为builder框架Request
|
||||
func RequestAdapter(ctx *fiber.Ctx) (*builder.Request, error) {
|
||||
|
||||
return &builder.Request{
|
||||
IPString: ctx.IP(),
|
||||
HeaderString: ctx.Request().Header.String(),
|
||||
MethodString: string(ctx.Method()),
|
||||
FullPathString: ctx.Route().Path,
|
||||
HostString: string(ctx.Hostname()),
|
||||
PathString: string(ctx.Path()),
|
||||
QueryString: string(ctx.Context().QueryArgs().QueryString()),
|
||||
BodyBuffer: ctx.Body(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 适配gofiber框架响应
|
||||
func ResponseAdapter(r *builder.Resource, responseType string, ctx *fiber.Ctx) error {
|
||||
var responseError error
|
||||
|
||||
result, err := r.Run()
|
||||
if err != nil {
|
||||
return ctx.JSON(msg.Error(err.Error(), ""))
|
||||
}
|
||||
|
||||
switch responseType {
|
||||
case "component":
|
||||
return ctx.JSON(result)
|
||||
case "action":
|
||||
return ctx.JSON(msg.Success("操作成功", "", result))
|
||||
case "file":
|
||||
return ctx.SendStream(bytes.NewReader(result.([]byte)))
|
||||
}
|
||||
|
||||
return responseError
|
||||
}
|
||||
|
||||
// 适配gofiber框架路由
|
||||
func RouteAdapter(b *builder.Resource, responseType string, ctx *fiber.Ctx) error {
|
||||
|
||||
// 适配请求
|
||||
request, err := RequestAdapter(ctx)
|
||||
if err != nil {
|
||||
return ctx.JSON(msg.Error(err.Error(), ""))
|
||||
}
|
||||
|
||||
// 适配响应
|
||||
resource := b.TransformRequest(request)
|
||||
return ResponseAdapter(resource, responseType, ctx)
|
||||
}
|
||||
|
||||
// 适配gofiber框架
|
||||
func Adapter(b *builder.Resource, app *fiber.App) {
|
||||
|
||||
// 后台路由组
|
||||
rg := app.Group("/api/admin")
|
||||
|
||||
// 登录
|
||||
rg.Get("/login/:resource/index", func(ctx *fiber.Ctx) error {
|
||||
return RouteAdapter(b, COMPONENT_RESPONSE, ctx)
|
||||
})
|
||||
rg.Post("/login/:resource/handle", func(ctx *fiber.Ctx) error {
|
||||
return RouteAdapter(b, ACTION_RESPONSE, ctx)
|
||||
})
|
||||
rg.Get("/login/:resource/captchaId", func(ctx *fiber.Ctx) error {
|
||||
return RouteAdapter(b, ACTION_RESPONSE, ctx)
|
||||
})
|
||||
rg.Get("/login/:resource/captcha/:id", func(ctx *fiber.Ctx) error {
|
||||
return RouteAdapter(b, FILE_RESPONSE, ctx)
|
||||
})
|
||||
|
||||
// 仪表盘
|
||||
rg.Get("/dashboard/:resource/index", func(ctx *fiber.Ctx) error {
|
||||
return RouteAdapter(b, COMPONENT_RESPONSE, ctx)
|
||||
})
|
||||
|
||||
// 增删改查
|
||||
rg.Get("/:resource/index", func(ctx *fiber.Ctx) error {
|
||||
return RouteAdapter(b, COMPONENT_RESPONSE, ctx)
|
||||
})
|
||||
}
|
160
pkg/adapter/hertzadapter/hertzadapter.go
Normal file
160
pkg/adapter/hertzadapter/hertzadapter.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package hertzadapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/cloudwego/hertz/pkg/app"
|
||||
"github.com/cloudwego/hertz/pkg/app/server"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
)
|
||||
|
||||
const JSON_RESPONSE = "json" // json类型响应
|
||||
const IMAGE_RESPONSE = "image" // 图片类型响应
|
||||
const EXCEL_RESPONSE = "excel" // Excel文件类型响应
|
||||
|
||||
// 将hertz框架的RequestContext转发到builder的Request
|
||||
func RequestAdapter(ctx *app.RequestContext) (*builder.Request, error) {
|
||||
body, err := ctx.Body()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &builder.Request{
|
||||
IPString: ctx.ClientIP(),
|
||||
HeaderString: string(ctx.Request.Header.Header()),
|
||||
MethodString: string(ctx.Method()),
|
||||
FullPathString: ctx.FullPath(),
|
||||
HostString: string(ctx.Host()),
|
||||
PathString: string(ctx.Path()),
|
||||
QueryString: string(ctx.Request.QueryString()),
|
||||
BodyBuffer: body,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 适配hertz框架响应
|
||||
func ResponseAdapter(r *builder.Resource, responseType string, ctx *app.RequestContext) {
|
||||
result, err := r.Run()
|
||||
if err != nil {
|
||||
ctx.JSON(200, msg.Error(err.Error(), ""))
|
||||
return
|
||||
}
|
||||
|
||||
switch responseType {
|
||||
case JSON_RESPONSE:
|
||||
ctx.JSON(200, result)
|
||||
case IMAGE_RESPONSE:
|
||||
ctx.Write(result.([]byte))
|
||||
}
|
||||
}
|
||||
|
||||
// 适配hertz框架路由
|
||||
func RouteAdapter(b *builder.Resource, responseType string, ctx *app.RequestContext) {
|
||||
body, err := ctx.Body()
|
||||
if err != nil {
|
||||
ctx.JSON(200, msg.Error(err.Error(), ""))
|
||||
return
|
||||
}
|
||||
|
||||
// 将hertz框架请求转换为builder框架请求
|
||||
request := &builder.Request{
|
||||
IPString: ctx.ClientIP(),
|
||||
HeaderString: string(ctx.Request.Header.Header()),
|
||||
MethodString: string(ctx.Method()),
|
||||
FullPathString: ctx.FullPath(),
|
||||
HostString: string(ctx.Host()),
|
||||
PathString: string(ctx.Path()),
|
||||
QueryString: string(ctx.Request.QueryString()),
|
||||
BodyBuffer: body,
|
||||
}
|
||||
|
||||
// 转换Request对象
|
||||
result, err := b.TransformRequest(request).Run()
|
||||
if err != nil {
|
||||
ctx.JSON(200, msg.Error(err.Error(), ""))
|
||||
return
|
||||
}
|
||||
|
||||
// 响应结果
|
||||
switch responseType {
|
||||
case JSON_RESPONSE:
|
||||
ctx.JSON(200, result)
|
||||
case IMAGE_RESPONSE:
|
||||
ctx.Write(result.([]byte))
|
||||
case EXCEL_RESPONSE:
|
||||
ctx.Response.Header.Set("Content-Disposition", "attachment; filename=data_"+time.Now().Format("20060102150405")+".xlsx")
|
||||
ctx.Response.Header.Set("Content-Type", "application/octet-stream")
|
||||
ctx.Write(result.([]byte))
|
||||
}
|
||||
}
|
||||
|
||||
// 适配hertz框架
|
||||
func Adapter(b *builder.Resource, r *server.Hertz) {
|
||||
|
||||
// 后台路由组
|
||||
rg := r.Group("/api/admin")
|
||||
|
||||
// 登录
|
||||
rg.GET("/login/:resource/index", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.POST("/login/:resource/handle", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/login/:resource/captchaId", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/login/:resource/captcha/:id", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, IMAGE_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/logout/:resource/handle", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
|
||||
// 仪表盘
|
||||
rg.GET("/dashboard/:resource/index", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
|
||||
// 增删改查
|
||||
rg.GET("/:resource/index", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/:resource/editable", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.Any("/:resource/action/:uriKey", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/:resource/create", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.POST("/:resource/store", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/:resource/edit", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/:resource/edit/values", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.POST("/:resource/save", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/:resource/detail", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/:resource/export", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, EXCEL_RESPONSE, ctx)
|
||||
})
|
||||
rg.Any("/:resource/import", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/:resource/import/template", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, EXCEL_RESPONSE, ctx)
|
||||
})
|
||||
rg.GET("/:resource/:uriKey/form", func(c context.Context, ctx *app.RequestContext) {
|
||||
RouteAdapter(b, JSON_RESPONSE, ctx)
|
||||
})
|
||||
}
|
45
pkg/app/handler/admin/actions/change_account.go
Normal file
45
pkg/app/handler/admin/actions/change_account.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
models "github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/hash"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ChangeAccount struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 执行行为句柄
|
||||
func (p *ChangeAccount) Handle(request *builder.Request, model *gorm.DB) interface{} {
|
||||
data := map[string]interface{}{}
|
||||
json.Unmarshal(request.Body(), &data)
|
||||
if data["avatar"] != "" {
|
||||
data["avatar"], _ = json.Marshal(data["avatar"])
|
||||
} else {
|
||||
data["avatar"] = nil
|
||||
}
|
||||
|
||||
// 加密密码
|
||||
if data["password"] != nil {
|
||||
data["password"] = hash.Make(data["password"].(string))
|
||||
}
|
||||
|
||||
// 获取登录管理员信息
|
||||
adminInfo, err := (&models.Admin{}).GetAuthUser(request.Token())
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
err = model.Where("id", adminInfo.Id).Updates(data).Error
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功", "", "")
|
||||
}
|
72
pkg/app/handler/admin/actions/change_status.go
Normal file
72
pkg/app/handler/admin/actions/change_status.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ChangeStatus struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *ChangeStatus) Init() *ChangeStatus {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 行为名称,当行为在表格行展示时,支持js表达式
|
||||
p.Name = "<%= (status==1 ? '禁用' : '启用') %>"
|
||||
|
||||
// 设置按钮类型,primary | ghost | dashed | link | text | default
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndexTableRow(true)
|
||||
|
||||
// 当行为在表格行展示时,支持js表达式
|
||||
p.WithConfirm("确定要<%= (status==1 ? '禁用' : '启用') %>数据吗?", "", "pop")
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 行为接口接收的参数,当行为在表格行展示的时候,可以配置当前行的任意字段
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
func (p *ChangeStatus) GetApiParams() []string {
|
||||
return []string{
|
||||
"id",
|
||||
"status",
|
||||
}
|
||||
}
|
||||
|
||||
// 执行行为句柄
|
||||
func (p *ChangeStatus) Handle(request *builder.Request, model *gorm.DB) interface{} {
|
||||
status := request.Query("status")
|
||||
if status == "" {
|
||||
return msg.Error("参数错误!", "")
|
||||
}
|
||||
|
||||
var fieldStatus int
|
||||
if status == "1" {
|
||||
fieldStatus = 0
|
||||
} else {
|
||||
fieldStatus = 1
|
||||
}
|
||||
|
||||
err := model.Update("status", fieldStatus).Error
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功", "", "")
|
||||
}
|
51
pkg/app/handler/admin/actions/change_web_config.go
Normal file
51
pkg/app/handler/admin/actions/change_web_config.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
models "github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ChangeWebConfig struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 执行行为句柄
|
||||
func (p *ChangeWebConfig) Handle(request *builder.Request, model *gorm.DB) interface{} {
|
||||
data := map[string]interface{}{}
|
||||
json.Unmarshal(request.Body(), &data)
|
||||
result := true
|
||||
|
||||
for k, v := range data {
|
||||
config := map[string]interface{}{}
|
||||
db.Client.Model(&models.Config{}).Where("name =?", k).First(&config)
|
||||
if getValue, ok := v.([]interface{}); ok {
|
||||
v, _ = json.Marshal(getValue)
|
||||
}
|
||||
if getValue, ok := v.([]map[string]interface{}); ok {
|
||||
v, _ = json.Marshal(getValue)
|
||||
}
|
||||
if getValue, ok := v.(map[string]interface{}); ok {
|
||||
v, _ = json.Marshal(getValue)
|
||||
}
|
||||
updateResult := db.Client.Model(&models.Config{}).Where("name", k).Update("value", v)
|
||||
if updateResult.Error != nil {
|
||||
result = false
|
||||
}
|
||||
}
|
||||
|
||||
if !result {
|
||||
return msg.Error("操作失败,请重试!", "")
|
||||
}
|
||||
|
||||
// 刷新网站配置
|
||||
(&models.Config{}).Refresh()
|
||||
|
||||
// 返回成功
|
||||
return msg.Success("操作成功", "", "")
|
||||
}
|
88
pkg/app/handler/admin/actions/create_drawer.go
Normal file
88
pkg/app/handler/admin/actions/create_drawer.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/action"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/form"
|
||||
)
|
||||
|
||||
type CreateDrawer struct {
|
||||
actions.Drawer
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *CreateDrawer) Init(name string) *CreateDrawer {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "primary"
|
||||
|
||||
// 图标
|
||||
p.Icon = "plus-circle"
|
||||
|
||||
// 文字
|
||||
p.Name = "创建" + name
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 关闭时销毁 Drawer 里的子元素
|
||||
p.DestroyOnClose = true
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndex(true)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *CreateDrawer) GetBody(request *builder.Request, resourceInstance interface{}) interface{} {
|
||||
|
||||
api := resourceInstance.(interface {
|
||||
CreationApi(*builder.Request, interface{}) string
|
||||
}).CreationApi(request, resourceInstance)
|
||||
|
||||
fields := resourceInstance.(interface {
|
||||
CreationFieldsWithinComponents(*builder.Request, interface{}) interface{}
|
||||
}).CreationFieldsWithinComponents(request, resourceInstance)
|
||||
|
||||
// 断言BeforeCreating方法,获取初始数据
|
||||
data := resourceInstance.(interface {
|
||||
BeforeCreating(*builder.Request) map[string]interface{}
|
||||
}).BeforeCreating(request)
|
||||
|
||||
return (&form.Component{}).
|
||||
Init().
|
||||
SetKey("createDrawerForm", false).
|
||||
SetApi(api).
|
||||
SetBody(fields).
|
||||
SetInitialValues(data).
|
||||
SetLabelCol(map[string]interface{}{
|
||||
"span": 6,
|
||||
}).
|
||||
SetWrapperCol(map[string]interface{}{
|
||||
"span": 18,
|
||||
})
|
||||
}
|
||||
|
||||
// 弹窗行为
|
||||
func (p *CreateDrawer) GetActions(request *builder.Request, resourceInstance interface{}) []interface{} {
|
||||
|
||||
return []interface{}{
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("取消").
|
||||
SetActionType("cancel"),
|
||||
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("提交").
|
||||
SetWithLoading(true).
|
||||
SetReload("table").
|
||||
SetActionType("submit").
|
||||
SetType("primary", false).
|
||||
SetSubmitForm("createDrawerForm"),
|
||||
}
|
||||
}
|
37
pkg/app/handler/admin/actions/create_link.go
Normal file
37
pkg/app/handler/admin/actions/create_link.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
)
|
||||
|
||||
type CreateLink struct {
|
||||
actions.Link
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *CreateLink) Init(name string) *CreateLink {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "primary"
|
||||
|
||||
// 图标
|
||||
p.Icon = "plus-circle"
|
||||
|
||||
// 文字
|
||||
p.Name = "创建" + name
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndex(true)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 跳转链接
|
||||
func (p *CreateLink) GetHref(request *builder.Request) string {
|
||||
return "#/index?api=" + strings.Replace(request.Path(), "/index", "/create", -1)
|
||||
}
|
88
pkg/app/handler/admin/actions/create_modal.go
Normal file
88
pkg/app/handler/admin/actions/create_modal.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/action"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/form"
|
||||
)
|
||||
|
||||
type CreateModal struct {
|
||||
actions.Modal
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *CreateModal) Init(name string) *CreateModal {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "primary"
|
||||
|
||||
// 图标
|
||||
p.Icon = "plus-circle"
|
||||
|
||||
// 文字
|
||||
p.Name = "创建" + name
|
||||
|
||||
// 关闭时销毁 Modal 里的子元素
|
||||
p.DestroyOnClose = true
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndex(true)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *CreateModal) GetBody(request *builder.Request, resourceInstance interface{}) interface{} {
|
||||
|
||||
api := resourceInstance.(interface {
|
||||
CreationApi(*builder.Request, interface{}) string
|
||||
}).CreationApi(request, resourceInstance)
|
||||
|
||||
fields := resourceInstance.(interface {
|
||||
CreationFieldsWithinComponents(*builder.Request, interface{}) interface{}
|
||||
}).CreationFieldsWithinComponents(request, resourceInstance)
|
||||
|
||||
// 断言BeforeCreating方法,获取初始数据
|
||||
data := resourceInstance.(interface {
|
||||
BeforeCreating(*builder.Request) map[string]interface{}
|
||||
}).BeforeCreating(request)
|
||||
|
||||
return (&form.Component{}).
|
||||
Init().
|
||||
SetKey("createModalForm", false).
|
||||
SetApi(api).
|
||||
SetBody(fields).
|
||||
SetInitialValues(data).
|
||||
SetLabelCol(map[string]interface{}{
|
||||
"span": 6,
|
||||
}).
|
||||
SetWrapperCol(map[string]interface{}{
|
||||
"span": 18,
|
||||
})
|
||||
}
|
||||
|
||||
// 弹窗行为
|
||||
func (p *CreateModal) GetActions(request *builder.Request, resourceInstance interface{}) []interface{} {
|
||||
|
||||
return []interface{}{
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("取消").
|
||||
SetActionType("cancel"),
|
||||
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("提交").
|
||||
SetWithLoading(true).
|
||||
SetReload("table").
|
||||
SetActionType("submit").
|
||||
SetType("primary", false).
|
||||
SetSubmitForm("createModalForm"),
|
||||
}
|
||||
}
|
64
pkg/app/handler/admin/actions/delete.go
Normal file
64
pkg/app/handler/admin/actions/delete.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Delete struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Delete) Init(name string) *Delete {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 行为名称,当行为在表格行展示时,支持js表达式
|
||||
p.Name = name
|
||||
|
||||
// 设置按钮类型,primary | ghost | dashed | link | text | default
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 当行为在表格行展示时,支持js表达式
|
||||
p.WithConfirm("确定要删除吗?", "删除后数据将无法恢复,请谨慎操作!", "modal")
|
||||
|
||||
if name == "删除" {
|
||||
p.SetOnlyOnIndexTableRow(true)
|
||||
}
|
||||
|
||||
if name == "批量删除" {
|
||||
p.SetOnlyOnIndexTableAlert(true)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 行为接口接收的参数,当行为在表格行展示的时候,可以配置当前行的任意字段
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
func (p *Delete) GetApiParams() []string {
|
||||
return []string{
|
||||
"id",
|
||||
}
|
||||
}
|
||||
|
||||
// 执行行为句柄
|
||||
func (p *Delete) Handle(request *builder.Request, model *gorm.DB) interface{} {
|
||||
err := model.Delete("").Error
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功", "", "")
|
||||
}
|
37
pkg/app/handler/admin/actions/detail_link.go
Normal file
37
pkg/app/handler/admin/actions/detail_link.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
)
|
||||
|
||||
type DetailLink struct {
|
||||
actions.Link
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *DetailLink) Init(name string) *DetailLink {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 设置按钮类型,primary | ghost | dashed | link | text | default
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 文字
|
||||
p.Name = name
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndexTableRow(true)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 跳转链接
|
||||
func (p *DetailLink) GetHref(request *builder.Request) string {
|
||||
return "#/index?api=" + strings.Replace(request.Path(), "/index", "/detail&id=${id}", -1)
|
||||
}
|
59
pkg/app/handler/admin/actions/disable.go
Normal file
59
pkg/app/handler/admin/actions/disable.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Disable struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Disable) Init(name string) *Disable {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 行为名称,当行为在表格行展示时,支持js表达式
|
||||
p.Name = name
|
||||
|
||||
// 设置按钮类型,primary | ghost | dashed | link | text | default
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndexTableAlert(true)
|
||||
|
||||
// 当行为在表格行展示时,支持js表达式
|
||||
p.WithConfirm("确定要禁用吗?", "禁用后数据将无法使用,请谨慎操作!", "modal")
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 行为接口接收的参数,当行为在表格行展示的时候,可以配置当前行的任意字段
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
func (p *Disable) GetApiParams() []string {
|
||||
return []string{
|
||||
"id",
|
||||
}
|
||||
}
|
||||
|
||||
// 执行行为句柄
|
||||
func (p *Disable) Handle(request *builder.Request, model *gorm.DB) interface{} {
|
||||
err := model.Update("status", 0).Error
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功", "", "")
|
||||
}
|
87
pkg/app/handler/admin/actions/edit_drawer.go
Normal file
87
pkg/app/handler/admin/actions/edit_drawer.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/action"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/form"
|
||||
)
|
||||
|
||||
type EditDrawer struct {
|
||||
actions.Drawer
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *EditDrawer) Init(name string) *EditDrawer {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 文字
|
||||
p.Name = name
|
||||
|
||||
// 关闭时销毁 Drawer 里的子元素
|
||||
p.DestroyOnClose = true
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndexTableRow(true)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *EditDrawer) GetBody(request *builder.Request, resourceInstance interface{}) interface{} {
|
||||
|
||||
api := resourceInstance.(interface {
|
||||
UpdateApi(*builder.Request, interface{}) string
|
||||
}).UpdateApi(request, resourceInstance)
|
||||
|
||||
initApi := resourceInstance.(interface {
|
||||
EditValueApi(*builder.Request) string
|
||||
}).EditValueApi(request)
|
||||
|
||||
fields := resourceInstance.(interface {
|
||||
UpdateFieldsWithinComponents(*builder.Request, interface{}) interface{}
|
||||
}).UpdateFieldsWithinComponents(request, resourceInstance)
|
||||
|
||||
return (&form.Component{}).
|
||||
Init().
|
||||
SetKey("editDrawerForm", false).
|
||||
SetApi(api).
|
||||
SetInitApi(initApi).
|
||||
SetBody(fields).
|
||||
SetLabelCol(map[string]interface{}{
|
||||
"span": 6,
|
||||
}).
|
||||
SetWrapperCol(map[string]interface{}{
|
||||
"span": 18,
|
||||
})
|
||||
}
|
||||
|
||||
// 弹窗行为
|
||||
func (p *EditDrawer) GetActions(request *builder.Request, resourceInstance interface{}) []interface{} {
|
||||
|
||||
return []interface{}{
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("取消").
|
||||
SetActionType("cancel"),
|
||||
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("提交").
|
||||
SetWithLoading(true).
|
||||
SetReload("table").
|
||||
SetActionType("submit").
|
||||
SetType("primary", false).
|
||||
SetSubmitForm("editDrawerForm"),
|
||||
}
|
||||
}
|
37
pkg/app/handler/admin/actions/edit_link.go
Normal file
37
pkg/app/handler/admin/actions/edit_link.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
)
|
||||
|
||||
type EditLink struct {
|
||||
actions.Link
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *EditLink) Init(name string) *EditLink {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 设置按钮类型,primary | ghost | dashed | link | text | default
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 文字
|
||||
p.Name = name
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndexTableRow(true)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 跳转链接
|
||||
func (p *EditLink) GetHref(request *builder.Request) string {
|
||||
return "#/index?api=" + strings.Replace(request.Path(), "/index", "/edit&id=${id}", -1)
|
||||
}
|
87
pkg/app/handler/admin/actions/edit_modal.go
Normal file
87
pkg/app/handler/admin/actions/edit_modal.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/action"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/form"
|
||||
)
|
||||
|
||||
type EditModal struct {
|
||||
actions.Modal
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *EditModal) Init(name string) *EditModal {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 文字
|
||||
p.Name = name
|
||||
|
||||
// 关闭时销毁 Modal 里的子元素
|
||||
p.DestroyOnClose = true
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndexTableRow(true)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *EditModal) GetBody(request *builder.Request, resourceInstance interface{}) interface{} {
|
||||
|
||||
api := resourceInstance.(interface {
|
||||
UpdateApi(*builder.Request, interface{}) string
|
||||
}).UpdateApi(request, resourceInstance)
|
||||
|
||||
initApi := resourceInstance.(interface {
|
||||
EditValueApi(*builder.Request) string
|
||||
}).EditValueApi(request)
|
||||
|
||||
fields := resourceInstance.(interface {
|
||||
UpdateFieldsWithinComponents(*builder.Request, interface{}) interface{}
|
||||
}).UpdateFieldsWithinComponents(request, resourceInstance)
|
||||
|
||||
return (&form.Component{}).
|
||||
Init().
|
||||
SetKey("editModalForm", false).
|
||||
SetApi(api).
|
||||
SetInitApi(initApi).
|
||||
SetBody(fields).
|
||||
SetLabelCol(map[string]interface{}{
|
||||
"span": 6,
|
||||
}).
|
||||
SetWrapperCol(map[string]interface{}{
|
||||
"span": 18,
|
||||
})
|
||||
}
|
||||
|
||||
// 弹窗行为
|
||||
func (p *EditModal) GetActions(request *builder.Request, resourceInstance interface{}) []interface{} {
|
||||
|
||||
return []interface{}{
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("取消").
|
||||
SetActionType("cancel"),
|
||||
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("提交").
|
||||
SetWithLoading(true).
|
||||
SetReload("table").
|
||||
SetActionType("submit").
|
||||
SetType("primary", false).
|
||||
SetSubmitForm("editModalForm"),
|
||||
}
|
||||
}
|
59
pkg/app/handler/admin/actions/enable.go
Normal file
59
pkg/app/handler/admin/actions/enable.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Enable struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Enable) Init(name string) *Enable {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 行为名称,当行为在表格行展示时,支持js表达式
|
||||
p.Name = name
|
||||
|
||||
// 设置按钮类型,primary | ghost | dashed | link | text | default
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndexTableAlert(true)
|
||||
|
||||
// 当行为在表格行展示时,支持js表达式
|
||||
p.WithConfirm("确定要启用吗?", "启用后数据将正常使用!", "modal")
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 行为接口接收的参数,当行为在表格行展示的时候,可以配置当前行的任意字段
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
func (p *Enable) GetApiParams() []string {
|
||||
return []string{
|
||||
"id",
|
||||
}
|
||||
}
|
||||
|
||||
// 执行行为句柄
|
||||
func (p *Enable) Handle(request *builder.Request, model *gorm.DB) interface{} {
|
||||
err := model.Update("status", 1).Error
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功", "", "")
|
||||
}
|
29
pkg/app/handler/admin/actions/form_back.go
Normal file
29
pkg/app/handler/admin/actions/form_back.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
)
|
||||
|
||||
type FormBack struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *FormBack) Init() *FormBack {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "default"
|
||||
|
||||
// 文字
|
||||
p.Name = "返回上一页"
|
||||
|
||||
// 行为类型
|
||||
p.ActionType = "back"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetShowOnForm().SetShowOnDetail()
|
||||
|
||||
return p
|
||||
}
|
29
pkg/app/handler/admin/actions/form_extra_back.go
Normal file
29
pkg/app/handler/admin/actions/form_extra_back.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
)
|
||||
|
||||
type FormExtraBack struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *FormExtraBack) Init() *FormExtraBack {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "link"
|
||||
|
||||
// 文字
|
||||
p.Name = "返回上一页"
|
||||
|
||||
// 行为类型
|
||||
p.ActionType = "back"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetShowOnFormExtra().SetShowOnDetailExtra()
|
||||
|
||||
return p
|
||||
}
|
29
pkg/app/handler/admin/actions/form_reset.go
Normal file
29
pkg/app/handler/admin/actions/form_reset.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
)
|
||||
|
||||
type FormReset struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *FormReset) Init() *FormReset {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "default"
|
||||
|
||||
// 文字
|
||||
p.Name = "重置"
|
||||
|
||||
// 行为类型
|
||||
p.ActionType = "reset"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetShowOnForm()
|
||||
|
||||
return p
|
||||
}
|
32
pkg/app/handler/admin/actions/form_submit.go
Normal file
32
pkg/app/handler/admin/actions/form_submit.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
)
|
||||
|
||||
type FormSubmit struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *FormSubmit) Init() *FormSubmit {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 类型
|
||||
p.Type = "primary"
|
||||
|
||||
// 文字
|
||||
p.Name = "提交"
|
||||
|
||||
// 行为类型
|
||||
p.ActionType = "submit"
|
||||
|
||||
// 是否具有loading,当action 的作用类型为ajax,submit时有效
|
||||
p.WithLoading = true
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnForm(true)
|
||||
|
||||
return p
|
||||
}
|
90
pkg/app/handler/admin/actions/import.go
Normal file
90
pkg/app/handler/admin/actions/import.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/action"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/form"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/space"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/tpl"
|
||||
)
|
||||
|
||||
type Import struct {
|
||||
actions.Modal
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Import) Init() *Import {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 文字
|
||||
p.Name = "导入数据"
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndex(true)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *Import) GetBody(request *builder.Request, resourceInstance interface{}) interface{} {
|
||||
api := "admin/" + request.Param("resource") + "/import"
|
||||
getTpl := (&tpl.Component{}).
|
||||
Init().
|
||||
SetBody("模板文件: <a href='/api/admin/" + request.Param("resource") + "/import/template?token=" + request.Token() + "' target='_blank'>下载模板</a>").
|
||||
SetStyle(map[string]interface{}{
|
||||
"marginLeft": "50px",
|
||||
})
|
||||
|
||||
fields := []interface{}{
|
||||
(&space.Component{}).
|
||||
Init().
|
||||
SetBody(getTpl).
|
||||
SetDirection("vertical").
|
||||
SetSize("middle").
|
||||
SetStyle(map[string]interface{}{
|
||||
"marginBottom": "20px",
|
||||
}),
|
||||
(&builder.AdminField{}).
|
||||
File("fileId", "导入文件").
|
||||
SetLimitNum(1).
|
||||
SetLimitType([]string{
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
}).
|
||||
SetHelp("请上传xls格式的文件"),
|
||||
}
|
||||
|
||||
return (&form.Component{}).
|
||||
Init().
|
||||
SetKey("importModalForm", false).
|
||||
SetApi(api).
|
||||
SetBody(fields).
|
||||
SetLabelCol(map[string]interface{}{
|
||||
"span": 6,
|
||||
}).
|
||||
SetWrapperCol(map[string]interface{}{
|
||||
"span": 18,
|
||||
})
|
||||
}
|
||||
|
||||
// 弹窗行为
|
||||
func (p *Import) GetActions(request *builder.Request, resourceInstance interface{}) []interface{} {
|
||||
|
||||
return []interface{}{
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("取消").
|
||||
SetActionType("cancel"),
|
||||
|
||||
(&action.Component{}).
|
||||
Init().
|
||||
SetLabel("提交").
|
||||
SetWithLoading(true).
|
||||
SetReload("table").
|
||||
SetActionType("submit").
|
||||
SetType("primary", false).
|
||||
SetSubmitForm("importModalForm"),
|
||||
}
|
||||
}
|
44
pkg/app/handler/admin/actions/more_actions.go
Normal file
44
pkg/app/handler/admin/actions/more_actions.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
)
|
||||
|
||||
type MoreActions struct {
|
||||
actions.Dropdown
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *MoreActions) Init(name string) *MoreActions {
|
||||
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 下拉框箭头是否显示
|
||||
p.Arrow = true
|
||||
|
||||
// 菜单弹出位置:bottomLeft bottomCenter bottomRight topLeft topCenter topRight
|
||||
p.Placement = "bottomLeft"
|
||||
|
||||
// 触发下拉的行为, 移动端不支持 hover,Array<click|hover|contextMenu>
|
||||
p.Trigger = []string{"hover"}
|
||||
|
||||
// 下拉根元素的样式
|
||||
p.OverlayStyle = map[string]interface{}{
|
||||
"zIndex": 999,
|
||||
}
|
||||
|
||||
// 设置按钮类型,primary | ghost | dashed | link | text | default
|
||||
p.Type = "link"
|
||||
|
||||
// 设置按钮大小,large | middle | small | default
|
||||
p.Size = "small"
|
||||
|
||||
// 文字
|
||||
p.Name = name
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndexTableRow(true)
|
||||
|
||||
return p
|
||||
}
|
35
pkg/app/handler/admin/actions/select_options.go
Normal file
35
pkg/app/handler/admin/actions/select_options.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type SelectOptions struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 执行行为句柄
|
||||
func (p *SelectOptions) Handle(request *builder.Request, model *gorm.DB) interface{} {
|
||||
resource := request.Param("resource")
|
||||
search := request.Query("search")
|
||||
lists := []map[string]interface{}{}
|
||||
results := []map[string]interface{}{}
|
||||
|
||||
switch resource {
|
||||
case "Some Field":
|
||||
model.Where("Some Field = ?", search).Find(&lists)
|
||||
for _, v := range lists {
|
||||
item := map[string]interface{}{
|
||||
"label": v["name"],
|
||||
"value": v["id"],
|
||||
}
|
||||
|
||||
results = append(results, item)
|
||||
}
|
||||
}
|
||||
|
||||
return msg.Success("操作成功", "", results)
|
||||
}
|
78
pkg/app/handler/admin/actions/sync_permission.go
Normal file
78
pkg/app/handler/admin/actions/sync_permission.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
models "github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type SyncPermission struct {
|
||||
actions.Action
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *SyncPermission) Init() *SyncPermission {
|
||||
// 初始化父结构
|
||||
p.ParentInit()
|
||||
|
||||
// 行为名称
|
||||
p.Name = "同步权限"
|
||||
|
||||
// 执行成功后刷新的组件
|
||||
p.Reload = "table"
|
||||
|
||||
// 是否具有loading,当action 的作用类型为ajax,submit时有效
|
||||
p.WithLoading = true
|
||||
|
||||
// 设置展示位置
|
||||
p.SetOnlyOnIndex(true)
|
||||
|
||||
// 行为类型
|
||||
p.ActionType = "ajax"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 执行行为句柄
|
||||
func (p *SyncPermission) Handle(request *builder.Request, model *gorm.DB) interface{} {
|
||||
// 获取当前权限
|
||||
permissions := builder.GetRoutes()
|
||||
data := []models.Permission{}
|
||||
|
||||
var names []string
|
||||
db.Client.Model(&models.Permission{}).Pluck("name", &names)
|
||||
for _, v := range permissions {
|
||||
has := false
|
||||
for _, nv := range names {
|
||||
if nv == v {
|
||||
has = true
|
||||
}
|
||||
}
|
||||
if has == false {
|
||||
permission := models.Permission{
|
||||
MenuId: 0,
|
||||
Name: v,
|
||||
GuardName: "admin",
|
||||
}
|
||||
data = append(data, permission)
|
||||
}
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return msg.Error("暂无新增权限!", "")
|
||||
}
|
||||
|
||||
err := model.Create(data).Error
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
err = db.Client.Model(&models.Permission{}).Where("name NOT IN ?", permissions).Delete("").Error
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功", "", "")
|
||||
}
|
35
pkg/app/handler/admin/dashboards/index.go
Normal file
35
pkg/app/handler/admin/dashboards/index.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package dashboards
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/metrics"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/admindashboard"
|
||||
)
|
||||
|
||||
type Index struct {
|
||||
admindashboard.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Index) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
p.Title = "仪表盘"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *Index) Cards(request *builder.Request) interface{} {
|
||||
|
||||
return []any{
|
||||
&metrics.TotalAdmin{},
|
||||
&metrics.TotalLog{},
|
||||
&metrics.TotalPicture{},
|
||||
&metrics.TotalFile{},
|
||||
&metrics.SystemInfo{},
|
||||
&metrics.TeamInfo{},
|
||||
}
|
||||
}
|
108
pkg/app/handler/admin/login/index.go
Normal file
108
pkg/app/handler/admin/login/index.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/dchest/captcha"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminlogin"
|
||||
"github.com/quarkcms/quark-go/pkg/hash"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
)
|
||||
|
||||
type Index struct {
|
||||
adminlogin.Template
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
Username string `json:"username" form:"username"`
|
||||
Password string `json:"password" form:"password"`
|
||||
CaptchaId string `json:"captchaId" form:"captchaId"`
|
||||
Captcha string `json:"captcha" form:"captcha"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Index) Init() interface{} {
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 登录页面Logo
|
||||
p.Logo = false
|
||||
|
||||
// 登录页面标题
|
||||
p.Title = "QuarkGo"
|
||||
|
||||
// 登录页面描述
|
||||
p.Description = "信息丰富的世界里,唯一稀缺的就是人类的注意力"
|
||||
|
||||
// 登录后跳转地址
|
||||
p.Redirect = "/index?api=/api/admin/dashboard/index/index"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 验证码ID
|
||||
func (p *Index) CaptchaId(request *builder.Request, resource *builder.Resource, templateInstance interface{}) interface{} {
|
||||
|
||||
return msg.Success("获取成功", "", map[string]string{
|
||||
"captchaId": captcha.NewLen(4),
|
||||
})
|
||||
}
|
||||
|
||||
// 生成验证码
|
||||
func (p *Index) Captcha(request *builder.Request, resource *builder.Resource, templateInstance interface{}) interface{} {
|
||||
id := request.Param("id")
|
||||
writer := bytes.Buffer{}
|
||||
captcha.WriteImage(&writer, id, 110, 38)
|
||||
|
||||
return writer.Bytes()
|
||||
}
|
||||
|
||||
// 登录方法
|
||||
func (p *Index) Handle(request *builder.Request, resource *builder.Resource, templateInstance interface{}) interface{} {
|
||||
loginRequest := &LoginRequest{}
|
||||
if err := request.BodyParser(loginRequest); err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
if loginRequest.CaptchaId == "" || loginRequest.Captcha == "" {
|
||||
return msg.Error("验证码不能为空", "")
|
||||
}
|
||||
|
||||
verifyResult := captcha.VerifyString(loginRequest.CaptchaId, loginRequest.Captcha)
|
||||
if !verifyResult {
|
||||
return msg.Error("验证码错误", "")
|
||||
}
|
||||
captcha.Reload(loginRequest.CaptchaId)
|
||||
|
||||
if loginRequest.Username == "" || loginRequest.Password == "" {
|
||||
return msg.Error("用户名或密码不能为空", "")
|
||||
}
|
||||
|
||||
adminInfo, err := (&model.Admin{}).GetInfoByUsername(loginRequest.Username)
|
||||
if err != nil {
|
||||
return msg.Error(err.Error(), "")
|
||||
}
|
||||
|
||||
// 检验账号和密码
|
||||
if !hash.Check(adminInfo.Password, loginRequest.Password) {
|
||||
return msg.Error("用户名或密码错误", "")
|
||||
}
|
||||
|
||||
config := builder.GetConfig()
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, (&model.Admin{}).GetClaims(adminInfo))
|
||||
|
||||
// 获取token字符串
|
||||
tokenString, err := token.SignedString([]byte(config.AppKey))
|
||||
|
||||
return msg.Success("获取成功", "", map[string]string{
|
||||
"token": tokenString,
|
||||
})
|
||||
}
|
||||
|
||||
// 退出方法
|
||||
func (p *Index) Logout(request *builder.Request, resource *builder.Resource, templateInstance interface{}) interface{} {
|
||||
|
||||
return msg.Success("退出成功", "", "")
|
||||
}
|
42
pkg/app/handler/admin/metrics/system_info.go
Normal file
42
pkg/app/handler/admin/metrics/system_info.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/builder/metrics"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/descriptions"
|
||||
"github.com/shirou/gopsutil/cpu"
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
)
|
||||
|
||||
type SystemInfo struct {
|
||||
metrics.AdminDescriptions
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *SystemInfo) Init() *SystemInfo {
|
||||
p.Title = "系统信息"
|
||||
p.Col = 12
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 计算数值
|
||||
func (p *SystemInfo) Calculate() *descriptions.Component {
|
||||
|
||||
field := &descriptions.Field{}
|
||||
memory, _ := mem.VirtualMemory()
|
||||
cpuPercent, _ := cpu.Percent(time.Second, false)
|
||||
|
||||
return p.Init().Result([]interface{}{
|
||||
field.Text("系统版本").SetValue("1.0.0"),
|
||||
field.Text("Fiber版本").SetValue("1.0.0"),
|
||||
field.Text("Golang版本").SetValue(runtime.Version()),
|
||||
field.Text("服务器操作系统").SetValue(runtime.GOOS + " " + runtime.GOARCH),
|
||||
field.Text("内存信息").SetValue(strconv.FormatUint(memory.Total/(1024*1024), 10) + "MB / " + fmt.Sprintf("%.0f", memory.UsedPercent) + "%"),
|
||||
field.Text("CPU使用率").SetValue(fmt.Sprintf("%.0f", cpuPercent[0]) + "%"),
|
||||
})
|
||||
}
|
33
pkg/app/handler/admin/metrics/team_info.go
Normal file
33
pkg/app/handler/admin/metrics/team_info.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder/metrics"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/descriptions"
|
||||
)
|
||||
|
||||
type TeamInfo struct {
|
||||
metrics.AdminDescriptions
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *TeamInfo) Init() *TeamInfo {
|
||||
p.Title = "团队信息"
|
||||
p.Col = 12
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 计算数值
|
||||
func (p *TeamInfo) Calculate() *descriptions.Component {
|
||||
|
||||
field := &descriptions.Field{}
|
||||
|
||||
return p.Init().Result([]interface{}{
|
||||
field.Text("作者").SetValue("tangtanglove"),
|
||||
field.Text("联系方式").SetValue("dai_hang_love@126.com"),
|
||||
field.Text("官方网址").SetValue("<a href='https://www.quarkcms.com' target='_blank'>www.quarkcms.com</a>"),
|
||||
field.Text("文档地址").SetValue("<a href='https://www.quarkcms.com' target='_blank'>查看文档</a>"),
|
||||
field.Text("BUG反馈").SetValue("<a href='https://github.com/quarkcms/quark-go/issues' target='_blank'>提交BUG</a>"),
|
||||
field.Text("代码仓储").SetValue("<a href='https://github.com/quarkcms/quark-go' target='_blank'>Github</a>"),
|
||||
})
|
||||
}
|
29
pkg/app/handler/admin/metrics/total_admin.go
Normal file
29
pkg/app/handler/admin/metrics/total_admin.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/metrics"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/statistic"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
type TotalAdmin struct {
|
||||
metrics.AdminValue
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *TotalAdmin) Init() *TotalAdmin {
|
||||
p.Title = "管理员数量"
|
||||
p.Col = 6
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 计算数值
|
||||
func (p *TotalAdmin) Calculate() *statistic.Component {
|
||||
|
||||
return p.
|
||||
Init().
|
||||
Count(db.Client.Model(&model.Admin{})).
|
||||
SetValueStyle(map[string]string{"color": "#3f8600"})
|
||||
}
|
31
pkg/app/handler/admin/metrics/total_file.go
Normal file
31
pkg/app/handler/admin/metrics/total_file.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/metrics"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/statistic"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
type TotalFile struct {
|
||||
metrics.AdminValue
|
||||
}
|
||||
|
||||
// 初始化
|
||||
|
||||
// 初始化
|
||||
func (p *TotalFile) Init() *TotalFile {
|
||||
p.Title = "文件数量"
|
||||
p.Col = 6
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 计算数值
|
||||
func (p *TotalFile) Calculate() *statistic.Component {
|
||||
|
||||
return p.
|
||||
Init().
|
||||
Count(db.Client.Model(&model.File{})).
|
||||
SetValueStyle(map[string]string{"color": "#cf1322"})
|
||||
}
|
29
pkg/app/handler/admin/metrics/total_log.go
Normal file
29
pkg/app/handler/admin/metrics/total_log.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/metrics"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/statistic"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
type TotalLog struct {
|
||||
metrics.AdminValue
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *TotalLog) Init() *TotalLog {
|
||||
p.Title = "日志数量"
|
||||
p.Col = 6
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 计算数值
|
||||
func (p *TotalLog) Calculate() *statistic.Component {
|
||||
|
||||
return p.
|
||||
Init().
|
||||
Count(db.Client.Model(&model.ActionLog{})).
|
||||
SetValueStyle(map[string]string{"color": "#999999"})
|
||||
}
|
29
pkg/app/handler/admin/metrics/total_picture.go
Normal file
29
pkg/app/handler/admin/metrics/total_picture.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/metrics"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/statistic"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
type TotalPicture struct {
|
||||
metrics.AdminValue
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *TotalPicture) Init() *TotalPicture {
|
||||
p.Title = "图片数量"
|
||||
p.Col = 6
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 计算数值
|
||||
func (p *TotalPicture) Calculate() *statistic.Component {
|
||||
|
||||
return p.
|
||||
Init().
|
||||
Count(db.Client.Model(&model.Picture{})).
|
||||
SetValueStyle(map[string]string{"color": "#cf1322"})
|
||||
}
|
23
pkg/app/handler/admin/providers.go
Normal file
23
pkg/app/handler/admin/providers.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/dashboards"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/login"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/resources"
|
||||
)
|
||||
|
||||
// 注册服务
|
||||
var Providers = []interface{}{
|
||||
&login.Index{},
|
||||
&dashboards.Index{},
|
||||
&resources.Admin{},
|
||||
&resources.Role{},
|
||||
&resources.Permission{},
|
||||
&resources.Menu{},
|
||||
&resources.ActionLog{},
|
||||
&resources.Config{},
|
||||
&resources.File{},
|
||||
&resources.Picture{},
|
||||
&resources.WebConfig{},
|
||||
&resources.Account{},
|
||||
}
|
148
pkg/app/handler/admin/resources/account.go
Normal file
148
pkg/app/handler/admin/resources/account.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Account) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "个人设置"
|
||||
|
||||
// 模型
|
||||
p.Model = &model.Admin{}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 表单接口
|
||||
func (p *Account) FormApi(request *builder.Request) string {
|
||||
|
||||
return "admin/account/action/change-account"
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *Account) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
|
||||
return []interface{}{
|
||||
|
||||
field.Image("avatar", "头像").OnlyOnForms(),
|
||||
|
||||
field.Text("nickname", "昵称").
|
||||
SetEditable(true).
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "昵称必须填写",
|
||||
},
|
||||
),
|
||||
|
||||
field.Text("email", "邮箱").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "邮箱必须填写",
|
||||
},
|
||||
).
|
||||
SetCreationRules(
|
||||
[]string{
|
||||
"unique:admins,email",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "邮箱已存在",
|
||||
},
|
||||
).
|
||||
SetUpdateRules(
|
||||
[]string{
|
||||
"unique:admins,email,{id}",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "邮箱已存在",
|
||||
},
|
||||
),
|
||||
|
||||
field.Text("phone", "手机号").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "手机号必须填写",
|
||||
},
|
||||
).
|
||||
SetCreationRules(
|
||||
[]string{
|
||||
"unique:admins,phone",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "手机号已存在",
|
||||
},
|
||||
).
|
||||
SetUpdateRules(
|
||||
[]string{
|
||||
"unique:admins,phone,{id}",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "手机号已存在",
|
||||
},
|
||||
),
|
||||
|
||||
field.Radio("sex", "性别").
|
||||
SetOptions(map[interface{}]interface{}{
|
||||
1: "男",
|
||||
2: "女",
|
||||
}).SetDefault(1),
|
||||
|
||||
field.Password("password", "密码").
|
||||
SetCreationRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "密码必须填写",
|
||||
},
|
||||
).OnlyOnForms(),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *Account) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.ChangeAccount{}),
|
||||
(&actions.FormSubmit{}).Init(),
|
||||
(&actions.FormReset{}).Init(),
|
||||
(&actions.FormBack{}).Init(),
|
||||
(&actions.FormExtraBack{}).Init(),
|
||||
}
|
||||
}
|
||||
|
||||
// 创建页面显示前回调
|
||||
func (p *Account) BeforeCreating(request *builder.Request) map[string]interface{} {
|
||||
data := map[string]interface{}{}
|
||||
adminInfo, _ := (&model.Admin{}).GetAuthUser(request.Token())
|
||||
db.Client.
|
||||
Model(p.Model).
|
||||
Where("id = ?", adminInfo.Id).
|
||||
First(&data)
|
||||
|
||||
delete(data, "password")
|
||||
|
||||
return data
|
||||
}
|
84
pkg/app/handler/admin/resources/action_log.go
Normal file
84
pkg/app/handler/admin/resources/action_log.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/searches"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/table"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ActionLog struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *ActionLog) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "操作日志"
|
||||
|
||||
// 模型
|
||||
p.Model = &model.ActionLog{}
|
||||
|
||||
// 分页
|
||||
p.PerPage = 10
|
||||
|
||||
p.WithExport = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 列表查询
|
||||
func (p *ActionLog) Query(request *builder.Request, query *gorm.DB) *gorm.DB {
|
||||
|
||||
return query.
|
||||
Select("action_logs.*,admins.username").
|
||||
Joins("left join admins on admins.id = action_logs.object_id").
|
||||
Where("type = ?", "admin")
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *ActionLog) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
|
||||
return []interface{}{
|
||||
field.ID("id", "ID"),
|
||||
field.Text("username", "用户"),
|
||||
field.Text("url", "行为").
|
||||
SetColumn(func(column *table.Column) *table.Column {
|
||||
return column.SetEllipsis(true)
|
||||
}),
|
||||
field.Text("ip", "IP"),
|
||||
field.Datetime("created_at", "发生时间", func() interface{} {
|
||||
if p.Field["created_at"] == nil {
|
||||
return p.Field["created_at"]
|
||||
}
|
||||
|
||||
return p.Field["created_at"].(time.Time).Format("2006-01-02 15:04:05")
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *ActionLog) Searches(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&searches.Input{}).Init("url", "行为"),
|
||||
(&searches.Input{}).Init("ip", "IP"),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *ActionLog) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.Delete{}).Init("批量删除"),
|
||||
(&actions.Delete{}).Init("删除"),
|
||||
}
|
||||
}
|
312
pkg/app/handler/admin/resources/admin.go
Normal file
312
pkg/app/handler/admin/resources/admin.go
Normal file
@@ -0,0 +1,312 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/searches"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
models "github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/table"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"github.com/quarkcms/quark-go/pkg/hash"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Admin struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Admin) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "管理员"
|
||||
|
||||
// 模型
|
||||
p.Model = &model.Admin{}
|
||||
|
||||
// 分页
|
||||
p.PerPage = 10
|
||||
|
||||
p.WithExport = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *Admin) Fields(request *builder.Request) []interface{} {
|
||||
|
||||
field := &builder.AdminField{}
|
||||
|
||||
// 角色列表
|
||||
roles, _ := (&model.Role{}).List()
|
||||
|
||||
return []interface{}{
|
||||
field.ID("id", "ID"),
|
||||
|
||||
field.Image("avatar", "头像").OnlyOnForms(),
|
||||
|
||||
field.Text("username", "用户名", func() interface{} {
|
||||
|
||||
return "<a href='#/index?api=/api/admin/admin/edit&id=" + strconv.Itoa(p.Field["id"].(int)) + "'>" + p.Field["username"].(string) + "</a>"
|
||||
}).
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
"min:6",
|
||||
"max:20",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "用户名必须填写",
|
||||
"min": "用户名不能少于6个字符",
|
||||
"max": "用户名不能超过20个字符",
|
||||
},
|
||||
).
|
||||
SetCreationRules(
|
||||
[]string{
|
||||
"unique:admins,username",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "用户名已存在",
|
||||
},
|
||||
).
|
||||
SetUpdateRules(
|
||||
[]string{
|
||||
"unique:admins,username,{id}",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "用户名已存在",
|
||||
},
|
||||
),
|
||||
|
||||
field.Checkbox("role_ids", "角色").
|
||||
SetOptions(roles).
|
||||
OnlyOnForms(),
|
||||
|
||||
field.Text("nickname", "昵称").
|
||||
SetEditable(true).
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "昵称必须填写",
|
||||
},
|
||||
),
|
||||
|
||||
field.Text("email", "邮箱").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "邮箱必须填写",
|
||||
},
|
||||
).
|
||||
SetCreationRules(
|
||||
[]string{
|
||||
"unique:admins,email",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "邮箱已存在",
|
||||
},
|
||||
).
|
||||
SetUpdateRules(
|
||||
[]string{
|
||||
"unique:admins,email,{id}",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "邮箱已存在",
|
||||
},
|
||||
),
|
||||
|
||||
field.Text("phone", "手机号").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "手机号必须填写",
|
||||
},
|
||||
).
|
||||
SetCreationRules(
|
||||
[]string{
|
||||
"unique:admins,phone",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "手机号已存在",
|
||||
},
|
||||
).
|
||||
SetUpdateRules(
|
||||
[]string{
|
||||
"unique:admins,phone,{id}",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "手机号已存在",
|
||||
},
|
||||
),
|
||||
|
||||
field.Radio("sex", "性别").
|
||||
SetOptions(map[interface{}]interface{}{
|
||||
1: "男",
|
||||
2: "女",
|
||||
}).SetDefault(1).
|
||||
SetColumn(func(column *table.Column) *table.Column {
|
||||
return column.SetFilters(true)
|
||||
}),
|
||||
|
||||
field.Password("password", "密码").
|
||||
SetCreationRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "密码必须填写",
|
||||
},
|
||||
).OnlyOnForms(),
|
||||
|
||||
field.Datetime("last_login_time", "最后登录时间", func() interface{} {
|
||||
if p.Field["last_login_time"] == nil {
|
||||
return p.Field["last_login_time"]
|
||||
}
|
||||
|
||||
return p.Field["last_login_time"].(time.Time).Format("2006-01-02 15:04:05")
|
||||
}).OnlyOnIndex(),
|
||||
|
||||
field.Switch("status", "状态").
|
||||
SetTrueValue("正常").
|
||||
SetFalseValue("禁用").
|
||||
SetEditable(true).
|
||||
SetDefault(true),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *Admin) Searches(request *builder.Request) []interface{} {
|
||||
|
||||
return []interface{}{
|
||||
(&searches.Input{}).Init("username", "用户名"),
|
||||
(&searches.Input{}).Init("nickname", "昵称"),
|
||||
(&searches.Status{}).Init(),
|
||||
(&searches.DateTimeRange{}).Init("last_login_time", "登录时间"),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *Admin) Actions(request *builder.Request) []interface{} {
|
||||
|
||||
return []interface{}{
|
||||
(&actions.Import{}).Init(),
|
||||
(&actions.CreateLink{}).Init(p.Title),
|
||||
(&actions.Delete{}).Init("批量删除"),
|
||||
(&actions.Disable{}).Init("批量禁用"),
|
||||
(&actions.Enable{}).Init("批量启用"),
|
||||
(&actions.DetailLink{}).Init("详情"),
|
||||
(&actions.MoreActions{}).Init("更多").SetActions([]interface{}{
|
||||
(&actions.EditLink{}).Init("编辑"),
|
||||
(&actions.Delete{}).Init("删除"),
|
||||
}),
|
||||
(&actions.FormSubmit{}).Init(),
|
||||
(&actions.FormReset{}).Init(),
|
||||
(&actions.FormBack{}).Init(),
|
||||
(&actions.FormExtraBack{}).Init(),
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑页面显示前回调
|
||||
func (p *Admin) BeforeEditing(request *builder.Request, data map[string]interface{}) map[string]interface{} {
|
||||
delete(data, "password")
|
||||
|
||||
roleIds := []int{}
|
||||
db.Client.
|
||||
Model(&model.ModelHasRole{}).
|
||||
Where("model_id = ?", data["id"]).
|
||||
Where("model_type = ?", "admin").
|
||||
Pluck("role_id", &roleIds)
|
||||
|
||||
data["role_ids"] = roleIds
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// 保存数据前回调
|
||||
func (p *Admin) BeforeSaving(request *builder.Request, submitData map[string]interface{}) (map[string]interface{}, error) {
|
||||
|
||||
// 加密密码
|
||||
if submitData["password"] != nil {
|
||||
submitData["password"] = hash.Make(submitData["password"].(string))
|
||||
}
|
||||
|
||||
// 暂时清理role_ids
|
||||
delete(submitData, "role_ids")
|
||||
|
||||
return submitData, nil
|
||||
}
|
||||
|
||||
// 保存后回调
|
||||
func (p *Admin) AfterSaved(request *builder.Request, model *gorm.DB) interface{} {
|
||||
data := map[string]interface{}{}
|
||||
json.Unmarshal(request.Body(), &data)
|
||||
if data["role_ids"] == nil {
|
||||
if model.Error != nil {
|
||||
return msg.Error(model.Error.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功!", strings.Replace("/index?api="+adminresource.IndexRoute, ":resource", request.Param("resource"), -1), "")
|
||||
}
|
||||
|
||||
var result *gorm.DB
|
||||
if request.IsCreating() {
|
||||
last := map[string]interface{}{}
|
||||
model.Order("id desc").First(&last) // hack
|
||||
roleData := []map[string]interface{}{}
|
||||
for _, v := range data["role_ids"].([]interface{}) {
|
||||
item := map[string]interface{}{
|
||||
"role_id": v,
|
||||
"model_type": "admin",
|
||||
"model_id": last["id"],
|
||||
}
|
||||
roleData = append(roleData, item)
|
||||
}
|
||||
if len(roleData) > 0 {
|
||||
// 同步角色
|
||||
result = db.Client.Model(&models.ModelHasRole{}).Create(roleData)
|
||||
}
|
||||
} else {
|
||||
|
||||
// 同步角色
|
||||
id := data["id"].(float64)
|
||||
roleData := []map[string]interface{}{}
|
||||
|
||||
// 先清空用户对应的角色
|
||||
db.Client.Model(&models.ModelHasRole{}).Where("model_id = ?", id).Where("model_type = ?", "admin").Delete("")
|
||||
for _, v := range data["role_ids"].([]interface{}) {
|
||||
item := map[string]interface{}{
|
||||
"role_id": v,
|
||||
"model_type": "admin",
|
||||
"model_id": int(id),
|
||||
}
|
||||
roleData = append(roleData, item)
|
||||
}
|
||||
if len(roleData) > 0 {
|
||||
// 同步角色
|
||||
result = db.Client.Model(&models.ModelHasRole{}).Create(roleData)
|
||||
}
|
||||
}
|
||||
|
||||
if result.Error != nil {
|
||||
return msg.Error(result.Error.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功!", strings.Replace("/index?api="+adminresource.IndexRoute, ":resource", request.Param("resource"), -1), "")
|
||||
}
|
139
pkg/app/handler/admin/resources/config.go
Normal file
139
pkg/app/handler/admin/resources/config.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/searches"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Config) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "配置"
|
||||
|
||||
// 模型
|
||||
p.Model = &model.Config{}
|
||||
|
||||
// 分页
|
||||
p.PerPage = 10
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *Config) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
|
||||
return []interface{}{
|
||||
field.ID("id", "ID"),
|
||||
|
||||
field.Text("title", "标题").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "标题必须填写",
|
||||
},
|
||||
),
|
||||
|
||||
field.Text("name", "名称").
|
||||
SetEditable(true).
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "名称必须填写",
|
||||
},
|
||||
).
|
||||
SetCreationRules(
|
||||
[]string{
|
||||
"unique:configs,name",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "名称已存在",
|
||||
},
|
||||
).
|
||||
SetUpdateRules(
|
||||
[]string{
|
||||
"unique:configs,name,{id}",
|
||||
},
|
||||
map[string]string{
|
||||
"unique": "名称已存在",
|
||||
},
|
||||
),
|
||||
|
||||
field.Radio("type", "表单类型").
|
||||
SetOptions(map[interface{}]interface{}{
|
||||
"text": "输入框",
|
||||
"textarea": "文本域",
|
||||
"picture": "图片",
|
||||
"file": "文件",
|
||||
"switch": "开关",
|
||||
}).
|
||||
SetDefault("text").
|
||||
OnlyOnForms(),
|
||||
|
||||
field.Text("sort", "排序").
|
||||
SetEditable(true).
|
||||
SetDefault(0).
|
||||
SetHelp("值越小越靠前").
|
||||
OnlyOnForms(),
|
||||
|
||||
field.Text("group_name", "分组名称").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "分组名称必须填写",
|
||||
},
|
||||
).OnlyOnForms(),
|
||||
|
||||
field.Text("remark", "备注").
|
||||
OnlyOnForms(),
|
||||
|
||||
field.Switch("status", "状态").
|
||||
SetTrueValue("正常").
|
||||
SetFalseValue("禁用").
|
||||
SetEditable(true).
|
||||
SetDefault(true),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *Config) Searches(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&searches.Input{}).Init("title", "标题"),
|
||||
(&searches.Input{}).Init("name", "名称"),
|
||||
(&searches.Status{}).Init(),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *Config) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.CreateDrawer{}).Init(p.Title),
|
||||
(&actions.Delete{}).Init("批量删除"),
|
||||
(&actions.Disable{}).Init("批量禁用"),
|
||||
(&actions.Enable{}).Init("批量启用"),
|
||||
(&actions.ChangeStatus{}).Init(),
|
||||
(&actions.EditDrawer{}).Init("编辑"),
|
||||
(&actions.Delete{}).Init("删除"),
|
||||
(&actions.FormSubmit{}).Init(),
|
||||
(&actions.FormReset{}).Init(),
|
||||
(&actions.FormBack{}).Init(),
|
||||
(&actions.FormExtraBack{}).Init(),
|
||||
}
|
||||
}
|
72
pkg/app/handler/admin/resources/file.go
Normal file
72
pkg/app/handler/admin/resources/file.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/searches"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/table"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *File) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "文件"
|
||||
|
||||
// 模型
|
||||
p.Model = &model.File{}
|
||||
|
||||
// 分页
|
||||
p.PerPage = 10
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *File) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
|
||||
return []interface{}{
|
||||
field.ID("id", "ID"),
|
||||
field.Text("name", "名称"),
|
||||
field.Text("size", "大小").
|
||||
SetColumn(func(column *table.Column) *table.Column {
|
||||
return column.SetSorter(true)
|
||||
}),
|
||||
field.Text("ext", "扩展名"),
|
||||
field.Datetime("created_at", "上传时间", func() interface{} {
|
||||
if p.Field["created_at"] == nil {
|
||||
return p.Field["created_at"]
|
||||
}
|
||||
|
||||
return p.Field["created_at"].(time.Time).Format("2006-01-02 15:04:05")
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *File) Searches(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&searches.Input{}).Init("name", "名称"),
|
||||
(&searches.DateTimeRange{}).Init("created_at", "上传时间"),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *File) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.Delete{}).Init("批量删除"),
|
||||
(&actions.Delete{}).Init("删除"),
|
||||
}
|
||||
}
|
207
pkg/app/handler/admin/resources/menu.go
Normal file
207
pkg/app/handler/admin/resources/menu.go
Normal file
@@ -0,0 +1,207 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/searches"
|
||||
models "github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"github.com/quarkcms/quark-go/pkg/lister"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Menu struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Menu) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "菜单"
|
||||
|
||||
// 模型
|
||||
p.Model = &models.Menu{}
|
||||
|
||||
// 分页
|
||||
p.PerPage = false
|
||||
|
||||
// 默认排序
|
||||
p.IndexOrder = "sort asc"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *Menu) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
|
||||
// 权限列表
|
||||
permissions, _ := (&models.Permission{}).List()
|
||||
|
||||
// 菜单列表
|
||||
menus, _ := (&models.Menu{}).OrderedList()
|
||||
|
||||
return []interface{}{
|
||||
field.Hidden("id", "ID"), // 列表读取且不展示的字段
|
||||
|
||||
field.Hidden("pid", "PID").OnlyOnIndex(), // 列表读取且不展示的字段
|
||||
|
||||
field.Text("name", "名称").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "名称必须填写",
|
||||
},
|
||||
),
|
||||
|
||||
field.Text("guard_name", "GuardName").
|
||||
SetDefault("admin").
|
||||
OnlyOnForms(),
|
||||
|
||||
field.Icon("icon", "图标").OnlyOnForms(),
|
||||
|
||||
field.Radio("type", "渲染组件").
|
||||
SetOptions(map[interface{}]interface{}{
|
||||
"default": "无组件",
|
||||
"engine": "引擎组件",
|
||||
}).SetDefault("engine"),
|
||||
|
||||
field.Text("path", "路由").
|
||||
SetEditable(true).
|
||||
SetHelp("前端路由或后端api"),
|
||||
|
||||
field.Select("pid", "父节点").
|
||||
SetOptions(menus).
|
||||
SetDefault(0).
|
||||
OnlyOnForms(),
|
||||
|
||||
field.Number("sort", "排序").
|
||||
SetEditable(true).
|
||||
SetDefault(0),
|
||||
|
||||
field.Select("permission_ids", "绑定权限").
|
||||
SetMode("tags").
|
||||
SetOptions(permissions).
|
||||
OnlyOnForms(),
|
||||
|
||||
field.Switch("status", "状态").
|
||||
SetTrueValue("正常").
|
||||
SetFalseValue("禁用").
|
||||
SetEditable(true).
|
||||
SetDefault(true),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *Menu) Searches(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&searches.Input{}).Init("name", "名称"),
|
||||
(&searches.Input{}).Init("path", "路由"),
|
||||
(&searches.Status{}).Init(),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *Menu) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.CreateDrawer{}).Init(p.Title),
|
||||
(&actions.Delete{}).Init("批量删除"),
|
||||
(&actions.Disable{}).Init("批量禁用"),
|
||||
(&actions.Enable{}).Init("批量启用"),
|
||||
(&actions.ChangeStatus{}).Init(),
|
||||
(&actions.EditDrawer{}).Init("编辑"),
|
||||
(&actions.Delete{}).Init("删除"),
|
||||
(&actions.FormSubmit{}).Init(),
|
||||
(&actions.FormReset{}).Init(),
|
||||
(&actions.FormBack{}).Init(),
|
||||
(&actions.FormExtraBack{}).Init(),
|
||||
}
|
||||
}
|
||||
|
||||
// 列表页面显示前回调
|
||||
func (p *Menu) BeforeIndexShowing(request *builder.Request, list []map[string]interface{}) []interface{} {
|
||||
data := request.AllQuerys()
|
||||
if search, ok := data["search"].(map[string]interface{}); ok == true && search != nil {
|
||||
result := []interface{}{}
|
||||
for _, v := range list {
|
||||
result = append(result, v)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 转换成树形表格
|
||||
tree, _ := lister.ListToTree(list, "id", "pid", "children", 0)
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
// 编辑页面显示前回调
|
||||
func (p *Menu) BeforeEditing(request *builder.Request, data map[string]interface{}) map[string]interface{} {
|
||||
id := request.Query("id", "")
|
||||
|
||||
if id != "" {
|
||||
menus := []int{}
|
||||
|
||||
db.Client.
|
||||
Model(&models.Permission{}).
|
||||
Where("menu_id = ?", id).
|
||||
Pluck("id", &menus)
|
||||
|
||||
data["permission_ids"] = menus
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// 保存数据前回调
|
||||
func (p *Menu) BeforeSaving(request *builder.Request, submitData map[string]interface{}) interface{} {
|
||||
|
||||
// 暂时清理permission_ids
|
||||
delete(submitData, "permission_ids")
|
||||
|
||||
return submitData
|
||||
}
|
||||
|
||||
// 保存后回调
|
||||
func (p *Menu) AfterSaved(request *builder.Request, model *gorm.DB) interface{} {
|
||||
var result *gorm.DB
|
||||
data := map[string]interface{}{}
|
||||
json.Unmarshal(request.Body(), &data)
|
||||
id := 0
|
||||
if request.IsCreating() {
|
||||
last := map[string]interface{}{}
|
||||
result = model.Order("id desc").First(&last) // 获取最后一条记录的id
|
||||
id = last["id"].(int)
|
||||
} else {
|
||||
id = int(data["id"].(float64))
|
||||
result = db.Client.
|
||||
Model(&models.Permission{}).
|
||||
Where("menu_id = ?", id).
|
||||
Update("menu_id", 0)
|
||||
}
|
||||
|
||||
if data["permission_ids"] != nil {
|
||||
result = db.Client.
|
||||
Model(&models.Permission{}).
|
||||
Where("id In ?", data["permission_ids"]).
|
||||
Update("menu_id", id)
|
||||
}
|
||||
|
||||
if result.Error != nil {
|
||||
return msg.Error(result.Error.Error(), "")
|
||||
}
|
||||
|
||||
return msg.Success("操作成功!", strings.Replace("/index?api="+adminresource.IndexRoute, ":resource", request.Param("resource"), -1), "")
|
||||
}
|
90
pkg/app/handler/admin/resources/permission.go
Normal file
90
pkg/app/handler/admin/resources/permission.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/searches"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
)
|
||||
|
||||
type Permission struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Permission) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "权限"
|
||||
|
||||
// 模型
|
||||
p.Model = &model.Permission{}
|
||||
|
||||
// 分页
|
||||
p.PerPage = 10
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *Permission) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
|
||||
return []interface{}{
|
||||
field.ID("id", "ID"),
|
||||
|
||||
field.Text("name", "名称").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "名称必须填写",
|
||||
},
|
||||
),
|
||||
|
||||
field.Text("guard_name", "GuardName").SetDefault("admin"),
|
||||
field.Datetime("created_at", "创建时间", func() interface{} {
|
||||
if p.Field["created_at"] == nil {
|
||||
return p.Field["created_at"]
|
||||
}
|
||||
|
||||
return p.Field["created_at"].(time.Time).Format("2006-01-02 15:04:05")
|
||||
}).OnlyOnIndex(),
|
||||
field.Datetime("updated_at", "更新时间", func() interface{} {
|
||||
if p.Field["updated_at"] == nil {
|
||||
return p.Field["updated_at"]
|
||||
}
|
||||
|
||||
return p.Field["updated_at"].(time.Time).Format("2006-01-02 15:04:05")
|
||||
}).OnlyOnIndex(),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *Permission) Searches(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&searches.Input{}).Init("name", "名称"),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *Permission) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.SyncPermission{}).Init(),
|
||||
(&actions.CreateModal{}).Init(p.Title),
|
||||
(&actions.Delete{}).Init("批量删除"),
|
||||
(&actions.EditModal{}).Init("编辑"),
|
||||
(&actions.Delete{}).Init("删除"),
|
||||
(&actions.FormSubmit{}).Init(),
|
||||
(&actions.FormReset{}).Init(),
|
||||
(&actions.FormBack{}).Init(),
|
||||
(&actions.FormExtraBack{}).Init(),
|
||||
}
|
||||
}
|
80
pkg/app/handler/admin/resources/picture.go
Normal file
80
pkg/app/handler/admin/resources/picture.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/searches"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/table"
|
||||
)
|
||||
|
||||
type Picture struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Picture) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "图片"
|
||||
|
||||
// 模型
|
||||
p.Model = &model.Picture{}
|
||||
|
||||
// 分页
|
||||
p.PerPage = 10
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *Picture) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
|
||||
return []interface{}{
|
||||
field.ID("id", "ID"),
|
||||
field.Text("path", "显示", func() interface{} {
|
||||
|
||||
return "<img src='" + (&model.Picture{}).GetPath(p.Field["id"]) + "' width=50 height=50 />"
|
||||
}),
|
||||
field.Text("name", "名称").SetColumn(func(column *table.Column) *table.Column {
|
||||
return column.SetEllipsis(true)
|
||||
}),
|
||||
field.Text("size", "大小").
|
||||
SetColumn(func(column *table.Column) *table.Column {
|
||||
return column.SetSorter(true)
|
||||
}),
|
||||
field.Text("width", "宽度"),
|
||||
field.Text("height", "高度"),
|
||||
field.Text("ext", "扩展名"),
|
||||
field.Datetime("created_at", "上传时间", func() interface{} {
|
||||
if p.Field["created_at"] == nil {
|
||||
return p.Field["created_at"]
|
||||
}
|
||||
|
||||
return p.Field["created_at"].(time.Time).Format("2006-01-02 15:04:05")
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *Picture) Searches(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&searches.Input{}).Init("name", "名称"),
|
||||
(&searches.DateTimeRange{}).Init("created_at", "上传时间"),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *Picture) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.Delete{}).Init("批量删除"),
|
||||
(&actions.Delete{}).Init("删除"),
|
||||
}
|
||||
}
|
222
pkg/app/handler/admin/resources/role.go
Normal file
222
pkg/app/handler/admin/resources/role.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/searches"
|
||||
models "github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Role struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Role) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "角色"
|
||||
|
||||
// 模型
|
||||
p.Model = &models.Role{}
|
||||
|
||||
// 分页
|
||||
p.PerPage = 10
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *Role) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
treeData, _ := (&models.Menu{}).Tree()
|
||||
|
||||
return []interface{}{
|
||||
field.ID("id", "ID"),
|
||||
|
||||
field.Text("name", "名称").
|
||||
SetRules(
|
||||
[]string{
|
||||
"required",
|
||||
},
|
||||
map[string]string{
|
||||
"required": "名称必须填写",
|
||||
},
|
||||
),
|
||||
|
||||
field.Text("guard_name", "GuardName").SetDefault("admin"),
|
||||
field.Tree("menu_ids", "权限").SetData(treeData).OnlyOnForms(),
|
||||
field.Datetime("created_at", "创建时间", func() interface{} {
|
||||
if p.Field["created_at"] == nil {
|
||||
return p.Field["created_at"]
|
||||
}
|
||||
|
||||
return p.Field["created_at"].(time.Time).Format("2006-01-02 15:04:05")
|
||||
}).OnlyOnIndex(),
|
||||
field.Datetime("updated_at", "更新时间", func() interface{} {
|
||||
if p.Field["updated_at"] == nil {
|
||||
return p.Field["updated_at"]
|
||||
}
|
||||
|
||||
return p.Field["updated_at"].(time.Time).Format("2006-01-02 15:04:05")
|
||||
}).OnlyOnIndex(),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
func (p *Role) Searches(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&searches.Input{}).Init("name", "名称"),
|
||||
}
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *Role) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.CreateLink{}).Init(p.Title),
|
||||
(&actions.Delete{}).Init("批量删除"),
|
||||
(&actions.EditLink{}).Init("编辑"),
|
||||
(&actions.Delete{}).Init("删除"),
|
||||
(&actions.FormSubmit{}).Init(),
|
||||
(&actions.FormReset{}).Init(),
|
||||
(&actions.FormBack{}).Init(),
|
||||
(&actions.FormExtraBack{}).Init(),
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑页面显示前回调
|
||||
func (p *Role) BeforeEditing(request *builder.Request, data map[string]interface{}) map[string]interface{} {
|
||||
id := request.Query("id", "")
|
||||
menus := []map[string]interface{}{}
|
||||
|
||||
db.Client.Model(&models.Menu{}).Find(&menus)
|
||||
|
||||
checkedMenus := []int{}
|
||||
for _, v := range menus {
|
||||
var permissionIds []int
|
||||
db.Client.
|
||||
Model(&models.Permission{}).
|
||||
Where("menu_id", v["id"]).
|
||||
Pluck("id", &permissionIds)
|
||||
|
||||
if len(permissionIds) > 0 {
|
||||
roleHasPermission := map[string]interface{}{}
|
||||
db.Client.
|
||||
Model(&models.RoleHasPermission{}).
|
||||
Where("permission_id IN ?", permissionIds).
|
||||
Where("role_id", id).
|
||||
First(&roleHasPermission)
|
||||
|
||||
if len(roleHasPermission) > 0 {
|
||||
checkedMenus = append(checkedMenus, v["id"].(int))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data["menu_ids"] = checkedMenus
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
// 保存数据前回调
|
||||
func (p *Role) BeforeSaving(request *builder.Request, submitData map[string]interface{}) interface{} {
|
||||
|
||||
// 根据菜单id获取所有权限
|
||||
var permissionIds []int
|
||||
db.Client.
|
||||
Model(&models.Permission{}).
|
||||
Where("menu_id IN ?", submitData["menu_ids"]).
|
||||
Pluck("id", &permissionIds)
|
||||
|
||||
if len(permissionIds) == 0 {
|
||||
return errors.New("获取的权限为空,请在菜单管理中绑定权限")
|
||||
}
|
||||
|
||||
delete(submitData, "menu_ids")
|
||||
|
||||
return submitData
|
||||
}
|
||||
|
||||
// 保存后回调
|
||||
func (p *Role) AfterSaved(request *builder.Request, model *gorm.DB) interface{} {
|
||||
data := map[string]interface{}{}
|
||||
json.Unmarshal(request.Body(), &data)
|
||||
|
||||
// 根据菜单id获取所有权限
|
||||
var permissionIds []int
|
||||
db.Client.
|
||||
Model(&models.Permission{}).
|
||||
Where("menu_id IN ?", data["menu_ids"]).
|
||||
Pluck("id", &permissionIds)
|
||||
|
||||
if len(permissionIds) == 0 {
|
||||
return errors.New("获取的权限为空,请先在菜单管理中绑定权限")
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
|
||||
if request.IsCreating() {
|
||||
lastRole := map[string]interface{}{}
|
||||
model.Order("id desc").First(&lastRole) // hack
|
||||
|
||||
// 同步权限
|
||||
result = p.syncPermissions(lastRole["id"].(int), permissionIds)
|
||||
} else {
|
||||
|
||||
// 同步权限
|
||||
id := data["id"].(float64)
|
||||
result = p.syncPermissions(int(id), permissionIds)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 保存后回调
|
||||
func (p *Role) syncPermissions(roleId int, permissionIds []int) *gorm.DB {
|
||||
permissionIds = p.arrayFilter(permissionIds)
|
||||
|
||||
// 先清空此角色的权限
|
||||
db.Client.Model(&models.RoleHasPermission{}).Where("role_id", roleId).Delete("")
|
||||
|
||||
data := []map[string]interface{}{}
|
||||
for _, v := range permissionIds {
|
||||
permission := map[string]interface{}{
|
||||
"role_id": roleId,
|
||||
"permission_id": v,
|
||||
}
|
||||
data = append(data, permission)
|
||||
}
|
||||
|
||||
return db.Client.Model(&models.RoleHasPermission{}).Create(data)
|
||||
}
|
||||
|
||||
// 数组去重
|
||||
func (p *Role) arrayFilter(list []int) []int {
|
||||
var x []int = []int{}
|
||||
for _, i := range list {
|
||||
if len(x) == 0 {
|
||||
x = append(x, i)
|
||||
} else {
|
||||
for k, v := range x {
|
||||
if i == v {
|
||||
break
|
||||
}
|
||||
if k == len(x)-1 {
|
||||
x = append(x, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return x
|
||||
}
|
171
pkg/app/handler/admin/resources/web_config.go
Normal file
171
pkg/app/handler/admin/resources/web_config.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/actions"
|
||||
models "github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template/adminresource"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/tabs"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
type WebConfig struct {
|
||||
adminresource.Template
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *WebConfig) Init() interface{} {
|
||||
|
||||
// 初始化模板
|
||||
p.TemplateInit()
|
||||
|
||||
// 标题
|
||||
p.Title = "网站配置"
|
||||
|
||||
// 模型
|
||||
p.Model = &models.Config{}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 表单接口
|
||||
func (p *WebConfig) FormApi(request *builder.Request) string {
|
||||
|
||||
return "admin/webConfig/action/change-web-config"
|
||||
}
|
||||
|
||||
// 字段
|
||||
func (p *WebConfig) Fields(request *builder.Request) []interface{} {
|
||||
field := &builder.AdminField{}
|
||||
groupNames := []string{}
|
||||
|
||||
db.Client.Model(p.Model).Where("status = ?", 1).Distinct("group_name").Pluck("group_name", &groupNames)
|
||||
|
||||
tabPanes := []interface{}{}
|
||||
for _, groupName := range groupNames {
|
||||
configs := []map[string]interface{}{}
|
||||
db.Client.
|
||||
Model(p.Model).
|
||||
Where("status = ?", 1).
|
||||
Where("group_name = ?", groupName).
|
||||
Order("sort asc").
|
||||
Find(&configs)
|
||||
|
||||
fields := []interface{}{}
|
||||
|
||||
for _, config := range configs {
|
||||
|
||||
remark, ok := config["remark"].(string)
|
||||
|
||||
if ok == false {
|
||||
remark = ""
|
||||
}
|
||||
|
||||
switch config["type"] {
|
||||
case "text":
|
||||
getField := field.
|
||||
Text(config["name"], config["title"]).SetExtra(remark)
|
||||
|
||||
fields = append(fields, getField)
|
||||
|
||||
case "textarea":
|
||||
getField := field.
|
||||
TextArea(config["name"], config["title"]).SetExtra(remark)
|
||||
|
||||
fields = append(fields, getField)
|
||||
|
||||
case "file":
|
||||
getField := field.
|
||||
File(config["name"], config["title"]).
|
||||
SetButton("上传" + config["title"].(string)).
|
||||
SetExtra(remark)
|
||||
|
||||
fields = append(fields, getField)
|
||||
|
||||
case "picture":
|
||||
getField := field.
|
||||
Image(config["name"], config["title"]).
|
||||
SetButton("上传" + config["title"].(string)).
|
||||
SetExtra(remark)
|
||||
|
||||
fields = append(fields, getField)
|
||||
|
||||
case "switch":
|
||||
getField := field.
|
||||
Switch(config["name"].(string), config["title"].(string)).
|
||||
SetTrueValue("正常").
|
||||
SetFalseValue("禁用").
|
||||
SetExtra(remark)
|
||||
|
||||
fields = append(fields, getField)
|
||||
}
|
||||
}
|
||||
|
||||
tabPane := (&tabs.TabPane{}).
|
||||
Init().
|
||||
SetTitle(groupName).
|
||||
SetBody(fields)
|
||||
|
||||
tabPanes = append(tabPanes, tabPane)
|
||||
}
|
||||
|
||||
return tabPanes
|
||||
}
|
||||
|
||||
// 行为
|
||||
func (p *WebConfig) Actions(request *builder.Request) []interface{} {
|
||||
return []interface{}{
|
||||
(&actions.ChangeWebConfig{}),
|
||||
(&actions.FormSubmit{}).Init(),
|
||||
(&actions.FormReset{}).Init(),
|
||||
(&actions.FormBack{}).Init(),
|
||||
(&actions.FormExtraBack{}).Init(),
|
||||
}
|
||||
}
|
||||
|
||||
// 创建页面显示前回调
|
||||
func (p *WebConfig) BeforeCreating(request *builder.Request) map[string]interface{} {
|
||||
configs := []map[string]interface{}{}
|
||||
data := map[string]interface{}{}
|
||||
|
||||
db.Client.
|
||||
Model(p.Model).
|
||||
Where("status = ?", 1).
|
||||
Find(&configs)
|
||||
|
||||
for _, config := range configs {
|
||||
data[config["name"].(string)] = config["value"]
|
||||
|
||||
if config["type"] == "switch" {
|
||||
if config["value"] != "0" {
|
||||
data[config["name"].(string)] = true
|
||||
} else {
|
||||
data[config["name"].(string)] = false
|
||||
}
|
||||
}
|
||||
|
||||
if config["type"] == "picture" || config["type"] == "file" {
|
||||
|
||||
// json字符串
|
||||
if strings.Contains(config["value"].(string), "{") {
|
||||
var jsonData interface{}
|
||||
json.Unmarshal([]byte(config["value"].(string)), &jsonData)
|
||||
|
||||
// 如果为map
|
||||
if mapData, ok := jsonData.(map[string]interface{}); ok {
|
||||
data[config["name"].(string)] = mapData
|
||||
}
|
||||
|
||||
// 如果为数组,返回第一个key的path
|
||||
if arrayData, ok := jsonData.([]map[string]interface{}); ok {
|
||||
data[config["name"].(string)] = arrayData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
31
pkg/app/handler/admin/searches/datetime_range.go
Normal file
31
pkg/app/handler/admin/searches/datetime_range.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package searches
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/searches"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DateTimeRange struct {
|
||||
searches.DatetimeRange
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *DateTimeRange) Init(column string, name string) *DateTimeRange {
|
||||
p.ParentInit()
|
||||
p.Column = column
|
||||
p.Name = name
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
func (p *DateTimeRange) Apply(request *builder.Request, query *gorm.DB, value interface{}) *gorm.DB {
|
||||
values, ok := value.(map[string]interface{})
|
||||
|
||||
if ok == false {
|
||||
return query
|
||||
}
|
||||
|
||||
return query.Where(p.Column+" BETWEEN ? AND ?", values["0"], values["1"])
|
||||
}
|
25
pkg/app/handler/admin/searches/input.go
Normal file
25
pkg/app/handler/admin/searches/input.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package searches
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/searches"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Input struct {
|
||||
searches.Search
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Input) Init(column string, name string) *Input {
|
||||
p.ParentInit()
|
||||
p.Column = column
|
||||
p.Name = name
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
func (p *Input) Apply(request *builder.Request, query *gorm.DB, value interface{}) *gorm.DB {
|
||||
return query.Where(p.Column+" LIKE ?", "%"+value.(string)+"%")
|
||||
}
|
41
pkg/app/handler/admin/searches/status.go
Normal file
41
pkg/app/handler/admin/searches/status.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package searches
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/searches"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
searches.Select
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Status) Init() *Status {
|
||||
p.ParentInit()
|
||||
p.Name = "状态"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
func (p *Status) Apply(request *builder.Request, query *gorm.DB, value interface{}) *gorm.DB {
|
||||
|
||||
var status int
|
||||
|
||||
if value.(string) == "on" {
|
||||
status = 1
|
||||
} else {
|
||||
status = 0
|
||||
}
|
||||
|
||||
return query.Where("status = ?", status)
|
||||
}
|
||||
|
||||
// 属性
|
||||
func (p *Status) Options(request *builder.Request) map[interface{}]interface{} {
|
||||
return map[interface{}]interface{}{
|
||||
"on": "正常",
|
||||
"off": "禁用",
|
||||
}
|
||||
}
|
0
pkg/app/handler/mix/.keep
Normal file
0
pkg/app/handler/mix/.keep
Normal file
66
pkg/app/install/install.go
Normal file
66
pkg/app/install/install.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package install
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
// 判断路径是否存在
|
||||
func PathExist(path string) bool {
|
||||
_, err := os.Stat(path) //os.Stat获取文件信息
|
||||
if err != nil {
|
||||
if os.IsExist(err) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 执行安装操作
|
||||
func Handle(request *builder.Request) error {
|
||||
|
||||
// 如果锁定文件存在则不执行安装步骤
|
||||
if PathExist("install.lock") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 迁移数据
|
||||
db.Client.AutoMigrate(
|
||||
&model.ActionLog{},
|
||||
&model.Admin{},
|
||||
&model.Config{},
|
||||
&model.Menu{},
|
||||
&model.File{},
|
||||
&model.FileCategory{},
|
||||
&model.Picture{},
|
||||
&model.PictureCategory{},
|
||||
&model.Permission{},
|
||||
&model.Role{},
|
||||
&model.ModelHasRole{},
|
||||
&model.RoleHasPermission{},
|
||||
&model.ModelHasPermission{},
|
||||
)
|
||||
|
||||
// 如果超级管理员不存在,初始化数据库数据
|
||||
adminInfo, err := (&model.Admin{}).GetInfoById(1)
|
||||
if err != nil && err.Error() != "record not found" {
|
||||
panic(err)
|
||||
}
|
||||
if adminInfo.Id == 0 {
|
||||
// 数据填充
|
||||
(&model.Admin{}).Seeder()
|
||||
(&model.Config{}).Seeder()
|
||||
(&model.Menu{}).Seeder()
|
||||
}
|
||||
|
||||
// 创建锁定文件
|
||||
file, _ := os.Create("install.lock")
|
||||
file.Close()
|
||||
|
||||
return nil
|
||||
}
|
71
pkg/app/middleware/middleware.go
Normal file
71
pkg/app/middleware/middleware.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/app/handler/admin/login"
|
||||
"github.com/quarkcms/quark-go/pkg/app/model"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
)
|
||||
|
||||
// 中间件
|
||||
func Handle(request *builder.Request) error {
|
||||
loginIndex := (&login.Index{}).Init()
|
||||
|
||||
// 获取登录模板定义的路由
|
||||
loginIndexRoutes := loginIndex.(interface {
|
||||
GetRoutes() []*builder.Route
|
||||
}).GetRoutes()
|
||||
|
||||
inLoginRoute := false
|
||||
for _, v := range loginIndexRoutes {
|
||||
if v.Path == request.FullPath() {
|
||||
inLoginRoute = true
|
||||
}
|
||||
}
|
||||
|
||||
// 排除登录路由
|
||||
if inLoginRoute {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取登录管理员信息
|
||||
adminInfo, err := (&model.Admin{}).GetAuthUser(request.Token())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
guardName := adminInfo.GuardName
|
||||
if guardName != "admin" {
|
||||
return errors.New("401 Unauthozied")
|
||||
}
|
||||
|
||||
// 管理员id
|
||||
if adminInfo.Id != 1 {
|
||||
permissions, err := (&model.Permission{}).GetListByAdminId(adminInfo.Id)
|
||||
if err != nil {
|
||||
return errors.New("403 Forbidden")
|
||||
}
|
||||
|
||||
hasPermission := false
|
||||
for _, v := range permissions {
|
||||
if "/"+v.Name == request.Path() {
|
||||
hasPermission = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasPermission {
|
||||
return errors.New("403 Forbidden")
|
||||
}
|
||||
}
|
||||
|
||||
// 记录操作日志
|
||||
(&model.ActionLog{}).InsertGetId(&model.ActionLog{
|
||||
ObjectId: adminInfo.Id,
|
||||
Url: request.Path(),
|
||||
Ip: request.IP(),
|
||||
Type: "admin",
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
28
pkg/app/model/action_log.go
Normal file
28
pkg/app/model/action_log.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
// 字段
|
||||
type ActionLog struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
ObjectId int `json:"object_id" gorm:"size:11;not null"`
|
||||
Username string `json:"username" gorm:"<-:false"`
|
||||
Url string `json:"url" gorm:"size:500;not null"`
|
||||
Remark string `json:"remark" gorm:"size:255;not null"`
|
||||
Ip string `json:"ip" gorm:"size:100;not null"`
|
||||
Type string `json:"type" gorm:"size:100;not null"`
|
||||
Status int `json:"status" gorm:"size:1;not null;default:1"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// 插入数据
|
||||
func (model *ActionLog) InsertGetId(data *ActionLog) (id int, Error error) {
|
||||
err := db.Client.Create(data).Error
|
||||
|
||||
return data.Id, err
|
||||
}
|
134
pkg/app/model/admin.go
Normal file
134
pkg/app/model/admin.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"github.com/quarkcms/quark-go/pkg/hash"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 字段
|
||||
type Admin struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
Username string `json:"username" gorm:"size:20;index:admins_username_unique,unique;not null"`
|
||||
Nickname string `json:"nickname" gorm:"size:200;not null"`
|
||||
Sex int `json:"sex" gorm:"size:4;not null;default:1"`
|
||||
Email string `json:"email" gorm:"size:50;index:admins_email_unique,unique;not null"`
|
||||
Phone string `json:"phone" gorm:"size:11;index:admins_phone_unique,unique;not null"`
|
||||
Password string `json:"password" gorm:"size:255;not null"`
|
||||
Avatar string `json:"avatar" gorm:"size:1000"`
|
||||
LastLoginIp string `json:"last_login_ip" gorm:"size:255"`
|
||||
LastLoginTime time.Time `json:"last_login_time"`
|
||||
Status int `json:"status" gorm:"size:1;not null;default:1"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `json:"deleted_at"`
|
||||
}
|
||||
|
||||
// 管理员JWT结构体
|
||||
type AdminClaims struct {
|
||||
Id int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Nickname string `json:"nickname"`
|
||||
Sex int `json:"sex"`
|
||||
Email string `json:"email"`
|
||||
Phone string `json:"phone"`
|
||||
Avatar string `json:"avatar"`
|
||||
GuardName string `json:"guard_name"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// 管理员Seeder
|
||||
func (model *Admin) Seeder() {
|
||||
seeders := []Admin{
|
||||
{Username: "administrator", Nickname: "超级管理员", Email: "admin@yourweb.com", Phone: "10086", Password: hash.Make("123456"), Sex: 1, Status: 1},
|
||||
}
|
||||
|
||||
db.Client.Create(&seeders)
|
||||
}
|
||||
|
||||
// 获取管理员JWT信息
|
||||
func (model *Admin) GetClaims(adminInfo *Admin) (adminClaims *AdminClaims) {
|
||||
adminClaims = &AdminClaims{
|
||||
adminInfo.Id,
|
||||
adminInfo.Username,
|
||||
adminInfo.Nickname,
|
||||
adminInfo.Sex,
|
||||
adminInfo.Email,
|
||||
adminInfo.Phone,
|
||||
adminInfo.Avatar,
|
||||
"admin",
|
||||
jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 过期时间,默认24小时
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()), // 颁发时间
|
||||
NotBefore: jwt.NewNumericDate(time.Now()), // 不早于时间
|
||||
Issuer: "QuarkGo", // 颁发人
|
||||
Subject: "Admin Token", // 主题信息
|
||||
},
|
||||
}
|
||||
|
||||
return adminClaims
|
||||
}
|
||||
|
||||
// 获取当前认证的用户信息,默认参数为tokenString
|
||||
func (model *Admin) GetAuthUser(authValue interface{}) (adminClaims *AdminClaims, Error error) {
|
||||
config := builder.GetConfig()
|
||||
token, err := jwt.ParseWithClaims(authValue.(string), &AdminClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(config.AppKey), nil
|
||||
})
|
||||
if err != nil {
|
||||
if ve, ok := err.(*jwt.ValidationError); ok {
|
||||
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
|
||||
return nil, errors.New("token格式错误")
|
||||
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
|
||||
return nil, errors.New("token已过期")
|
||||
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
|
||||
return nil, errors.New("token未生效")
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(*AdminClaims); ok && token.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("token不可用")
|
||||
}
|
||||
|
||||
// 通过ID获取管理员信息
|
||||
func (model *Admin) GetInfoById(id interface{}) (admin *Admin, Error error) {
|
||||
err := db.Client.Where("status = ?", 1).Where("id = ?", id).First(&admin).Error
|
||||
|
||||
return admin, err
|
||||
}
|
||||
|
||||
// 通过用户名获取管理员信息
|
||||
func (model *Admin) GetInfoByUsername(username string) (admin *Admin, Error error) {
|
||||
err := db.Client.Where("status = ?", 1).Where("username = ?", username).First(&admin).Error
|
||||
|
||||
return admin, err
|
||||
}
|
||||
|
||||
// 通过ID获取管理员拥有的菜单列表
|
||||
func (model *Admin) GetMenuListById(id interface{}) (menuList interface{}, Error error) {
|
||||
|
||||
return (&Menu{}).GetListByAdminId(id.(int))
|
||||
}
|
||||
|
||||
// 更新最后一次登录数据
|
||||
func (model *Admin) UpdateLastLogin(uid int, lastLoginIp string, lastLoginTime time.Time) error {
|
||||
data := Admin{
|
||||
LastLoginIp: lastLoginIp,
|
||||
LastLoginTime: lastLoginTime,
|
||||
}
|
||||
|
||||
return db.Client.
|
||||
Where("id = ?", uid).
|
||||
Updates(&data).Error
|
||||
}
|
66
pkg/app/model/config.go
Normal file
66
pkg/app/model/config.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
// 字段
|
||||
type Config struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
Title string `json:"title" gorm:"size:255;not null"`
|
||||
Type string `json:"type" gorm:"size:20;not null"`
|
||||
Name string `json:"name" gorm:"size:255;not null"`
|
||||
Sort int `json:"sort" gorm:"size:11;default:0"`
|
||||
GroupName string `json:"group_name" gorm:"size:255;not null"`
|
||||
Value string `json:"value" gorm:"size:2000"`
|
||||
Remark string `json:"remark" gorm:"size:100;not null"`
|
||||
Status int `json:"status" gorm:"size:1;not null;default:1"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// 存储配置
|
||||
var webConfig = make(map[string]string)
|
||||
|
||||
// 配置表
|
||||
func (model *Config) Seeder() {
|
||||
seeders := []Config{
|
||||
{Title: "网站名称", Type: "text", Name: "WEB_SITE_NAME", Sort: 0, GroupName: "基本", Value: "QuarkCMS", Remark: "", Status: 1},
|
||||
{Title: "关键字", Type: "text", Name: "WEB_SITE_KEYWORDS", Sort: 0, GroupName: "基本", Value: "QuarkCMS", Remark: "", Status: 1},
|
||||
{Title: "描述", Type: "textarea", Name: "WEB_SITE_DESCRIPTION", Sort: 0, GroupName: "基本", Value: "QuarkCMS", Remark: "", Status: 1},
|
||||
{Title: "Logo", Type: "picture", Name: "WEB_SITE_LOGO", Sort: 0, GroupName: "基本", Value: "", Remark: "", Status: 1},
|
||||
{Title: "统计代码", Type: "textarea", Name: "WEB_SITE_SCRIPT", Sort: 0, GroupName: "基本", Value: "", Remark: "", Status: 1},
|
||||
{Title: "网站域名", Type: "text", Name: "WEB_SITE_DOMAIN", Sort: 0, GroupName: "基本", Value: "", Remark: "", Status: 1},
|
||||
{Title: "网站版权", Type: "text", Name: "WEB_SITE_COPYRIGHT", Sort: 0, GroupName: "基本", Value: "© Company 2018", Remark: "", Status: 1},
|
||||
{Title: "开启SSL", Type: "switch", Name: "SSL_OPEN", Sort: 0, GroupName: "基本", Value: "0", Remark: "", Status: 1},
|
||||
{Title: "开启网站", Type: "switch", Name: "WEB_SITE_OPEN", Sort: 0, GroupName: "基本", Value: "1", Remark: "", Status: 1},
|
||||
{Title: "KeyID", Type: "text", Name: "OSS_ACCESS_KEY_ID", Sort: 0, GroupName: "阿里云存储", Value: "", Remark: "你的AccessKeyID", Status: 1},
|
||||
{Title: "KeySecret", Type: "text", Name: "OSS_ACCESS_KEY_SECRET", Sort: 0, GroupName: "阿里云存储", Value: "", Remark: "你的AccessKeySecret", Status: 1},
|
||||
{Title: "EndPoint", Type: "text", Name: "OSS_ENDPOINT", Sort: 0, GroupName: "阿里云存储", Value: "", Remark: "地域节点", Status: 1},
|
||||
{Title: "Bucket域名", Type: "text", Name: "OSS_BUCKET", Sort: 0, GroupName: "阿里云存储", Value: "", Remark: "", Status: 1},
|
||||
{Title: "自定义域名", Type: "text", Name: "OSS_MYDOMAIN", Sort: 0, GroupName: "阿里云存储", Value: "", Remark: "例如:oss.web.com", Status: 1},
|
||||
{Title: "开启云存储", Type: "switch", Name: "OSS_OPEN", Sort: 0, GroupName: "阿里云存储", Value: "0", Remark: "", Status: 1},
|
||||
}
|
||||
|
||||
db.Client.Create(&seeders)
|
||||
}
|
||||
|
||||
// 刷新配置
|
||||
func (model *Config) Refresh() {
|
||||
configs := []Config{}
|
||||
db.Client.Where("status", 1).Find(&configs)
|
||||
for _, config := range configs {
|
||||
webConfig[config.Name] = config.Value
|
||||
}
|
||||
}
|
||||
|
||||
// 获取配置信息
|
||||
func (model *Config) GetValue(key string) string {
|
||||
if len(webConfig) == 0 {
|
||||
model.Refresh()
|
||||
}
|
||||
|
||||
return webConfig[key]
|
||||
}
|
143
pkg/app/model/file.go
Normal file
143
pkg/app/model/file.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"github.com/xuri/excelize/v2"
|
||||
)
|
||||
|
||||
// 字段
|
||||
type File struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
ObjType string `json:"obj_type" gorm:"size:255"`
|
||||
ObjId int `json:"obj_id" gorm:"size:11;default:0"`
|
||||
FileCategoryId int `json:"file_category_id" gorm:"size:11;default:0"`
|
||||
Sort int `json:"sort" gorm:"size:11;default:0"`
|
||||
Name string `json:"name" gorm:"size:255;not null"`
|
||||
Size string `json:"size" gorm:"size:20;default:0"`
|
||||
Ext string `json:"ext" gorm:"size:255"`
|
||||
Path string `json:"path" gorm:"size:255;not null"`
|
||||
Md5 string `json:"md5" gorm:"size:255;not null"`
|
||||
Status int `json:"status" gorm:"size:1;not null;default:1"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// 插入数据并返回ID
|
||||
func (model *File) InsertGetId(data *File) (id int, Error error) {
|
||||
err := db.Client.Create(&data).Error
|
||||
|
||||
return data.Id, err
|
||||
}
|
||||
|
||||
// 获取文件路径
|
||||
func (model *File) GetPath(id interface{}) string {
|
||||
http, path := "", ""
|
||||
webSiteDomain := (&Config{}).GetValue("WEB_SITE_DOMAIN")
|
||||
WebConfig := (&Config{}).GetValue("SSL_OPEN")
|
||||
if webSiteDomain != "" {
|
||||
if WebConfig == "1" {
|
||||
http = "https://"
|
||||
} else {
|
||||
http = "http://"
|
||||
}
|
||||
}
|
||||
|
||||
if getId, ok := id.(string); ok {
|
||||
if strings.Contains(getId, "//") && !strings.Contains(getId, "{") {
|
||||
return getId
|
||||
}
|
||||
if strings.Contains(getId, "./") && !strings.Contains(getId, "{") {
|
||||
// 如果设置域名,则加上域名前缀
|
||||
return http + webSiteDomain + strings.Replace(getId, "./storage/app/public", "/storage", -1)
|
||||
}
|
||||
// json字符串
|
||||
if strings.Contains(getId, "{") {
|
||||
var jsonData interface{}
|
||||
json.Unmarshal([]byte(getId), &jsonData)
|
||||
// 如果为map
|
||||
if mapData, ok := jsonData.(map[string]interface{}); ok {
|
||||
path = mapData["path"].(string)
|
||||
}
|
||||
// 如果为数组,返回第一个key的path
|
||||
if arrayData, ok := jsonData.([]map[string]interface{}); ok {
|
||||
path = arrayData[0]["path"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
if strings.Contains(path, "//") {
|
||||
return path
|
||||
}
|
||||
if strings.Contains(path, "./") {
|
||||
path = strings.Replace(path, "./storage/app/public", "/storage", -1)
|
||||
}
|
||||
if path != "" {
|
||||
// 如果设置域名,则加上域名前缀
|
||||
return http + webSiteDomain + path
|
||||
}
|
||||
}
|
||||
|
||||
file := &File{}
|
||||
db.Client.Where("id", id).Where("status", 1).First(&file)
|
||||
if file.Id != 0 {
|
||||
path = file.Path
|
||||
if strings.Contains(path, "//") {
|
||||
return path
|
||||
}
|
||||
if strings.Contains(path, "./") {
|
||||
path = strings.Replace(path, "./storage/app/public", "/storage", -1)
|
||||
}
|
||||
if path != "" {
|
||||
// 如果设置域名,则加上域名前缀
|
||||
return http + webSiteDomain + path
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// 获取Excel文件数据
|
||||
func (model *File) GetExcelData(fileId int) (data [][]interface{}, Error error) {
|
||||
filePath := ""
|
||||
file := &File{}
|
||||
err := db.Client.Where("id", fileId).Where("status", 1).First(&file).Error
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
if file.Id != 0 {
|
||||
filePath = file.Path
|
||||
}
|
||||
if filePath == "" {
|
||||
return data, errors.New("参数错误!")
|
||||
}
|
||||
|
||||
f, err := excelize.OpenFile(filePath)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}()
|
||||
|
||||
rows, err := f.GetRows("Sheet1")
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
for _, row := range rows {
|
||||
getRows := []interface{}{}
|
||||
for _, colCell := range row {
|
||||
getRows = append(getRows, colCell)
|
||||
}
|
||||
data = append(data, getRows)
|
||||
}
|
||||
|
||||
return data, err
|
||||
}
|
11
pkg/app/model/file_category.go
Normal file
11
pkg/app/model/file_category.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
// 字段
|
||||
type FileCategory struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
ObjType string `json:"obj_type" gorm:"size:100"`
|
||||
ObjId int `json:"obj_id" gorm:"size:11;default:0"`
|
||||
Title string `json:"title" gorm:"size:255;not null"`
|
||||
Sort int `json:"sort" gorm:"size:11;default:0"`
|
||||
Description string `json:"description" gorm:"size:255"`
|
||||
}
|
198
pkg/app/model/menu.go
Normal file
198
pkg/app/model/menu.go
Normal file
@@ -0,0 +1,198 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-basic/uuid"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"github.com/quarkcms/quark-go/pkg/lister"
|
||||
)
|
||||
|
||||
// 字段
|
||||
type Menu struct {
|
||||
Key string `json:"key" gorm:"<-:false"`
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
Name string `json:"name" gorm:"size:100;not null"`
|
||||
GuardName string `json:"group_name" gorm:"size:100;not null"`
|
||||
Icon string `json:"icon" gorm:"size:100;"`
|
||||
Type string `json:"type" gorm:"size:100;not null"`
|
||||
Pid int `json:"pid" gorm:"size:11;default:0"`
|
||||
Sort int `json:"sort" gorm:"size:11;default:0"`
|
||||
Path string `json:"path" gorm:"size:255"`
|
||||
Show int `json:"show" gorm:"size:1;not null;default:1"`
|
||||
Status int `json:"status" gorm:"size:1;not null;default:1"`
|
||||
Locale string `json:"locale" gorm:"<-:false"`
|
||||
HideInMenu bool `json:"hide_in_menu" gorm:"<-:false"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// 菜单表
|
||||
func (p *Menu) Seeder() {
|
||||
seeders := []Menu{
|
||||
{Id: 1, Name: "控制台", GuardName: "admin", Icon: "icon-home", Type: "default", Pid: 0, Sort: 0, Path: "/dashboard", Show: 1, Status: 1},
|
||||
{Id: 2, Name: "主页", GuardName: "admin", Icon: "", Type: "engine", Pid: 1, Sort: 0, Path: "/api/admin/dashboard/index/index", Show: 1, Status: 1},
|
||||
{Id: 3, Name: "管理员", GuardName: "admin", Icon: "icon-admin", Type: "default", Pid: 0, Sort: 0, Path: "/admin", Show: 1, Status: 1},
|
||||
{Id: 4, Name: "管理员列表", GuardName: "admin", Icon: "", Type: "engine", Pid: 3, Sort: 0, Path: "/api/admin/admin/index", Show: 1, Status: 1},
|
||||
{Id: 5, Name: "权限列表", GuardName: "admin", Icon: "", Type: "engine", Pid: 3, Sort: 0, Path: "/api/admin/permission/index", Show: 1, Status: 1},
|
||||
{Id: 6, Name: "角色列表", GuardName: "admin", Icon: "", Type: "engine", Pid: 3, Sort: 0, Path: "/api/admin/role/index", Show: 1, Status: 1},
|
||||
{Id: 7, Name: "系统配置", GuardName: "admin", Icon: "icon-setting", Type: "default", Pid: 0, Sort: 0, Path: "/system", Show: 1, Status: 1},
|
||||
{Id: 8, Name: "设置管理", GuardName: "admin", Icon: "", Type: "default", Pid: 7, Sort: 0, Path: "/system/config", Show: 1, Status: 1},
|
||||
{Id: 9, Name: "网站设置", GuardName: "admin", Icon: "", Type: "engine", Pid: 8, Sort: 0, Path: "/api/admin/webConfig/setting/form", Show: 1, Status: 1},
|
||||
{Id: 10, Name: "配置管理", GuardName: "admin", Icon: "", Type: "engine", Pid: 8, Sort: 0, Path: "/api/admin/config/index", Show: 1, Status: 1},
|
||||
{Id: 11, Name: "菜单管理", GuardName: "admin", Icon: "", Type: "engine", Pid: 7, Sort: 0, Path: "/api/admin/menu/index", Show: 1, Status: 1},
|
||||
{Id: 12, Name: "操作日志", GuardName: "admin", Icon: "", Type: "engine", Pid: 7, Sort: 0, Path: "/api/admin/actionLog/index", Show: 1, Status: 1},
|
||||
{Id: 13, Name: "附件空间", GuardName: "admin", Icon: "icon-attachment", Type: "default", Pid: 0, Sort: 0, Path: "/attachment", Show: 1, Status: 1},
|
||||
{Id: 14, Name: "文件管理", GuardName: "admin", Icon: "", Type: "engine", Pid: 13, Sort: 0, Path: "/api/admin/file/index", Show: 1, Status: 1},
|
||||
{Id: 15, Name: "图片管理", GuardName: "admin", Icon: "", Type: "engine", Pid: 13, Sort: 0, Path: "/api/admin/picture/index", Show: 1, Status: 1},
|
||||
{Id: 16, Name: "我的账号", GuardName: "admin", Icon: "icon-user", Type: "default", Pid: 0, Sort: 0, Path: "/account", Show: 1, Status: 1},
|
||||
{Id: 17, Name: "个人设置", GuardName: "admin", Icon: "", Type: "engine", Pid: 16, Sort: 0, Path: "/api/admin/account/setting/form", Show: 1, Status: 1},
|
||||
}
|
||||
|
||||
db.Client.Create(&seeders)
|
||||
}
|
||||
|
||||
// 获取菜单的有序列表
|
||||
func (model *Menu) OrderedList() (list []map[string]interface{}, Error error) {
|
||||
var menus []map[string]interface{}
|
||||
err := db.Client.
|
||||
Model(&model).
|
||||
Where("guard_name = ?", "admin").
|
||||
Order("sort asc,id asc").
|
||||
Find(&menus).Error
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
menuTrees, err := lister.ListToTree(menus, "id", "pid", "children", 0)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
menuTreeList, err := lister.TreeToOrderedList(menuTrees, 0, "name", "children")
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
list = append(list, map[string]interface{}{
|
||||
"label": "根节点",
|
||||
"value": 0,
|
||||
})
|
||||
for _, v := range menuTreeList {
|
||||
option := map[string]interface{}{
|
||||
"label": v.((map[string]interface{}))["name"],
|
||||
"value": v.(map[string]interface{})["id"],
|
||||
}
|
||||
list = append(list, option)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// 获取菜单的tree
|
||||
func (model *Menu) Tree() (list []interface{}, Error error) {
|
||||
menus := []Menu{}
|
||||
err := db.Client.Where("status = ?", 1).Select("name", "id", "pid").Find(&menus).Error
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
menuList := []map[string]interface{}{}
|
||||
for _, v := range menus {
|
||||
item := map[string]interface{}{
|
||||
"key": v.Id,
|
||||
"pid": v.Pid,
|
||||
"title": v.Name,
|
||||
}
|
||||
menuList = append(menuList, item)
|
||||
}
|
||||
|
||||
return lister.ListToTree(menuList, "key", "pid", "children", 0)
|
||||
}
|
||||
|
||||
// 通过管理员ID权限菜单
|
||||
func (model *Menu) GetListByAdminId(adminId int) (menuList interface{}, Error error) {
|
||||
menus := []Menu{}
|
||||
var menuKey int
|
||||
|
||||
if adminId == 1 {
|
||||
db.Client.Where("status = ?", 1).Where("guard_name", "admin").Order("sort asc").Find(&menus)
|
||||
} else {
|
||||
var menuIds []int
|
||||
permissions, err := (&Permission{}).GetListByAdminId(adminId)
|
||||
if err != nil {
|
||||
return menuList, err
|
||||
}
|
||||
|
||||
if permissions != nil {
|
||||
for key, v := range permissions {
|
||||
menuIds[key] = v.MenuId
|
||||
}
|
||||
}
|
||||
|
||||
var pids1 []int
|
||||
// 三级查询列表
|
||||
db.Client.
|
||||
Where("status = ?", 1).
|
||||
Where("id in (?)", menuIds).
|
||||
Where("pid <> ?", 0).
|
||||
Order("sort asc").
|
||||
Find(&menus)
|
||||
for key, v := range menus {
|
||||
if v.Pid != 0 {
|
||||
pids1[key] = v.Pid
|
||||
}
|
||||
menuKey = key
|
||||
}
|
||||
|
||||
var pids2 []int
|
||||
menu2 := []Menu{}
|
||||
// 二级查询列表
|
||||
db.Client.
|
||||
Where("status = ?", 1).
|
||||
Where("id in (?)", pids1).
|
||||
Where("pid <> ?", 0).
|
||||
Order("sort asc").
|
||||
Find(&menu2)
|
||||
for key, v := range menu2 {
|
||||
if v.Pid != 0 {
|
||||
pids2[key] = v.Pid
|
||||
}
|
||||
menuKey = menuKey + key
|
||||
menus[menuKey] = v
|
||||
}
|
||||
|
||||
menu3 := []Menu{}
|
||||
// 一级查询列表
|
||||
db.Client.
|
||||
Where("status = ?", 1).
|
||||
Where("id in (?)", pids2).
|
||||
Where("pid", 0).
|
||||
Order("sort asc").
|
||||
Find(&menu3)
|
||||
for key, v := range menu3 {
|
||||
menuKey = menuKey + key
|
||||
menus[menuKey] = v
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range menus {
|
||||
v.Key = uuid.New()
|
||||
v.Locale = "menu" + strings.Replace(v.Path, "/", ".", -1)
|
||||
|
||||
if v.Show == 1 {
|
||||
v.HideInMenu = false
|
||||
} else {
|
||||
v.HideInMenu = true
|
||||
}
|
||||
|
||||
if v.Type == "engine" {
|
||||
v.Path = "/index?api=" + v.Path
|
||||
}
|
||||
|
||||
menus[k] = v
|
||||
}
|
||||
|
||||
return lister.ListToTree(menus, "id", "pid", "routes", 0)
|
||||
}
|
63
pkg/app/model/permission.go
Normal file
63
pkg/app/model/permission.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
// 权限
|
||||
type Permission struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
MenuId int `json:"menu_id" gorm:"size:11;default:0"`
|
||||
Name string `json:"name" gorm:"size:100;not null"`
|
||||
GuardName string `json:"guard_name" gorm:"size:100"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// 获取列表
|
||||
func (model *Permission) List() (list []map[string]interface{}, Error error) {
|
||||
permissions := []Permission{}
|
||||
err := db.Client.Find(&permissions).Error
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
for _, v := range permissions {
|
||||
option := map[string]interface{}{
|
||||
"label": v.Name,
|
||||
"value": v.Id,
|
||||
}
|
||||
|
||||
list = append(list, option)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// 通过权限id集合获取权限列表
|
||||
func (model *Permission) GetListByIds(permissionIds []int) (permissions []Permission, Error error) {
|
||||
err := db.Client.Where("id in (?)", &permissionIds).Find(&permissions).Error
|
||||
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// 通过管理员ID获取权限列表
|
||||
func (model *Permission) GetListByAdminId(id int) (permissions []Permission, Error error) {
|
||||
|
||||
// 管理员拥有的角色id集合
|
||||
roleIds, err := (&ModelHasRole{}).GetRoleIdsByAdminId(id)
|
||||
if err != nil {
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
// 角色拥有的权限id集合
|
||||
permissionIds, err := (&RoleHasPermission{}).GetPermissionIdsByRoleIds(roleIds)
|
||||
if err != nil {
|
||||
return permissions, err
|
||||
}
|
||||
|
||||
// 角色权限列表
|
||||
return (&Permission{}).GetListByIds(permissionIds)
|
||||
}
|
118
pkg/app/model/picture.go
Normal file
118
pkg/app/model/picture.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
// 字段
|
||||
type Picture struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
ObjType string `json:"obj_type" gorm:"size:255"`
|
||||
ObjId int `json:"obj_id" gorm:"size:11;default:0"`
|
||||
PictureCategoryId int `json:"picture_category_id" gorm:"size:11;default:0"`
|
||||
Sort int `json:"sort" gorm:"size:11;default:0"`
|
||||
Name string `json:"name" gorm:"size:255;not null"`
|
||||
Size string `json:"size" gorm:"size:20;default:0"`
|
||||
Width int `json:"width" gorm:"size:11;default:0"`
|
||||
Height int `json:"height" gorm:"size:11;default:0"`
|
||||
Ext string `json:"ext" gorm:"size:255"`
|
||||
Path string `json:"path" gorm:"size:255;not null"`
|
||||
Md5 string `json:"md5" gorm:"size:255;not null"`
|
||||
Status int `json:"status" gorm:"size:1;not null;default:1"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// 插入数据并返回ID
|
||||
func (model *Picture) InsertGetId(data map[string]interface{}) (id int, Error error) {
|
||||
size := strconv.FormatInt(data["size"].(int64), 10)
|
||||
picture := Picture{
|
||||
ObjType: data["obj_type"].(string),
|
||||
ObjId: data["obj_id"].(int),
|
||||
Name: data["name"].(string),
|
||||
Size: size,
|
||||
Md5: data["md5"].(string),
|
||||
Path: data["path"].(string),
|
||||
Width: data["width"].(int),
|
||||
Height: data["height"].(int),
|
||||
Ext: data["ext"].(string),
|
||||
Status: 1,
|
||||
}
|
||||
err := db.Client.Create(&picture).Error
|
||||
if err != nil {
|
||||
return id, err
|
||||
}
|
||||
|
||||
return picture.Id, nil
|
||||
}
|
||||
|
||||
// 获取图片路径
|
||||
func (model *Picture) GetPath(id interface{}) string {
|
||||
http, path := "", ""
|
||||
webSiteDomain := (&Config{}).GetValue("WEB_SITE_DOMAIN")
|
||||
WebConfig := (&Config{}).GetValue("SSL_OPEN")
|
||||
if webSiteDomain != "" {
|
||||
if WebConfig == "1" {
|
||||
http = "https://"
|
||||
} else {
|
||||
http = "http://"
|
||||
}
|
||||
}
|
||||
|
||||
if getId, ok := id.(string); ok {
|
||||
if strings.Contains(getId, "//") && !strings.Contains(getId, "{") {
|
||||
return getId
|
||||
}
|
||||
if strings.Contains(getId, "./") && !strings.Contains(getId, "{") {
|
||||
// 如果设置域名,则加上域名前缀
|
||||
return http + webSiteDomain + strings.Replace(getId, "./storage/app/public", "/storage", -1)
|
||||
}
|
||||
|
||||
// json字符串
|
||||
if strings.Contains(getId, "{") {
|
||||
var jsonData interface{}
|
||||
json.Unmarshal([]byte(getId), &jsonData)
|
||||
if mapData, ok := jsonData.(map[string]interface{}); ok {
|
||||
path = mapData["url"].(string)
|
||||
}
|
||||
|
||||
// 如果为数组,返回第一个key的path
|
||||
if arrayData, ok := jsonData.([]map[string]interface{}); ok {
|
||||
path = arrayData[0]["url"].(string)
|
||||
}
|
||||
}
|
||||
if strings.Contains(path, "//") {
|
||||
return path
|
||||
}
|
||||
if strings.Contains(path, "./") {
|
||||
path = strings.Replace(path, "./storage/app/public", "/storage", -1)
|
||||
}
|
||||
if path != "" {
|
||||
// 如果设置域名,则加上域名前缀
|
||||
return http + webSiteDomain + path
|
||||
}
|
||||
}
|
||||
|
||||
picture := &Picture{}
|
||||
db.Client.Where("id", id).Where("status", 1).First(&picture)
|
||||
if picture.Id != 0 {
|
||||
path = picture.Path
|
||||
if strings.Contains(path, "//") {
|
||||
return path
|
||||
}
|
||||
if strings.Contains(path, "./") {
|
||||
path = strings.Replace(path, "./storage/app/public", "/storage", -1)
|
||||
}
|
||||
}
|
||||
if path != "" {
|
||||
// 如果设置域名,则加上域名前缀
|
||||
return http + webSiteDomain + path
|
||||
}
|
||||
|
||||
return http + webSiteDomain + "/admin/default.png"
|
||||
}
|
11
pkg/app/model/picture_category.go
Normal file
11
pkg/app/model/picture_category.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
// 字段
|
||||
type PictureCategory struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
ObjType string `json:"obj_type" gorm:"size:100"`
|
||||
ObjId int `json:"obj_id" gorm:"size:11;default:0"`
|
||||
Title string `json:"title" gorm:"size:255;not null"`
|
||||
Sort int `json:"sort" gorm:"size:11;default:0"`
|
||||
Description string `json:"description" gorm:"size:255"`
|
||||
}
|
73
pkg/app/model/role.go
Normal file
73
pkg/app/model/role.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
)
|
||||
|
||||
// 角色
|
||||
type Role struct {
|
||||
Id int `json:"id" gorm:"autoIncrement"`
|
||||
Name string `json:"name" gorm:"size:255;not null"`
|
||||
GuardName string `json:"guard_name" gorm:"size:100;not null"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// 模型角色关联表
|
||||
type ModelHasRole struct {
|
||||
RoleId int `json:"role_id" gorm:"index:model_has_roles_model_id_model_type_index"`
|
||||
ModelType string `json:"model_type" gorm:"size:255;not null"`
|
||||
ModelId int `json:"model_id" gorm:"index:model_has_roles_model_id_model_type_index"`
|
||||
}
|
||||
|
||||
// 角色权限关联表
|
||||
type RoleHasPermission struct {
|
||||
PermissionId int `json:"permission_id" gorm:"size:11;not null"`
|
||||
RoleId int `json:"role_id" gorm:"index:role_has_permissions_role_id_foreign"`
|
||||
}
|
||||
|
||||
// 模型权限关联表
|
||||
type ModelHasPermission struct {
|
||||
PermissionId int `json:"permission_id" gorm:"index:model_has_permissions_model_id_model_type_index"`
|
||||
ModelType string `json:"model_type" gorm:"size:255;not null"`
|
||||
ModelId int `json:"model_id" gorm:"index:model_has_permissions_model_id_model_type_index"`
|
||||
}
|
||||
|
||||
// 获取角色列表
|
||||
func (model *Role) List() (list map[interface{}]interface{}, Error error) {
|
||||
roles := []Role{}
|
||||
err := db.Client.Find(&roles).Error
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
for _, v := range roles {
|
||||
list[v.Id] = v.Name
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// 通过管理员ID获取角色相关
|
||||
func (model *ModelHasRole) GetListByAdminId(id int) (modelHasRole *ModelHasRole, Error error) {
|
||||
err := db.Client.Where("model_id", id).Where("model_type", "admin").First(&modelHasRole).Error
|
||||
|
||||
return modelHasRole, err
|
||||
}
|
||||
|
||||
// 通过管理员ID获取角色id集合
|
||||
func (model *ModelHasRole) GetRoleIdsByAdminId(id int) (roleIds []int, Error error) {
|
||||
err := db.Client.Model(model).Where("model_id", id).Where("model_type", "admin").Pluck("id", &roleIds).Error
|
||||
|
||||
return roleIds, err
|
||||
}
|
||||
|
||||
// 通过角色id集合获取权限id集合
|
||||
func (model *RoleHasPermission) GetPermissionIdsByRoleIds(roleIds []int) (permissionIds []int, Error error) {
|
||||
// 角色权限id
|
||||
err := db.Client.Model(model).Where("role_id in (?)", roleIds).Pluck("id", &permissionIds).Error
|
||||
|
||||
return permissionIds, err
|
||||
}
|
52
pkg/app/model/time.go
Normal file
52
pkg/app/model/time.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//自定义时间
|
||||
type Time time.Time
|
||||
|
||||
func (t *Time) UnmarshalJSON(data []byte) error {
|
||||
if string(data) == "null" {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
//前端接收的时间字符串
|
||||
str := string(data)
|
||||
//去除接收的str收尾多余的"
|
||||
timeStr := strings.Trim(str, "\"")
|
||||
t1, err := time.Parse("2006-01-02 15:04:05", timeStr)
|
||||
*t = Time(t1)
|
||||
return err
|
||||
}
|
||||
|
||||
func (t Time) MarshalJSON() ([]byte, error) {
|
||||
formatted := fmt.Sprintf("\"%v\"", time.Time(t).Format("2006-01-02 15:04:05"))
|
||||
return []byte(formatted), nil
|
||||
}
|
||||
|
||||
func (t Time) Value() (driver.Value, error) {
|
||||
// Time 转换成 time.Time 类型
|
||||
tTime := time.Time(t)
|
||||
return tTime.Format("2006-01-02 15:04:05"), nil
|
||||
}
|
||||
|
||||
func (t *Time) Scan(v interface{}) error {
|
||||
switch vt := v.(type) {
|
||||
case time.Time:
|
||||
// 字符串转成 time.Time 类型
|
||||
*t = Time(vt)
|
||||
case string:
|
||||
// 字符串转成 time.Time 类型
|
||||
getTime, _ := time.Parse("2006-01-02 15:04:05", vt)
|
||||
*t = Time(getTime)
|
||||
default:
|
||||
return errors.New("类型处理错误")
|
||||
}
|
||||
return nil
|
||||
}
|
633
pkg/builder/actions/action.go
Normal file
633
pkg/builder/actions/action.go
Normal file
@@ -0,0 +1,633 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gobeam/stringy"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
Name string `json:"name"`
|
||||
Reload string `json:"reload"`
|
||||
ActionType string `json:"actionType"`
|
||||
SubmitForm string `json:"submitForm"`
|
||||
Icon string `json:"icon"`
|
||||
Type string `json:"type"`
|
||||
Size string `json:"size"`
|
||||
WithLoading bool `json:"withLoading"`
|
||||
Fields interface{} `json:"fields"`
|
||||
ConfirmTitle string `json:"confirmTitle"`
|
||||
ConfirmText string `json:"confirmText"`
|
||||
ConfirmType string `json:"confirmType"`
|
||||
OnlyOnIndex bool `json:"onlyOnIndex"`
|
||||
OnlyOnForm bool `json:"onlyOnForm"`
|
||||
OnlyOnDetail bool `json:"onlyOnDetail"`
|
||||
ShowOnIndex bool `json:"showOnIndex"`
|
||||
ShowOnIndexTableRow bool `json:"showOnIndexTableRow"`
|
||||
ShowOnIndexTableAlert bool `json:"showOnIndexTableAlert"`
|
||||
ShowOnForm bool `json:"showOnForm"`
|
||||
ShowOnFormExtra bool `json:"showOnFormExtra"`
|
||||
ShowOnDetail bool `json:"showOnDetail"`
|
||||
ShowOnDetailExtra bool `json:"showOnDetailExtra"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Action) ParentInit() interface{} {
|
||||
p.ActionType = "ajax"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 行为key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetUriKey(action interface{}) string {
|
||||
uriKey := reflect.TypeOf(action).String()
|
||||
uriKey = strings.Replace(uriKey, "*actions.", "", -1)
|
||||
uriKey = stringy.New(uriKey).KebabCase("?", "").ToLower()
|
||||
|
||||
return uriKey
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取名称
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetName() string {
|
||||
return p.Name
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行成功后刷新的组件
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetReload() string {
|
||||
return p.Reload
|
||||
}
|
||||
|
||||
/**
|
||||
* 行为接口接收的参数,当行为在表格行展示的时候,可以配置当前行的任意字段
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
func (p *Action) GetApiParams() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行行为的接口
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetApi(request *builder.Request) string {
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 【必填】这是 action 最核心的配置,来指定该 action 的作用类型,支持:ajax、link、url、drawer、dialog、confirm、cancel、prev、next、copy、close。
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetActionType() string {
|
||||
return p.ActionType
|
||||
}
|
||||
|
||||
/**
|
||||
* 当action 的作用类型为submit的时候,可以指定提交哪个表格,submitForm为提交表单的key值,为空时提交当前表单
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetSubmitForm() string {
|
||||
return p.SubmitForm
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮类型,primary | ghost | dashed | link | text | default
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetType() string {
|
||||
return p.Type
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮大小,large | middle | small | default
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetSize() string {
|
||||
return p.Size
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否具有loading,当action 的作用类型为ajax,submit时有效
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
func (p *Action) GetWithLoading() bool {
|
||||
return p.WithLoading
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置按钮的图标组件
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Action) GetIcon() string {
|
||||
return p.Icon
|
||||
}
|
||||
|
||||
/**
|
||||
* 行为表单字段
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
func (p *Action) GetFields() interface{} {
|
||||
return p.Fields
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认标题
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
func (p *Action) GetConfirmTitle() string {
|
||||
return p.ConfirmTitle
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认文字
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
func (p *Action) GetConfirmText() string {
|
||||
return p.ConfirmText
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认类型
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
func (p *Action) GetConfirmType() string {
|
||||
return p.ConfirmType
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置行为前的确认操作
|
||||
*
|
||||
* @param string title
|
||||
* @param string text
|
||||
* @param string confirmType
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) WithConfirm(title string, text string, confirmType string) *Action {
|
||||
|
||||
p.ConfirmTitle = title
|
||||
p.ConfirmText = text
|
||||
p.ConfirmType = confirmType
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 只在列表页展示
|
||||
*
|
||||
* @param bool value
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetOnlyOnIndex(value bool) *Action {
|
||||
p.OnlyOnIndex = value
|
||||
p.ShowOnIndex = value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnIndexTableRow = !value
|
||||
p.ShowOnIndexTableAlert = !value
|
||||
p.ShowOnForm = !value
|
||||
p.ShowOnFormExtra = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnDetailExtra = !value
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 除了列表页外展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetExceptOnIndex() *Action {
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnIndexTableRow = true
|
||||
p.ShowOnIndexTableAlert = true
|
||||
p.ShowOnForm = true
|
||||
p.ShowOnFormExtra = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnDetailExtra = true
|
||||
p.ShowOnIndex = false
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 只在表单页展示
|
||||
*
|
||||
* @param bool value
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetOnlyOnForm(value bool) *Action {
|
||||
p.ShowOnForm = value
|
||||
p.ShowOnIndexTableAlert = !value
|
||||
p.ShowOnIndex = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnIndexTableRow = !value
|
||||
p.ShowOnFormExtra = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnDetailExtra = !value
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 除了表单页外展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetExceptOnForm() *Action {
|
||||
p.ShowOnIndexTableAlert = true
|
||||
p.ShowOnIndex = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnIndexTableRow = true
|
||||
p.ShowOnForm = false
|
||||
p.ShowOnFormExtra = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnDetailExtra = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 只在表单页右上角自定义区域展示
|
||||
*
|
||||
* @param bool value
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetOnlyOnFormExtra(value bool) *Action {
|
||||
p.ShowOnForm = !value
|
||||
p.ShowOnIndexTableAlert = !value
|
||||
p.ShowOnIndex = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnIndexTableRow = !value
|
||||
p.ShowOnFormExtra = value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnDetailExtra = !value
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 除了表单页右上角自定义区域外展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetExceptOnFormExtra() *Action {
|
||||
p.ShowOnIndexTableAlert = true
|
||||
p.ShowOnIndex = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnIndexTableRow = true
|
||||
p.ShowOnForm = true
|
||||
p.ShowOnFormExtra = false
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnDetailExtra = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 只在详情页展示
|
||||
*
|
||||
* @param bool value
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetOnlyOnDetail(value bool) *Action {
|
||||
p.OnlyOnDetail = value
|
||||
p.ShowOnDetail = value
|
||||
p.ShowOnIndex = !value
|
||||
p.ShowOnIndexTableRow = !value
|
||||
p.ShowOnIndexTableAlert = !value
|
||||
p.ShowOnForm = !value
|
||||
p.ShowOnFormExtra = !value
|
||||
p.ShowOnDetailExtra = !value
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 除了详情页外展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetExceptOnDetail() *Action {
|
||||
p.ShowOnIndex = true
|
||||
p.ShowOnDetail = false
|
||||
p.ShowOnIndexTableRow = true
|
||||
p.ShowOnIndexTableAlert = true
|
||||
p.ShowOnForm = true
|
||||
p.ShowOnFormExtra = true
|
||||
p.ShowOnDetailExtra = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 只在详情页右上角自定义区域展示
|
||||
*
|
||||
* @param bool value
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetOnlyOnDetailExtra(value bool) *Action {
|
||||
p.ShowOnForm = !value
|
||||
p.ShowOnIndexTableAlert = !value
|
||||
p.ShowOnIndex = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnIndexTableRow = !value
|
||||
p.ShowOnFormExtra = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnDetailExtra = value
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 除了详情页右上角自定义区域外展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetExceptOnDetailExtra() *Action {
|
||||
p.ShowOnIndexTableAlert = true
|
||||
p.ShowOnIndex = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnIndexTableRow = true
|
||||
p.ShowOnForm = true
|
||||
p.ShowOnFormExtra = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnDetailExtra = false
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在表格行内展示
|
||||
*
|
||||
* @param bool value
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetOnlyOnIndexTableRow(value bool) *Action {
|
||||
p.ShowOnIndexTableRow = value
|
||||
p.ShowOnIndex = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnIndexTableAlert = !value
|
||||
p.ShowOnForm = !value
|
||||
p.ShowOnFormExtra = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnDetailExtra = !value
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 除了表格行内外展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetExceptOnIndexTableRow() *Action {
|
||||
p.ShowOnIndexTableRow = false
|
||||
p.ShowOnIndex = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnIndexTableAlert = true
|
||||
p.ShowOnForm = true
|
||||
p.ShowOnFormExtra = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnDetailExtra = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在表格多选弹出层展示
|
||||
*
|
||||
* @param bool value
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetOnlyOnIndexTableAlert(value bool) *Action {
|
||||
p.ShowOnIndexTableAlert = value
|
||||
p.ShowOnIndex = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnIndexTableRow = !value
|
||||
p.ShowOnForm = !value
|
||||
p.ShowOnFormExtra = !value
|
||||
p.ShowOnDetail = !value
|
||||
p.ShowOnDetailExtra = !value
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 除了表格多选弹出层外展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetExceptOnIndexTableAlert() *Action {
|
||||
p.ShowOnIndexTableAlert = false
|
||||
p.ShowOnIndex = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnIndexTableRow = true
|
||||
p.ShowOnForm = true
|
||||
p.ShowOnFormExtra = true
|
||||
p.ShowOnDetail = true
|
||||
p.ShowOnDetailExtra = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在列表页展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetShowOnIndex() *Action {
|
||||
p.ShowOnIndex = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在表单页展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetShowOnForm() *Action {
|
||||
p.ShowOnForm = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在表单页右上角自定义区域展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetShowOnFormExtra() *Action {
|
||||
p.ShowOnFormExtra = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在详情页展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetShowOnDetail() *Action {
|
||||
p.ShowOnDetail = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在详情页右上角自定义区域展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetShowOnDetailExtra() *Action {
|
||||
p.ShowOnDetailExtra = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在表格行内展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetShowOnIndexTableRow() *Action {
|
||||
p.ShowOnIndexTableRow = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 在多选弹出层展示
|
||||
*
|
||||
* @return p
|
||||
*/
|
||||
func (p *Action) SetShowOnIndexTableAlert() *Action {
|
||||
p.ShowOnIndexTableAlert = true
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否在列表页展示
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
func (p *Action) ShownOnIndex() bool {
|
||||
if p.OnlyOnIndex == true {
|
||||
return true
|
||||
}
|
||||
|
||||
if p.OnlyOnDetail {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.OnlyOnForm {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.ShowOnIndex
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否在表单页展示
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
func (p *Action) ShownOnForm() bool {
|
||||
if p.OnlyOnForm == true {
|
||||
return true
|
||||
}
|
||||
|
||||
if p.OnlyOnDetail {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.OnlyOnIndex {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.ShowOnForm
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否在详情页展示
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
func (p *Action) ShownOnDetail() bool {
|
||||
if p.OnlyOnDetail {
|
||||
return true
|
||||
}
|
||||
|
||||
if p.OnlyOnIndex {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.OnlyOnForm {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.ShowOnDetail
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否在表格行内展示
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
func (p *Action) ShownOnIndexTableRow() bool {
|
||||
return p.ShowOnIndexTableRow
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否在多选弹出层展示
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
func (p *Action) ShownOnIndexTableAlert() bool {
|
||||
return p.ShowOnIndexTableAlert
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否在表单页右上角自定义区域展示
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
func (p *Action) ShownOnFormExtra() bool {
|
||||
return p.ShowOnFormExtra
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否在详情页右上角自定义区域展示
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
func (p *Action) ShownOnDetailExtra() bool {
|
||||
return p.ShowOnDetailExtra
|
||||
}
|
37
pkg/builder/actions/drawer.go
Normal file
37
pkg/builder/actions/drawer.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package actions
|
||||
|
||||
import "github.com/quarkcms/quark-go/pkg/builder"
|
||||
|
||||
type Drawer struct {
|
||||
Action
|
||||
Width int `json:"width"`
|
||||
DestroyOnClose bool `json:"destroyOnClose"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Drawer) ParentInit() interface{} {
|
||||
p.ActionType = "drawer"
|
||||
p.Width = 520
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 宽度
|
||||
func (p *Drawer) GetWidth() int {
|
||||
return p.Width
|
||||
}
|
||||
|
||||
// 关闭时销毁 Modal 里的子元素
|
||||
func (p *Drawer) GetDestroyOnClose() bool {
|
||||
return p.DestroyOnClose
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *Drawer) GetBody(request *builder.Request, resourceInstance interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 弹窗行为
|
||||
func (p *Drawer) GetActions(request *builder.Request, resourceInstance interface{}) []interface{} {
|
||||
return []interface{}{}
|
||||
}
|
209
pkg/builder/actions/dropdown.go
Normal file
209
pkg/builder/actions/dropdown.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package actions
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/action"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/menu"
|
||||
)
|
||||
|
||||
type Dropdown struct {
|
||||
Action
|
||||
Arrow bool `json:"arrow"`
|
||||
Placement string `json:"placement"`
|
||||
Trigger []string `json:"trigger"`
|
||||
OverlayStyle map[string]interface{} `json:"overlayStyle"`
|
||||
Actions []interface{} `json:"actions"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Dropdown) ParentInit() interface{} {
|
||||
p.ActionType = "dropdown"
|
||||
p.Placement = "bottomLeft"
|
||||
p.Trigger = append(p.Trigger, "hover")
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 是否显示箭头图标
|
||||
func (p *Dropdown) GetArrow() bool {
|
||||
return p.Arrow
|
||||
}
|
||||
|
||||
// 菜单弹出位置:bottomLeft bottomCenter bottomRight topLeft topCenter topRight
|
||||
func (p *Dropdown) GetPlacement() string {
|
||||
return p.Placement
|
||||
}
|
||||
|
||||
// 触发下拉的行为, 移动端不支持 hover,Array<click|hover|contextMenu>
|
||||
func (p *Dropdown) GetTrigger() []string {
|
||||
return p.Trigger
|
||||
}
|
||||
|
||||
// 下拉根元素的样式
|
||||
func (p *Dropdown) GetOverlayStyle() map[string]interface{} {
|
||||
return p.OverlayStyle
|
||||
}
|
||||
|
||||
// 菜单
|
||||
func (p *Dropdown) GetOverlay(request *builder.Request, templateInstance interface{}) interface{} {
|
||||
actions := p.GetActions()
|
||||
items := []interface{}{}
|
||||
|
||||
for _, v := range actions {
|
||||
action := p.buildAction(request, v, templateInstance)
|
||||
items = append(items, action)
|
||||
}
|
||||
|
||||
return (&menu.Component{}).Init().SetItems(items)
|
||||
}
|
||||
|
||||
//创建行为组件
|
||||
func (p *Dropdown) buildAction(request *builder.Request, item interface{}, templateInstance interface{}) interface{} {
|
||||
name := item.(interface{ GetName() string }).GetName()
|
||||
withLoading := item.(interface{ GetWithLoading() bool }).GetWithLoading()
|
||||
reload := item.(interface{ GetReload() string }).GetReload()
|
||||
|
||||
// uri唯一标识
|
||||
uriKey := item.(interface {
|
||||
GetUriKey(interface{}) string
|
||||
}).GetUriKey(item)
|
||||
|
||||
// 获取api
|
||||
api := item.(interface {
|
||||
GetApi(*builder.Request) string
|
||||
}).GetApi(request)
|
||||
|
||||
// 获取api替换参数
|
||||
params := item.(interface {
|
||||
GetApiParams() []string
|
||||
}).GetApiParams()
|
||||
|
||||
if api == "" {
|
||||
api = p.buildActionApi(request, params, uriKey)
|
||||
}
|
||||
|
||||
actionType := item.(interface{ GetActionType() string }).GetActionType()
|
||||
buttonType := item.(interface{ GetType() string }).GetType()
|
||||
size := item.(interface{ GetSize() string }).GetSize()
|
||||
icon := item.(interface{ GetIcon() string }).GetIcon()
|
||||
confirmTitle := item.(interface{ GetConfirmTitle() string }).GetConfirmTitle()
|
||||
confirmText := item.(interface{ GetConfirmText() string }).GetConfirmText()
|
||||
confirmType := item.(interface{ GetConfirmType() string }).GetConfirmType()
|
||||
|
||||
getAction := (&menu.Item{}).Init().
|
||||
Init().
|
||||
SetLabel(name).
|
||||
SetWithLoading(withLoading).
|
||||
SetReload(reload).
|
||||
SetApi(api).
|
||||
SetActionType(actionType).
|
||||
SetType(buttonType, false).
|
||||
SetSize(size)
|
||||
|
||||
if icon != "" {
|
||||
getAction = getAction.
|
||||
SetIcon(icon)
|
||||
}
|
||||
|
||||
switch actionType {
|
||||
case "link":
|
||||
href := item.(interface {
|
||||
GetHref(request *builder.Request) string
|
||||
}).GetHref(request)
|
||||
target := item.(interface {
|
||||
GetTarget(request *builder.Request) string
|
||||
}).GetTarget(request)
|
||||
|
||||
getAction = getAction.
|
||||
SetLink(href, target).
|
||||
SetStyle(map[string]interface{}{
|
||||
"color": "#1890ff",
|
||||
})
|
||||
case "modal":
|
||||
formWidth := item.(interface {
|
||||
GetWidth() int
|
||||
}).GetWidth()
|
||||
|
||||
formDestroyOnClose := item.(interface {
|
||||
GetDestroyOnClose() bool
|
||||
}).GetDestroyOnClose()
|
||||
|
||||
formBody := item.(interface {
|
||||
GetBody(request *builder.Request, templateInstance interface{}) interface{}
|
||||
}).GetBody(request, templateInstance)
|
||||
|
||||
formActions := item.(interface {
|
||||
GetActions(request *builder.Request, templateInstance interface{}) []interface{}
|
||||
}).GetActions(request, templateInstance)
|
||||
|
||||
getAction = getAction.SetModal(func(modal *action.Modal) interface{} {
|
||||
return modal.
|
||||
SetTitle(name).
|
||||
SetWidth(formWidth).
|
||||
SetBody(formBody).
|
||||
SetActions(formActions).
|
||||
SetDestroyOnClose(formDestroyOnClose)
|
||||
})
|
||||
case "drawer":
|
||||
formWidth := item.(interface {
|
||||
GetWidth() int
|
||||
}).GetWidth()
|
||||
|
||||
formDestroyOnClose := item.(interface {
|
||||
GetDestroyOnClose() bool
|
||||
}).GetDestroyOnClose()
|
||||
|
||||
formBody := item.(interface {
|
||||
GetBody(request *builder.Request, templateInstance interface{}) interface{}
|
||||
}).GetBody(request, templateInstance)
|
||||
|
||||
formActions := item.(interface {
|
||||
GetActions(request *builder.Request, templateInstance interface{}) []interface{}
|
||||
}).GetActions(request, templateInstance)
|
||||
|
||||
getAction = getAction.SetDrawer(func(drawer *action.Drawer) interface{} {
|
||||
return drawer.
|
||||
SetTitle(name).
|
||||
SetWidth(formWidth).
|
||||
SetBody(formBody).
|
||||
SetActions(formActions).
|
||||
SetDestroyOnClose(formDestroyOnClose)
|
||||
})
|
||||
}
|
||||
|
||||
if confirmTitle != "" {
|
||||
getAction = getAction.
|
||||
SetWithConfirm(confirmTitle, confirmText, confirmType)
|
||||
}
|
||||
|
||||
return getAction
|
||||
}
|
||||
|
||||
// 下拉菜单行为
|
||||
func (p *Dropdown) SetActions(actions []interface{}) *Dropdown {
|
||||
p.Actions = actions
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 获取下拉菜单行为
|
||||
func (p *Dropdown) GetActions() []interface{} {
|
||||
return p.Actions
|
||||
}
|
||||
|
||||
//创建行为接口
|
||||
func (p *Dropdown) buildActionApi(request *builder.Request, params []string, uriKey string) string {
|
||||
paramsUri := ""
|
||||
for _, v := range params {
|
||||
paramsUri = paramsUri + v + "=${" + v + "}&"
|
||||
}
|
||||
|
||||
api := strings.Replace(request.Path(), "/index", "/action/"+uriKey, -1)
|
||||
if paramsUri != "" {
|
||||
api = api + "?" + paramsUri
|
||||
}
|
||||
|
||||
return api
|
||||
}
|
35
pkg/builder/actions/link.go
Normal file
35
pkg/builder/actions/link.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package actions
|
||||
|
||||
import "github.com/quarkcms/quark-go/pkg/builder"
|
||||
|
||||
type Link struct {
|
||||
Action
|
||||
Href string `json:"href"`
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Link) ParentInit() interface{} {
|
||||
p.ActionType = "link"
|
||||
p.Target = "_self"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取跳转链接
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Link) GetHref(request *builder.Request) string {
|
||||
return p.Href
|
||||
}
|
||||
|
||||
/**
|
||||
* 相当于 a 链接的 target 属性,href 存在时生效
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Link) GetTarget(request *builder.Request) string {
|
||||
return p.Target
|
||||
}
|
37
pkg/builder/actions/modal.go
Normal file
37
pkg/builder/actions/modal.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package actions
|
||||
|
||||
import "github.com/quarkcms/quark-go/pkg/builder"
|
||||
|
||||
type Modal struct {
|
||||
Action
|
||||
Width int `json:"width"`
|
||||
DestroyOnClose bool `json:"destroyOnClose"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Modal) ParentInit() interface{} {
|
||||
p.ActionType = "modal"
|
||||
p.Width = 520
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 宽度
|
||||
func (p *Modal) GetWidth() int {
|
||||
return p.Width
|
||||
}
|
||||
|
||||
// 关闭时销毁 Modal 里的子元素
|
||||
func (p *Modal) GetDestroyOnClose() bool {
|
||||
return p.DestroyOnClose
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *Modal) GetBody(request *builder.Request, templateInstance interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 弹窗行为
|
||||
func (p *Modal) GetActions(request *builder.Request, templateInstance interface{}) []interface{} {
|
||||
return []interface{}{}
|
||||
}
|
894
pkg/builder/adminfield.go
Normal file
894
pkg/builder/adminfield.go
Normal file
@@ -0,0 +1,894 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/form/fields"
|
||||
)
|
||||
|
||||
// 后台字段组件
|
||||
type AdminField struct{}
|
||||
|
||||
// ID组件
|
||||
func (p *AdminField) ID(params ...interface{}) *fields.ID {
|
||||
field := (&fields.ID{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// Hidden组件
|
||||
func (p *AdminField) Hidden(params ...interface{}) *fields.Hidden {
|
||||
field := (&fields.Hidden{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 输入框组件
|
||||
func (p *AdminField) Text(params ...interface{}) *fields.Text {
|
||||
field := (&fields.Text{}).Init()
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请输入" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请输入" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 文本域组件
|
||||
func (p *AdminField) TextArea(params ...interface{}) *fields.TextArea {
|
||||
field := (&fields.TextArea{}).Init()
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请输入" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请输入" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 密码框组件
|
||||
func (p *AdminField) Password(params ...interface{}) *fields.Password {
|
||||
field := (&fields.Password{}).Init()
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请输入" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请输入" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 单选组件
|
||||
func (p *AdminField) Radio(params ...string) *fields.Radio {
|
||||
field := &fields.Radio{}
|
||||
|
||||
if len(params) == 2 {
|
||||
field.Init().SetName(params[0]).SetLabel(params[1])
|
||||
} else {
|
||||
field.Init().SetName(params[0]).SetLabel(params[0])
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 多选组件
|
||||
func (p *AdminField) Checkbox(params ...string) *fields.Checkbox {
|
||||
field := &fields.Checkbox{}
|
||||
|
||||
if len(params) == 2 {
|
||||
field.Init().SetName(params[0]).SetLabel(params[1])
|
||||
} else {
|
||||
field.Init().SetName(params[0]).SetLabel(params[0])
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 日期组件
|
||||
func (p *AdminField) Date(params ...interface{}) *fields.Date {
|
||||
field := &fields.Date{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 日期范围组件
|
||||
func (p *AdminField) DateRange(params ...interface{}) *fields.DateRange {
|
||||
field := &fields.DateRange{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 日期时间组件
|
||||
func (p *AdminField) Datetime(params ...interface{}) *fields.Datetime {
|
||||
field := &fields.Datetime{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 日期时间范围组件
|
||||
func (p *AdminField) DatetimeRange(params ...interface{}) *fields.DatetimeRange {
|
||||
field := &fields.DatetimeRange{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 开关组件
|
||||
func (p *AdminField) Switch(params ...string) *fields.Switch {
|
||||
field := &fields.Switch{}
|
||||
|
||||
if len(params) == 2 {
|
||||
field.Init().SetName(params[0]).SetLabel(params[1])
|
||||
} else {
|
||||
field.Init().SetName(params[0]).SetLabel(params[0])
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 树形组件
|
||||
func (p *AdminField) Tree(params ...interface{}) *fields.Tree {
|
||||
field := (&fields.Tree{}).Init()
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请选择" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请选择" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 图标组件
|
||||
func (p *AdminField) Icon(params ...interface{}) *fields.Icon {
|
||||
field := (&fields.Icon{}).Init()
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请选择" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请选择" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 下拉框组件
|
||||
func (p *AdminField) Select(params ...interface{}) *fields.Select {
|
||||
field := (&fields.Select{}).Init()
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请选择" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请选择" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 级联菜单组件
|
||||
func (p *AdminField) Cascader(params ...interface{}) *fields.Select {
|
||||
field := (&fields.Select{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 图片组件
|
||||
func (p *AdminField) Image(params ...interface{}) *fields.Image {
|
||||
field := (&fields.Image{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 文件组件
|
||||
func (p *AdminField) File(params ...interface{}) *fields.File {
|
||||
field := (&fields.File{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 文本展示组件
|
||||
func (p *AdminField) Display(label string) *fields.Display {
|
||||
field := (&fields.Display{}).Init()
|
||||
field.SetLabel(label)
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 编辑器组件
|
||||
func (p *AdminField) Editor(params ...interface{}) *fields.Editor {
|
||||
field := (&fields.Editor{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 分组组件
|
||||
func (p *AdminField) Group(label string, items []interface{}) *fields.Group {
|
||||
field := (&fields.Group{}).Init()
|
||||
|
||||
field.SetBody(items).SetLabel(label)
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// List组件
|
||||
func (p *AdminField) List(params ...interface{}) *fields.List {
|
||||
field := (&fields.List{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 地图组件
|
||||
func (p *AdminField) Map(params ...interface{}) *fields.Map {
|
||||
field := (&fields.Map{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 地图围栏组件
|
||||
func (p *AdminField) Geofence(params ...interface{}) *fields.Geofence {
|
||||
field := (&fields.Geofence{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 日期-月组件
|
||||
func (p *AdminField) Month(params ...interface{}) *fields.Month {
|
||||
field := &fields.Month{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 数组输入框组件
|
||||
func (p *AdminField) Number(params ...interface{}) *fields.Number {
|
||||
field := (&fields.Number{}).Init()
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请输入" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.SetPlaceholder("请输入" + params[1].(string))
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 日期-季度组件
|
||||
func (p *AdminField) Quarter(params ...interface{}) *fields.Quarter {
|
||||
field := &fields.Quarter{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 搜索组件
|
||||
func (p *AdminField) Search(params ...interface{}) *fields.Search {
|
||||
field := (&fields.Search{}).Init()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 时间范围组件
|
||||
func (p *AdminField) TimeRange(params ...interface{}) *fields.TimeRange {
|
||||
field := &fields.TimeRange{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 时间组件
|
||||
func (p *AdminField) Time(params ...interface{}) *fields.Time {
|
||||
field := &fields.Time{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 周组件
|
||||
func (p *AdminField) Week(params ...interface{}) *fields.Week {
|
||||
field := &fields.Week{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// 年组件
|
||||
func (p *AdminField) Year(params ...interface{}) *fields.Year {
|
||||
field := &fields.Year{}
|
||||
|
||||
placeholder := reflect.
|
||||
ValueOf(field).
|
||||
Elem().
|
||||
FieldByName("Placeholder").String()
|
||||
|
||||
if len(params) >= 2 {
|
||||
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[1].(string))
|
||||
if len(params) == 3 {
|
||||
|
||||
// 判断是否为闭包函数
|
||||
closure, ok := params[2].(func() interface{})
|
||||
if ok {
|
||||
field.SetCallback(closure)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if placeholder == "" {
|
||||
field.Init().SetPlaceholder("请选择")
|
||||
}
|
||||
|
||||
field.SetName(params[0].(string)).SetLabel(params[0].(string))
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
// Select组合组件
|
||||
func (p *AdminField) Selects(body interface{}) *fields.Selects {
|
||||
field := &fields.Selects{}
|
||||
|
||||
field.Init().SetBody(body)
|
||||
|
||||
return field
|
||||
}
|
232
pkg/builder/builder.go
Normal file
232
pkg/builder/builder.go
Normal file
@@ -0,0 +1,232 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/quarkcms/quark-go/pkg/dal"
|
||||
"github.com/quarkcms/quark-go/pkg/github"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 静态文件URL
|
||||
const RespositoryURL = "https://github.com/quarkcms/quark-go/tree/2.0/website/"
|
||||
|
||||
type DBConfig struct {
|
||||
Dialector gorm.Dialector
|
||||
Opts gorm.Option
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
AppKey string // 应用加密Key,用于JWT认证
|
||||
AppName string // 应用名称
|
||||
DBConfig *DBConfig // 数据库配置
|
||||
StaticPath string // 静态文件目录
|
||||
Providers []interface{} // 服务列表
|
||||
AdminLayout *AdminLayout // 后台布局
|
||||
Routes []string // 路由列表
|
||||
}
|
||||
|
||||
// 全局配置
|
||||
var AppConfig *Config
|
||||
|
||||
// 初始化对象
|
||||
func New(config *Config) *Resource {
|
||||
|
||||
// 初始化数据库
|
||||
if config.DBConfig != nil {
|
||||
dal.InitDB(config.DBConfig.Dialector, config.DBConfig.Opts)
|
||||
}
|
||||
|
||||
// 初始化配置
|
||||
SetConfig(config)
|
||||
|
||||
// 定义结构体
|
||||
resource := &Resource{
|
||||
Providers: AppConfig.Providers,
|
||||
}
|
||||
|
||||
// 下载静态文件
|
||||
github.Download(RespositoryURL, config.StaticPath)
|
||||
|
||||
// 调用初始化方法
|
||||
return resource
|
||||
}
|
||||
|
||||
// 转换Request对象
|
||||
func (p *Resource) TransformRequest(request *Request) *Resource {
|
||||
requestInstance := request.Init()
|
||||
|
||||
// 定义结构体
|
||||
resource := &Resource{
|
||||
Providers: p.Providers,
|
||||
UseHandlers: p.UseHandlers,
|
||||
Request: requestInstance,
|
||||
}
|
||||
|
||||
// 初始化路由列表
|
||||
p.InitRoutes()
|
||||
|
||||
// 调用初始化方法
|
||||
return resource
|
||||
}
|
||||
|
||||
// 初始化路由列表
|
||||
func (p *Resource) InitRoutes() {
|
||||
if AppConfig.Routes != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var routes []string
|
||||
for _, provider := range AppConfig.Providers {
|
||||
|
||||
// 初始化
|
||||
getTemplateInstance := provider.(interface {
|
||||
Init() interface{}
|
||||
}).Init()
|
||||
|
||||
// 获取模板定义的路由
|
||||
templateInstanceRoutes := getTemplateInstance.(interface {
|
||||
GetRoutes() []*Route
|
||||
}).GetRoutes()
|
||||
|
||||
for _, v := range templateInstanceRoutes {
|
||||
providerName := reflect.TypeOf(provider).String()
|
||||
getNames := strings.Split(providerName, ".")
|
||||
structName := getNames[len(getNames)-1]
|
||||
|
||||
if strings.Contains(v.Path, ":resource") {
|
||||
path := strings.Replace(v.Path, ":resource", strings.ToLower(structName), -1)
|
||||
//处理行为
|
||||
if strings.Contains(path, ":uriKey") {
|
||||
actions := getTemplateInstance.(interface {
|
||||
Actions(request *Request) []interface{}
|
||||
}).Actions(p.Request)
|
||||
|
||||
for _, av := range actions {
|
||||
|
||||
// uri唯一标识
|
||||
uriKey := av.(interface {
|
||||
GetUriKey(interface{}) string
|
||||
}).GetUriKey(av)
|
||||
|
||||
actionType := av.(interface{ GetActionType() string }).GetActionType()
|
||||
if actionType == "dropdown" {
|
||||
dropdownActions := av.(interface{ GetActions() []interface{} }).GetActions()
|
||||
for _, dropdownAction := range dropdownActions {
|
||||
uriKey := dropdownAction.(interface {
|
||||
GetUriKey(interface{}) string
|
||||
}).GetUriKey(dropdownAction) // uri唯一标识
|
||||
|
||||
path = strings.Replace(path, ":uriKey", uriKey, -1)
|
||||
}
|
||||
} else {
|
||||
path = strings.Replace(path, ":uriKey", uriKey, -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
routes = append(routes, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AppConfig.Routes = routes
|
||||
}
|
||||
|
||||
// 获取后台默认布局
|
||||
func getDefaultAdminLayout(adminLayout *AdminLayout) *AdminLayout {
|
||||
defalutAdminLayout := &AdminLayout{
|
||||
"QuarkGo",
|
||||
false,
|
||||
[]map[string]interface{}{
|
||||
{
|
||||
"component": "icon",
|
||||
"icon": "icon-question-circle",
|
||||
"tooltip": "使用文档",
|
||||
"href": "https://www.quarkcms.com/",
|
||||
"target": "_blank",
|
||||
"style": map[string]interface{}{
|
||||
"color": "#000",
|
||||
},
|
||||
},
|
||||
},
|
||||
"side",
|
||||
false,
|
||||
"dark",
|
||||
"Fluid",
|
||||
"dark",
|
||||
"#1890ff",
|
||||
true,
|
||||
true,
|
||||
"//at.alicdn.com/t/font_1615691_3pgkh5uyob.js",
|
||||
"zh-CN",
|
||||
208,
|
||||
time.Now().Format("2006") + " QuarkGo",
|
||||
[]map[string]interface{}{
|
||||
{
|
||||
"title": "Quark",
|
||||
"href": "http://www.quarkcms.com/",
|
||||
},
|
||||
{
|
||||
"title": "爱小圈",
|
||||
"href": "http://www.ixiaoquan.com",
|
||||
},
|
||||
{
|
||||
"title": "Github",
|
||||
"href": "https://github.com/quarkcms",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 设置布局
|
||||
copier.CopyWithOption(defalutAdminLayout, adminLayout, copier.Option{IgnoreEmpty: true})
|
||||
|
||||
return defalutAdminLayout
|
||||
}
|
||||
|
||||
// 设置配置
|
||||
func SetConfig(config *Config) {
|
||||
|
||||
// 初始化后台布局
|
||||
config.AdminLayout = getDefaultAdminLayout(config.AdminLayout)
|
||||
|
||||
// 赋给全局变量
|
||||
AppConfig = config
|
||||
}
|
||||
|
||||
// 获取当前配置
|
||||
func GetConfig() *Config {
|
||||
|
||||
return AppConfig
|
||||
}
|
||||
|
||||
// 获取当前AdminLayout配置
|
||||
func GetAdminLayoutConfig() *AdminLayout {
|
||||
|
||||
return AppConfig.AdminLayout
|
||||
}
|
||||
|
||||
// 获取路由列表
|
||||
func GetRoutes() []string {
|
||||
|
||||
return AppConfig.Routes
|
||||
}
|
||||
|
||||
// 通用调用方法
|
||||
func (p *Resource) Use(args interface{}) *Resource {
|
||||
argsName := reflect.TypeOf(args).String()
|
||||
|
||||
switch argsName {
|
||||
case "*builder.AdminLayout":
|
||||
AppConfig.AdminLayout = getDefaultAdminLayout(args.(*AdminLayout))
|
||||
case "func(*builder.Request) error":
|
||||
p.UseHandlers = append(p.UseHandlers, args.(func(request *Request) error))
|
||||
default:
|
||||
panic(argsName + " arguments was not found")
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
14
pkg/builder/metrics/admin_descriptions.go
Normal file
14
pkg/builder/metrics/admin_descriptions.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/descriptions"
|
||||
)
|
||||
|
||||
type AdminDescriptions struct {
|
||||
AdminMetrics
|
||||
}
|
||||
|
||||
// 包含组件的结果
|
||||
func (p *AdminDescriptions) Result(value interface{}) *descriptions.Component {
|
||||
return (&descriptions.Component{}).Init().SetTitle(p.Title).SetItems(value)
|
||||
}
|
6
pkg/builder/metrics/admin_metrics.go
Normal file
6
pkg/builder/metrics/admin_metrics.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package metrics
|
||||
|
||||
type AdminMetrics struct {
|
||||
Title string
|
||||
Col int
|
||||
}
|
24
pkg/builder/metrics/admin_value.go
Normal file
24
pkg/builder/metrics/admin_value.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/statistic"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type AdminValue struct {
|
||||
AdminMetrics
|
||||
Precision int
|
||||
}
|
||||
|
||||
// 记录条数
|
||||
func (p *AdminValue) Count(DB *gorm.DB) *statistic.Component {
|
||||
var count int64
|
||||
DB.Count(&count)
|
||||
|
||||
return p.Result(count)
|
||||
}
|
||||
|
||||
// 包含组件的结果
|
||||
func (p *AdminValue) Result(value int64) *statistic.Component {
|
||||
return (&statistic.Component{}).Init().SetTitle(p.Title).SetValue(value)
|
||||
}
|
229
pkg/builder/request.go
Normal file
229
pkg/builder/request.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/derekstavis/go-qs"
|
||||
"github.com/gobeam/stringy"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
IPString string `json:"IPString"` // 请求的ip地址
|
||||
HeaderString string `json:"headerString"` // 请求的Header字符串
|
||||
MethodString string `json:"methodString"` // 请求方法
|
||||
FullPathString string `json:"fullPathString"` // 路由
|
||||
HostString string `json:"hostString"` // 主机地址
|
||||
PathString string `json:"pathString"` // URL路径
|
||||
QueryString string `json:"queryString"` // 请求参数
|
||||
Headers map[string]string `json:"headers"` // 请求的Headers
|
||||
Params map[string]string `json:"params"` // URL param
|
||||
Querys map[string]interface{} `json:"querys"` // URL querys
|
||||
BodyBuffer []byte `json:"bodyBuffer"` // 请求的Body数据
|
||||
}
|
||||
|
||||
type ParamValue struct {
|
||||
Key int
|
||||
Value string
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Request) Init() *Request {
|
||||
p.parseParams()
|
||||
p.parseHeaders()
|
||||
p.parseQuerys()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// Method return request method.
|
||||
//
|
||||
// Returned value is valid until returning from RequestHandler.
|
||||
func (p *Request) Method() string {
|
||||
return p.MethodString
|
||||
}
|
||||
|
||||
// FullPath returns a matched route full path. For not found routes
|
||||
// returns an empty string.
|
||||
//
|
||||
// router.GET("/user/:id", func(c *hertz.RequestContext) {
|
||||
// c.FullPath() == "/user/:id" // true
|
||||
// })
|
||||
func (p *Request) FullPath() string {
|
||||
return p.FullPathString
|
||||
}
|
||||
|
||||
// Host returns requested host.
|
||||
//
|
||||
// The host is valid until returning from RequestHandler.
|
||||
func (p *Request) Host() string {
|
||||
return p.HostString
|
||||
}
|
||||
|
||||
// Path returns requested path.
|
||||
//
|
||||
// The path is valid until returning from RequestHandler.
|
||||
func (p *Request) Path() string {
|
||||
return p.PathString
|
||||
}
|
||||
|
||||
// IP tries to parse the headers in [X-Real-Ip, X-Forwarded-For]. It calls RemoteIP() under the hood
|
||||
func (p *Request) IP() string {
|
||||
return p.IPString
|
||||
}
|
||||
|
||||
// OriginalURL returns url query data
|
||||
func (p *Request) OriginalURL() string {
|
||||
return p.QueryString
|
||||
}
|
||||
|
||||
// Body returns body data
|
||||
func (p *Request) Body() []byte {
|
||||
return p.BodyBuffer
|
||||
}
|
||||
|
||||
// Param returns the value of the URL param.
|
||||
// It is a shortcut for c.Params.ByName(key)
|
||||
func (p *Request) parseParams() {
|
||||
params := map[string]string{}
|
||||
fullPaths := strings.Split(p.FullPath(), "/")
|
||||
paramValues := []*ParamValue{}
|
||||
for k, v := range fullPaths {
|
||||
if strings.Contains(v, ":") {
|
||||
v = stringy.New(v).ReplaceFirst(":", "")
|
||||
mapValue := &ParamValue{
|
||||
Key: k,
|
||||
Value: v,
|
||||
}
|
||||
paramValues = append(paramValues, mapValue)
|
||||
}
|
||||
}
|
||||
|
||||
paths := strings.Split(p.Path(), "/")
|
||||
for _, v := range paramValues {
|
||||
params[v.Value] = paths[v.Key]
|
||||
}
|
||||
|
||||
p.Params = params
|
||||
}
|
||||
|
||||
// Param returns the value of the URL param.
|
||||
// It is a shortcut for c.Params.ByName(key)
|
||||
//
|
||||
// router.GET("/user/:id", func(c *hertz.RequestContext) {
|
||||
// // a GET request to /user/john
|
||||
// id := c.Param("id") // id == "john"
|
||||
// })
|
||||
func (p *Request) Param(key string) string {
|
||||
return p.Params[key]
|
||||
}
|
||||
|
||||
// Query returns the value of the URL Querys.
|
||||
func (p *Request) parseQuerys() {
|
||||
querys, err := qs.Unmarshal(p.QueryString)
|
||||
if err == nil {
|
||||
p.Querys = querys
|
||||
}
|
||||
}
|
||||
|
||||
// Query returns the value of the URL query.
|
||||
func (p *Request) Query(params ...interface{}) interface{} {
|
||||
if len(params) == 2 {
|
||||
if p.Querys[params[0].(string)] == nil {
|
||||
return params[1]
|
||||
}
|
||||
}
|
||||
|
||||
return p.Querys[params[0].(string)]
|
||||
}
|
||||
|
||||
// AllQuerys returns all query arguments from RequestURI.
|
||||
func (p *Request) AllQuerys() map[string]interface{} {
|
||||
return p.Querys
|
||||
}
|
||||
|
||||
// ResourceName returns the value of the URL Resource param.
|
||||
// If request path is "/api/admin/login/index" and route is "/api/admin/login/:resource"
|
||||
//
|
||||
// resourceName := p.ResourceName() // resourceName = "index"
|
||||
func (p *Request) ResourceName() string {
|
||||
return p.Param("resource")
|
||||
}
|
||||
|
||||
// BodyParser binds the request body to a struct.
|
||||
// It supports decoding the following content types based on the Content-Type header:
|
||||
// application/json, application/xml, application/x-www-form-urlencoded, multipart/form-data
|
||||
// If none of the content types above are matched, it will return a ErrUnprocessableEntity error
|
||||
func (p *Request) BodyParser(out interface{}) error {
|
||||
return json.Unmarshal(p.BodyBuffer, out)
|
||||
}
|
||||
|
||||
// 解析头部数据
|
||||
func (p *Request) parseHeaders() {
|
||||
params := map[string]string{}
|
||||
headers := strings.Split(p.HeaderString, "\r\n")
|
||||
for _, v := range headers {
|
||||
header := strings.Split(v, ": ")
|
||||
if len(header) == 2 {
|
||||
params[header[0]] = header[1]
|
||||
}
|
||||
}
|
||||
|
||||
p.Headers = params
|
||||
}
|
||||
|
||||
// 获取请求头数据
|
||||
func (p *Request) Header(key string) string {
|
||||
return p.Headers[key]
|
||||
}
|
||||
|
||||
// 获取Header中的token
|
||||
func (p *Request) Token() string {
|
||||
authorization := p.Header("Authorization")
|
||||
authorizations := strings.Split(authorization, " ")
|
||||
if len(authorizations) == 2 {
|
||||
return authorizations[1]
|
||||
}
|
||||
|
||||
queryToken := p.Query("token", "")
|
||||
if queryToken.(string) != "" {
|
||||
return queryToken.(string)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// 判断当前页面是否为列表页面 todo
|
||||
func (p *Request) IsIndex() bool {
|
||||
uri := strings.Split(p.Path(), "/")
|
||||
|
||||
return (uri[len(uri)-1] == "index")
|
||||
}
|
||||
|
||||
//判断当前页面是否为创建页面
|
||||
func (p *Request) IsCreating() bool {
|
||||
uri := strings.Split(p.Path(), "/")
|
||||
|
||||
return (uri[len(uri)-1] == "create") || (uri[len(uri)-1] == "store")
|
||||
}
|
||||
|
||||
// 判断当前页面是否为编辑页面
|
||||
func (p *Request) IsEditing() bool {
|
||||
uri := strings.Split(p.Path(), "/")
|
||||
|
||||
return (uri[len(uri)-1] == "edit") || (uri[len(uri)-1] == "update")
|
||||
}
|
||||
|
||||
// 判断当前页面是否为详情页面
|
||||
func (p *Request) IsDetail() bool {
|
||||
uri := strings.Split(p.Path(), "/")
|
||||
|
||||
return (uri[len(uri)-1] == "detail")
|
||||
}
|
||||
|
||||
// 判断当前页面是否为导出页面
|
||||
func (p *Request) isExport() bool {
|
||||
uri := strings.Split(p.Path(), "/")
|
||||
|
||||
return (uri[len(uri)-1] == "export")
|
||||
}
|
169
pkg/builder/resource.go
Normal file
169
pkg/builder/resource.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Route struct {
|
||||
Path string
|
||||
HandlerName string
|
||||
}
|
||||
|
||||
type AdminLayout struct {
|
||||
Title string // layout 的左上角 的 title
|
||||
Logo interface{} // layout 的左上角 的 logo
|
||||
HeaderActions []map[string]interface{} // layout 的头部行为
|
||||
Layout string // layout 的菜单模式,side:右侧导航,top:顶部导航,mix:混合模式
|
||||
SplitMenus bool // layout 的菜单模式为mix时,是否自动分割菜单
|
||||
HeaderTheme string // layout 的菜单模式为mix时,顶部主题 'dark' | 'light'
|
||||
ContentWidth string // layout 的内容模式,Fluid:定宽 1200px,Fixed:自适应
|
||||
NavTheme string // 导航的主题,'light' | 'dark'
|
||||
PrimaryColor string // 主题色,"#1890ff"
|
||||
FixedHeader bool // 是否固定 header 到顶部
|
||||
FixSiderbar bool // 是否固定导航
|
||||
IconfontUrl string // 使用 IconFont 的图标配置
|
||||
Locale string // 当前 layout 的语言设置,'zh-CN' | 'zh-TW' | 'en-US'
|
||||
SiderWidth int // 侧边菜单宽度
|
||||
Copyright string // 网站版权 time.Now().Format("2006") + " QuarkGo"
|
||||
Links []map[string]interface{} // 友情链接
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
Providers []interface{} // 服务列表
|
||||
Request *Request // 请求数据
|
||||
TemplateInstance interface{} // 资源模板实例
|
||||
UseHandlers []func(request *Request) error // 中间件方法
|
||||
}
|
||||
|
||||
// 解析UseHandler方法
|
||||
func (p *Resource) UseHandlerParser() error {
|
||||
var err error
|
||||
|
||||
// 执行本资源的方法
|
||||
for _, Handler := range p.UseHandlers {
|
||||
err = Handler(p.Request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析路由方法
|
||||
func (p *Resource) RouteParser() (interface{}, error) {
|
||||
var (
|
||||
result interface{}
|
||||
err error
|
||||
templateInstance interface{}
|
||||
)
|
||||
|
||||
// 获取模板实例
|
||||
templateInstance, err = p.GetTemplateInstance()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置模板实例
|
||||
p.SetTemplateInstance(templateInstance)
|
||||
|
||||
// 执行挂载的方法
|
||||
templateInstanceRoutes := templateInstance.(interface {
|
||||
GetRoutes() []*Route
|
||||
}).GetRoutes()
|
||||
|
||||
for _, v := range templateInstanceRoutes {
|
||||
if v.Path == p.Request.FullPath() {
|
||||
handlerResult := reflect.
|
||||
ValueOf(templateInstance).
|
||||
MethodByName(v.HandlerName).
|
||||
Call([]reflect.Value{
|
||||
reflect.ValueOf(p.Request),
|
||||
reflect.ValueOf(p),
|
||||
reflect.ValueOf(templateInstance),
|
||||
})
|
||||
|
||||
if len(handlerResult) == 1 {
|
||||
result = handlerResult[0].Interface()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 替换路由中的资源参数
|
||||
//
|
||||
// url := p.RouteToResourceUrl("/api/admin/login/:resource/captchaId") // url = "/api/admin/login/index/captchaId"
|
||||
func (p *Resource) RouteToResourceUrl(route string) string {
|
||||
resourceName := p.Request.ResourceName()
|
||||
|
||||
return strings.ReplaceAll(route, ":resource", resourceName)
|
||||
}
|
||||
|
||||
// 根据路由判断是否为当前加载实例
|
||||
func (p *Resource) IsCurrentTemplateInstance(provider interface{}) bool {
|
||||
providerName := reflect.TypeOf(provider).String()
|
||||
getNames := strings.Split(providerName, ".")
|
||||
structName := getNames[len(getNames)-1]
|
||||
resourceName := p.Request.ResourceName()
|
||||
|
||||
// fmt.Println(providerName)
|
||||
// fmt.Println(resourceName)
|
||||
|
||||
return strings.EqualFold(strings.ToLower(structName), strings.ToLower(resourceName))
|
||||
}
|
||||
|
||||
// 获取当前模板实例
|
||||
func (p *Resource) GetTemplateInstance() (interface{}, error) {
|
||||
var templateInstance interface{}
|
||||
|
||||
for _, provider := range p.Providers {
|
||||
|
||||
// 初始化
|
||||
getTemplateInstance := provider.(interface {
|
||||
Init() interface{}
|
||||
}).Init()
|
||||
|
||||
// 获取模板定义的路由
|
||||
templateInstanceRoutes := getTemplateInstance.(interface {
|
||||
GetRoutes() []*Route
|
||||
}).GetRoutes()
|
||||
|
||||
for _, v := range templateInstanceRoutes {
|
||||
if v.Path == p.Request.FullPath() {
|
||||
if p.IsCurrentTemplateInstance(provider) {
|
||||
// 设置实例
|
||||
templateInstance = getTemplateInstance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if templateInstance == nil {
|
||||
return nil, errors.New("未获取到实例")
|
||||
}
|
||||
|
||||
return templateInstance, nil
|
||||
}
|
||||
|
||||
// 设置当前模板实例
|
||||
func (p *Resource) SetTemplateInstance(templateInstance interface{}) {
|
||||
// 设置实例
|
||||
p.TemplateInstance = templateInstance
|
||||
}
|
||||
|
||||
// 处理执行
|
||||
func (p *Resource) Run() (interface{}, error) {
|
||||
|
||||
// 解析UseHandler方法
|
||||
err := p.UseHandlerParser()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 解析路由
|
||||
return p.RouteParser()
|
||||
}
|
12
pkg/builder/searches/date.go
Normal file
12
pkg/builder/searches/date.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package searches
|
||||
|
||||
type Date struct {
|
||||
Search
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Date) ParentInit() interface{} {
|
||||
p.Component = "date"
|
||||
|
||||
return p
|
||||
}
|
13
pkg/builder/searches/date_range.go
Normal file
13
pkg/builder/searches/date_range.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package searches
|
||||
|
||||
type DateRange struct {
|
||||
Search
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *DateRange) ParentInit() interface{} {
|
||||
p.Component = "date"
|
||||
p.Operator = "between"
|
||||
|
||||
return p
|
||||
}
|
12
pkg/builder/searches/datetime.go
Normal file
12
pkg/builder/searches/datetime.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package searches
|
||||
|
||||
type Datetime struct {
|
||||
Search
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Datetime) ParentInit() interface{} {
|
||||
p.Component = "datetime"
|
||||
|
||||
return p
|
||||
}
|
13
pkg/builder/searches/datetime_range.go
Normal file
13
pkg/builder/searches/datetime_range.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package searches
|
||||
|
||||
type DatetimeRange struct {
|
||||
Search
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *DatetimeRange) ParentInit() interface{} {
|
||||
p.Component = "datetime"
|
||||
p.Operator = "between"
|
||||
|
||||
return p
|
||||
}
|
101
pkg/builder/searches/search.go
Normal file
101
pkg/builder/searches/search.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package searches
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gobeam/stringy"
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Search struct {
|
||||
Column string `json:"column"`
|
||||
Name string `json:"name"`
|
||||
Component string `json:"component"`
|
||||
Operator string `json:"operator"`
|
||||
Api string `json:"api"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Search) ParentInit() interface{} {
|
||||
p.Component = "input"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段名
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Search) GetColumn(search interface{}) string {
|
||||
|
||||
if p.Column == "" {
|
||||
column := reflect.TypeOf(search).String()
|
||||
column = strings.Replace(column, "*searches.", "", -1)
|
||||
return stringy.New(column).ToLower()
|
||||
}
|
||||
|
||||
return p.Column
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取名称
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Search) GetName() string {
|
||||
return p.Name
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组件名称
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Search) GetComponent() string {
|
||||
return p.Component
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取接口
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Search) GetApi() string {
|
||||
return p.Api
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作符
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
func (p *Search) GetOperator() string {
|
||||
return p.Operator
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
func (p *Search) GetDefault() interface{} {
|
||||
return true
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
func (p *Search) Apply(request *builder.Request, query *gorm.DB, value interface{}) *gorm.DB {
|
||||
return query
|
||||
}
|
||||
|
||||
// 属性
|
||||
func (p *Search) Options(request *builder.Request) map[interface{}]interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 单向联动,返回数据类型:map[string]string{"field": "you_want_load_field","api": "admin/resource_name/action/select-options"}
|
||||
func (p *Search) Load(request *builder.Request) map[string]string {
|
||||
return nil
|
||||
}
|
12
pkg/builder/searches/select.go
Normal file
12
pkg/builder/searches/select.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package searches
|
||||
|
||||
type Select struct {
|
||||
Search
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Select) ParentInit() interface{} {
|
||||
p.Component = "select"
|
||||
|
||||
return p
|
||||
}
|
110
pkg/builder/template/admindashboard/admindashboard.go
Normal file
110
pkg/builder/template/admindashboard/admindashboard.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package admindashboard
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/quarkcms/quark-go/pkg/builder"
|
||||
"github.com/quarkcms/quark-go/pkg/builder/template"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/card"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/descriptions"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/grid"
|
||||
"github.com/quarkcms/quark-go/pkg/component/admin/statistic"
|
||||
"github.com/quarkcms/quark-go/pkg/dal/db"
|
||||
"github.com/quarkcms/quark-go/pkg/msg"
|
||||
)
|
||||
|
||||
// 后台登录模板
|
||||
type Template struct {
|
||||
template.AdminTemplate
|
||||
Title string // 标题
|
||||
SubTitle string // 子标题
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (p *Template) Init() interface{} {
|
||||
p.TemplateInit()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 初始化模板
|
||||
func (p *Template) TemplateInit() interface{} {
|
||||
|
||||
// 初始化数据对象
|
||||
p.DB = db.Client
|
||||
|
||||
// 清空路由
|
||||
p.Routes = nil
|
||||
|
||||
// 注册路由
|
||||
p.AddRoute("/api/admin/dashboard/:resource/index", "Render") // 后台仪表盘路由
|
||||
|
||||
// 标题
|
||||
p.Title = "仪表盘"
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// 内容
|
||||
func (p *Template) Cards(request *builder.Request) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 组件渲染
|
||||
func (p *Template) Render(request *builder.Request, resource *builder.Resource, templateInstance interface{}) interface{} {
|
||||
cards := templateInstance.(interface {
|
||||
Cards(*builder.Request) interface{}
|
||||
}).Cards(request)
|
||||
if cards == nil {
|
||||
return msg.Error("请实现Cards内容", "")
|
||||
}
|
||||
|
||||
var cols []interface{}
|
||||
var body []interface{}
|
||||
var colNum int = 0
|
||||
for key, v := range cards.([]interface{}) {
|
||||
|
||||
// 断言statistic组件类型
|
||||
statistic, ok := v.(interface{ Calculate() *statistic.Component })
|
||||
item := (&card.Component{}).Init()
|
||||
if ok {
|
||||
item = item.SetBody(statistic.Calculate())
|
||||
} else {
|
||||
// 断言descriptions组件类型
|
||||
descriptions, ok := v.(interface {
|
||||
Calculate() *descriptions.Component
|
||||
})
|
||||
if ok {
|
||||
item = item.SetBody(descriptions.Calculate())
|
||||
}
|
||||
}
|
||||
|
||||
col := reflect.
|
||||
ValueOf(v).
|
||||
Elem().
|
||||
FieldByName("Col").Int()
|
||||
colInfo := (&grid.Col{}).Init().SetSpan(int(col)).SetBody(item)
|
||||
cols = append(cols, colInfo)
|
||||
colNum = colNum + int(col)
|
||||
if colNum%24 == 0 {
|
||||
row := (&grid.Row{}).Init().SetGutter(8).SetBody(cols)
|
||||
if key != 1 {
|
||||
row = row.SetStyle(map[string]interface{}{"marginTop": "20px"})
|
||||
}
|
||||
body = append(body, row)
|
||||
cols = nil
|
||||
}
|
||||
}
|
||||
|
||||
if cols != nil {
|
||||
row := (&grid.Row{}).Init().SetGutter(8).SetBody(cols)
|
||||
if colNum > 24 {
|
||||
row = row.SetStyle(map[string]interface{}{"marginTop": "20px"})
|
||||
}
|
||||
body = append(body, row)
|
||||
}
|
||||
|
||||
return templateInstance.(interface {
|
||||
PageComponentRender(request *builder.Request, templateInstance interface{}, body interface{}) interface{}
|
||||
}).PageComponentRender(request, templateInstance, body)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user