{"id":30930267,"url":"https://github.com/peteryangs/superadminpage20","last_synced_at":"2026-02-14T11:05:59.999Z","repository":{"id":133974900,"uuid":"373555501","full_name":"PeterYangs/superAdminPage20","owner":"PeterYangs","description":"superAdminPage20","archived":false,"fork":false,"pushed_at":"2025-03-13T13:53:06.000Z","size":283,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-13T14:37:06.635Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PeterYangs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-03T15:27:42.000Z","updated_at":"2025-03-13T13:53:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"443ef7c1-a0d6-4128-9f38-f8f6ee8780f6","html_url":"https://github.com/PeterYangs/superAdminPage20","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/PeterYangs/superAdminPage20","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminPage20","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminPage20/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminPage20/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminPage20/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PeterYangs","download_url":"https://codeload.github.com/PeterYangs/superAdminPage20/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeterYangs%2FsuperAdminPage20/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274448137,"owners_count":25287120,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-10T10:44:03.372Z","updated_at":"2026-02-14T11:05:54.979Z","avatar_url":"https://github.com/PeterYangs.png","language":"Vue","funding_links":[],"categories":[],"sub_categories":[],"readme":"# superAdmin\n\n开箱即用的后台框架\n\n[中文文档](https://www.kancloud.cn/peter_yang/v001/2401726)\n\n### 在线demo\n\nhttps://www.peterdemo.net\n\n账号：test\n\n密码：Aa123456\n\n### 前端仓库\nhttps://github.com/PeterYangs/superAdminPage20\n\n### 环境要求\n\nredis\n\nmysql\n\n### Quick start\n\n**controller**\n\n```go\npackage controller\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"github.com/gin-gonic/gin\"\n\t\"gin-web/response\"\n)\n\n// Index 主页\nfunc Index(c *contextPlus.Context) *response.Response {\n\n\treturn response.Resp().Json(gin.H{\"data\": \"hello world\"})\n}\n```\n\n**route**\n\nroute/web.go\n\n```go\npackage routes\n\nimport (\n\t\"gin-web/controller\"\n\t\"gin-web/controller/file\"\n\t\"gin-web/controller/regex\"\n\t\"gin-web/kernel\"\n\t\"gin-web/middleware\"\n\t\"github.com/gin-gonic/gin\"\n)\n\nfunc _init(_r group) {\n\n\t//路由组，支持嵌套\n\t_r.Group(\"/api\", func(g group) {\n\n\t\tg.Registered(GET, \"/\", controller.Index).Bind()\n\t\tg.Registered(GET, \"/gg\", controller.Index).Bind()\n\n\t\tg.Group(\"/login\", func(g2 group) {\n\n\t\t\tg2.Registered(GET, \"/\", controller.Index).Bind()\n\t\t})\n\n\t}, middleware.GoOn)\n\n\t//单路由\n\t_r.Registered(GET, \"/\", controller.Index).Bind()\n\n\t_r.Registered(GET, \"/check\", controller.CheckCaptcha).Bind()\n\n}\n\n```\n\n**session**\n\n```go\nfunc Session(c *contextPlus.Context) *response.Response {\n\n    c.Session.Set(\"key\", \"value\")\n\n    c.Session.Get(\"key\")\n\n    return nil\n}\n```\n\n**全局中间件**\n\n```go\npackage kernel\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"gin-web/middleware/accessLog\"\n\t\"gin-web/middleware/exception\"\n\t\"gin-web/middleware/session\"\n)\n\n// Middleware 全局中间件\nvar Middleware []contextPlus.HandlerFunc\n\nfunc Load() {\n\n\tMiddleware = []contextPlus.HandlerFunc{\n\t\texception.Exception,\n\t\tsession.StartSession,\n\t\taccessLog.AccessLog,\n\t}\n\n}\n```\n\n\n\n**验证码**\n\n获取验证码\n\n```go\nfunc Captcha(c *contextPlus.Context) *response.Response {\n\n    b := c.GetCaptcha()\n\n    c.Header(\"content-type\", \"image/png\")\n\n    return response.Resp().Byte(b)\n}\n```\n\n检查验证码\n\n```go\nfunc CheckCaptcha(c *contextPlus.Context) *response.Response {\n\n    code := c.Query(\"code\")\n\n    bool:= c.CheckCaptcha(code)\n\n    return response.Resp().Json(gin.H{\"bool\":code})\n\n}\n```\n\n**参数验证**\n\n```go\npackage regex\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"github.com/gin-gonic/gin\"\n)\n\n// Regex 参数规则验证示例，路由为 /regex/:name ,请求为 /regex/1sds?test[]=1\u0026test[]=2,regex标记只支持string和[]string两个类型\nfunc Regex(c *contextPlus.Context) *response.Response {\n\n\ttype regex struct {\n\t\tTest []string `form:\"test[]\" json:\"test\" regex:\"[0-9a-z/]+\"`\n\t\tName string   `uri:\"name\" json:\"name\" regex:\"[0-9a-z]+\"`\n\t}\n\n\tvar t regex\n\n\terr := c.ShouldBindPlus(\u0026t)\n\n\tif err != nil {\n\n\t\treturn response.Resp().Json(gin.H{\"code\": 2, \"msg\": err.Error()})\n\n\t}\n\n\treturn response.Resp().Json(gin.H{\"code\": 1, \"msg\": \"hello world\"})\n}\n\n```\n\n**数据库迁移**\n\n```shell\n\n[root@localhost ~]# go run  .\\artisan\\bin\\artisan.go\nUse the arrow keys to navigate: ↓ ↑ → ←\n? 选择类型:\n  \u003e 数据库迁移\n    数据填充\n    生成key\n    生成任务类\n\n```\n\n迁移文件\n\n```go\npackage migrate_2019_08_12_055619_create_admin_table\n\nimport \"gin-web/migrate\"\n\nfunc Up() {\n\n\tmigrate.Create(\"admin\", func(createMigrate *migrate.Migrate) {\n\n\t\tcreateMigrate.Name = \"migrate_2019_08_12_055619_create_admin_table\"\n\n\t\t//主键\n\t\tcreateMigrate.BigIncrements(\"id\")\n\n\t\t//int\n\t\tcreateMigrate.Integer(\"user_id\").Unsigned().Nullable().Default(0).Unique().Comment(\"用户id\")\n\n\t\t//varchar\n\t\tcreateMigrate.String(\"title\", 255).Default(\"\").Comment(\"标题\")\n\n\t\t//text\n\t\tcreateMigrate.Text(\"content\").Default(migrate.Null).Comment(\"内容\")\n\n\t\t//索引\n\t\tcreateMigrate.Unique(\"user_id\", \"title\")\n\n\t})\n\n}\n\nfunc Down() {\n\n\tmigrate.DropIfExists(\"admin\")\n\n}\n\n```\n\n**限流器**\n\n```go\npackage loginLimiter\n\nimport (\n\t\"gin-web/component/limiter\"\n\t\"gin-web/contextPlus\"\n\t\"golang.org/x/time/rate\"\n\t\"time\"\n)\n\nfunc LoginLimiter(c *contextPlus.Context) {\n\n\t//每秒生成一个令牌，桶的大小是10,第三个参数是自定义key，根据自定义的key寻找限流器（默认是每1分钟清理一次过期的限流器）\n\tif !limiter.NewLimiter(rate.Every(1*time.Second), 10, c.ClientIP()).Allow() {\n\n\t\tc.String(500, \"访问频率过高\")\n\n\t\tc.Abort()\n\n\t}\n\n}\n\n```\n\n**分布式锁**\n\n非阻塞\n\n```go\nfunc Index(c *contextPlus.Context) *response.Response {\n\n    //申请一个锁，过期时间是10秒\n    lock := redis.GetClient().Lock(\"lock\", 10*time.Second)\n\n    //释放锁\n    defer lock.Release()\n\n    //是否拿到锁\n    if lock.Get() {\n\n        return response.Resp().Json(gin.H{\"res\": true})\n    \n    }\n\n    return response.Resp().Json(gin.H{\"res\": false})\n\n}\n```\n\n阻塞\n\n```go\nfunc Index(c *contextPlus.Context) *response.Response {\n\n    //申请一个锁，过期时间是10秒\n    lock := redis.GetClient().Lock(\"lock\", 10*time.Second)\n\n    defer lock.Release()\n\n    //是否拿到锁\n    if lock.Block(time.Second * 3) {\n    \t\n    \ttime.Sleep(4 * time.Second)\n\n        return response.Resp().Json(gin.H{\"res\": true})\n    }\n\n    return response.Resp().Json(gin.H{\"res\": false})\n\n}\n```\n\n**消息队列**\n\n生成任务类\n```shell\n[root@localhost superAdminApi20]# go run artisan/bin/artisan.go\nUse the arrow keys to navigate: ↓ ↑ → ←\n? 选择类型:\n    数据库迁移\n    数据填充\n    生成key\n  \u003e 生成任务类\n```\n\n任务类\n```go\npackage access\n\nimport (\n\t\"gin-web/database\"\n\t\"gin-web/model\"\n\t\"gin-web/task\"\n)\n\ntype TaskAccess struct {\n\ttask.BaseTask\n\tParameters *Parameter\n}\n\ntype Parameter struct {\n\ttask.Parameter\n\tIp      string\n\tUrl     string\n\tParams  string\n\tAdminId float64\n}\n\nfunc NewTask(ip string, url string, params string, adminId float64) *TaskAccess {\n\n\treturn \u0026TaskAccess{\n\n\t\tBaseTask: task.BaseTask{\n\t\t\tTaskName: \"access\",\n\t\t},\n\t\tParameters: \u0026Parameter{\n\t\t\tIp:      ip,\n\t\t\tUrl:     url,\n\t\t\tParams:  params,\n\t\t\tAdminId: adminId,\n\t\t},\n\t}\n}\n\nfunc (t *TaskAccess) Run() {\n\n\tdatabase.GetDb().Create(\u0026model.Access{\n\t\tIp:      t.Parameters.Ip,\n\t\tUrl:     t.Parameters.Url,\n\t\tParams:  t.Parameters.Params,\n\t\tAdminId: t.Parameters.AdminId,\n\t})\n\n}\n\nfunc (t *TaskAccess) BindParameters(p map[string]interface{}) {\n\n\tt.BaseTask.Bind(t.Parameters, p)\n\n}\n\n```\n\n\n即时任务\n\n```go\npackage controller\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"gin-web/queue\"\n\t\"gin-web/response\"\n\t\"gin-web/task/email\"\n\t\"gin-web/task/sms\"\n)\n\nfunc Task(c *contextPlus.Context) *response.Response {\n\n\tqueue.Dispatch(email.NewTask(\"904801074@qq.com\", \"title\", \"content\")).Queue(\"low\").Run()\n\n\treturn response.Resp().Api(1, \"123\", \"\")\n\n}\n```\n\n延迟队列\n\n```go\npackage controller\n\nimport (\n\t\"gin-web/contextPlus\"\n\t\"gin-web/queue\"\n\t\"gin-web/response\"\n\t\"gin-web/task/email\"\n\t\"gin-web/task/sms\"\n\t\"time\"\n)\n\nfunc Task(c *contextPlus.Context) *response.Response {\n\n\tqueue.Dispatch(email.NewTask(\"904801074@qq.com\", \"title\", \"content\")).Queue(\"low\").Delay(100 * time.Second).Run()\n\n\treturn response.Resp().Api(1, \"123\", \"\")\n\n}\n```\n**任务调度**\n\ncrontab/conf.go\n```go\npackage crontab\n\nimport \"fmt\"\n\nfunc Registered(c *crontab) {\n\n\tc.newSchedule().everyHour().function(func() {\n\n\t\tfmt.Println(\"每小时\")\n\n\t})\n\n\tc.newSchedule().hourlyAt(16).everyMinute().function(func() {\n\n\t\tfmt.Println(\"每个16点的每分钟\")\n\n\t})\n\n\tc.newSchedule().minuteAt(18).function(func() {\n\n\t\tfmt.Println(\"每小时的第18分钟\")\n\n\t})\n\n\tc.newSchedule().everyMinute().function(func() {\n\n\t\t//panic(\"模拟报错\")\n\n\t\tfmt.Println(\"每分钟\")\n\n\t})\n\n\tc.newSchedule().everyMinuteAt(2).function(func() {\n\n\t\tfmt.Println(\"每2分钟\")\n\n\t})\n\n\tc.newSchedule().everyDay().hourlyAt(16).minuteAt(36).function(func() {\n\n\t\tfmt.Println(\"每天16点36分\")\n\n\t})\n\n\tc.newSchedule().dayAt(23).hourlyAt(16).minuteAt(50).function(func() {\n\n\t\tfmt.Println(\"23号16点50分\")\n\n\t})\n\n\tc.newSchedule().dayAt(24).hourBetween(8, 10).function(func() {\n\n\t\tfmt.Println(\"24号8点-10点\")\n\n\t})\n\n\tc.newSchedule().hourBetween(8, 9).everyMinute().function(func() {\n\n\t\tfmt.Println(\"24号8点-9点每分钟\")\n\n\t})\n\n\tc.newSchedule().dayBetween(22, 24).everyHour().everyMinute().function(func() {\n\n\t\tfmt.Println(\"22号-24号每分钟\")\n\n\t})\n\n}\n\n```\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeteryangs%2Fsuperadminpage20","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeteryangs%2Fsuperadminpage20","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeteryangs%2Fsuperadminpage20/lists"}