mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-09-22 08:30:42 +02:00
✨ Database grouping by field https://github.com/siyuan-note/siyuan/issues/10964
This commit is contained in:
parent
b357047290
commit
17c59cb2ca
11 changed files with 64 additions and 69 deletions
|
@ -191,12 +191,13 @@ type View struct {
|
||||||
Table *LayoutTable `json:"table,omitempty"` // 表格布局
|
Table *LayoutTable `json:"table,omitempty"` // 表格布局
|
||||||
Gallery *LayoutGallery `json:"gallery,omitempty"` // 画廊布局
|
Gallery *LayoutGallery `json:"gallery,omitempty"` // 画廊布局
|
||||||
|
|
||||||
Groups []*View `json:"groups,omitempty"` // 分组视图列表
|
Groups []*View `json:"groups,omitempty"` // 分组视图列表
|
||||||
GroupCalcSum bool `json:"groupCalcSum,omitempty"` // 分组是否计算总和
|
GroupItemIDs []string `json:"groupItemIds,omitempty"` // 分组项目 ID 列表,用于维护分组中的所有项目
|
||||||
GroupName string `json:"groupName,omitempty"` // 分组名称
|
GroupCalcSum bool `json:"groupCalcSum,omitempty"` // 分组是否计算总和
|
||||||
GroupFolded bool `json:"groupFolded,omitempty"` // 分组是否折叠
|
GroupName string `json:"groupName,omitempty"` // 分组名称
|
||||||
GroupHidden bool `json:"groupHidden,omitempty"` // 分组是否隐藏
|
GroupFolded bool `json:"groupFolded,omitempty"` // 分组是否折叠
|
||||||
GroupDefault bool `json:"groupDefault,omitempty"` // 是否为默认分组
|
GroupHidden bool `json:"groupHidden,omitempty"` // 分组是否隐藏
|
||||||
|
GroupDefault bool `json:"groupDefault,omitempty"` // 是否为默认分组
|
||||||
}
|
}
|
||||||
|
|
||||||
// LayoutType 描述了视图布局类型。
|
// LayoutType 描述了视图布局类型。
|
||||||
|
@ -252,12 +253,24 @@ func NewGalleryView() (ret *View) {
|
||||||
|
|
||||||
// Viewable 描述了视图的接口。
|
// Viewable 描述了视图的接口。
|
||||||
type Viewable interface {
|
type Viewable interface {
|
||||||
Filterable
|
|
||||||
Sortable
|
|
||||||
Calculable
|
|
||||||
|
|
||||||
|
// Filter 根据视图中设置的过滤器进行过滤。
|
||||||
|
Filter(attrView *AttributeView)
|
||||||
|
|
||||||
|
// Sort 根据视图中设置的排序规则进行排序。
|
||||||
|
Sort(attrView *AttributeView)
|
||||||
|
|
||||||
|
// Calc 根据视图中设置的计算规则进行计算。
|
||||||
|
Calc()
|
||||||
|
|
||||||
|
// GetType 获取视图的布局类型。
|
||||||
GetType() LayoutType
|
GetType() LayoutType
|
||||||
|
|
||||||
|
// GetID 获取视图的 ID。
|
||||||
GetID() string
|
GetID() string
|
||||||
|
|
||||||
|
// SetGroups 设置视图分组列表。
|
||||||
|
SetGroups(viewables []Viewable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAttributeView(id string) (ret *AttributeView) {
|
func NewAttributeView(id string) (ret *AttributeView) {
|
||||||
|
|
|
@ -16,13 +16,6 @@
|
||||||
|
|
||||||
package av
|
package av
|
||||||
|
|
||||||
// Calculable 接口定义了可计算的视图类型。
|
|
||||||
type Calculable interface {
|
|
||||||
|
|
||||||
// Calc 根据视图中设置的计算规则进行计算。
|
|
||||||
Calc()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ColumnCalc 描述了列(字段)计算操作和结果的结构。
|
// ColumnCalc 描述了列(字段)计算操作和结果的结构。
|
||||||
type ColumnCalc struct {
|
type ColumnCalc struct {
|
||||||
Operator CalcOperator `json:"operator"` // 计算操作符
|
Operator CalcOperator `json:"operator"` // 计算操作符
|
||||||
|
|
|
@ -24,13 +24,6 @@ import (
|
||||||
"github.com/siyuan-note/siyuan/kernel/util"
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Filterable 接口定义了可过滤的视图类型。
|
|
||||||
type Filterable interface {
|
|
||||||
|
|
||||||
// Filter 根据视图中设置的过滤器进行过滤。
|
|
||||||
Filter(attrView *AttributeView)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ViewFilter 描述了视图过滤器的结构。
|
// ViewFilter 描述了视图过滤器的结构。
|
||||||
type ViewFilter struct {
|
type ViewFilter struct {
|
||||||
Column string `json:"column"` // 列(字段)ID
|
Column string `json:"column"` // 列(字段)ID
|
||||||
|
|
|
@ -66,6 +66,8 @@ type BaseInstance struct {
|
||||||
WrapField bool `json:"wrapField"` // 是否换行字段内容
|
WrapField bool `json:"wrapField"` // 是否换行字段内容
|
||||||
Folded bool `json:"folded,omitempty"` // 是否折叠
|
Folded bool `json:"folded,omitempty"` // 是否折叠
|
||||||
Hidden bool `json:"hidden,omitempty"` // 是否隐藏
|
Hidden bool `json:"hidden,omitempty"` // 是否隐藏
|
||||||
|
|
||||||
|
Groups []Viewable `json:"groups,omitempty"` // 分组实例列表
|
||||||
}
|
}
|
||||||
|
|
||||||
func (baseInstance *BaseInstance) GetSorts() []*ViewSort {
|
func (baseInstance *BaseInstance) GetSorts() []*ViewSort {
|
||||||
|
@ -76,6 +78,14 @@ func (baseInstance *BaseInstance) GetFilters() []*ViewFilter {
|
||||||
return baseInstance.Filters
|
return baseInstance.Filters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (baseInstance *BaseInstance) SetGroups(viewables []Viewable) {
|
||||||
|
baseInstance.Groups = viewables
|
||||||
|
}
|
||||||
|
|
||||||
|
func (baseInstance *BaseInstance) GetID() string {
|
||||||
|
return baseInstance.ID
|
||||||
|
}
|
||||||
|
|
||||||
// BaseInstanceField 描述了实例字段的基础结构。
|
// BaseInstanceField 描述了实例字段的基础结构。
|
||||||
type BaseInstanceField struct {
|
type BaseInstanceField struct {
|
||||||
ID string `json:"id"` // ID
|
ID string `json:"id"` // ID
|
||||||
|
|
|
@ -97,8 +97,6 @@ type Gallery struct {
|
||||||
Fields []*GalleryField `json:"fields"` // 画廊字段
|
Fields []*GalleryField `json:"fields"` // 画廊字段
|
||||||
Cards []*GalleryCard `json:"cards"` // 画廊卡片
|
Cards []*GalleryCard `json:"cards"` // 画廊卡片
|
||||||
CardCount int `json:"cardCount"` // 画廊总卡片数
|
CardCount int `json:"cardCount"` // 画廊总卡片数
|
||||||
|
|
||||||
Groups []*Gallery `json:"groups,omitempty"` // 分组实例列表
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GalleryCard 描述了画廊实例卡片的结构。
|
// GalleryCard 描述了画廊实例卡片的结构。
|
||||||
|
@ -179,10 +177,6 @@ func (gallery *Gallery) GetType() LayoutType {
|
||||||
return LayoutTypeGallery
|
return LayoutTypeGallery
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gallery *Gallery) GetID() string {
|
|
||||||
return gallery.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gallery *Gallery) Sort(attrView *AttributeView) {
|
func (gallery *Gallery) Sort(attrView *AttributeView) {
|
||||||
sort0(gallery, attrView)
|
sort0(gallery, attrView)
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,6 @@ type Table struct {
|
||||||
Columns []*TableColumn `json:"columns"` // 表格列
|
Columns []*TableColumn `json:"columns"` // 表格列
|
||||||
Rows []*TableRow `json:"rows"` // 表格行
|
Rows []*TableRow `json:"rows"` // 表格行
|
||||||
RowCount int `json:"rowCount"` // 表格总行数
|
RowCount int `json:"rowCount"` // 表格总行数
|
||||||
|
|
||||||
Groups []*Table `json:"groups,omitempty"` // 分组实例列表
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableColumn 描述了表格实例列的结构。
|
// TableColumn 描述了表格实例列的结构。
|
||||||
|
|
|
@ -24,13 +24,6 @@ import (
|
||||||
"github.com/siyuan-note/siyuan/kernel/util"
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sortable 接口定义了可排序的视图类型。
|
|
||||||
type Sortable interface {
|
|
||||||
|
|
||||||
// Sort 根据视图中设置的排序规则进行排序。
|
|
||||||
Sort(attrView *AttributeView)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ViewSort 描述了视图排序规则的结构。
|
// ViewSort 描述了视图排序规则的结构。
|
||||||
type ViewSort struct {
|
type ViewSort struct {
|
||||||
Column string `json:"column"` // 列(字段)ID
|
Column string `json:"column"` // 列(字段)ID
|
||||||
|
|
|
@ -85,7 +85,7 @@ func SetAttributeViewGroup(avID, blockID string, group *av.ViewGroup) error {
|
||||||
v := av.NewTableView()
|
v := av.NewTableView()
|
||||||
v.Table = av.NewLayoutTable()
|
v.Table = av.NewLayoutTable()
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
v.Table.RowIDs = append(v.Table.RowIDs, row.ID)
|
v.GroupItemIDs = append(v.GroupItemIDs, row.ID)
|
||||||
}
|
}
|
||||||
view.Groups = append(view.Groups, v)
|
view.Groups = append(view.Groups, v)
|
||||||
}
|
}
|
||||||
|
@ -1285,34 +1285,24 @@ func renderAttributeView(attrView *av.AttributeView, viewID, query string, page,
|
||||||
checkAttrView(attrView, view)
|
checkAttrView(attrView, view)
|
||||||
upgradeAttributeViewSpec(attrView)
|
upgradeAttributeViewSpec(attrView)
|
||||||
|
|
||||||
if nil != view.Group && 0 < len(view.Groups) {
|
viewable = sql.RenderView(view, attrView, query)
|
||||||
var instances []av.Viewable
|
err = renderViewableInstance(viewable, view, attrView, page, pageSize)
|
||||||
for _, groupView := range view.Groups {
|
if nil != err {
|
||||||
groupView.Table.Columns = view.Table.Columns
|
|
||||||
groupViewable := sql.RenderView(groupView, attrView, query)
|
|
||||||
err = renderViewableInstance(groupViewable, view, attrView, page, pageSize)
|
|
||||||
if nil != err {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
instances = append(instances, groupViewable)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewable = instances[0]
|
|
||||||
switch view.LayoutType {
|
|
||||||
case av.LayoutTypeTable:
|
|
||||||
for i := 1; i < len(instances); i++ {
|
|
||||||
viewable.(*av.Table).Groups = append(viewable.(*av.Table).Groups, instances[i].(*av.Table))
|
|
||||||
}
|
|
||||||
case av.LayoutTypeGallery:
|
|
||||||
for i := 1; i < len(instances); i++ {
|
|
||||||
viewable.(*av.Gallery).Groups = append(viewable.(*av.Gallery).Groups, instances[i].(*av.Gallery))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
viewable = sql.RenderView(view, attrView, query)
|
var groups []av.Viewable
|
||||||
err = renderViewableInstance(viewable, view, attrView, page, pageSize)
|
for _, groupView := range view.Groups {
|
||||||
|
groupView.Table.Columns = view.Table.Columns
|
||||||
|
groupViewable := sql.RenderView(groupView, attrView, query)
|
||||||
|
err = renderViewableInstance(groupViewable, view, attrView, page, pageSize)
|
||||||
|
if nil != err {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groups = append(groups, groupViewable)
|
||||||
|
}
|
||||||
|
viewable.SetGroups(groups)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ func RenderTemplateField(ial map[string]string, keyValues []*av.KeyValues, tplCo
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateAttrViewItems(attrView *av.AttributeView) (ret map[string][]*av.KeyValues) {
|
func generateAttrViewItems(attrView *av.AttributeView, view *av.View) (ret map[string][]*av.KeyValues) {
|
||||||
ret = map[string][]*av.KeyValues{}
|
ret = map[string][]*av.KeyValues{}
|
||||||
for _, keyValues := range attrView.KeyValues {
|
for _, keyValues := range attrView.KeyValues {
|
||||||
for _, val := range keyValues.Values {
|
for _, val := range keyValues.Values {
|
||||||
|
@ -200,6 +200,17 @@ func generateAttrViewItems(attrView *av.AttributeView) (ret map[string][]*av.Key
|
||||||
ret[val.BlockID] = values
|
ret[val.BlockID] = values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果是分组视图,则需要过滤掉不在分组中的项目
|
||||||
|
if 0 < len(view.GroupItemIDs) {
|
||||||
|
tmp := map[string][]*av.KeyValues{}
|
||||||
|
for _, groupItemID := range view.GroupItemIDs {
|
||||||
|
if _, ok := ret[groupItemID]; ok {
|
||||||
|
tmp[groupItemID] = ret[groupItemID]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = tmp
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,8 @@ func RenderAttributeViewGallery(attrView *av.AttributeView, view *av.View, query
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
cardsValues := generateAttrViewItems(attrView) // 生成卡片
|
cardsValues := generateAttrViewItems(attrView, view) // 生成卡片
|
||||||
filterNotFoundAttrViewItems(&cardsValues) // 过滤掉不存在的卡片
|
filterNotFoundAttrViewItems(&cardsValues) // 过滤掉不存在的卡片
|
||||||
|
|
||||||
// 批量加载绑定块对应的树
|
// 批量加载绑定块对应的树
|
||||||
var ialIDs []string
|
var ialIDs []string
|
||||||
|
|
|
@ -71,8 +71,8 @@ func RenderAttributeViewTable(attrView *av.AttributeView, view *av.View, query s
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
rowsValues := generateAttrViewItems(attrView) // 生成行
|
rowsValues := generateAttrViewItems(attrView, view) // 生成行
|
||||||
filterNotFoundAttrViewItems(&rowsValues) // 过滤掉不存在的行
|
filterNotFoundAttrViewItems(&rowsValues) // 过滤掉不存在的行
|
||||||
|
|
||||||
// 生成行单元格
|
// 生成行单元格
|
||||||
for rowID, rowValues := range rowsValues {
|
for rowID, rowValues := range rowsValues {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue