发布v2.7.8Beta1 (#1957)

* beta:2.7.8-a 增加自动化创建树形结构 (#1941)

* feat: 支持创建树形结构

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>

* 优化user store部分写法

* Update user.js

* feat: 升级版本号

* Dev 278 beta2 (#1954)

* 在关闭详情弹窗后 detailFrom为空对象,arr为undefined 使用slice控制台会报错

* 查询不重置pageSize

* 优化主题模式相关内容

* 优化弹窗手机端显示

* bugfix:PostgreSQL initdb (#1953)

* bugfix:postgresql增加显示指定template

---------

Co-authored-by: PiexlMax(奇淼 <165128580+pixelmaxQm@users.noreply.github.com>

---------

Co-authored-by: zayn <972858472@qq.com>
Co-authored-by: Azir <2075125282@qq.com>
Co-authored-by: Qing Liang <106448173+xue-ding-e@users.noreply.github.com>

* docs:调整部分代码注释以及代码格式

* feat: 自动化代码字典支持多选

* fix:调整值接收器和指针接收器

* feat: 支持导出表格复制,优化增加方法页面。

* chore:初始化代码规范化。

---------

Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com>
Co-authored-by: Azir <2075125282@qq.com>
Co-authored-by: zayn <972858472@qq.com>
Co-authored-by: Qing Liang <106448173+xue-ding-e@users.noreply.github.com>
Co-authored-by: cjb <75364055@qq.com>
This commit is contained in:
PiexlMax(奇淼 2024-12-08 21:17:21 +08:00 committed by GitHub
parent 80c54ad890
commit 283143e1bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
69 changed files with 3609 additions and 480 deletions

View File

@ -70,7 +70,7 @@ func (a *AutoCodePluginApi) Packaged(c *gin.Context) {
response.OkWithMessage(fmt.Sprintf("打包成功,文件路径为:%s", zipPath), c)
}
// Packaged
// InitMenu
// @Tags AutoCodePlugin
// @Summary 打包插件
// @Security ApiKeyAuth
@ -94,7 +94,7 @@ func (a *AutoCodePluginApi) InitMenu(c *gin.Context) {
response.OkWithMessage("文件变更成功", c)
}
// Packaged
// InitAPI
// @Tags AutoCodePlugin
// @Summary 打包插件
// @Security ApiKeyAuth

View File

@ -82,7 +82,7 @@ func (a *AutoCodeTemplateApi) Create(c *gin.Context) {
}
}
// Create
// AddFunc
// @Tags AddFunc
// @Summary 增加方法
// @Security ApiKeyAuth

View File

@ -39,7 +39,7 @@ func RunWindowsServer() {
fmt.Printf(`
欢迎使用 gin-vue-admin
当前版本:v2.7.7
当前版本:v2.7.8-beta1
加群方式:微信号shouzi_1994 QQ群470239250
项目地址https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,7 @@
definitions:
common.JSONMap:
additionalProperties: true
type: object
config.AliyunOSS:
properties:
access-key-id:
@ -150,6 +153,23 @@ definitions:
description: 本地文件存储路径
type: string
type: object
config.Minio:
properties:
access-key-id:
type: string
access-key-secret:
type: string
base-path:
type: string
bucket-name:
type: string
bucket-url:
type: string
endpoint:
type: string
use-ssl:
type: boolean
type: object
config.Mongo:
properties:
auth-source:
@ -409,6 +429,9 @@ definitions:
db:
description: 单实例模式下redis的哪个数据库
type: integer
name:
description: 代表当前实例的名字
type: string
password:
description: 密码
type: string
@ -454,6 +477,8 @@ definitions:
allOf:
- $ref: '#/definitions/config.Local'
description: oss
minio:
$ref: '#/definitions/config.Minio'
mongo:
$ref: '#/definitions/config.Mongo'
mssql:
@ -470,6 +495,10 @@ definitions:
$ref: '#/definitions/config.Qiniu'
redis:
$ref: '#/definitions/config.Redis'
redis-list:
items:
$ref: '#/definitions/config.Redis'
type: array
sqlite:
$ref: '#/definitions/config.Sqlite'
system:
@ -597,6 +626,9 @@ definitions:
use-redis:
description: 使用redis
type: boolean
use-strict-auth:
description: 使用树形角色分配模式
type: boolean
type: object
config.TencentCOS:
properties:
@ -800,6 +832,156 @@ definitions:
type: array
type: object
request.AutoCode:
properties:
abbreviation:
description: Struct简称
example: Struct简称
type: string
autoCreateApiToSql:
description: 是否自动创建api
example: false
type: boolean
autoCreateBtnAuth:
description: 是否自动创建按钮权限
example: false
type: boolean
autoCreateMenuToSql:
description: 是否自动创建menu
example: false
type: boolean
autoCreateResource:
description: 是否自动创建资源标识
example: false
type: boolean
autoMigrate:
description: 是否自动迁移表结构
example: false
type: boolean
businessDB:
description: 业务数据库
example: 业务数据库
type: string
description:
description: Struct中文名称
example: Struct中文名称
type: string
fields:
items:
$ref: '#/definitions/request.AutoCodeField'
type: array
gvaModel:
description: 是否使用gva默认Model
example: false
type: boolean
humpPackageName:
description: go文件名称
example: go文件名称
type: string
isAdd:
description: 是否新增
example: false
type: boolean
isTree:
description: 是否树形结构
example: false
type: boolean
onlyTemplate:
description: 是否只生成模板
example: false
type: boolean
package:
type: string
packageName:
description: 文件名称
example: 文件名称
type: string
primaryField:
$ref: '#/definitions/request.AutoCodeField'
structName:
description: Struct名称
example: Struct名称
type: string
tableName:
description: 表名
example: 表名
type: string
treeJson:
description: 展示的树json字段
example: 展示的树json字段
type: string
type: object
request.AutoCodeField:
properties:
checkDataSource:
description: 是否检查数据源
type: boolean
clearable:
description: 是否可清空
type: boolean
columnName:
description: 数据库字段
type: string
comment:
description: 数据库字段描述
type: string
dataSource:
allOf:
- $ref: '#/definitions/request.DataSource'
description: 数据源
dataTypeLong:
description: 数据库字段长度
type: string
defaultValue:
description: 是否必填
type: string
desc:
description: 是否前端详情
type: boolean
dictType:
description: 字典
type: string
errorText:
description: 校验失败文字
type: string
excel:
description: 是否导入/导出
type: boolean
fieldDesc:
description: 中文名
type: string
fieldIndexType:
description: 索引类型
type: string
fieldJson:
description: FieldJson
type: string
fieldName:
description: Field名
type: string
fieldSearchHide:
description: 是否隐藏查询条件
type: boolean
fieldSearchType:
description: 搜索条件
type: string
fieldType:
description: Field数据类型
type: string
form:
description: Front bool `json:"front"` // 是否前端可见
type: boolean
primaryKey:
description: 是否主键
type: boolean
require:
description: 是否必填
type: boolean
sort:
description: 是否增加排序
type: boolean
table:
description: 是否前端表格列
type: boolean
type: object
request.CasbinInReceive:
properties:
@ -829,6 +1011,22 @@ definitions:
description: 密码
type: string
type: object
request.DataSource:
properties:
association:
description: 关联关系 1 一对一 2 一对多
type: integer
dbName:
type: string
hasDeletedAt:
type: boolean
label:
type: string
table:
type: string
value:
type: string
type: object
request.Empty:
type: object
request.GetAuthorityId:
@ -843,6 +1041,26 @@ definitions:
description: 主键ID
type: integer
type: object
request.GetUserList:
properties:
email:
type: string
keyword:
description: 关键字
type: string
nickName:
type: string
page:
description: 页码
type: integer
pageSize:
description: 每页大小
type: integer
phone:
type: string
username:
type: string
type: object
request.IdsReq:
properties:
ids:
@ -1577,23 +1795,51 @@ definitions:
description: 用户id
type: integer
type: object
system.SysParams:
properties:
ID:
description: 主键ID
type: integer
createdAt:
description: 创建时间
type: string
desc:
description: 参数说明
type: string
key:
description: 参数键
type: string
name:
description: 参数名称
type: string
updatedAt:
description: 更新时间
type: string
value:
description: 参数值
type: string
required:
- key
- name
- value
type: object
system.SysUser:
properties:
ID:
description: 主键ID
type: integer
authorities:
description: 多用户角色
items:
$ref: '#/definitions/system.SysAuthority'
type: array
authority:
$ref: '#/definitions/system.SysAuthority'
allOf:
- $ref: '#/definitions/system.SysAuthority'
description: 用户角色
authorityId:
description: 用户角色ID
type: integer
baseColor:
description: 基础颜色
type: string
createdAt:
description: 创建时间
type: string
@ -1609,12 +1855,13 @@ definitions:
nickName:
description: 用户昵称
type: string
originSetting:
allOf:
- $ref: '#/definitions/common.JSONMap'
description: 配置
phone:
description: 用户手机号
type: string
sideMode:
description: 用户侧边主题
type: string
updatedAt:
description: 更新时间
type: string
@ -1634,7 +1881,7 @@ info:
contact: {}
description: 使用gin+vue进行极速开发的全栈开发基础平台
title: Gin-Vue-Admin Swagger API接口文档
version: v2.7.7
version: v2.7.8-beta1
paths:
/api/createApi:
post:
@ -1812,7 +2059,7 @@ paths:
tags:
- SysApi
/api/getApiGroups:
post:
get:
consumes:
- application/json
produces:
@ -2079,7 +2326,7 @@ paths:
tags:
- Authority
/authority/updateAuthority:
post:
put:
consumes:
- application/json
parameters:
@ -2347,7 +2594,7 @@ paths:
summary: 获取当前表所有字段
tags:
- AutoCode
/autoCode/getDatabase:
/autoCode/getDB:
get:
consumes:
- application/json
@ -2504,6 +2751,54 @@ paths:
summary: 获取package
tags:
- AutoCodePackage
/autoCode/initAPI:
post:
consumes:
- application/json
produces:
- application/json
responses:
"200":
description: 打包插件成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
additionalProperties: true
type: object
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 打包插件
tags:
- AutoCodePlugin
/autoCode/initMenu:
post:
consumes:
- application/json
produces:
- application/json
responses:
"200":
description: 打包插件成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
additionalProperties: true
type: object
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 打包插件
tags:
- AutoCodePlugin
/autoCode/installPlugin:
post:
consumes:
@ -2567,7 +2862,7 @@ paths:
tags:
- AutoCodeTemplate
/autoCode/pubPlug:
get:
post:
consumes:
- application/json
parameters:
@ -2989,6 +3284,34 @@ paths:
tags:
- ExaFileUploadAndDownload
/fileUploadAndDownload/findFile:
get:
consumes:
- multipart/form-data
parameters:
- description: Find the file, 查找文件
in: formData
name: file
required: true
type: file
produces:
- application/json
responses:
"200":
description: 查找文件,返回包括文件详情
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/response.FileResponse'
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 查找文件
tags:
- ExaFileUploadAndDownload
post:
consumes:
- multipart/form-data
@ -3047,6 +3370,32 @@ paths:
summary: 分页文件列表
tags:
- ExaFileUploadAndDownload
/fileUploadAndDownload/importURL:
post:
parameters:
- description: 对象
in: body
name: data
required: true
schema:
$ref: '#/definitions/example.ExaFileUploadAndDownload'
produces:
- application/json
responses:
"200":
description: 导入URL
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 导入URL
tags:
- ExaFileUploadAndDownload
/fileUploadAndDownload/removeChunk:
post:
consumes:
@ -4553,6 +4902,243 @@ paths:
summary: 分页获取SysOperationRecord列表
tags:
- SysOperationRecord
/sysParams/createSysParams:
post:
consumes:
- application/json
parameters:
- description: 创建参数
in: body
name: data
required: true
schema:
$ref: '#/definitions/system.SysParams'
produces:
- application/json
responses:
"200":
description: 创建成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 创建参数
tags:
- SysParams
/sysParams/deleteSysParams:
delete:
consumes:
- application/json
parameters:
- description: 删除参数
in: body
name: data
required: true
schema:
$ref: '#/definitions/system.SysParams'
produces:
- application/json
responses:
"200":
description: 删除成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 删除参数
tags:
- SysParams
/sysParams/deleteSysParamsByIds:
delete:
consumes:
- application/json
produces:
- application/json
responses:
"200":
description: 批量删除成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 批量删除参数
tags:
- SysParams
/sysParams/findSysParams:
get:
consumes:
- application/json
parameters:
- description: 主键ID
in: query
name: ID
type: integer
- description: 创建时间
in: query
name: createdAt
type: string
- description: 参数说明
in: query
name: desc
type: string
- description: 参数键
in: query
name: key
required: true
type: string
- description: 参数名称
in: query
name: name
required: true
type: string
- description: 更新时间
in: query
name: updatedAt
type: string
- description: 参数值
in: query
name: value
required: true
type: string
produces:
- application/json
responses:
"200":
description: 查询成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/system.SysParams'
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 用id查询参数
tags:
- SysParams
/sysParams/getSysParam:
get:
consumes:
- application/json
parameters:
- description: key
in: query
name: key
required: true
type: string
produces:
- application/json
responses:
"200":
description: 获取成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/system.SysParams'
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 根据key获取参数value
tags:
- SysParams
/sysParams/getSysParamsList:
get:
consumes:
- application/json
parameters:
- in: query
name: endCreatedAt
type: string
- in: query
name: key
type: string
- description: 关键字
in: query
name: keyword
type: string
- in: query
name: name
type: string
- description: 页码
in: query
name: page
type: integer
- description: 每页大小
in: query
name: pageSize
type: integer
- in: query
name: startCreatedAt
type: string
produces:
- application/json
responses:
"200":
description: 获取成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/response.PageResult'
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 分页获取参数列表
tags:
- SysParams
/sysParams/updateSysParams:
put:
consumes:
- application/json
parameters:
- description: 更新参数
in: body
name: data
required: true
schema:
$ref: '#/definitions/system.SysParams'
produces:
- application/json
responses:
"200":
description: 更新成功
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 更新参数
tags:
- SysParams
/system/getServerInfo:
post:
produces:
@ -4672,6 +5258,38 @@ paths:
summary: 设置用户信息
tags:
- SysUser
/user/SetSelfSetting:
put:
consumes:
- application/json
parameters:
- description: 用户配置数据
in: body
name: data
required: true
schema:
additionalProperties: true
type: object
produces:
- application/json
responses:
"200":
description: 设置用户配置
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
additionalProperties: true
type: object
msg:
type: string
type: object
security:
- ApiKeyAuth: []
summary: 设置用户配置
tags:
- SysUser
/user/admin_register:
post:
parameters:
@ -4786,7 +5404,7 @@ paths:
name: data
required: true
schema:
$ref: '#/definitions/request.PageInfo'
$ref: '#/definitions/request.GetUserList'
produces:
- application/json
responses:

View File

@ -18,7 +18,7 @@ func init() {
system.RegisterInit(initOrderEnsureTables, &ensureTables{})
}
func (ensureTables) InitializerName() string {
func (e *ensureTables) InitializerName() string {
return "ensure_tables_created"
}
func (e *ensureTables) InitializeData(ctx context.Context) (next context.Context, err error) {

View File

@ -1,3 +1,5 @@
package initialize
/*
* @Author: 逆光飞翔 191180776@qq.com
* @Date: 2022-12-08 17:25:49
@ -6,7 +8,6 @@
* @FilePath: \server\initialize\gorm_mssql.go
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
package initialize
import (
"github.com/flipped-aurora/gin-vue-admin/server/config"
@ -44,8 +45,8 @@ func GormMssqlByConfig(m config.Mssql) *gorm.DB {
return nil
}
mssqlConfig := sqlserver.Config{
DSN: m.Dsn(), // DSN data source name
DefaultStringSize: 191, // string 类型字段的默认长度
DSN: m.Dsn(), // DSN data source name
DefaultStringSize: 191, // string 类型字段的默认长度
}
if db, err := gorm.Open(sqlserver.New(mssqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil {
panic(err)

View File

@ -14,7 +14,7 @@ import (
//go:generate go mod download
// @title Gin-Vue-Admin Swagger API接口文档
// @version v2.7.7
// @version v2.7.8-beta1
// @description 使用gin+vue进行极速开发的全栈开发基础平台
// @securityDefinitions.apikey ApiKeyAuth
// @in header

View File

@ -34,3 +34,10 @@ func (m *JSONMap) Scan(value interface{}) error {
}
return nil
}
type TreeNode[T any] interface {
GetChildren() []T
SetChildren(children T)
GetID() int
GetParentID() int
}

View File

@ -27,6 +27,8 @@ type AutoCode struct {
AutoCreateMenuToSql bool `json:"autoCreateMenuToSql" example:"false"` // 是否自动创建menu
AutoCreateBtnAuth bool `json:"autoCreateBtnAuth" example:"false"` // 是否自动创建按钮权限
OnlyTemplate bool `json:"onlyTemplate" example:"false"` // 是否只生成模板
IsTree bool `json:"isTree" example:"false"` // 是否树形结构
TreeJson string `json:"treeJson" example:"展示的树json字段"` // 展示的树json字段
IsAdd bool `json:"isAdd" example:"false"` // 是否新增
Fields []*AutoCodeField `json:"fields"`
Module string `json:"-"`

View File

@ -1,12 +1,12 @@
package request
// Casbin info structure
// CasbinInfo Casbin info structure
type CasbinInfo struct {
Path string `json:"path"` // 路径
Method string `json:"method"` // 方法
}
// Casbin structure for input parameters
// CasbinInReceive Casbin structure for input parameters
type CasbinInReceive struct {
AuthorityId uint `json:"authorityId"` // 权限id
CasbinInfos []CasbinInfo `json:"casbinInfos"`

View File

@ -15,6 +15,7 @@ type InitDB struct {
Password string `json:"password"` // 数据库密码
DBName string `json:"dbName" binding:"required"` // 数据库名
DBPath string `json:"dbPath"` // sqlite数据库文件路径
Template string `json:"template"` // postgresql指定template
}
// MysqlEmptyDsn msyql 空数据库 建库链接

View File

@ -5,7 +5,7 @@ import (
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
)
// Add menu authority info structure
// AddMenuAuthorityInfo Add menu authority info structure
type AddMenuAuthorityInfo struct {
Menus []system.SysBaseMenu `json:"menus"`
AuthorityId uint `json:"authorityId"` // 角色ID

View File

@ -18,7 +18,7 @@ type Register struct {
Email string `json:"email" example:"电子邮箱"`
}
// User login structure
// Login User login structure
type Login struct {
Username string `json:"username"` // 用户名
Password string `json:"password"` // 密码
@ -26,19 +26,19 @@ type Login struct {
CaptchaId string `json:"captchaId"` // 验证码ID
}
// Modify password structure
// ChangePasswordReq Modify password structure
type ChangePasswordReq struct {
ID uint `json:"-"` // 从 JWT 中提取 user id避免越权
Password string `json:"password"` // 密码
NewPassword string `json:"newPassword"` // 新密码
}
// Modify user's auth structure
// SetUserAuth Modify user's auth structure
type SetUserAuth struct {
AuthorityId uint `json:"authorityId"` // 角色ID
}
// Modify user's auth structure
// SetUserAuthorities Modify user's auth structure
type SetUserAuthorities struct {
ID uint
AuthorityIds []uint `json:"authorityIds"` // 角色ID

View File

@ -5,7 +5,9 @@ import (
"{{.Module}}/global"
"{{.Module}}/model/common/response"
"{{.Module}}/model/{{.Package}}"
{{- if not .IsTree}}
{{.Package}}Req "{{.Module}}/model/{{.Package}}/request"
{{- end }}
"github.com/gin-gonic/gin"
"go.uber.org/zap"
{{- if .AutoCreateResource}}
@ -142,6 +144,25 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Find{{.StructName}}(c *gin.Conte
response.OkWithData(re{{.Abbreviation}}, c)
}
{{- if .IsTree }}
// Get{{.StructName}}List 分页获取{{.Description}}列表,Tree模式下不接受参数
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Context) {
list, err := {{.Abbreviation}}Service.Get{{.StructName}}InfoList()
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:" + err.Error(), c)
return
}
response.OkWithDetailed(list, "获取成功", c)
}
{{- else }}
// Get{{.StructName}}List 分页获取{{.Description}}列表
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
@ -171,6 +192,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Co
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
{{- end }}
{{- if .HasDataSource }}
// Get{{.StructName}}DataSource 获取{{.StructName}}的数据源
@ -199,7 +221,6 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}DataSource(c *
// @Summary 不需要鉴权的{{.Description}}接口
// @accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}Public(c *gin.Context) {

View File

@ -72,6 +72,10 @@ type {{.StructName}} struct {
UpdatedBy uint `gorm:"column:updated_by;comment:更新者"`
DeletedBy uint `gorm:"column:deleted_by;comment:删除者"`
{{- end }}
{{- if .IsTree }}
Children []*{{.StructName}} `json:"children" gorm:"-"` //子节点
ParentID int `json:"parentID" gorm:"column:parent_id;comment:父节点"`
{{- end }}
{{- end }}
}
@ -82,5 +86,26 @@ func ({{.StructName}}) TableName() string {
}
{{ end }}
{{if .IsTree }}
// GetChildren 实现TreeNode接口
func (s *{{.StructName}}) GetChildren() []*{{.StructName}} {
return s.Children
}
{{ end }}
// SetChildren 实现TreeNode接口
func (s *{{.StructName}}) SetChildren(children *{{.StructName}}) {
s.Children = append(s.Children, children)
}
// GetID 实现TreeNode接口
func (s *{{.StructName}}) GetID() int {
return int({{if not .GvaModel}}*{{- end }}s.{{.PrimaryField.FieldName}})
}
// GetParentID 实现TreeNode接口
func (s *{{.StructName}}) GetParentID() int {
return s.ParentID
}
{{ end }}
{{ end }}

View File

@ -60,7 +60,12 @@ import (
{{- if not .OnlyTemplate }}
"{{.Module}}/global"
"{{.Module}}/model/{{.Package}}"
{{- if not .IsTree}}
{{.Package}}Req "{{.Module}}/model/{{.Package}}/request"
{{- else }}
"{{.Module}}/utils"
"errors"
{{- end }}
{{- if .AutoCreateResource }}
"gorm.io/gorm"
{{- end}}
@ -80,6 +85,17 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service) Create{{.StructName}}({{
// Delete{{.StructName}} 删除{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}({{.PrimaryField.FieldJson}} string{{- if .AutoCreateResource -}},userID uint{{- end -}}) (err error) {
{{- if .IsTree }}
var count int64
err = {{$db}}.Find(&{{.Package}}.{{.StructName}}{},"parent_id = ?",{{.PrimaryField.FieldJson}}).Count(&count).Error
if count > 0 {
return errors.New("此节点存在子节点不允许删除")
}
if err != nil {
return err
}
{{- end }}
{{- if .AutoCreateResource }}
err = {{$db}}.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&{{.Package}}.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} = ?", {{.PrimaryField.FieldJson}}).Update("deleted_by", userID).Error; err != nil {
@ -129,6 +145,20 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}({{.Pri
return
}
{{- if .IsTree }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}记录,Tree模式下不添加分页和搜索
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoList() (list []*{{.Package}}.{{.StructName}},err error) {
// 创建db
db := {{$db}}.Model(&{{.Package}}.{{.StructName}}{})
var {{.Abbreviation}}s []*{{.Package}}.{{.StructName}}
err = db.Find(&{{.Abbreviation}}s).Error
return utils.BuildTree({{.Abbreviation}}s), err
}
{{- else }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoList(info {{.Package}}Req.{{.StructName}}Search) (list []{{.Package}}.{{.StructName}}, total int64, err error) {
@ -193,6 +223,8 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoLis
return {{.Abbreviation}}s, total, err
}
{{- end }}
{{- if .HasDataSource }}
func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}DataSource() (res map[string][]map[string]any, err error) {
res = make(map[string][]map[string]any)
@ -215,4 +247,4 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}Public(
// 此方法为获取数据源定义的数据
// 请自行实现
}
{{- end }}
{{- end }}

View File

@ -13,7 +13,7 @@
{{- end }}
{{- if eq .FieldType "string" }}
{{- if .DictType}}
<el-select v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
@ -95,7 +95,7 @@ const {{ $element }}Options = ref([])
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource}} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if or .DataSource}} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
@ -165,6 +165,20 @@ getDataSourceFunc()
<div>
<div class="gva-form-box">
<el-form :model="formData" ref="elFormRef" label-position="right" :rules="rule" label-width="80px">
{{- if .IsTree }}
<el-form-item label="父节点:" prop="parentID" >
<el-tree-select
v-model="formData.parentID"
:data="[rootNode,...tableData]"
check-strictly
:render-after-expand="false"
:props="defaultProps"
clearable
style="width: 240px"
placeholder="根节点"
/>
</el-form-item>
{{- end }}
{{- range .Fields}}
{{- if .Form }}
<el-form-item label="{{.FieldDesc}}:" prop="{{.FieldJson}}">
@ -178,7 +192,7 @@ getDataSourceFunc()
{{- end }}
{{- if eq .FieldType "string" }}
{{- if .DictType}}
<el-select v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
@ -239,6 +253,9 @@ import {
{{- if .HasDataSource }}
get{{.StructName}}DataSource,
{{- end }}
{{- if .IsTree }}
get{{.StructName}}List,
{{- end }}
create{{.StructName}},
update{{.StructName}},
find{{.StructName}}
@ -277,6 +294,32 @@ import ArrayCtrl from '@/components/arrayCtrl/arrayCtrl.vue'
const route = useRoute()
const router = useRouter()
{{- if .IsTree }}
const tableData = ref([])
const defaultProps = {
children: "children",
label: "{{ .TreeJson }}",
value: "{{ .PrimaryField.FieldJson }}"
}
const rootNode = {
{{ .PrimaryField.FieldJson }}: 0,
{{ .TreeJson }}: '根节点',
children: []
}
const getTableData = async() => {
const table = await get{{.StructName}}List()
if (table.code === 0) {
tableData.value = table.data || []
}
}
getTableData()
{{- end }}
// 提交按钮loading
const btnLoading = ref(false)
@ -285,6 +328,9 @@ const type = ref('')
const {{ $element }}Options = ref([])
{{- end }}
const formData = ref({
{{- if .IsTree }}
parentID: undefined,
{{- end }}
{{- range .Fields}}
{{- if .Form }}
{{- if eq .FieldType "bool" }}
@ -297,7 +343,7 @@ const formData = ref({
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource }} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if or .DataSource }} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),

View File

@ -19,7 +19,7 @@
</el-form-item>
{{- else if .DictType}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
<el-select v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
@ -37,13 +37,7 @@
<el-input v-model.number="searchInfo.end{{.FieldName}}" placeholder="最大值" />
{{- else}}
{{- if .DictType}}
<el-select v-model="searchInfo.{{.FieldJson}}" placeholder="请选择" style="width:100%" :clearable="true" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else}}
<el-input v-model.number="searchInfo.{{.FieldJson}}" placeholder="搜索条件" />
{{- end }}
{{- end}}
{{- else if eq .FieldType "time.Time"}}
{{if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
@ -86,7 +80,11 @@
{{- else if .DictType}}
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120">
<template #default="scope">
{{if eq .FieldType "array"}}
<el-tag class="mr-1" v-for="item in scope.row.{{.FieldJson}}" :key="item"> {{"{{"}} filterDict(item,{{.DictType}}Options) {{"}}"}}</el-tag>
{{- else }}
{{"{{"}} filterDict(scope.row.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
{{end}}
</template>
</el-table-column>
{{- else if eq .FieldType "bool" }}
@ -183,8 +181,14 @@
// 此字段为json结构可以前端自行控制展示和数据绑定模式 需绑定json的key为 formData.{{.FieldJson}} 后端会按照json的类型进行存取
{{"{{"}} formData.{{.FieldJson}} {{"}}"}}
{{- end }}
{{- if eq .FieldType "array" }}
{{- if eq .FieldType "array" }}
{{- if .DictType}}
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
<ArrayCtrl v-model="formData.{{ .FieldJson }}" editable/>
{{- end }}
{{- end }}
{{- if eq .FieldType "int" }}
<el-input v-model.number="formData.{{ .FieldJson }}" :clearable="{{.Clearable}}" placeholder="请输入{{.FieldDesc}}" />
@ -291,7 +295,7 @@ const {{ $element }}Options = ref([])
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource}} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if .DataSource}} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
@ -363,6 +367,7 @@ getDataSourceFunc()
{{- if not .OnlyTemplate}}
<template>
<div>
{{- if not .IsTree }}
<div class="gva-search-box">
<el-form ref="elSearchFormRef" :inline="true" :model="searchInfo" class="demo-form-inline" :rules="searchRule" @keyup.enter="onSubmit">
{{- if .GvaModel }}
@ -397,7 +402,7 @@ getDataSourceFunc()
</el-form-item>
{{- else if .DictType}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
<el-select v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-select {{if eq .FieldType "array"}} multiple {{end}}v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
@ -415,13 +420,7 @@ getDataSourceFunc()
<el-input v-model.number="searchInfo.end{{.FieldName}}" placeholder="最大值" />
{{- else}}
{{- if .DictType}}
<el-select v-model="searchInfo.{{.FieldJson}}" placeholder="请选择" style="width:100%" :clearable="true" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else}}
<el-input v-model.number="searchInfo.{{.FieldJson}}" placeholder="搜索条件" />
{{- end }}
{{- end}}
{{- else if eq .FieldType "time.Time"}}
{{if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
@ -463,7 +462,7 @@ getDataSourceFunc()
</el-form-item>
{{- else if .DictType}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
<el-select v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
@ -475,13 +474,7 @@ getDataSourceFunc()
<el-input v-model.number="searchInfo.end{{.FieldName}}" placeholder="最大值" />
{{- else}}
{{- if .DictType}}
<el-select v-model="searchInfo.{{.FieldJson}}" placeholder="请选择" style="width:100%" :clearable="true" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else}}
<el-input v-model.number="searchInfo.{{.FieldJson}}" placeholder="搜索条件" />
{{- end }}
{{- end}}
{{- else if eq .FieldType "time.Time"}}
{{if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
@ -515,9 +508,10 @@ getDataSourceFunc()
</el-form-item>
</el-form>
</div>
{{- end }}
<div class="gva-table-box">
<div class="gva-btn-list">
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.add"{{ end }} type="primary" icon="plus" @click="openDialog">新增</el-button>
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.add"{{ end }} type="primary" icon="plus" @click="openDialog()">新增</el-button>
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.batchDelete"{{ end }} icon="delete" style="margin-left: 10px;" :disabled="!multipleSelection.length" @click="onDelete">删除</el-button>
{{ if .HasExcel -}}
<ExportTemplate {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.exportTemplate"{{ end }} template-id="{{$templateID}}" />
@ -538,7 +532,7 @@ getDataSourceFunc()
>
<el-table-column type="selection" width="55" />
{{ if .GvaModel }}
<el-table-column align="left" label="日期" prop="createdAt" width="180">
<el-table-column align="left" label="日期" prop="createdAt" {{- if .IsTree }} min-{{- end }}width="180">
<template #default="scope">{{ "{{ formatDate(scope.row.CreatedAt) }}" }}</template>
</el-table-column>
{{ end }}
@ -559,7 +553,11 @@ getDataSourceFunc()
{{- else if .DictType}}
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120">
<template #default="scope">
{{"{{"}} filterDict(scope.row.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
{{if eq .FieldType "array"}}
<el-tag class="mr-1" v-for="item in scope.row.{{.FieldJson}}" :key="item"> {{"{{"}} filterDict(item,{{.DictType}}Options) {{"}}"}}</el-tag>
{{- else }}
{{"{{"}} filterDict(scope.row.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
{{end}}
</template>
</el-table-column>
{{- else if eq .FieldType "bool" }}
@ -627,11 +625,14 @@ getDataSourceFunc()
{{- end }}
{{- end }}
{{- end }}
<el-table-column align="left" label="操作" fixed="right" min-width="240">
<el-table-column align="left" label="操作" fixed="right" :min-width="appStore.operateMinWith">
<template #default="scope">
{{- if .IsTree }}
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.add"{{ end }} type="primary" link class="table-button" @click="openDialog(scope.row)"><el-icon style="margin-right: 5px"><InfoFilled /></el-icon>新增子节点</el-button>
{{- end }}
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.info"{{ end }} type="primary" link class="table-button" @click="getDetails(scope.row)"><el-icon style="margin-right: 5px"><InfoFilled /></el-icon>查看</el-button>
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.edit"{{ end }} type="primary" link icon="edit" class="table-button" @click="update{{.StructName}}Func(scope.row)">编辑</el-button>
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.delete"{{ end }} type="primary" link icon="delete" @click="deleteRow(scope.row)">删除</el-button>
<el-button {{ if .IsTree }}v-if="!scope.row.children?.length" {{ end }} {{if $global.AutoCreateBtnAuth }}v-auth="btnAuth.delete"{{ end }} type="primary" link icon="delete" @click="deleteRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@ -647,7 +648,7 @@ getDataSourceFunc()
/>
</div>
</div>
<el-drawer destroy-on-close size="800" v-model="dialogFormVisible" :show-close="false" :before-close="closeDialog">
<el-drawer destroy-on-close :size="appStore.drawerSize" v-model="dialogFormVisible" :show-close="false" :before-close="closeDialog">
<template #header>
<div class="flex justify-between items-center">
<span class="text-lg">{{"{{"}}type==='create'?'新增':'编辑'{{"}}"}}</span>
@ -659,6 +660,20 @@ getDataSourceFunc()
</template>
<el-form :model="formData" label-position="top" ref="elFormRef" :rules="rule" label-width="80px">
{{- if .IsTree }}
<el-form-item label="父节点:" prop="parentID" >
<el-tree-select
v-model="formData.parentID"
:data="[rootNode,...tableData]"
check-strictly
:render-after-expand="false"
:props="defaultProps"
clearable
style="width: 240px"
placeholder="根节点"
/>
</el-form-item>
{{- end }}
{{- range .Fields}}
{{- if .Form}}
<el-form-item label="{{.FieldDesc}}:" prop="{{.FieldJson}}" >
@ -687,7 +702,13 @@ getDataSourceFunc()
{{"{{"}} formData.{{.FieldJson}} {{"}}"}}
{{- end }}
{{- if eq .FieldType "array" }}
{{- if .DictType}}
<el-select multiple v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
<ArrayCtrl v-model="formData.{{ .FieldJson }}" editable/>
{{- end }}
{{- end }}
{{- if eq .FieldType "int" }}
<el-input v-model.number="formData.{{ .FieldJson }}" :clearable="{{.Clearable}}" placeholder="请输入{{.FieldDesc}}" />
@ -732,8 +753,23 @@ getDataSourceFunc()
</el-form>
</el-drawer>
<el-drawer destroy-on-close size="800" v-model="detailShow" :show-close="true" :before-close="closeDetailShow" title="查看">
<el-drawer destroy-on-close :size="appStore.drawerSize" v-model="detailShow" :show-close="true" :before-close="closeDetailShow" title="查看">
<el-descriptions :column="1" border>
{{- if .IsTree }}
<el-descriptions-item label="父节点">
<el-tree-select
v-model="detailFrom.parentID"
:data="[rootNode,...tableData]"
check-strictly
disabled
:render-after-expand="false"
:props="defaultProps"
clearable
style="width: 240px"
placeholder="根节点"
/>
</el-descriptions-item>
{{- end }}
{{- range .Fields}}
{{- if .Desc }}
<el-descriptions-item label="{{ .FieldDesc }}">
@ -747,6 +783,14 @@ getDataSourceFunc()
<span>{{"{{"}} filterDataSource(dataSource.{{.FieldJson}},detailFrom.{{.FieldJson}}) {{"}}"}}</span>
{{- end }}
</template>
{{- else if .DictType}}
<template #default="scope">
{{if eq .FieldType "array"}}
<el-tag class="mr-1" v-for="item in detailFrom.{{.FieldJson}}" :key="item"> {{"{{"}} filterDict(item,{{.DictType}}Options) {{"}}"}}</el-tag>
{{- else }}
{{"{{"}} filterDict(detailFrom.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
{{end}}
</template>
{{- else if and (ne .FieldType "picture" ) (ne .FieldType "pictures" ) (ne .FieldType "file" ) (ne .FieldType "array" ) }}
{{"{{"}} detailFrom.{{.FieldJson}} {{"}}"}}
{{- else }}
@ -821,6 +865,7 @@ import { ref, reactive } from 'vue'
// 引入按钮权限标识
import { useBtnAuth } from '@/utils/btnAuth'
{{- end }}
import { useAppStore } from "@/pinia"
{{if .HasExcel -}}
// 导出组件
@ -843,6 +888,7 @@ defineOptions({
// 提交按钮loading
const btnLoading = ref(false)
const appStore = useAppStore()
// 控制更多查询条件显示/隐藏状态
const showAllQuery = ref(false)
@ -852,6 +898,9 @@ const showAllQuery = ref(false)
const {{ $element }}Options = ref([])
{{- end }}
const formData = ref({
{{- if .IsTree }}
parentID:undefined,
{{- end }}
{{- range .Fields}}
{{- if .Form}}
{{- if eq .FieldType "bool" }}
@ -864,7 +913,7 @@ const formData = ref({
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource}} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if .DataSource}} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
@ -999,6 +1048,7 @@ const sortChange = ({ prop, order }) => {
}
{{- end}}
{{- if not .IsTree }}
// 重置
const onReset = () => {
searchInfo.value = {}
@ -1040,6 +1090,28 @@ const getTableData = async() => {
pageSize.value = table.data.pageSize
}
}
{{- else }}
// 树选择器配置
const defaultProps = {
children: "children",
label: "{{ .TreeJson }}",
value: "{{ .PrimaryField.FieldJson }}"
}
const rootNode = {
{{ .PrimaryField.FieldJson }}: 0,
{{ .TreeJson }}: '根节点',
children: []
}
// 查询
const getTableData = async() => {
const table = await get{{.StructName}}List()
if (table.code === 0) {
tableData.value = table.data || []
}
}
{{- end }}
getTableData()
@ -1140,8 +1212,11 @@ const delete{{.StructName}}Func = async (row) => {
const dialogFormVisible = ref(false)
// 打开弹窗
const openDialog = () => {
const openDialog = ({{- if .IsTree -}}row{{- end -}}) => {
type.value = 'create'
{{- if .IsTree }}
formData.value.parentID = row ? row.{{.PrimaryField.FieldJson}} : undefined
{{- end }}
dialogFormVisible.value = true
}
@ -1161,7 +1236,7 @@ const closeDialog = () => {
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource }} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if .DataSource }} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),

View File

@ -5,7 +5,9 @@ import (
"{{.Module}}/global"
"{{.Module}}/model/common/response"
"{{.Module}}/plugin/{{.Package}}/model"
{{- if not .IsTree}}
"{{.Module}}/plugin/{{.Package}}/model/request"
{{- end }}
"github.com/gin-gonic/gin"
"go.uber.org/zap"
{{- if .AutoCreateResource}}
@ -142,6 +144,25 @@ func (a *{{.Abbreviation}}) Find{{.StructName}}(c *gin.Context) {
response.OkWithData(re{{.Abbreviation}}, c)
}
{{- if .IsTree }}
// Get{{.StructName}}List 分页获取{{.Description}}列表
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func (a *{{.Abbreviation}}) Get{{.StructName}}List(c *gin.Context) {
list, err := service{{ .StructName }}.Get{{.StructName}}InfoList()
if err != nil {
global.GVA_LOG.Error("获取失败!", zap.Error(err))
response.FailWithMessage("获取失败:" + err.Error(), c)
return
}
response.OkWithDetailed(list, "获取成功", c)
}
{{- else }}
// Get{{.StructName}}List 分页获取{{.Description}}列表
// @Tags {{.StructName}}
// @Summary 分页获取{{.Description}}列表
@ -171,6 +192,7 @@ func (a *{{.Abbreviation}}) Get{{.StructName}}List(c *gin.Context) {
PageSize: pageInfo.PageSize,
}, "获取成功", c)
}
{{- end }}
{{- if .HasDataSource }}
// Get{{.StructName}}DataSource 获取{{.StructName}}的数据源
@ -197,7 +219,6 @@ func (a *{{.Abbreviation}}) Get{{.StructName}}DataSource(c *gin.Context) {
// @Summary 不需要鉴权的{{.Description}}接口
// @accept application/json
// @Produce application/json
// @Param data query request.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
func (a *{{.Abbreviation}}) Get{{.StructName}}Public(c *gin.Context) {

View File

@ -71,6 +71,10 @@ type {{.StructName}} struct {
UpdatedBy uint `gorm:"column:updated_by;comment:更新者"`
DeletedBy uint `gorm:"column:deleted_by;comment:删除者"`
{{- end }}
{{- if .IsTree }}
Children []*{{.StructName}} `json:"children" gorm:"-"` //子节点
ParentID int `json:"parentID" gorm:"column:parent_id;comment:父节点"`
{{- end }}
{{- end }}
}
@ -80,4 +84,29 @@ func ({{.StructName}}) TableName() string {
return "{{.TableName}}"
}
{{ end }}
{{ end }}
{{if .IsTree }}
// GetChildren 实现TreeNode接口
func (s *{{.StructName}}) GetChildren() []*{{.StructName}} {
return s.Children
}
// SetChildren 实现TreeNode接口
func (s *{{.StructName}}) SetChildren(children *{{.StructName}}) {
s.Children = append(s.Children, children)
}
// GetID 实现TreeNode接口
func (s *{{.StructName}}) GetID() int {
return int({{if not .GvaModel}}*{{- end }}s.{{.PrimaryField.FieldName}})
}
// GetParentID 实现TreeNode接口
func (s *{{.StructName}}) GetParentID() int {
return s.ParentID
}
{{ end }}
{{ end }}

View File

@ -60,10 +60,17 @@ import (
{{- if not .OnlyTemplate }}
"{{.Module}}/global"
"{{.Module}}/plugin/{{.Package}}/model"
{{- if not .IsTree }}
"{{.Module}}/plugin/{{.Package}}/model/request"
{{- else }}
"errors"
{{- end }}
{{- if .AutoCreateResource }}
"gorm.io/gorm"
{{- end}}
{{- if .IsTree }}
"{{.Module}}/utils"
{{- end }}
{{- end }}
)
@ -88,6 +95,18 @@ func (s *{{.Abbreviation}}) Create{{.StructName}}({{.Abbreviation}} *model.{{.St
// Delete{{.StructName}} 删除{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Delete{{.StructName}}({{.PrimaryField.FieldJson}} string{{- if .AutoCreateResource -}},userID uint{{- end -}}) (err error) {
{{- if .IsTree }}
var count int64
err = {{$db}}.Find(&model.{{.StructName}}{},"parent_id = ?",{{.PrimaryField.FieldJson}}).Count(&count).Error
if count > 0 {
return errors.New("此节点存在子节点不允许删除")
}
if err != nil {
return err
}
{{- end }}
{{- if .AutoCreateResource }}
err = {{$db}}.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&model.{{.StructName}}{}).Where("{{.PrimaryField.ColumnName}} = ?", {{.PrimaryField.FieldJson}}).Update("deleted_by", userID).Error; err != nil {
@ -137,6 +156,20 @@ func (s *{{.Abbreviation}}) Get{{.StructName}}({{.PrimaryField.FieldJson}} strin
return
}
{{- if .IsTree }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}记录,Tree模式下不添加分页和搜索
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList() (list []*model.{{.StructName}},err error) {
// 创建db
db := {{$db}}.Model(&model.{{.StructName}}{})
var {{.Abbreviation}}s []*model.{{.StructName}}
err = db.Find(&{{.Abbreviation}}s).Error
return utils.BuildTree({{.Abbreviation}}s), err
}
{{- else }}
// Get{{.StructName}}InfoList 分页获取{{.Description}}记录
// Author [yourname](https://github.com/yourname)
func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(info request.{{.StructName}}Search) (list []model.{{.StructName}}, total int64, err error) {
@ -199,7 +232,7 @@ func (s *{{.Abbreviation}}) Get{{.StructName}}InfoList(info request.{{.StructNam
err = db.Find(&{{.Abbreviation}}s).Error
return {{.Abbreviation}}s, total, err
}
{{- end }}
{{- if .HasDataSource }}
func (s *{{.Abbreviation}})Get{{.StructName}}DataSource() (res map[string][]map[string]any, err error) {
res = make(map[string][]map[string]any)
@ -222,4 +255,4 @@ func (s *{{.Abbreviation}})Get{{.StructName}}DataSource() (res map[string][]map[
func (s *{{.Abbreviation}})Get{{.StructName}}Public() {
}
{{- end }}
{{- end }}

View File

@ -13,7 +13,7 @@
{{- end }}
{{- if eq .FieldType "string" }}
{{- if .DictType}}
<el-select v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
@ -95,7 +95,7 @@ const {{ $element }}Options = ref([])
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource}} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if or .DataSource}} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
@ -148,6 +148,7 @@ const {{ $element }}Options = ref([])
{{- if .HasDataSource }}
// 请引用
get{{.StructName}}DataSource,
// 获取数据源
const dataSource = ref([])
const getDataSourceFunc = async()=>{
@ -159,13 +160,27 @@ const getDataSourceFunc = async()=>{
getDataSourceFunc()
{{- end }}
{{- else }}
{{- if not .OnlyTemplate}}
{{- if not .OnlyTemplate }}
<template>
<div>
<div class="gva-form-box">
<el-form :model="formData" ref="elFormRef" label-position="right" :rules="rule" label-width="80px">
{{- if .IsTree }}
<el-form-item label="父节点:" prop="parentID" >
<el-tree-select
v-model="formData.parentID"
:data="[rootNode,...tableData]"
check-strictly
:render-after-expand="false"
:props="defaultProps"
clearable
style="width: 240px"
placeholder="根节点"
/>
</el-form-item>
{{- end }}
{{- range .Fields}}
{{- if .Form }}
{{- if .Form }}
<el-form-item label="{{.FieldDesc}}:" prop="{{.FieldJson}}">
{{- if .CheckDataSource}}
<el-select {{if eq .DataSource.Association 2}} multiple {{ end }} v-model="formData.{{.FieldJson}}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
@ -177,7 +192,7 @@ getDataSourceFunc()
{{- end }}
{{- if eq .FieldType "string" }}
{{- if .DictType}}
<el-select v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
@ -219,13 +234,13 @@ getDataSourceFunc()
{{- end }}
{{- if eq .FieldType "array" }}
<ArrayCtrl v-model="formData.{{ .FieldJson }}" editable/>
{{- end }}
{{- end }}
{{- end }}
</el-form-item>
{{- end }}
{{- end }}
<el-form-item>
<el-button type="primary" @click="save">保存</el-button>
<el-button :loading="btnLoading" type="primary" @click="save">保存</el-button>
<el-button type="primary" @click="back">返回</el-button>
</el-form-item>
</el-form>
@ -238,10 +253,13 @@ import {
{{- if .HasDataSource }}
get{{.StructName}}DataSource,
{{- end }}
{{- if .IsTree }}
get{{.StructName}}List,
{{- end }}
create{{.StructName}},
update{{.StructName}},
find{{.StructName}}
} from '@/plugin/{{.Package}}/api/{{.PackageName}}'
} from '@/api/{{.Package}}/{{.PackageName}}'
defineOptions({
name: '{{.StructName}}Form'
@ -272,14 +290,47 @@ import RichEdit from '@/components/richtext/rich-edit.vue'
import ArrayCtrl from '@/components/arrayCtrl/arrayCtrl.vue'
{{- end }}
const route = useRoute()
const router = useRouter()
{{- if .IsTree }}
const tableData = ref([])
const defaultProps = {
children: "children",
label: "{{ .TreeJson }}",
value: "{{ .PrimaryField.FieldJson }}"
}
const rootNode = {
{{ .PrimaryField.FieldJson }}: 0,
{{ .TreeJson }}: '根节点',
children: []
}
const getTableData = async() => {
const table = await get{{.StructName}}List()
if (table.code === 0) {
tableData.value = table.data || []
}
}
getTableData()
{{- end }}
// 提交按钮loading
const btnLoading = ref(false)
const type = ref('')
{{- range $index, $element := .DictTypes}}
const {{ $element }}Options = ref([])
{{- end }}
const formData = ref({
{{- if .IsTree }}
parentID: undefined,
{{- end }}
{{- range .Fields}}
{{- if .Form }}
{{- if eq .FieldType "bool" }}
@ -292,7 +343,7 @@ const formData = ref({
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource }} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if or .DataSource }} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
@ -324,7 +375,6 @@ const formData = ref({
// 验证规则
const rule = reactive({
{{- range .Fields }}
{{- if .Form }}
{{- if eq .Require true }}
{{.FieldJson }} : [{
required: true,
@ -332,7 +382,6 @@ const rule = reactive({
trigger: ['input','blur'],
}],
{{- end }}
{{- end }}
{{- end }}
})
@ -369,8 +418,9 @@ const init = async () => {
init()
// 保存按钮
const save = async() => {
btnLoading.value = true
elFormRef.value?.validate( async (valid) => {
if (!valid) return
if (!valid) return btnLoading.value = false
let res
switch (type.value) {
case 'create':
@ -383,6 +433,7 @@ const save = async() => {
res = await create{{.StructName}}(formData.value)
break
}
btnLoading.value = false
if (res.code === 0) {
ElMessage({
type: 'success',

View File

@ -1,6 +1,5 @@
{{- $global := . }}
{{- $templateID := printf "%s_%s" .Package .StructName }}
{{- if .IsAdd }}
// 请在搜索条件中增加如下代码
{{- range .Fields}} {{- if .FieldSearchType}} {{- if eq .FieldType "bool" }}
@ -20,7 +19,7 @@
</el-form-item>
{{- else if .DictType}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
<el-select v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
@ -38,13 +37,7 @@
<el-input v-model.number="searchInfo.end{{.FieldName}}" placeholder="最大值" />
{{- else}}
{{- if .DictType}}
<el-select v-model="searchInfo.{{.FieldJson}}" placeholder="请选择" style="width:100%" :clearable="true" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else}}
<el-input v-model.number="searchInfo.{{.FieldJson}}" placeholder="搜索条件" />
{{- end }}
{{- end}}
{{- else if eq .FieldType "time.Time"}}
{{if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
@ -87,7 +80,11 @@
{{- else if .DictType}}
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120">
<template #default="scope">
{{if eq .FieldType "array"}}
<el-tag class="mr-1" v-for="item in scope.row.{{.FieldJson}}" :key="item"> {{"{{"}} filterDict(item,{{.DictType}}Options) {{"}}"}}</el-tag>
{{- else }}
{{"{{"}} filterDict(scope.row.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
{{end}}
</template>
</el-table-column>
{{- else if eq .FieldType "bool" }}
@ -185,8 +182,14 @@
{{"{{"}} formData.{{.FieldJson}} {{"}}"}}
{{- end }}
{{- if eq .FieldType "array" }}
{{- if .DictType}}
<el-select multiple v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
<ArrayCtrl v-model="formData.{{ .FieldJson }}" editable/>
{{- end }}
{{- end }}
{{- if eq .FieldType "int" }}
<el-input v-model.number="formData.{{ .FieldJson }}" :clearable="{{.Clearable}}" placeholder="请输入{{.FieldDesc}}" />
{{- end }}
@ -272,6 +275,7 @@
{{- range $index, $element := .DictTypes}}
const {{ $element }}Options = ref([])
{{- end }}
// setOptions方法中增加如下调用
{{- range $index, $element := .DictTypes }}
@ -291,7 +295,7 @@ const {{ $element }}Options = ref([])
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource}} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if .DataSource}} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
@ -341,15 +345,18 @@ const {{ $element }}Options = ref([])
{{- end }}
{{- end }}
{{- if .HasDataSource }}
// 请引用
get{{.StructName}}DataSource,
// 获取数据源
const dataSource = ref({})
const getDataSourceFunc = async()=>{
const res = await get{{.StructName}}DataSource()
if (res.code === 0) {
dataSource.value = res.data
dataSource.value = res.data || []
}
}
getDataSourceFunc()
@ -360,6 +367,7 @@ getDataSourceFunc()
{{- if not .OnlyTemplate}}
<template>
<div>
{{- if not .IsTree }}
<div class="gva-search-box">
<el-form ref="elSearchFormRef" :inline="true" :model="searchInfo" class="demo-form-inline" :rules="searchRule" @keyup.enter="onSubmit">
{{- if .GvaModel }}
@ -394,15 +402,15 @@ getDataSourceFunc()
</el-form-item>
{{- else if .DictType}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
<el-select v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-select {{if eq .FieldType "array"}} multiple {{end}}v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
{{- else if .CheckDataSource}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
<el-select {{if eq .DataSource.Association 2}} multiple {{ end }} v-model="searchInfo.{{.FieldJson}}" placeholder="请选择{{.FieldDesc}}" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in dataSource.{{.FieldJson}}" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else if .CheckDataSource}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
<el-select {{if eq .DataSource.Association 2}} multiple {{ end }} v-model="searchInfo.{{.FieldJson}}" placeholder="请选择{{.FieldDesc}}" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in dataSource.{{.FieldJson}}" :key="key" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
{{- else}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
@ -412,13 +420,7 @@ getDataSourceFunc()
<el-input v-model.number="searchInfo.end{{.FieldName}}" placeholder="最大值" />
{{- else}}
{{- if .DictType}}
<el-select v-model="searchInfo.{{.FieldJson}}" placeholder="请选择" style="width:100%" :clearable="true" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else}}
<el-input v-model.number="searchInfo.{{.FieldJson}}" placeholder="搜索条件" />
{{- end }}
{{- end}}
{{- else if eq .FieldType "time.Time"}}
{{if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
@ -439,7 +441,6 @@ getDataSourceFunc()
{{- else}}
<el-input v-model="searchInfo.{{.FieldJson}}" placeholder="搜索条件" />
{{- end}}
</el-form-item>{{ end }}{{ end }}{{ end }}{{ end }}
<template v-if="showAllQuery">
@ -461,7 +462,7 @@ getDataSourceFunc()
</el-form-item>
{{- else if .DictType}}
<el-form-item label="{{.FieldDesc}}" prop="{{.FieldJson}}">
<el-select v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-select {{if eq .FieldType "array"}}multiple {{end}}v-model="searchInfo.{{.FieldJson}}" clearable placeholder="请选择" @clear="()=>{searchInfo.{{.FieldJson}}=undefined}">
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
@ -473,13 +474,7 @@ getDataSourceFunc()
<el-input v-model.number="searchInfo.end{{.FieldName}}" placeholder="最大值" />
{{- else}}
{{- if .DictType}}
<el-select v-model="searchInfo.{{.FieldJson}}" placeholder="请选择" style="width:100%" :clearable="true" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else}}
<el-input v-model.number="searchInfo.{{.FieldJson}}" placeholder="搜索条件" />
{{- end }}
{{- end}}
{{- else if eq .FieldType "time.Time"}}
{{if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
@ -513,9 +508,10 @@ getDataSourceFunc()
</el-form-item>
</el-form>
</div>
{{- end }}
<div class="gva-table-box">
<div class="gva-btn-list">
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.add"{{ end }} type="primary" icon="plus" @click="openDialog">新增</el-button>
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.add"{{ end }} type="primary" icon="plus" @click="openDialog()">新增</el-button>
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.batchDelete"{{ end }} icon="delete" style="margin-left: 10px;" :disabled="!multipleSelection.length" @click="onDelete">删除</el-button>
{{ if .HasExcel -}}
<ExportTemplate {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.exportTemplate"{{ end }} template-id="{{$templateID}}" />
@ -536,7 +532,7 @@ getDataSourceFunc()
>
<el-table-column type="selection" width="55" />
{{ if .GvaModel }}
<el-table-column align="left" label="日期" prop="createdAt" width="180">
<el-table-column align="left" label="日期" prop="createdAt" {{- if .IsTree }} min-{{- end }}width="180">
<template #default="scope">{{ "{{ formatDate(scope.row.CreatedAt) }}" }}</template>
</el-table-column>
{{ end }}
@ -557,7 +553,11 @@ getDataSourceFunc()
{{- else if .DictType}}
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120">
<template #default="scope">
{{"{{"}} filterDict(scope.row.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
{{if eq .FieldType "array"}}
<el-tag class="mr-1" v-for="item in scope.row.{{.FieldJson}}" :key="item"> {{"{{"}} filterDict(item,{{.DictType}}Options) {{"}}"}}</el-tag>
{{- else }}
{{"{{"}} filterDict(scope.row.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
{{end}}
</template>
</el-table-column>
{{- else if eq .FieldType "bool" }}
@ -614,22 +614,25 @@ getDataSourceFunc()
[JSON]
</template>
</el-table-column>
{{- else if eq .FieldType "array" }}
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
{{- else if eq .FieldType "array" }}
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<ArrayCtrl v-model="scope.row.{{ .FieldJson }}"/>
</template>
</el-table-column>
{{- else }}
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120" />
{{- end }}
</template>
</el-table-column>
{{- else }}
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120" />
{{- end }}
{{- end }}
{{- end }}
<el-table-column align="left" label="操作" fixed="right" min-width="240">
<template #default="scope">
{{- if .IsTree }}
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.add"{{ end }} type="primary" link class="table-button" @click="openDialog(scope.row)"><el-icon style="margin-right: 5px"><InfoFilled /></el-icon>新增子节点</el-button>
{{- end }}
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.info"{{ end }} type="primary" link class="table-button" @click="getDetails(scope.row)"><el-icon style="margin-right: 5px"><InfoFilled /></el-icon>查看</el-button>
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.edit"{{ end }} type="primary" link icon="edit" class="table-button" @click="update{{.StructName}}Func(scope.row)">编辑</el-button>
<el-button {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.delete"{{ end }} type="primary" link icon="delete" @click="deleteRow(scope.row)">删除</el-button>
<el-button {{ if .IsTree }}v-if="!scope.row.children?.length"{{ end }} {{ if $global.AutoCreateBtnAuth }}v-auth="btnAuth.delete"{{ end }} type="primary" link icon="delete" @click="deleteRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@ -650,15 +653,29 @@ getDataSourceFunc()
<div class="flex justify-between items-center">
<span class="text-lg">{{"{{"}}type==='create'?'新增':'编辑'{{"}}"}}</span>
<div>
<el-button type="primary" @click="enterDialog">确 定</el-button>
<el-button :loading="btnLoading" type="primary" @click="enterDialog">确 定</el-button>
<el-button @click="closeDialog">取 消</el-button>
</div>
</div>
</template>
<el-form :model="formData" label-position="top" ref="elFormRef" :rules="rule" label-width="80px">
{{- if .IsTree }}
<el-form-item label="父节点:" prop="parentID" >
<el-tree-select
v-model="formData.parentID"
:data="[rootNode,...tableData]"
check-strictly
:render-after-expand="false"
:props="defaultProps"
clearable
style="width: 240px"
placeholder="根节点"
/>
</el-form-item>
{{- end }}
{{- range .Fields}}
{{- if .Form}}
{{- if .Form}}
<el-form-item label="{{.FieldDesc}}:" prop="{{.FieldJson}}" >
{{- if .CheckDataSource}}
<el-select {{if eq .DataSource.Association 2}} multiple {{ end }} v-model="formData.{{.FieldJson}}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
@ -685,7 +702,13 @@ getDataSourceFunc()
{{"{{"}} formData.{{.FieldJson}} {{"}}"}}
{{- end }}
{{- if eq .FieldType "array" }}
{{- if .DictType}}
<el-select multiple v-model="formData.{{ .FieldJson }}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in {{ .DictType }}Options" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
<ArrayCtrl v-model="formData.{{ .FieldJson }}" editable/>
{{- end }}
{{- end }}
{{- if eq .FieldType "int" }}
<el-input v-model.number="formData.{{ .FieldJson }}" :clearable="{{.Clearable}}" placeholder="请输入{{.FieldDesc}}" />
@ -730,51 +753,70 @@ getDataSourceFunc()
</el-form>
</el-drawer>
<el-drawer destroy-on-close size="800" v-model="detailShow" :show-close="true" :before-close="closeDetailShow" title="查看">
<el-descriptions column="1" border>
{{- range .Fields}}
{{- if .Desc }}
<el-descriptions-item label="{{ .FieldDesc }}">
{{- if .CheckDataSource }}
<template #default="scope">
{{- if eq .DataSource.Association 2}}
<el-tag v-for="(item,key) in filterDataSource(dataSource.{{.FieldJson}},detailFrom.{{.FieldJson}})" :key="key">
{{ "{{ item }}" }}
</el-tag>
{{- else }}
<span>{{"{{"}} filterDataSource(dataSource.{{.FieldJson}},detailFrom.{{.FieldJson}}) {{"}}"}}</span>
{{- end }}
</template>
<el-drawer destroy-on-close size="800" v-model="detailShow" :show-close="true" :before-close="closeDetailShow" title="查看">
<el-descriptions :column="1" border>
{{- if .IsTree }}
<el-descriptions-item label="父节点">
<el-tree-select
v-model="detailFrom.parentID"
:data="[rootNode,...tableData]"
check-strictly
disabled
:render-after-expand="false"
:props="defaultProps"
clearable
style="width: 240px"
placeholder="根节点"
/>
</el-descriptions-item>
{{- end }}
{{- range .Fields}}
{{- if .Desc }}
<el-descriptions-item label="{{ .FieldDesc }}">
{{- if .CheckDataSource }}
<template #default="scope">
{{- if eq .DataSource.Association 2}}
<el-tag v-for="(item,key) in filterDataSource(dataSource.{{.FieldJson}},detailFrom.{{.FieldJson}})" :key="key">
{{ "{{ item }}" }}
</el-tag>
{{- else }}
<span>{{"{{"}} filterDataSource(dataSource.{{.FieldJson}},detailFrom.{{.FieldJson}}) {{"}}"}}</span>
{{- end }}
</template>
{{- else if .DictType}}
<template #default="scope">
{{if eq .FieldType "array"}}
<el-tag class="mr-1" v-for="item in detailFrom.{{.FieldJson}}" :key="item"> {{"{{"}} filterDict(item,{{.DictType}}Options) {{"}}"}}</el-tag>
{{- else }}
{{"{{"}} filterDict(detailFrom.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
{{end}}
</template>
{{- else if and (ne .FieldType "picture" ) (ne .FieldType "pictures" ) (ne .FieldType "file" ) (ne .FieldType "array" ) }}
{{"{{"}} detailFrom.{{.FieldJson}} {{"}}"}}
{{- else }}
{{- if eq .FieldType "picture" }}
<el-image style="width: 50px; height: 50px" :preview-src-list="returnArrImg(detailFrom.{{ .FieldJson }})" :src="getUrl(detailFrom.{{ .FieldJson }})" fit="cover" />
{{- end }}
{{- if eq .FieldType "array" }}
<ArrayCtrl v-model="detailFrom.{{ .FieldJson }}"/>
{{- end }}
{{- if eq .FieldType "pictures" }}
<el-image style="width: 50px; height: 50px; margin-right: 10px" :preview-src-list="returnArrImg(detailFrom.{{ .FieldJson }})" :initial-index="index" v-for="(item,index) in detailFrom.{{ .FieldJson }}" :key="index" :src="getUrl(item)" fit="cover" />
{{- end }}
{{- if eq .FieldType "file" }}
<div class="fileBtn" v-for="(item,index) in detailFrom.{{ .FieldJson }}" :key="index">
<el-button type="primary" text bg @click="onDownloadFile(item.url)">
<el-icon style="margin-right: 5px"><Download /></el-icon>
{{"{{"}}item.name{{"}}"}}
</el-button>
</div>
{{- end }}
{{"{{"}} detailFrom.{{.FieldJson}} {{"}}"}}
{{- else }}
{{- if eq .FieldType "picture" }}
<el-image style="width: 50px; height: 50px" :preview-src-list="returnArrImg(detailFrom.{{ .FieldJson }})" :src="getUrl(detailFrom.{{ .FieldJson }})" fit="cover" />
{{- end }}
{{- if eq .FieldType "array" }}
<ArrayCtrl v-model="detailFrom.{{ .FieldJson }}"/>
{{- end }}
{{- if eq .FieldType "pictures" }}
<el-image style="width: 50px; height: 50px; margin-right: 10px" :preview-src-list="returnArrImg(detailFrom.{{ .FieldJson }})" :initial-index="index" v-for="(item,index) in detailFrom.{{ .FieldJson }}" :key="index" :src="getUrl(item)" fit="cover" />
{{- end }}
{{- if eq .FieldType "file" }}
<div class="fileBtn" v-for="(item,index) in detailFrom.{{ .FieldJson }}" :key="index">
<el-button type="primary" text bg @click="onDownloadFile(item.url)">
<el-icon style="margin-right: 5px"><Download /></el-icon>
{{"{{"}}item.name{{"}}"}}
</el-button>
</div>
{{- end }}
</el-descriptions-item>
{{- end }}
{{- end }}
</el-descriptions>
</el-drawer>
</el-descriptions-item>
{{- end }}
{{- end }}
</el-descriptions>
</el-drawer>
</div>
</template>
@ -805,7 +847,6 @@ import SelectImage from '@/components/selectImage/selectImage.vue'
import RichEdit from '@/components/richtext/rich-edit.vue'
{{- end }}
{{- if .HasFile }}
// 文件选择组件
import SelectFile from '@/components/selectFile/selectFile.vue'
@ -844,6 +885,9 @@ defineOptions({
const btnAuth = useBtnAuth()
{{- end }}
// 提交按钮loading
const btnLoading = ref(false)
// 控制更多查询条件显示/隐藏状态
const showAllQuery = ref(false)
@ -852,45 +896,48 @@ const showAllQuery = ref(false)
const {{ $element }}Options = ref([])
{{- end }}
const formData = ref({
{{- if .IsTree }}
parentID:undefined,
{{- end }}
{{- range .Fields}}
{{- if .Form}}
{{- if eq .FieldType "bool" }}
{{.FieldJson}}: false,
{{- end }}
{{- if eq .FieldType "string" }}
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "richtext" }}
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource}} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
{{- end }}
{{- if eq .FieldType "float64" }}
{{.FieldJson}}: 0,
{{- end }}
{{- if eq .FieldType "picture" }}
{{.FieldJson}}: "",
{{- end }}
{{- if eq .FieldType "video" }}
{{.FieldJson}}: "",
{{- end }}
{{- if eq .FieldType "pictures" }}
{{.FieldJson}}: [],
{{- end }}
{{- if eq .FieldType "file" }}
{{.FieldJson}}: [],
{{- end }}
{{- if eq .FieldType "json" }}
{{.FieldJson}}: {},
{{- end }}
{{- if eq .FieldType "array" }}
{{.FieldJson}}: [],
{{- end }}
{{- end }}
{{- if .Form}}
{{- if eq .FieldType "bool" }}
{{.FieldJson}}: false,
{{- end }}
{{- if eq .FieldType "string" }}
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "richtext" }}
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if .DataSource}} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
{{- end }}
{{- if eq .FieldType "float64" }}
{{.FieldJson}}: 0,
{{- end }}
{{- if eq .FieldType "picture" }}
{{.FieldJson}}: "",
{{- end }}
{{- if eq .FieldType "video" }}
{{.FieldJson}}: "",
{{- end }}
{{- if eq .FieldType "pictures" }}
{{.FieldJson}}: [],
{{- end }}
{{- if eq .FieldType "file" }}
{{.FieldJson}}: [],
{{- end }}
{{- if eq .FieldType "json" }}
{{.FieldJson}}: {},
{{- end }}
{{- if eq .FieldType "array" }}
{{.FieldJson}}: [],
{{- end }}
{{- end }}
{{- end }}
})
@ -910,7 +957,7 @@ const formData = ref({
// 验证规则
const rule = reactive({
{{- range .Fields }}
{{- if .Form }}
{{- if .Form }}
{{- if eq .Require true }}
{{.FieldJson }} : [{
required: true,
@ -926,7 +973,7 @@ const rule = reactive({
{{- end }}
],
{{- end }}
{{- end }}
{{- end }}
{{- end }}
})
@ -978,13 +1025,13 @@ const searchInfo = ref({})
const sortChange = ({ prop, order }) => {
const sortMap = {
{{- range .Fields}}
{{- if .Table}}
{{- if and .Sort}}
{{- if not (eq .ColumnName "")}}
{{.FieldJson}}: '{{.ColumnName}}',
{{- end}}
{{- if .Table}}
{{- if and .Sort}}
{{- if not (eq .ColumnName "")}}
{{.FieldJson}}: '{{.ColumnName}}',
{{- end}}
{{- end}}
{{- end}}
{{- end}}
}
@ -999,6 +1046,7 @@ const sortChange = ({ prop, order }) => {
}
{{- end}}
{{- if not .IsTree }}
// 重置
const onReset = () => {
searchInfo.value = {}
@ -1040,6 +1088,28 @@ const getTableData = async() => {
pageSize.value = table.data.pageSize
}
}
{{- else }}
// 树选择器配置
const defaultProps = {
children: "children",
label: "{{ .TreeJson }}",
value: "{{ .PrimaryField.FieldJson }}"
}
const rootNode = {
{{ .PrimaryField.FieldJson }}: 0,
{{ .TreeJson }}: '根节点',
children: []
}
// 查询
const getTableData = async() => {
const table = await get{{.StructName}}List()
if (table.code === 0) {
tableData.value = table.data || []
}
}
{{- end }}
getTableData()
@ -1140,8 +1210,11 @@ const delete{{.StructName}}Func = async (row) => {
const dialogFormVisible = ref(false)
// 打开弹窗
const openDialog = () => {
const openDialog = ({{- if .IsTree -}}row{{- end -}}) => {
type.value = 'create'
{{- if .IsTree }}
formData.value.parentID = row ? row.{{.PrimaryField.FieldJson}} : undefined
{{- end }}
dialogFormVisible.value = true
}
@ -1161,7 +1234,7 @@ const closeDialog = () => {
{{.FieldJson}}: '',
{{- end }}
{{- if eq .FieldType "int" }}
{{.FieldJson}}: {{- if or .DictType .DataSource }} undefined{{ else }} 0{{- end }},
{{.FieldJson}}: {{- if .DataSource }} undefined{{ else }} 0{{- end }},
{{- end }}
{{- if eq .FieldType "time.Time" }}
{{.FieldJson}}: new Date(),
@ -1193,8 +1266,9 @@ const closeDialog = () => {
}
// 弹窗确定
const enterDialog = async () => {
btnLoading.value = true
elFormRef.value?.validate( async (valid) => {
if (!valid) return
if (!valid) return btnLoading.value = false
let res
switch (type.value) {
case 'create':
@ -1207,6 +1281,7 @@ const enterDialog = async () => {
res = await create{{.StructName}}(formData.value)
break
}
btnLoading.value = false
if (res.code === 0) {
ElMessage({
type: 'success',
@ -1223,7 +1298,6 @@ const downloadFile = (url) => {
}
{{end}}
const detailFrom = ref({})
// 查看详情控制标记
@ -1284,5 +1358,6 @@ defineOptions({
</script>
<style>
</style>
{{- end}}
{{- end}}
{{- end }}
{{- end }}

View File

@ -58,7 +58,7 @@ func (e *FileUploadAndDownloadService) CreateFileChunk(id uint, fileChunkPath st
func (e *FileUploadAndDownloadService) DeleteFileChunk(fileMd5 string, filePath string) error {
var chunks []example.ExaFileChunk
var file example.ExaFile
err := global.GVA_DB.Where("file_md5 = ? ", fileMd5).First(&file).
err := global.GVA_DB.Where("file_md5 = ?", fileMd5).First(&file).
Updates(map[string]interface{}{
"IsFinish": true,
"file_path": filePath,

View File

@ -169,8 +169,8 @@ func (casbinService *CasbinService) AddPolicies(db *gorm.DB, rules [][]string) e
return db.Create(&casbinRules).Error
}
func (CasbinService *CasbinService) FreshCasbin() (err error) {
e := CasbinService.Casbin()
func (casbinService *CasbinService) FreshCasbin() (err error) {
e := casbinService.Casbin()
err = e.LoadPolicy()
return err
}

View File

@ -54,7 +54,12 @@ func (h PgsqlInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (n
} // 如果没有数据库名, 则跳出初始化数据
dsn := conf.PgsqlEmptyDsn()
createSql := fmt.Sprintf("CREATE DATABASE %s;", c.Dbname)
var createSql string
if conf.Template != "" {
createSql = fmt.Sprintf("CREATE DATABASE %s WITH TEMPLATE %s;", c.Dbname, conf.Template)
} else {
createSql = fmt.Sprintf("CREATE DATABASE %s;", c.Dbname)
}
if err = createDatabase(dsn, "pgx", createSql); err != nil {
return nil, err
} // 创建数据库

View File

@ -33,7 +33,7 @@ func (i *initExaFileMysql) TableCreated(ctx context.Context) bool {
return db.Migrator().HasTable(&example.ExaFileUploadAndDownload{})
}
func (i initExaFileMysql) InitializerName() string {
func (i *initExaFileMysql) InitializerName() string {
return example.ExaFileUploadAndDownload{}.TableName()
}

View File

@ -17,7 +17,7 @@ func init() {
system.RegisterInit(initOrderApi, &initApi{})
}
func (i initApi) InitializerName() string {
func (i *initApi) InitializerName() string {
return sysModel.SysApi{}.TableName()
}

View File

@ -17,7 +17,7 @@ func init() {
system.RegisterInit(initOrderApiIgnore, &initApiIgnore{})
}
func (i initApiIgnore) InitializerName() string {
func (i *initApiIgnore) InitializerName() string {
return sysModel.SysIgnoreApi{}.TableName()
}

View File

@ -26,7 +26,7 @@ func (i *initMenuAuthority) TableCreated(ctx context.Context) bool {
return false // always replace
}
func (i initMenuAuthority) InitializerName() string {
func (i *initMenuAuthority) InitializerName() string {
return "sys_menu_authorities"
}
@ -35,11 +35,12 @@ func (i *initMenuAuthority) InitializeData(ctx context.Context) (next context.Co
if !ok {
return ctx, system.ErrMissingDBContext
}
authorities, ok := ctx.Value(initAuthority{}.InitializerName()).([]sysModel.SysAuthority)
initAuth := &initAuthority{}
authorities, ok := ctx.Value(initAuth.InitializerName()).([]sysModel.SysAuthority)
if !ok {
return ctx, errors.Wrap(system.ErrMissingDependentContext, "创建 [菜单-权限] 关联失败, 未找到权限表初始化数据")
}
menus, ok := ctx.Value(initMenu{}.InitializerName()).([]sysModel.SysBaseMenu)
menus, ok := ctx.Value(new(initMenu).InitializerName()).([]sysModel.SysBaseMenu)
if !ok {
return next, errors.Wrap(errors.New(""), "创建 [菜单-权限] 关联失败, 未找到菜单表初始化数据")
}

View File

@ -34,7 +34,7 @@ func (i *initAuthority) TableCreated(ctx context.Context) bool {
return db.Migrator().HasTable(&sysModel.SysAuthority{})
}
func (i initAuthority) InitializerName() string {
func (i *initAuthority) InitializerName() string {
return sysModel.SysAuthority{}.TableName()
}

View File

@ -34,7 +34,7 @@ func (i *initCasbin) TableCreated(ctx context.Context) bool {
return db.Migrator().HasTable(&adapter.CasbinRule{})
}
func (i initCasbin) InitializerName() string {
func (i *initCasbin) InitializerName() string {
var entity adapter.CasbinRule
return entity.TableName()
}

View File

@ -33,7 +33,7 @@ func (i *initDict) TableCreated(ctx context.Context) bool {
return db.Migrator().HasTable(&sysModel.SysDictionary{})
}
func (i initDict) InitializerName() string {
func (i *initDict) InitializerName() string {
return sysModel.SysDictionary{}.TableName()
}

View File

@ -34,7 +34,7 @@ func (i *initDictDetail) TableCreated(ctx context.Context) bool {
return db.Migrator().HasTable(&sysModel.SysDictionaryDetail{})
}
func (i initDictDetail) InitializerName() string {
func (i *initDictDetail) InitializerName() string {
return sysModel.SysDictionaryDetail{}.TableName()
}
@ -43,7 +43,7 @@ func (i *initDictDetail) InitializeData(ctx context.Context) (context.Context, e
if !ok {
return ctx, system.ErrMissingDBContext
}
dicts, ok := ctx.Value(initDict{}.InitializerName()).([]sysModel.SysDictionary)
dicts, ok := ctx.Value(new(initDict).InitializerName()).([]sysModel.SysDictionary)
if !ok {
return ctx, errors.Wrap(system.ErrMissingDependentContext,
fmt.Sprintf("未找到 %s 表初始化数据", sysModel.SysDictionary{}.TableName()))

View File

@ -17,7 +17,7 @@ func init() {
system.RegisterInit(initOrderExcelTemplate, &initExcelTemplate{})
}
func (i initExcelTemplate) InitializerName() string {
func (i *initExcelTemplate) InitializerName() string {
return "sys_export_templates"
}

View File

@ -18,7 +18,7 @@ func init() {
system.RegisterInit(initOrderMenu, &initMenu{})
}
func (i initMenu) InitializerName() string {
func (i *initMenu) InitializerName() string {
return SysBaseMenu{}.TableName()
}

View File

@ -35,7 +35,7 @@ func (i *initUser) TableCreated(ctx context.Context) bool {
return db.Migrator().HasTable(&sysModel.SysUser{})
}
func (i initUser) InitializerName() string {
func (i *initUser) InitializerName() string {
return sysModel.SysUser{}.TableName()
}
@ -79,7 +79,7 @@ func (i *initUser) InitializeData(ctx context.Context) (next context.Context, er
return ctx, errors.Wrap(err, sysModel.SysUser{}.TableName()+"表数据初始化失败!")
}
next = context.WithValue(ctx, i.InitializerName(), entities)
authorityEntities, ok := ctx.Value(initAuthority{}.InitializerName()).([]sysModel.SysAuthority)
authorityEntities, ok := ctx.Value(new(initAuthority).InitializerName()).([]sysModel.SysAuthority)
if !ok {
return next, errors.Wrap(system.ErrMissingDependentContext, "创建 [用户-权限] 关联失败, 未找到权限表初始化数据")
}

View File

@ -158,7 +158,7 @@ func CreateApiStructAst(apis []system.SysApi) *[]ast.Expr {
return &apiElts
}
// 检查是否存在Import
// CheckImport 检查是否存在Import
func CheckImport(file *ast.File, importPath string) bool {
for _, imp := range file.Imports {
// Remove quotes around the import path

View File

@ -10,7 +10,7 @@ import (
"os"
)
// 自动为 gorm.go 注册一个自动迁移
// AddRegisterTablesAst 自动为 gorm.go 注册一个自动迁移
func AddRegisterTablesAst(path, funcName, pk, varName, dbName, model string) {
modelPk := fmt.Sprintf("github.com/flipped-aurora/gin-vue-admin/server/model/%s", pk)
src, err := os.ReadFile(path)
@ -147,7 +147,7 @@ func addAutoMigrate(astBody *ast.BlockStmt, dbname string, pk string, model stri
}
}
// 为automigrate增加实参
// NeedAppendModel 为automigrate增加实参
func NeedAppendModel(callNode ast.Node, pk string, model string) bool {
flag := true
ast.Inspect(callNode, func(node ast.Node) bool {

View File

@ -2,6 +2,7 @@ package utils
import (
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/model/common"
"math/rand"
"reflect"
"strings"
@ -67,7 +68,7 @@ func MaheHump(s string) string {
return strings.Join(words, "")
}
// 随机字符串
// RandomString 随机字符串
func RandomString(n int) string {
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
b := make([]rune, n)
@ -80,3 +81,28 @@ func RandomString(n int) string {
func RandomInt(min, max int) int {
return min + rand.Intn(max-min)
}
// BuildTree 用于构建一个树形结构
func BuildTree[T common.TreeNode[T]](nodes []T) []T {
nodeMap := make(map[int]T)
// 创建一个基本map
for i := range nodes {
nodeMap[nodes[i].GetID()] = nodes[i]
}
for i := range nodes {
if nodes[i].GetParentID() != 0 {
parent := nodeMap[nodes[i].GetParentID()]
parent.SetChildren(nodes[i])
}
}
var rootNodes []T
for i := range nodeMap {
if nodeMap[i].GetParentID() == 0 {
rootNodes = append(rootNodes, nodeMap[i])
}
}
return rootNodes
}

View File

@ -43,7 +43,7 @@ func (j *JWT) CreateClaims(baseClaims request.BaseClaims) request.CustomClaims {
return claims
}
// 创建一个token
// CreateToken 创建一个token
func (j *JWT) CreateToken(claims request.CustomClaims) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(j.SigningKey)
@ -57,7 +57,7 @@ func (j *JWT) CreateTokenByOldToken(oldToken string, claims request.CustomClaims
return v.(string), err
}
// 解析 token
// ParseToken 解析 token
func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
return j.SigningKey, nil

View File

@ -72,7 +72,7 @@ func (t *timer) AddTaskByFunc(cronName string, spec string, fun func(), taskName
return id, err
}
// AddTaskByFuncWithSeconds 通过函数的方法使用WithSeconds添加任务
// AddTaskByFuncWithSecond 通过函数的方法使用WithSeconds添加任务
func (t *timer) AddTaskByFuncWithSecond(cronName string, spec string, fun func(), taskName string, option ...cron.Option) (cron.EntryID, error) {
t.Lock()
defer t.Unlock()
@ -186,7 +186,7 @@ func (t *timer) StopCron(cronName string) {
}
}
// Remove 从cronName 删除指定任务
// RemoveTask 从cronName 删除指定任务
func (t *timer) RemoveTask(cronName string, id int) {
t.Lock()
defer t.Unlock()

View File

@ -1,6 +1,6 @@
{
"name": "gin-vue-admin",
"version": "2.7.7",
"version": "2.7.8-beta1",
"private": true,
"scripts": {
"serve": "node openDocument.js && vite --host --mode development",
@ -17,6 +17,7 @@
"@vue-office/excel": "^1.7.11",
"@vue-office/pdf": "^2.0.2",
"@vueuse/core": "^11.0.3",
"@vueuse/integrations": "^12.0.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"ace-builds": "^1.36.4",
@ -27,7 +28,6 @@
"echarts": "5.5.1",
"element-plus": "^2.8.5",
"highlight.js": "^11.10.0",
"js-cookie": "^3.0.5",
"marked": "14.1.1",
"marked-highlight": "^2.1.4",
"mitt": "^3.0.1",
@ -39,6 +39,7 @@
"sortablejs": "^1.15.3",
"spark-md5": "^3.0.2",
"tailwindcss": "^3.4.10",
"universal-cookie": "^7",
"vform3-builds": "^3.0.10",
"vite-auto-import-svg": "^1.1.0",
"vue": "^3.5.7",

View File

@ -90,11 +90,11 @@
const quickArr = [
{
label: '亮色主题',
func: () => changeMode('light')
func: () => changeMode(false)
},
{
label: '暗色主题',
func: () => changeMode('dark')
func: () => changeMode(true)
},
{
label: '退出登录',
@ -135,12 +135,8 @@
dialogVisible.value = false
}
const changeMode = (e) => {
if (e === null) {
appStore.toggleTheme(false)
return
}
appStore.toggleTheme(true)
const changeMode = (darkMode) => {
appStore.toggleTheme(darkMode)
}
const close = () => {

View File

@ -23,7 +23,7 @@
/>
</div>
<el-drawer v-model="drawer" title="媒体库" size="650px">
<el-drawer v-model="drawer" title="媒体库" :size="appStore.drawerSize">
<warning-bar title="点击“文件名/备注”可以编辑文件名或者备注内容。" />
<div class="gva-btn-list gap-2">
<upload-common :image-common="imageCommon" @on-success="getImageList" />
@ -124,6 +124,9 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import { Picture as IconPicture } from '@element-plus/icons-vue'
import selectComponent from '@/components/selectImage/selectComponent.vue'
import { useAppStore } from "@/pinia";
const appStore = useAppStore()
const imageUrl = ref('')
const imageCommon = ref('')

View File

@ -17,7 +17,7 @@ export const viteLogo = (env) => {
`> 欢迎使用Gin-Vue-Admin开源地址https://github.com/flipped-aurora/gin-vue-admin`
)
)
console.log(greenText(`> 当前版本:v2.7.7`))
console.log(greenText(`> 当前版本:vv2.7.8-beta1`))
console.log(greenText(`> 加群方式:微信shouzi_1994 QQ群470239250`))
console.log(
greenText(`> 项目地址https://github.com/flipped-aurora/gin-vue-admin`)

View File

@ -10,7 +10,7 @@ export default {
register(app)
console.log(`
欢迎使用 Gin-Vue-Admin
当前版本:v2.7.7
当前版本:v2.7.8-beta1
加群方式:微信shouzi_1994 QQ群622360840
项目地址https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com

View File

@ -7,7 +7,7 @@ import { useAppStore } from '@/pinia'
export default function useChartOption(sourceOption) {
const appStore = useAppStore()
const isDark = computed(() => {
return appStore.theme === 'dark'
return appStore.isDark
})
const chartOption = computed(() => {
return sourceOption(isDark.value)

View File

@ -64,4 +64,4 @@
"/src/plugin/announcement/form/info.vue": "InfoForm",
"/src/plugin/announcement/view/info.vue": "Info",
"/src/plugin/email/view/index.vue": "Email"
}
}

View File

@ -1,8 +1,12 @@
import { defineStore } from 'pinia'
import { ref, watchEffect, reactive } from 'vue'
import { setBodyPrimaryColor } from '@/utils/format'
import { useDark, usePreferredDark } from '@vueuse/core'
export const useAppStore = defineStore('app', () => {
const device = ref('')
const drawerSize = ref('')
const operateMinWith = ref('240')
const config = reactive({
weakness: false,
grey: false,
@ -16,14 +20,17 @@ export const useAppStore = defineStore('app', () => {
side_mode: 'normal'
})
const theme = ref('auto')
const isDark = useDark({
selector: 'html',
attribute: 'class',
valueDark: 'dark',
valueLight: 'light',
})
const toggleTheme = (dark) => {
if (dark) {
theme.value = 'dark'
} else {
theme.value = 'light'
}
const preferredDark = usePreferredDark()
const toggleTheme = (darkMode) => {
isDark.value = darkMode
}
const toggleWeakness = (e) => {
@ -43,6 +50,13 @@ export const useAppStore = defineStore('app', () => {
}
const toggleDevice = (e) => {
if(e === 'mobile'){
drawerSize.value = '100%'
operateMinWith.value = '80'
}else {
drawerSize.value = '800'
operateMinWith.value = '240'
}
device.value = e
}
@ -50,15 +64,14 @@ export const useAppStore = defineStore('app', () => {
config.darkMode = e
}
const toggleDarkModeAuto = () => {
// 处理浏览器主题
const darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
const dark = darkQuery.matches
toggleTheme(dark)
darkQuery.addEventListener('change', (e) => {
toggleTheme(e.matches)
})
}
// 监听系统主题变化
watchEffect(() => {
if (config.darkMode === 'auto') {
isDark.value = preferredDark.value
return
}
isDark.value = config.darkMode === 'dark'
})
const toggleConfigSideWidth = (e) => {
config.layout_side_width = e
@ -76,55 +89,26 @@ export const useAppStore = defineStore('app', () => {
config.show_watermark = e
}
const toggleSideModel = (e) => {
const toggleSideMode = (e) => {
config.side_mode = e
}
// 监听色弱模式和灰色模式
watchEffect(() => {
if (theme.value === 'dark') {
document.documentElement.classList.add('dark')
document.documentElement.classList.remove('light')
} else {
document.documentElement.classList.add('light')
document.documentElement.classList.remove('dark')
}
})
watchEffect(() => {
// 色弱模式监听处理
if (config.weakness) {
document.documentElement.classList.add('html-weakenss')
} else {
document.documentElement.classList.remove('html-weakenss')
}
})
watchEffect(() => {
// 灰色模式监听处理
if (config.grey) {
document.documentElement.classList.add('html-grey')
} else {
document.documentElement.classList.remove('html-grey')
}
document.documentElement.classList.toggle('html-weakenss', config.weakness)
document.documentElement.classList.toggle('html-grey', config.grey)
})
// 监听主题色
watchEffect(() => {
if (config.darkMode === 'auto') {
toggleDarkModeAuto()
}
if (config.darkMode === 'dark') {
toggleTheme(true)
} else {
toggleTheme(false)
}
})
watchEffect(() => {
setBodyPrimaryColor(config.primaryColor, theme.value)
setBodyPrimaryColor(config.primaryColor, isDark.value ? 'dark' : 'light')
})
return {
theme,
isDark,
device,
drawerSize,
operateMinWith,
config,
toggleTheme,
toggleDevice,
@ -137,6 +121,6 @@ export const useAppStore = defineStore('app', () => {
toggleConfigSideCollapsedWidth,
toggleConfigSideItemHeight,
toggleConfigWatermark,
toggleSideModel
toggleSideMode
}
})

View File

@ -3,9 +3,10 @@ import { jsonInBlacklist } from '@/api/jwt'
import router from '@/router/index'
import { ElLoading, ElMessage } from 'element-plus'
import { defineStore } from 'pinia'
import { ref, watch } from 'vue'
import { ref, computed } from 'vue'
import { useRouterStore } from './router'
import cookie from 'js-cookie'
import { useCookies } from '@vueuse/integrations/useCookies'
import { useStorage } from '@vueuse/core'
import { useAppStore } from '@/pinia'
@ -19,9 +20,10 @@ export const useUserStore = defineStore('user', () => {
headerImg: '',
authority: {}
})
const token = ref(
window.localStorage.getItem('token') || cookie.get('x-token') || ''
)
const token = useStorage('token', '')
const xToken = useCookies('x-token')
const currentToken = computed(() => token.value || xToken.value || '')
const setUserInfo = (val) => {
userInfo.value = val
if (val.originSetting) {
@ -33,11 +35,11 @@ export const useUserStore = defineStore('user', () => {
const setToken = (val) => {
token.value = val
xToken.value = val
}
const NeedInit = async () => {
token.value = ''
window.localStorage.removeItem('token')
await ClearStorage()
await router.push({ name: 'Init', replace: true })
}
@ -57,49 +59,49 @@ export const useUserStore = defineStore('user', () => {
}
/* 登录*/
const LoginIn = async (loginInfo) => {
loadingInstance.value = ElLoading.service({
fullscreen: true,
text: '登录中,请稍候...'
})
try {
loadingInstance.value = ElLoading.service({
fullscreen: true,
text: '登录中,请稍候...'
})
const res = await login(loginInfo)
const res = await login(loginInfo)
if (res.code !== 0) {
ElMessage.error(res.message || '登录失败')
return false
}
// 登陆成功,设置用户信息和权限相关信息
setUserInfo(res.data.user)
setToken(res.data.token)
// 登陆失败,直接返回
if (res.code !== 0) {
loadingInstance.value.close()
// 初始化路由信息
const routerStore = useRouterStore()
await routerStore.SetAsyncRouter()
const asyncRouters = routerStore.asyncRouters
// 注册到路由表里
asyncRouters.forEach((asyncRouter) => {
router.addRoute(asyncRouter)
})
if (!router.hasRoute(userInfo.value.authority.defaultRouter)) {
ElMessage.error('请联系管理员进行授权')
} else {
await router.replace({ name: userInfo.value.authority.defaultRouter })
}
const isWindows = /windows/i.test(navigator.userAgent)
window.localStorage.setItem('osType', isWindows ? 'WIN' : 'MAC')
// 全部操作均结束关闭loading并返回
return true
} catch (error) {
console.error('LoginIn error:', error)
return false
} finally {
loadingInstance.value?.close()
}
// 登陆成功,设置用户信息和权限相关信息
setUserInfo(res.data.user)
setToken(res.data.token)
// 初始化路由信息
const routerStore = useRouterStore()
await routerStore.SetAsyncRouter()
const asyncRouters = routerStore.asyncRouters
// 注册到路由表里
asyncRouters.forEach((asyncRouter) => {
router.addRoute(asyncRouter)
})
if (!router.hasRoute(userInfo.value.authority.defaultRouter)) {
ElMessage.error('请联系管理员进行授权')
} else {
await router.replace({ name: userInfo.value.authority.defaultRouter })
}
const isWin = ref(/windows/i.test(navigator.userAgent))
if (isWin.value) {
window.localStorage.setItem('osType', 'WIN')
} else {
window.localStorage.setItem('osType', 'MAC')
}
// 全部操作均结束关闭loading并返回
loadingInstance.value.close()
return true
}
/* 登出*/
const LoginOut = async () => {
@ -119,22 +121,14 @@ export const useUserStore = defineStore('user', () => {
/* 清理数据 */
const ClearStorage = async () => {
token.value = ''
xToken.value = ''
sessionStorage.clear()
window.localStorage.removeItem('token')
cookie.remove('x-token')
localStorage.removeItem('originSetting')
}
watch(
() => token.value,
() => {
window.localStorage.setItem('token', token.value)
}
)
return {
userInfo,
token,
token: currentToken,
NeedInit,
ResetUserInfo,
GetUserInfo,

View File

@ -25,8 +25,7 @@
}
})
const dotColor = computed(() => {
console.log(appStore.theme)
return appStore.theme === 'dark' ? '#333' : '#E5E8EF'
return appStore.isDark ? '#333' : '#E5E8EF'
})
const graphicFactory = (side) => {
return {

View File

@ -111,6 +111,12 @@
placeholder="请输入sqlite数据库文件存放路径"
/>
</el-form-item>
<el-form-item v-if="form.dbType === 'pgsql'" label="template">
<el-input
v-model="form.template"
placeholder="请输入postgresql指定template"
/>
</el-form-item>
<el-form-item>
<div style="text-align: right">
<el-button type="primary" @click="onSubmit">立即初始化</el-button>
@ -192,7 +198,8 @@
userName: 'postgres',
password: '',
dbName: 'gva',
dbPath: ''
dbPath: '',
template: 'template0'
})
break
case 'oracle':

View File

@ -9,7 +9,8 @@
>
<div class="flex items-center cursor-pointer flex-1">
<div
class="flex items-center cursor-pointer min-w-48"
class="flex items-center cursor-pointer"
:class="isMobile ? '' : 'min-w-48'"
@click="router.push({ path: '/' })"
>
<img

View File

@ -58,10 +58,9 @@
effect="dark"
content="切换主题"
placement="bottom"
:disabled="appStore.theme === 'auto'"
>
<el-icon
v-if="appStore.theme === 'dark'"
v-if="appStore.isDark"
class="w-8 h-8 shadow rounded-full border border-gray-600 cursor-pointer border-solid"
@click="appStore.toggleTheme(false)"
>

View File

@ -62,7 +62,7 @@
import { useAppStore } from '@/pinia'
import { storeToRefs } from 'pinia'
const appStore = useAppStore()
const { config, theme, device } = storeToRefs(appStore)
const { config, isDark, device } = storeToRefs(appStore)
defineOptions({
name: 'GvaLayout'
@ -75,7 +75,7 @@
watchEffect(() => {
font.color =
theme.value === 'dark' ? 'rgba(255,255,255, .15)' : 'rgba(0, 0, 0, .15)'
isDark.value ? 'rgba(255,255,255, .15)' : 'rgba(0, 0, 0, .15)'
})
const router = useRouter()

View File

@ -71,7 +71,7 @@
v-model="config.side_mode"
:options="sideModes"
size="default"
@change="appStore.toggleSideModel"
@change="appStore.toggleSideMode"
/>
<!-- <el-select
v-model="config.side_mode"

View File

@ -102,7 +102,7 @@
</template>
</el-table-column>
<el-table-column align="left" fixed="right" label="操作" width="200">
<el-table-column align="left" fixed="right" label="操作" :min-width="appStore.operateMinWith">
<template #default="scope">
<el-button
icon="edit"
@ -138,7 +138,7 @@
<el-drawer
v-model="syncApiFlag"
size="80%"
:size="appStore.drawerSize"
:before-close="closeSyncDialog"
:show-close="false"
>
@ -341,7 +341,7 @@
<el-drawer
v-model="dialogFormVisible"
size="60%"
:size="appStore.drawerSize"
:before-close="closeDialog"
:show-close="false"
>
@ -420,11 +420,14 @@
import ExportTemplate from '@/components/exportExcel/exportTemplate.vue'
import ImportExcel from '@/components/exportExcel/importExcel.vue'
import { butler } from '@/api/autoCode'
import { useAppStore } from "@/pinia";
defineOptions({
name: 'Api'
})
const appStore = useAppStore()
const methodFilter = (value) => {
const target = methodOptions.value.filter((item) => item.value === value)[0]
return target && `${target.label}`

View File

@ -62,7 +62,7 @@
</el-table>
</div>
<!-- 新增角色弹窗 -->
<el-drawer v-model="authorityFormVisible" :show-close="false">
<el-drawer v-model="authorityFormVisible" :size="appStore.drawerSize" :show-close="false">
<template #header>
<div class="flex justify-between items-center">
<span class="text-lg">{{ authorityTitleForm }}</span>
@ -114,8 +114,7 @@
<el-drawer
v-if="drawer"
v-model="drawer"
:with-header="false"
size="40%"
:size="appStore.drawerSize"
title="角色配置"
>
<el-tabs :before-leave="autoEnter" type="border-card">
@ -154,6 +153,7 @@
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useAppStore } from "@/pinia"
defineOptions({
name: 'Authority'
@ -175,6 +175,7 @@
const drawer = ref(false)
const dialogType = ref('add')
const activeRow = ref({})
const appStore = useAppStore()
const authorityTitleForm = ref('新增角色')
const authorityFormVisible = ref(false)

View File

@ -49,7 +49,7 @@
</div>
<el-drawer
v-model="drawerFormVisible"
size="30%"
:size="appStore.drawerSize"
:show-close="false"
:before-close="closeDrawer"
>
@ -120,11 +120,14 @@
import sysDictionaryDetail from './sysDictionaryDetail.vue'
import { Edit } from '@element-plus/icons-vue'
import { useAppStore } from "@/pinia";
defineOptions({
name: 'SysDictionary'
})
const appStore = useAppStore()
const selectID = ref(0)
const formData = ref({

View File

@ -45,7 +45,7 @@
width="120"
/>
<el-table-column align="left" label="操作" width="180">
<el-table-column align="left" label="操作" :min-width="appStore.operateMinWith">
<template #default="scope">
<el-button
type="primary"
@ -82,7 +82,7 @@
<el-drawer
v-model="drawerFormVisible"
size="30%"
:size="appStore.drawerSize"
:show-close="false"
:before-close="closeDrawer"
>
@ -156,11 +156,14 @@
import { ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { formatBoolean, formatDate } from '@/utils/format'
import { useAppStore } from "@/pinia";
defineOptions({
name: 'SysDictionaryDetail'
})
const appStore = useAppStore()
const props = defineProps({
sysDictionaryID: {
type: Number,

View File

@ -72,7 +72,7 @@
min-width="360"
prop="component"
/>
<el-table-column align="left" fixed="right" label="操作" width="300">
<el-table-column align="left" fixed="right" label="操作" :min-width="appStore.operateMinWith">
<template #default="scope">
<el-button
type="primary"
@ -104,7 +104,7 @@
</div>
<el-drawer
v-model="dialogFormVisible"
size="60%"
:size="appStore.drawerSize"
:before-close="handleClose"
:show-close="false"
>
@ -423,11 +423,14 @@
import ComponentsCascader from '@/view/superAdmin/menu/components/components-cascader.vue'
import pathInfo from '@/pathInfo.json'
import { useAppStore } from "@/pinia";
defineOptions({
name: 'Menus'
})
const appStore = useAppStore()
const rules = reactive({
path: [{ required: true, message: '请输入菜单name', trigger: 'blur' }],
component: [{ required: true, message: '请输入文件路径', trigger: 'blur' }],

View File

@ -105,7 +105,7 @@
</template>
</el-table-column>
<el-table-column label="操作" min-width="250" fixed="right">
<el-table-column label="操作" :min-width="appStore.operateMinWith" fixed="right">
<template #default="scope">
<el-button
type="primary"
@ -145,7 +145,7 @@
</div>
<el-drawer
v-model="addUserDialog"
size="60%"
:size="appStore.drawerSize"
:show-close="false"
:close-on-press-escape="false"
:close-on-click-modal="false"
@ -236,11 +236,14 @@
import { nextTick, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import SelectImage from '@/components/selectImage/selectImage.vue'
import { useAppStore } from "@/pinia";
defineOptions({
name: 'User'
})
const appStore = useAppStore()
const searchInfo = ref({
username: '',
nickname: '',

View File

@ -84,7 +84,7 @@
<el-select
v-model="middleDate.dictType"
style="width: 100%"
:disabled="middleDate.fieldType !== 'string'"
:disabled="middleDate.fieldType !== 'string' && middleDate.fieldType !== 'array'"
placeholder="请选择字典"
clearable
>

View File

@ -416,6 +416,26 @@
<el-checkbox v-model="form.onlyTemplate" />
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item>
<template #label>
<el-tooltip
content="注会自动创建parentID来进行父子关系关联,仅支持主键为int类型"
placement="bottom"
effect="light"
>
<div>
树型结构 <el-icon><QuestionFilled /></el-icon>
</div>
</el-tooltip>
</template>
<div class="flex gap-2 items-center">
<el-checkbox v-model="form.isTree" />
<el-input v-model="form.treeJson" :disabled="!form.isTree" placeholder="前端展示json属性"></el-input>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
@ -1024,6 +1044,8 @@
gvaModel: true,
autoCreateResource: false,
onlyTemplate: false,
isTree: false,
treeJson: "",
fields: []
})
const rules = ref({
@ -1137,6 +1159,13 @@
}
const autoCodeForm = ref(null)
const enterForm = async (isPreview) => {
if (form.value.isTree && !form.value.treeJson){
ElMessage({
type: 'error',
message: '请填写树型结构的前端展示json属性'
})
return false
}
if (!form.value.onlyTemplate) {
if (form.value.fields.length <= 0) {
ElMessage({
@ -1445,6 +1474,8 @@
gvaModel: true,
autoCreateResource: false,
onlyTemplate: false,
isTree: false,
treeJson: "",
fields: []
}
await nextTick()

View File

@ -148,49 +148,64 @@
:model="autoFunc"
label-width="80px"
>
<el-form-item label="包名:">
<el-input
v-model="autoFunc.package"
placeholder="请输入包名"
disabled
/>
</el-form-item>
<el-form-item label="结构体名:">
<el-input
v-model="autoFunc.structName"
placeholder="请输入结构体名"
disabled
/>
</el-form-item>
<el-form-item label="前端文件名:">
<el-input
v-model="autoFunc.packageName"
placeholder="请输入文件名"
disabled
/>
</el-form-item>
<el-form-item label="后端文件名:">
<el-input
v-model="autoFunc.humpPackageName"
placeholder="请输入文件名"
disabled
/>
</el-form-item>
<el-form-item label="描述:">
<el-input
v-model="autoFunc.description"
placeholder="请输入描述"
disabled
/>
</el-form-item>
<el-form-item label="缩写:">
<el-input
v-model="autoFunc.abbreviation"
placeholder="请输入缩写"
disabled
/>
</el-form-item>
<el-row :gutter="12">
<el-col :span="8">
<el-form-item label="包名:">
<el-input
v-model="autoFunc.package"
placeholder="请输入包名"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结构体名:">
<el-input
v-model="autoFunc.structName"
placeholder="请输入结构体名"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="前端文件名:">
<el-input
v-model="autoFunc.packageName"
placeholder="请输入文件名"
disabled
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="12">
<el-col :span="8">
<el-form-item label="后端文件名:">
<el-input
v-model="autoFunc.humpPackageName"
placeholder="请输入文件名"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="描述:">
<el-input
v-model="autoFunc.description"
placeholder="请输入描述"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="缩写:">
<el-input
v-model="autoFunc.abbreviation"
placeholder="请输入缩写"
disabled
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="是否AI填充">
<el-switch v-model="autoFunc.isAi" />
<span class="text-sm text-red-600 p-2"
@ -378,7 +393,7 @@
funcFlag.value = true
}
const funcFlag = ref(false)
const funcFlag = ref(true)
const closeFunc = () => {
funcFlag.value = false

View File

@ -121,9 +121,18 @@
label="模板信息"
prop="templateInfo"
min-width="120"
show-overflow-tooltip
/>
<el-table-column align="left" label="操作" min-width="120">
<el-table-column align="left" label="操作" min-width="280">
<template #default="scope">
<el-button
type="primary"
link
icon="documentCopy"
class="table-button"
@click="copyFunc(scope.row)"
>复制</el-button
>
<el-button
type="primary"
link
@ -834,6 +843,28 @@ JOINS模式下不支持导入
//
const type = ref('')
//
const copyFunc = async (row) => {
let copyData
const res = await findSysExportTemplate({ ID: row.ID })
if (res.code === 0) {
copyData = JSON.parse(JSON.stringify(res.data.resysExportTemplate))
if (!copyData.conditions) {
copyData.conditions = []
}
if (!copyData.joinTemplate) {
copyData.joinTemplate = []
}
delete copyData.ID
delete copyData.CreatedAt
delete copyData.UpdatedAt
copyData.templateID = copyData.templateID + '_copy'
copyData.name = copyData.name + '_copy'
formData.value = copyData
dialogFormVisible.value = true
}
}
//
const updateSysExportTemplateFunc = async (row) => {
const res = await findSysExportTemplate({ ID: row.ID })