Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 12 commits into from
Nov 20, 2024
7 changes: 7 additions & 0 deletions server/model/common/basetypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
2 changes: 2 additions & 0 deletions server/model/system/request/sys_auto_code.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:"-"`
Expand Down
23 changes: 22 additions & 1 deletion server/resource/package/server/api/api.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand Down Expand Up @@ -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}}列表
Expand Down Expand Up @@ -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}}的数据源
Expand Down Expand Up @@ -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) {
Expand Down
27 changes: 26 additions & 1 deletion server/resource/package/server/model/model.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
}

Expand All @@ -82,5 +86,26 @@ func ({{.StructName}}) TableName() string {
}
{{ 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}})
}

{{ end }}
// GetParentID 实现TreeNode接口
func (s *{{.StructName}}) GetParentID() int {
return s.ParentID
}
{{ end }}

{{ end }}
34 changes: 33 additions & 1 deletion server/resource/package/server/service/service.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand All @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand All @@ -215,4 +247,4 @@ func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}Public(
// 此方法为获取数据源定义的数据
// 请自行实现
}
{{- end }}
{{- end }}
46 changes: 46 additions & 0 deletions server/resource/package/web/view/form.vue.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -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}}">
Expand Down Expand Up @@ -239,6 +253,9 @@ import {
{{- if .HasDataSource }}
get{{.StructName}}DataSource,
{{- end }}
{{- if .IsTree }}
get{{.StructName}}List,
{{- end }}
create{{.StructName}},
update{{.StructName}},
find{{.StructName}}
Expand Down Expand Up @@ -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)

Expand All @@ -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" }}
Expand Down
71 changes: 67 additions & 4 deletions server/resource/package/web/view/table.vue.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,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 }}
Expand Down Expand Up @@ -515,9 +516,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}}" />
Expand All @@ -538,7 +540,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 }}
Expand Down Expand Up @@ -629,9 +631,12 @@ getDataSourceFunc()
{{- 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>
Expand Down Expand Up @@ -659,6 +664,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}}" >
Expand Down Expand Up @@ -734,6 +753,21 @@ getDataSourceFunc()

<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 }}">
Expand Down Expand Up @@ -852,6 +886,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" }}
Expand Down Expand Up @@ -999,6 +1036,7 @@ const sortChange = ({ prop, order }) => {
}
{{- end}}

{{- if not .IsTree }}
// 重置
const onReset = () => {
searchInfo.value = {}
Expand Down Expand Up @@ -1040,6 +1078,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()

Expand Down Expand Up @@ -1140,8 +1200,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
}

Expand Down
Loading
Loading