mirror of
https://github.com/flipped-aurora/gin-vue-admin.git
synced 2026-09-21 20:35:16 +00:00
Merge branch 'gva_gormv2_dev' of https://github.com/songzhibin97/gin-vue-admin into gva_gormv2_dev
This commit is contained in:
@@ -6,10 +6,8 @@ type ApiGroup struct {
|
||||
CustomerApi
|
||||
ExcelApi
|
||||
FileUploadAndDownloadApi
|
||||
SimpleUploaderApi
|
||||
}
|
||||
|
||||
var fileUploadAndDownloadService = service.ServiceGroupApp.ExampleServiceGroup.FileUploadAndDownloadService
|
||||
var customerService = service.ServiceGroupApp.ExampleServiceGroup.CustomerService
|
||||
var excelService = service.ServiceGroupApp.ExampleServiceGroup.ExcelService
|
||||
var simpleUploaderService = service.ServiceGroupApp.ExampleServiceGroup.SimpleUploaderService
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/example"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type SimpleUploaderApi struct {
|
||||
}
|
||||
|
||||
// @Tags SimpleUploader
|
||||
// @Summary 断点续传插件版示例
|
||||
// @Security ApiKeyAuth
|
||||
// @accept multipart/form-data
|
||||
// @Produce application/json
|
||||
// @Param file formData file true "断点续传插件版示例"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"切片创建成功"}"
|
||||
// @Router /SimpleUploaderApi/upload [post]
|
||||
func (s *SimpleUploaderApi) SimpleUploaderUpload(c *gin.Context) {
|
||||
var chunk example.ExaSimpleUploader
|
||||
_, header, err := c.Request.FormFile("file")
|
||||
chunk.Filename = c.PostForm("filename")
|
||||
chunk.ChunkNumber = c.PostForm("chunkNumber")
|
||||
chunk.CurrentChunkSize = c.PostForm("currentChunkSize")
|
||||
chunk.Identifier = c.PostForm("identifier")
|
||||
chunk.TotalSize = c.PostForm("totalSize")
|
||||
chunk.TotalChunks = c.PostForm("totalChunks")
|
||||
var chunkDir = "./chunk/" + chunk.Identifier + "/"
|
||||
hasDir, _ := utils.PathExists(chunkDir)
|
||||
if !hasDir {
|
||||
if err := utils.CreateDir(chunkDir); err != nil {
|
||||
global.GVA_LOG.Error("创建目录失败!", zap.Any("err", err))
|
||||
}
|
||||
}
|
||||
chunkPath := chunkDir + chunk.Filename + chunk.ChunkNumber
|
||||
err = c.SaveUploadedFile(header, chunkPath)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("切片创建失败!", zap.Any("err", err))
|
||||
response.FailWithMessage("切片创建失败", c)
|
||||
return
|
||||
}
|
||||
chunk.CurrentChunkPath = chunkPath
|
||||
err = simpleUploaderService.SaveChunk(chunk)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("切片创建失败!", zap.Any("err", err))
|
||||
response.FailWithMessage("切片创建失败", c)
|
||||
return
|
||||
} else {
|
||||
response.OkWithMessage("切片创建成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// @Tags SimpleUploader
|
||||
// @Summary 断点续传插件版示例
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param md5 query string true "md5"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
|
||||
// @Router /SimpleUploaderApi/checkFileMd5 [get]
|
||||
func (s *SimpleUploaderApi) CheckFileMd5(c *gin.Context) {
|
||||
md5 := c.Query("md5")
|
||||
err, chunks, isDone := simpleUploaderService.CheckFileMd5(md5)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("md5读取失败!", zap.Any("err", err))
|
||||
response.FailWithMessage("md5读取失败", c)
|
||||
} else {
|
||||
response.OkWithDetailed(gin.H{
|
||||
"chunks": chunks,
|
||||
"isDone": isDone,
|
||||
}, "查询成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// @Tags SimpleUploader
|
||||
// @Summary 合并文件
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param md5 query string true "md5"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"合并成功"}"
|
||||
// @Router /SimpleUploaderApi/mergeFileMd5 [get]
|
||||
func (s *SimpleUploaderApi) MergeFileMd5(c *gin.Context) {
|
||||
md5 := c.Query("md5")
|
||||
fileName := c.Query("fileName")
|
||||
err := simpleUploaderService.MergeFileMd5(md5, fileName)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("md5读取失败!", zap.Any("err", err))
|
||||
response.FailWithMessage("md5读取失败", c)
|
||||
} else {
|
||||
response.OkWithMessage("合并成功", c)
|
||||
}
|
||||
}
|
||||
@@ -155,8 +155,7 @@ func (autoApi *AutoCodeApi) CreateTemp(c *gin.Context) {
|
||||
err := autoCodeService.CreateTemp(a, apiIds...)
|
||||
if err != nil {
|
||||
if errors.Is(err, system.AutoMoveErr) {
|
||||
c.Writer.Header().Add("success", "false")
|
||||
c.Writer.Header().Add("msgtype", "success")
|
||||
c.Writer.Header().Add("success", "true")
|
||||
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
|
||||
} else {
|
||||
c.Writer.Header().Add("success", "false")
|
||||
|
||||
@@ -48,7 +48,6 @@ func MysqlTables(db *gorm.DB) {
|
||||
example.ExaFileUploadAndDownload{},
|
||||
example.ExaFile{},
|
||||
example.ExaFileChunk{},
|
||||
example.ExaSimpleUploader{},
|
||||
example.ExaCustomer{},
|
||||
system.SysOperationRecord{},
|
||||
system.SysAutoCodeHistory{},
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/ws"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify"
|
||||
//email "github.com/flipped-aurora/gva-plug-email" // 在线仓库模式
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/email" // 本地插件仓库地址模式
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/example_plugin"
|
||||
@@ -34,4 +34,10 @@ func InstallPlugin(PublicGroup *gin.RouterGroup, PrivateGroup *gin.RouterGroup)
|
||||
global.GVA_CONFIG.Email.Port,
|
||||
global.GVA_CONFIG.Email.IsSSL,
|
||||
))
|
||||
|
||||
// 钉钉通知,暂时开放权限
|
||||
PluginInit(PublicGroup, notify.CreateDDPlug(
|
||||
"https://oapi.dingtalk.com/robot/send",
|
||||
"8ded23f91917dc4f6275f44ba5ef243e6ed1d2cc74de83f01a6f5f5f39905671",
|
||||
"SECaecf452bd6e671ab0d47469c3ad933e32fcc47b335333049a1b8961606192f38"))
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ func Routers() *gin.Engine {
|
||||
systemRouter.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理
|
||||
exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由
|
||||
exampleRouter.InitExcelRouter(PrivateGroup) // 表格导入导出
|
||||
exampleRouter.InitSimpleUploaderRouter(PrivateGroup) // 断点续传(插件版)
|
||||
exampleRouter.InitCustomerRouter(PrivateGroup) // 客户路由
|
||||
|
||||
// Code generated by github.com/flipped-aurora/gin-vue-admin/server Begin; DO NOT EDIT.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package example
|
||||
|
||||
type ExaSimpleUploader struct {
|
||||
ChunkNumber string `json:"chunkNumber" gorm:"comment:当前切片标记"`
|
||||
CurrentChunkSize string `json:"currentChunkSize" gorm:"comment:当前切片容量"`
|
||||
CurrentChunkPath string `json:"currentChunkPath" gorm:"comment:切片本地路径"`
|
||||
TotalSize string `json:"totalSize" gorm:"comment:总容量"`
|
||||
Identifier string `json:"identifier" gorm:"comment:文件标识(md5)"`
|
||||
Filename string `json:"filename" gorm:"comment:文件名"`
|
||||
TotalChunks string `json:"totalChunks" gorm:"comment:切片总数"`
|
||||
IsDone bool `json:"isDone" gorm:"comment:是否上传完成"`
|
||||
FilePath string `json:"filePath" gorm:"comment:文件本地路径"`
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
## GVA 邮件发送功能插件
|
||||
#### 开发者:GIN-VUE-ADMIN 官方
|
||||
|
||||
### 使用步骤
|
||||
|
||||
@@ -27,8 +28,9 @@
|
||||
true,
|
||||
))
|
||||
|
||||
#### 2. 配置说明
|
||||
### 2. 配置说明
|
||||
|
||||
#### 2-1 全局配置结构体说明
|
||||
//其中 Form 和 Secret 通常来说就是用户名和密码
|
||||
|
||||
type Email struct {
|
||||
@@ -40,8 +42,17 @@
|
||||
Port int // 端口 请前往QQ或者你要发邮件的邮箱查看其smtp协议 大多为 465
|
||||
IsSSL bool // 是否SSL 是否开启SSL
|
||||
}
|
||||
#### 2-2 入参结构说明
|
||||
//其中 Form 和 Secret 通常来说就是用户名和密码
|
||||
|
||||
### 方法API
|
||||
type Email struct {
|
||||
To string `json:"to"` // 邮件发送给谁
|
||||
Subject string `json:"subject"` // 邮件标题
|
||||
Body string `json:"body"` // 邮件内容
|
||||
}
|
||||
|
||||
|
||||
### 3. 方法API
|
||||
|
||||
utils.EmailTest(邮件标题,邮件主体) 发送测试邮件
|
||||
例:utils.EmailTest("测试邮件","测试邮件")
|
||||
@@ -49,3 +60,16 @@
|
||||
例:utils.ErrorToEmail("测试邮件","测试邮件")
|
||||
utils.Email(目标邮箱多个的话用逗号分隔,邮件标题,邮件主体) 发送测试邮件
|
||||
例:utils.Email(”a.qq.com,b.qq.com“,"测试邮件","测试邮件")
|
||||
|
||||
### 4. 可直接调用的接口
|
||||
|
||||
测试接口: /email/emailTest [post] 已配置swagger
|
||||
|
||||
发送邮件接口接口: /email/emailSend [post] 已配置swagger
|
||||
入参:
|
||||
type Email struct {
|
||||
To string `json:"to"` // 邮件发送给谁
|
||||
Subject string `json:"subject"` // 邮件标题
|
||||
Body string `json:"body"` // 邮件内容
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
email_response "github.com/flipped-aurora/gin-vue-admin/server/plugin/email/model/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/email/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
@@ -25,3 +26,21 @@ func (s *EmailApi) EmailTest(c *gin.Context) {
|
||||
response.OkWithData("发送成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// @Tags System
|
||||
// @Summary 发送邮件
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param data body email_response.Email true "发送邮件必须的参数"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}"
|
||||
// @Router /email/sendEmail [post]
|
||||
func (s *EmailApi) SendEmail(c *gin.Context) {
|
||||
var email email_response.Email
|
||||
_ = c.ShouldBindJSON(&email)
|
||||
if err := service.ServiceGroupApp.SendEmail(email.To, email.Subject, email.Body); err != nil {
|
||||
global.GVA_LOG.Error("发送失败!", zap.Any("err", err))
|
||||
response.FailWithMessage("发送失败", c)
|
||||
} else {
|
||||
response.OkWithData("发送成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package response
|
||||
|
||||
type Email struct {
|
||||
To string `json:"to"` // 邮件发送给谁
|
||||
Subject string `json:"subject"` // 邮件标题
|
||||
Body string `json:"body"` // 邮件内容
|
||||
}
|
||||
@@ -12,7 +12,9 @@ type EmailRouter struct {
|
||||
func (s *EmailRouter) InitEmailRouter(Router *gin.RouterGroup) {
|
||||
emailRouter := Router.Use(middleware.OperationRecord())
|
||||
var EmailApi = api.ApiGroupApp.EmailApi.EmailTest
|
||||
var SendEmail = api.ApiGroupApp.EmailApi.SendEmail
|
||||
{
|
||||
emailRouter.POST("emailTest", EmailApi) // 发送测试邮件
|
||||
emailRouter.POST("emailTest", EmailApi) // 发送测试邮件
|
||||
emailRouter.POST("sendEmail", SendEmail) // 发送邮件
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,16 @@ func (e *EmailService) EmailTest() (err error) {
|
||||
err = utils.EmailTest(subject, body)
|
||||
return err
|
||||
}
|
||||
|
||||
//@author: [maplepie](https://github.com/maplepie)
|
||||
//@function: EmailTest
|
||||
//@description: 发送邮件测试
|
||||
//@return: err error
|
||||
//@params to string 收件人
|
||||
//@params subject string 标题(主题)
|
||||
//@params body string 邮件内容
|
||||
|
||||
func (e *EmailService) SendEmail(to, subject, body string) (err error) {
|
||||
err = utils.Email(to, subject, body)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
## GVA 钉钉群通知插件
|
||||
|
||||
本插件用于向钉钉群推送消息
|
||||
|
||||
### 1. 使用场景
|
||||
|
||||
- 当服务运行异常时,可以向钉钉推送异常信息,便于及时发现解决问题
|
||||
- 推送一些关键业务的运行日志等
|
||||
|
||||
### 2. 配置说明
|
||||
|
||||
钉钉 token 等相关信息的获取,请参考 [钉钉官网](https://developers.dingtalk.com/document/robots/custom-robot-access?spm=ding_open_doc.document.0.0.7f8710afbfzduV#topic-2026027)
|
||||
|
||||
在`plugin/notify/global/global.go` 文件中配置钉钉通知的URL ,Token 等
|
||||
|
||||
```go
|
||||
// 在gin-vue-admin 主程序的initialize中的plugin的InstallPlugin 函数中写入如下代码
|
||||
PluginInit(PublicGroup, notify.CreateDDPlug(
|
||||
URL,
|
||||
Token,
|
||||
密钥))
|
||||
}
|
||||
```
|
||||
|
||||
### 3 参数说明
|
||||
#### 3-1 全局参数说明
|
||||
|
||||
```go
|
||||
Url string `mapstructure:"url" json:"url" yaml:"url"` // Url
|
||||
Token string `mapstructure:"token" json:"token" yaml:"token"` // access_token
|
||||
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥
|
||||
```
|
||||
#### 3-2 请求入参说明
|
||||
```go
|
||||
|
||||
|
||||
```
|
||||
|
||||
### 3方法API(可调用方法)
|
||||
```go
|
||||
|
||||
//content 发送的内容
|
||||
//atMobiles 需要艾特的人的手机号
|
||||
//isAtAll 是否艾特全体
|
||||
SendTextMessage(content string,atMobiles []string,isAtAll bool)
|
||||
|
||||
//content 发送的内容
|
||||
//title 内容标题
|
||||
//picUrl 配图
|
||||
//messageUrl 点击跳转路径
|
||||
SendLinkMessage(content,title,picUrl,messageUrl string)
|
||||
|
||||
//content 发送的内容(markdown语法)
|
||||
//title 内容标题
|
||||
//atMobiles 需要艾特的人的手机号
|
||||
//isAtAll 是否艾特全体
|
||||
SendMarkdownMessage(content,title string,atMobiles []string,isAtAll bool)
|
||||
|
||||
```
|
||||
|
||||
### 4. 可直接调用接口
|
||||
|
||||
发送文字消息接口: /notify/sendTextMessage [post] 已配置swagger
|
||||
发送图文链接消息接口: /notify/sendLinkMessage [post] 已配置swagger
|
||||
发送markdown消息接口: /notify/sendMarkdownMessage [post] 已配置swagger
|
||||
|
||||
入参:
|
||||
type Email struct {
|
||||
To string `json:"to"` // 邮件发送给谁
|
||||
Subject string `json:"subject"` // 邮件标题
|
||||
Body string `json:"body"` // 邮件内容
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
|
||||
notify_response "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/model/response"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Api struct {
|
||||
}
|
||||
|
||||
// @Tags Notify
|
||||
// @Summary 发送文字消息接口
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param data body notify_response.TextNotify true "发送文字消息的参数"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}"
|
||||
// @Router /notify/sendTextMessage [post]
|
||||
func (s *Api) SendTextMessage(c *gin.Context) {
|
||||
var textNotify notify_response.TextNotify
|
||||
_ = c.ShouldBindJSON(&textNotify)
|
||||
if err := service.ServiceGroupApp.SendTextMessage(textNotify.Content, textNotify.AtMobiles, textNotify.IsAtAll); err != nil {
|
||||
global.GVA_LOG.Error("发送失败!", zap.Any("err", err))
|
||||
response.FailWithMessage("发送失败", c)
|
||||
} else {
|
||||
response.OkWithData("发送成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// @Tags Notify
|
||||
// @Summary 发送图文链接消息接口
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param data body notify_response.LinkNotify true "发送图文链接消息的参数"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}"
|
||||
// @Router /notify/sendLinkMessage [post]
|
||||
func (s *Api) SendLinkMessage(c *gin.Context) {
|
||||
var linkNotify notify_response.LinkNotify
|
||||
_ = c.ShouldBindJSON(&linkNotify)
|
||||
if err := service.ServiceGroupApp.SendLinkMessage(linkNotify.Content, linkNotify.Title, linkNotify.PicUrl, linkNotify.MessageUrl); err != nil {
|
||||
global.GVA_LOG.Error("发送失败!", zap.Any("err", err))
|
||||
response.FailWithMessage("发送失败", c)
|
||||
} else {
|
||||
response.OkWithData("发送成功", c)
|
||||
}
|
||||
}
|
||||
|
||||
// @Tags Notify
|
||||
// @Summary 发送markdown消息接口
|
||||
// @Security ApiKeyAuth
|
||||
// @Produce application/json
|
||||
// @Param data body notify_response.MarkdownNotify true "发送markdown消息的参数"
|
||||
// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}"
|
||||
// @Router /notify/sendMarkdownMessage [post]
|
||||
func (s *Api) SendMarkdownMessage(c *gin.Context) {
|
||||
var markdownNotify notify_response.MarkdownNotify
|
||||
_ = c.ShouldBindJSON(&markdownNotify)
|
||||
if err := service.ServiceGroupApp.SendMarkdownMessage(markdownNotify.Content, markdownNotify.Title, markdownNotify.AtMobiles, markdownNotify.IsAtAll); err != nil {
|
||||
global.GVA_LOG.Error("发送失败!", zap.Any("err", err))
|
||||
response.FailWithMessage("发送失败", c)
|
||||
} else {
|
||||
response.OkWithData("发送成功", c)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package api
|
||||
|
||||
type ApiGroup struct {
|
||||
Api
|
||||
}
|
||||
|
||||
var ApiGroupApp = new(ApiGroup)
|
||||
@@ -0,0 +1,7 @@
|
||||
package config
|
||||
|
||||
type DingDing struct {
|
||||
Url string `mapstructure:"url" json:"url" yaml:"url"` // Url
|
||||
Token string `mapstructure:"token" json:"token" yaml:"token"` // access_token
|
||||
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package global
|
||||
|
||||
import "github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/config"
|
||||
|
||||
var GlobalConfig_ = &config.DingDing{}
|
||||
@@ -0,0 +1,28 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/router"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ddPlugin struct {
|
||||
Secret string
|
||||
Token string
|
||||
Url string
|
||||
}
|
||||
|
||||
func CreateDDPlug(url, Token, Secret string) *ddPlugin {
|
||||
global.GlobalConfig_.Url = url
|
||||
global.GlobalConfig_.Token = Token
|
||||
global.GlobalConfig_.Secret = Secret
|
||||
return &ddPlugin{}
|
||||
}
|
||||
|
||||
func (*ddPlugin) Register(group *gin.RouterGroup) {
|
||||
router.RouterGroupApp.InitRouter(group)
|
||||
}
|
||||
|
||||
func (*ddPlugin) RouterPath() string {
|
||||
return "notify"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package response
|
||||
|
||||
type TextNotify struct { // 文字信息
|
||||
Content string `json:"content"` // 发送的内容
|
||||
AtMobiles []string `json:"atMobiles"` // 需要艾特的人的手机号
|
||||
IsAtAll bool `json:"isAtAll"` // 是否艾特全体
|
||||
}
|
||||
|
||||
type LinkNotify struct { // 图文链接信息
|
||||
Content string `json:"content"` // 发送的内容
|
||||
Title string `json:"title"` // 内容标题
|
||||
PicUrl string `json:"picUrl"` // 配图
|
||||
MessageUrl string `json:"messageUrl"` // 点击跳转路径
|
||||
}
|
||||
|
||||
type MarkdownNotify struct { // markdown信息
|
||||
Title string `json:"title"` // 内容标题
|
||||
Content string `json:"content"` // 发送的内容
|
||||
AtMobiles []string `json:"atMobiles"` // 需要艾特的人的手机号
|
||||
IsAtAll bool `json:"isAtAll"` // 是否艾特全体
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package router
|
||||
|
||||
type RouterGroup struct {
|
||||
NotifyRouter
|
||||
}
|
||||
|
||||
var RouterGroupApp = new(RouterGroup)
|
||||
@@ -0,0 +1,18 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/api"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type NotifyRouter struct {
|
||||
}
|
||||
|
||||
func (s *NotifyRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
router := Router.Use(middleware.OperationRecord())
|
||||
var SendTextMessage = api.ApiGroupApp.Api.SendTextMessage
|
||||
{
|
||||
router.POST("sendTextMessage", SendTextMessage)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package service
|
||||
|
||||
type ServiceGroup struct {
|
||||
NotifyService
|
||||
}
|
||||
|
||||
var ServiceGroupApp = new(ServiceGroup)
|
||||
@@ -0,0 +1,157 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/notify/global"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NotifyService struct {
|
||||
}
|
||||
|
||||
//@author: [Espoir](https://github.com/nightsimon)
|
||||
//@function: SendTextMessage
|
||||
//@description: 发送钉钉文字信息
|
||||
//@params content string发送的文字内容
|
||||
//@params atMobiles []string 艾特的手机号
|
||||
//@params isAtAll bool 是否艾特全体
|
||||
//@return: err error
|
||||
|
||||
func (e *NotifyService) SendTextMessage(content string, atMobiles []string, isAtAll bool) (err error) {
|
||||
msg := map[string]interface{}{
|
||||
"msgtype": "text",
|
||||
"text": map[string]string{
|
||||
"content": content,
|
||||
},
|
||||
"at": map[string]interface{}{
|
||||
"atMobiles": atMobiles,
|
||||
"isAtAll": isAtAll,
|
||||
},
|
||||
}
|
||||
return SendMessage(msg)
|
||||
}
|
||||
|
||||
//@author: [Espoir](https://github.com/nightsimon)
|
||||
//@function: SendLinkMessage
|
||||
//@description: 发送钉钉图文链接信息
|
||||
//@params content string 发送的文字内容
|
||||
//@params title string 发送的标题
|
||||
//@params picUrl string 艾特的手机号
|
||||
//@params messageUrl string 是否艾特全体
|
||||
//@return: err error
|
||||
|
||||
func (e *NotifyService) SendLinkMessage(content, title, picUrl, messageUrl string) (err error) {
|
||||
msg := map[string]interface{}{
|
||||
"msgtype": "link",
|
||||
"link": map[string]string{
|
||||
"text": content,
|
||||
"title": title,
|
||||
"picUrl": picUrl,
|
||||
"messageUrl": messageUrl,
|
||||
},
|
||||
}
|
||||
return SendMessage(msg)
|
||||
}
|
||||
|
||||
//@author: [Espoir](https://github.com/nightsimon)
|
||||
//@function: SendMarkdownMessage
|
||||
//@description: 发送钉钉Markdown信息
|
||||
//@params content 发送的文字内容
|
||||
//@params title 发送的标题
|
||||
//@params atMobiles []string 艾特的手机号
|
||||
//@params isAtAll bool 是否艾特全体
|
||||
//@return: err error
|
||||
|
||||
func (e *NotifyService) SendMarkdownMessage(content, title string, atMobiles []string, isAtAll bool) (err error) {
|
||||
msg := map[string]interface{}{
|
||||
"msgtype": "markdown",
|
||||
"markdown": map[string]string{
|
||||
"text": content,
|
||||
"title": title,
|
||||
},
|
||||
"at": map[string]interface{}{
|
||||
"atMobiles": atMobiles,
|
||||
"isAtAll": isAtAll,
|
||||
},
|
||||
}
|
||||
return SendMessage(msg)
|
||||
}
|
||||
|
||||
func SendMessage(msg interface{}) error {
|
||||
body := bytes.NewBuffer(nil)
|
||||
err := json.NewEncoder(body).Encode(msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("msg json failed, msg: %v, err: %v", msg, err.Error())
|
||||
}
|
||||
|
||||
value := url.Values{}
|
||||
value.Set("access_token", global.GlobalConfig_.Token)
|
||||
if global.GlobalConfig_.Secret != "" {
|
||||
t := time.Now().UnixNano() / 1e6
|
||||
value.Set("timestamp", fmt.Sprintf("%d", t))
|
||||
value.Set("sign", sign(t, global.GlobalConfig_.Secret))
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(http.MethodPost, global.GlobalConfig_.Url, body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error request: %v", err.Error())
|
||||
}
|
||||
request.URL.RawQuery = value.Encode()
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
res, err := (&http.Client{}).Do(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("send dingTalk message failed, error: %v", err.Error())
|
||||
}
|
||||
defer func() { _ = res.Body.Close() }()
|
||||
result, err := ioutil.ReadAll(res.Body)
|
||||
|
||||
if res.StatusCode != 200 {
|
||||
return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, "http code is not 200"))
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, err.Error()))
|
||||
}
|
||||
|
||||
type response struct {
|
||||
ErrCode int `json:"errcode"`
|
||||
}
|
||||
var ret response
|
||||
|
||||
if err := json.Unmarshal(result, &ret); err != nil {
|
||||
return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, err.Error()))
|
||||
}
|
||||
|
||||
if ret.ErrCode != 0 {
|
||||
return fmt.Errorf("send dingTalk message failed, %s", httpError(request, res, result, "errcode is not 0"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func httpError(request *http.Request, response *http.Response, body []byte, error string) string {
|
||||
return fmt.Sprintf(
|
||||
"http request failure, error: %s, status code: %d, %s %s, body:\n%s",
|
||||
error,
|
||||
response.StatusCode,
|
||||
request.Method,
|
||||
request.URL.String(),
|
||||
string(body),
|
||||
)
|
||||
}
|
||||
func sign(t int64, secret string) string {
|
||||
strToHash := fmt.Sprintf("%d\n%s", t, secret)
|
||||
hmac256 := hmac.New(sha256.New, []byte(secret))
|
||||
hmac256.Write([]byte(strToHash))
|
||||
data := hmac256.Sum(nil)
|
||||
return base64.StdEncoding.EncodeToString(data)
|
||||
}
|
||||
|
||||
// 其余方法请参考 https://developers.dingtalk.com/document/robots/custom-robot-access?spm=ding_open_doc.document.0.0.7f8710afbfzduV#topic-2026027
|
||||
@@ -0,0 +1 @@
|
||||
package utils
|
||||
File diff suppressed because one or more lines are too long
@@ -5,5 +5,3 @@
|
||||
项目github:"https://github.com/piexlmax/github.com/flipped-aurora/gin-vue-admin/server"
|
||||
|
||||
希望大家给个star多多鼓励
|
||||
|
||||
暂时不保存大家生成的结构体 只为方便一次性使用
|
||||
@@ -4,7 +4,7 @@
|
||||
{{- range .Fields}}
|
||||
<el-form-item label="{{.FieldDesc}}:">
|
||||
{{- if eq .FieldType "bool" }}
|
||||
<el-switch active-color="#13ce66" inactive-color="#ff4949" active-text="是" inactive-text="否" v-model="formData.{{.FieldJson}}" clearable ></el-switch>
|
||||
<el-switch v-model="formData.{{.FieldJson}}" active-color="#13ce66" inactive-color="#ff4949" active-text="是" inactive-text="否" clearable ></el-switch>
|
||||
{{- end }}
|
||||
{{- if eq .FieldType "string" }}
|
||||
<el-input v-model="formData.{{.FieldJson}}" clearable placeholder="请输入" />
|
||||
@@ -19,7 +19,7 @@
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if eq .FieldType "time.Time" }}
|
||||
<el-date-picker type="date" placeholder="选择日期" v-model="formData.{{ .FieldJson }}" clearable></el-date-picker>
|
||||
<el-date-picker v-model="formData.{{ .FieldJson }}" type="date" placeholder="选择日期" clearable></el-date-picker>
|
||||
{{- end }}
|
||||
{{- if eq .FieldType "float64" }}
|
||||
<el-input-number v-model="formData.{{ .FieldJson }}" :precision="2" clearable></el-input-number>
|
||||
|
||||
@@ -24,13 +24,15 @@
|
||||
<el-form-item>
|
||||
<el-button size="mini" type="primary" icon="el-icon-search" @click="onSubmit">查询</el-button>
|
||||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openDialog">新增</el-button>
|
||||
<el-popover v-model="deleteVisible" placement="top" width="160">
|
||||
<el-popover v-model:visible="deleteVisible" placement="top" width="160">
|
||||
<p>确定要删除吗?</p>
|
||||
<div style="text-align: right; margin: 0">
|
||||
<el-button size="mini" type="text" @click="deleteVisible = false">取消</el-button>
|
||||
<el-button size="mini" type="primary" @click="onDelete">确定</el-button>
|
||||
</div>
|
||||
<el-button slot="reference" icon="el-icon-delete" size="mini" type="danger" style="margin-left: 10px;">批量删除</el-button>
|
||||
<template #reference>
|
||||
<el-button icon="el-icon-delete" size="mini" type="danger" style="margin-left: 10px;">批量删除</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -46,24 +48,24 @@
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="日期" width="180">
|
||||
<template slot-scope="scope">{{ "{{ scope.row.CreatedAt|formatDate }}" }}</template>
|
||||
<template #default="scope">{{ "{{ formatDate(scope.row.CreatedAt) }}" }}</template>
|
||||
</el-table-column>
|
||||
{{- range .Fields}}
|
||||
{{- if .DictType}}
|
||||
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120">
|
||||
<template slot-scope="scope">
|
||||
<template #default="scope">
|
||||
{{"{{"}} filterDict(scope.row.{{.FieldJson}},"{{.DictType}}") {{"}}"}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
{{- else if eq .FieldType "bool" }}
|
||||
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120">
|
||||
<template slot-scope="scope">{{ "{{scope.row."}}{{.FieldJson}}{{"|formatBoolean}}" }}</template>
|
||||
<template #default="scope">{{"{{"}} formatBoolean(scope.row.{{.FieldJson}}) {{"}}"}}</template>
|
||||
</el-table-column> {{- else }}
|
||||
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120" />
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
<el-table-column label="按钮组">
|
||||
<template slot-scope="scope">
|
||||
<template #default="scope">
|
||||
<el-button size="small" type="primary" icon="el-icon-edit" class="table-button" @click="update{{.StructName}}(scope.row)">变更</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteRow(scope.row)">删除</el-button>
|
||||
</template>
|
||||
@@ -79,12 +81,12 @@
|
||||
@current-change="handleCurrentChange"
|
||||
@size-change="handleSizeChange"
|
||||
/>
|
||||
<el-dialog :before-close="closeDialog" :visible.sync="dialogFormVisible" title="弹窗操作">
|
||||
<el-dialog v-model="dialogFormVisible" :before-close="closeDialog" title="弹窗操作">
|
||||
<el-form :model="formData" label-position="right" label-width="80px">
|
||||
{{- range .Fields}}
|
||||
<el-form-item label="{{.FieldDesc}}:">
|
||||
{{- if eq .FieldType "bool" }}
|
||||
<el-switch active-color="#13ce66" inactive-color="#ff4949" active-text="是" inactive-text="否" v-model="formData.{{.FieldJson}}" clearable ></el-switch>
|
||||
<el-switch v-model="formData.{{.FieldJson}}" active-color="#13ce66" inactive-color="#ff4949" active-text="是" inactive-text="否" clearable ></el-switch>
|
||||
{{- end }}
|
||||
{{- if eq .FieldType "string" }}
|
||||
<el-input v-model="formData.{{.FieldJson}}" clearable placeholder="请输入" />
|
||||
@@ -99,7 +101,7 @@
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if eq .FieldType "time.Time" }}
|
||||
<el-date-picker type="date" placeholder="选择日期" v-model="formData.{{ .FieldJson }}" clearable />
|
||||
<el-date-picker v-model="formData.{{ .FieldJson }}" type="date" placeholder="选择日期" clearable />
|
||||
{{- end }}
|
||||
{{- if eq .FieldType "float64" }}
|
||||
<el-input-number v-model="formData.{{ .FieldJson }}" :precision="2" clearable />
|
||||
@@ -107,10 +109,12 @@
|
||||
</el-form-item>
|
||||
{{- end }}
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeDialog">取 消</el-button>
|
||||
<el-button type="primary" @click="enterDialog">确 定</el-button>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closeDialog">取 消</el-button>
|
||||
<el-button type="primary" @click="enterDialog">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -124,27 +128,9 @@ import {
|
||||
find{{.StructName}},
|
||||
get{{.StructName}}List
|
||||
} from '@/api/{{.PackageName}}' // 此处请自行替换地址
|
||||
import { formatTimeToStr } from '@/utils/date'
|
||||
import infoList from '@/mixins/infoList'
|
||||
export default {
|
||||
name: '{{.StructName}}',
|
||||
filters: {
|
||||
formatDate: function(time) {
|
||||
if (time !== null && time !== '') {
|
||||
var date = new Date(time)
|
||||
return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss')
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
formatBoolean: function(bool) {
|
||||
if (bool != null) {
|
||||
return bool ? '是' : '否'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [infoList],
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -4,5 +4,4 @@ type RouterGroup struct {
|
||||
CustomerRouter
|
||||
ExcelRouter
|
||||
FileUploadAndDownloadRouter
|
||||
SimpleUploaderRouter
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
v1 "github.com/flipped-aurora/gin-vue-admin/server/api/v1"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type SimpleUploaderRouter struct{}
|
||||
|
||||
func (e *SimpleUploaderRouter) InitSimpleUploaderRouter(Router *gin.RouterGroup) {
|
||||
simpleUploaderRouter := Router.Group("simpleUploader")
|
||||
var simpleUploaderApi = v1.ApiGroupApp.ExampleApiGroup.SimpleUploaderApi
|
||||
{
|
||||
simpleUploaderRouter.POST("upload", simpleUploaderApi.SimpleUploaderUpload) // 上传功能
|
||||
simpleUploaderRouter.GET("checkFileMd5", simpleUploaderApi.CheckFileMd5) // 文件完整度验证
|
||||
simpleUploaderRouter.GET("mergeFileMd5", simpleUploaderApi.MergeFileMd5) // 合并文件
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,4 @@ type ServiceGroup struct {
|
||||
FileUploadAndDownloadService
|
||||
CustomerService
|
||||
ExcelService
|
||||
SimpleUploaderService
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/example"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type SimpleUploaderService struct {
|
||||
}
|
||||
|
||||
//@author: [piexlmax](https://github.com/piexlmax)
|
||||
//@function: SaveChunk
|
||||
//@description: 保存文件切片路径
|
||||
//@param: uploader model.ExaSimpleUploader
|
||||
//@return: err error
|
||||
|
||||
func (exa *SimpleUploaderService) SaveChunk(uploader example.ExaSimpleUploader) (err error) {
|
||||
return global.GVA_DB.Create(uploader).Error
|
||||
}
|
||||
|
||||
//@author: [piexlmax](https://github.com/piexlmax)
|
||||
//@function: CheckFileMd5
|
||||
//@description: 检查文件是否已经上传过
|
||||
//@param: md5 string
|
||||
//@return: err error, uploads []model.ExaSimpleUploader, isDone bool
|
||||
|
||||
func (exa *SimpleUploaderService) CheckFileMd5(md5 string) (err error, uploads []example.ExaSimpleUploader, isDone bool) {
|
||||
err = global.GVA_DB.Find(&uploads, "identifier = ? AND is_done = ?", md5, false).Error
|
||||
isDone = errors.Is(global.GVA_DB.First(&example.ExaSimpleUploader{}, "identifier = ? AND is_done = ?", md5, true).Error, gorm.ErrRecordNotFound)
|
||||
return err, uploads, !isDone
|
||||
}
|
||||
|
||||
//@author: [piexlmax](https://github.com/piexlmax)
|
||||
//@function: MergeFileMd5
|
||||
//@description: 合并文件
|
||||
//@param: md5 string, fileName string
|
||||
//@return: err error
|
||||
|
||||
func (exa *SimpleUploaderService) MergeFileMd5(md5 string, fileName string) (err error) {
|
||||
finishDir := "./finish/"
|
||||
dir := "./chunk/" + md5
|
||||
// 如果文件上传成功 不做后续操作 通知成功即可
|
||||
if !errors.Is(global.GVA_DB.First(&example.ExaSimpleUploader{}, "identifier = ? AND is_done = ?", md5, true).Error, gorm.ErrRecordNotFound) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 打开切片文件夹
|
||||
rd, err := ioutil.ReadDir(dir)
|
||||
_ = os.MkdirAll(finishDir, os.ModePerm)
|
||||
// 创建目标文件
|
||||
fd, err := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 关闭文件
|
||||
defer fd.Close()
|
||||
// 将切片文件按照顺序写入
|
||||
for k := range rd {
|
||||
content, _ := ioutil.ReadFile(dir + "/" + fileName + strconv.Itoa(k+1))
|
||||
_, err = fd.Write(content)
|
||||
if err != nil {
|
||||
_ = os.Remove(finishDir + fileName)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
|
||||
// 删除切片信息
|
||||
if err = tx.Delete(&example.ExaSimpleUploader{}, "identifier = ? AND is_done = ?", md5, false).Error; err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
data := example.ExaSimpleUploader{
|
||||
Identifier: md5,
|
||||
IsDone: true,
|
||||
FilePath: finishDir + fileName,
|
||||
Filename: fileName,
|
||||
}
|
||||
// 添加文件信息
|
||||
if err = tx.Create(&data).Error; err != nil {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
err = os.RemoveAll(dir) // 清除切片
|
||||
return err
|
||||
}
|
||||
@@ -247,7 +247,7 @@ func (autoCodeService *AutoCodeService) CreateTemp(autoCode system.AutoCodeStruc
|
||||
return err
|
||||
}
|
||||
if autoCode.AutoMoveFile {
|
||||
return errors.New("创建代码成功并移动文件成功")
|
||||
return system.AutoMoveErr
|
||||
}
|
||||
return nil
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ func (initDBService *InitDBService) InitDB(conf request.InitDB) error {
|
||||
example.ExaFileUploadAndDownload{},
|
||||
example.ExaFile{},
|
||||
example.ExaFileChunk{},
|
||||
example.ExaSimpleUploader{},
|
||||
example.ExaCustomer{},
|
||||
system.SysOperationRecord{},
|
||||
system.SysAutoCodeHistory{},
|
||||
|
||||
@@ -36,7 +36,6 @@ var authorityMenus = []AuthorityMenus{
|
||||
{"888", 18},
|
||||
{"888", 19},
|
||||
{"888", 20},
|
||||
{"888", 21},
|
||||
{"888", 22},
|
||||
{"888", 23},
|
||||
{"888", 24},
|
||||
|
||||
@@ -35,8 +35,7 @@ var menus = []system.SysBaseMenu{
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 18, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "3", Path: "dictionary", Name: "dictionary", Component: "view/superAdmin/dictionary/sysDictionary.vue", Sort: 5, Meta: system.Meta{Title: "字典管理", Icon: "notebook-2"}},
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 19, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: true, ParentId: "3", Path: "dictionaryDetail/:id", Name: "dictionaryDetail", Component: "view/superAdmin/dictionary/sysDictionaryDetail.vue", Sort: 1, Meta: system.Meta{Title: "字典详情", Icon: "s-order"}},
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 20, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "3", Path: "operation", Name: "operation", Component: "view/superAdmin/operation/sysOperationRecord.vue", Sort: 6, Meta: system.Meta{Title: "操作历史", Icon: "time"}},
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 21, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, Hidden: false, ParentId: "9", Path: "simpleUploader", Name: "simpleUploader", Component: "view/example/simpleUploader/simpleUploader", Sort: 6, Meta: system.Meta{Title: "断点续传(插件版)", Icon: "upload"}},
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 22, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "https://www.github.com/flipped-aurora/gin-vue-admin/server.com", Name: "https://www.github.com/flipped-aurora/gin-vue-admin/server.com", Hidden: false, Component: "/", Sort: 0, Meta: system.Meta{Title: "官方网站", Icon: "s-home"}},
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 22, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "https://www.gin-vue-admin.com", Name: "https://www.gin-vue-admin.com", Hidden: false, Component: "/", Sort: 0, Meta: system.Meta{Title: "官方网站", Icon: "s-home"}},
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 23, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "0", Path: "state", Name: "state", Hidden: false, Component: "view/system/state.vue", Sort: 6, Meta: system.Meta{Title: "服务器状态", Icon: "cloudy"}},
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 24, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "14", Path: "autoCodeAdmin", Name: "autoCodeAdmin", Hidden: false, Component: "view/systemTools/autoCodeAdmin/index.vue", Sort: 1, Meta: system.Meta{Title: "自动化代码管理", Icon: "s-finance"}},
|
||||
{GVA_MODEL: global.GVA_MODEL{ID: 25, CreatedAt: time.Now(), UpdatedAt: time.Now()}, MenuLevel: 0, ParentId: "14", Path: "autoCodeEdit/:id", Name: "autoCodeEdit", Hidden: true, Component: "view/systemTools/autoCode/index.vue", Sort: 0, Meta: system.Meta{Title: "自动化代码(复用)", Icon: "s-finance"}},
|
||||
|
||||
Reference in New Issue
Block a user