Daniel 2025-07-02 17:02:40 +08:00
parent 45f10bf62a
commit eca87831fe
No known key found for this signature in database
GPG key ID: 86211BA83DF03017
10 changed files with 99 additions and 190 deletions

View file

@ -190,6 +190,7 @@ type View struct {
LayoutType LayoutType `json:"type"` // 当前布局类型 LayoutType LayoutType `json:"type"` // 当前布局类型
Table *LayoutTable `json:"table,omitempty"` // 表格布局 Table *LayoutTable `json:"table,omitempty"` // 表格布局
Gallery *LayoutGallery `json:"gallery,omitempty"` // 画廊布局 Gallery *LayoutGallery `json:"gallery,omitempty"` // 画廊布局
ItemIDs []string `json:"itemIds,omitempty"` // 项目 ID 列表,用于维护所有项目
Groups []*View `json:"groups,omitempty"` // 分组视图列表 Groups []*View `json:"groups,omitempty"` // 分组视图列表
GroupItemIDs []string `json:"groupItemIds,omitempty"` // 分组项目 ID 列表,用于维护分组中的所有项目 GroupItemIDs []string `json:"groupItemIds,omitempty"` // 分组项目 ID 列表,用于维护分组中的所有项目
@ -276,7 +277,7 @@ type Viewable interface {
func NewAttributeView(id string) (ret *AttributeView) { func NewAttributeView(id string) (ret *AttributeView) {
view, blockKey, selectKey := NewTableViewWithBlockKey(ast.NewNodeID()) view, blockKey, selectKey := NewTableViewWithBlockKey(ast.NewNodeID())
ret = &AttributeView{ ret = &AttributeView{
Spec: 2, Spec: 3,
ID: id, ID: id,
KeyValues: []*KeyValues{{Key: blockKey}, {Key: selectKey}}, KeyValues: []*KeyValues{{Key: blockKey}, {Key: selectKey}},
ViewID: view.ID, ViewID: view.ID,
@ -418,14 +419,8 @@ func SaveAttributeView(av *AttributeView) (err error) {
// 视图值去重 // 视图值去重
for _, view := range av.Views { for _, view := range av.Views {
if nil != view.Table { // 项目自定义排序去重
// 行去重 view.ItemIDs = gulu.Str.RemoveDuplicatedElem(view.ItemIDs)
view.Table.RowIDs = gulu.Str.RemoveDuplicatedElem(view.Table.RowIDs)
}
if nil != view.Gallery {
// 行去重
view.Gallery.CardIDs = gulu.Str.RemoveDuplicatedElem(view.Gallery.CardIDs)
}
// 分页大小 // 分页大小
if 1 > view.PageSize { if 1 > view.PageSize {
@ -614,14 +609,13 @@ func (av *AttributeView) Clone() (ret *AttributeView) {
for _, column := range view.Table.Columns { for _, column := range view.Table.Columns {
column.ID = keyIDMap[column.ID] column.ID = keyIDMap[column.ID]
} }
view.Table.RowIDs = []string{}
case LayoutTypeGallery: case LayoutTypeGallery:
view.Gallery.ID = ast.NewNodeID() view.Gallery.ID = ast.NewNodeID()
for _, cardField := range view.Gallery.CardFields { for _, cardField := range view.Gallery.CardFields {
cardField.ID = keyIDMap[cardField.ID] cardField.ID = keyIDMap[cardField.ID]
} }
view.Gallery.CardIDs = []string{}
} }
view.ItemIDs = []string{}
} }
ret.ViewID = ret.Views[0].ID ret.ViewID = ret.Views[0].ID

View file

@ -27,6 +27,33 @@ import (
func UpgradeSpec(av *AttributeView) { func UpgradeSpec(av *AttributeView) {
upgradeSpec1(av) upgradeSpec1(av)
upgradeSpec2(av) upgradeSpec2(av)
upgradeSpec3(av)
}
func upgradeSpec3(av *AttributeView) {
if 3 <= av.Spec {
return
}
// 将 view.table.rowIds 或 view.gallery.cardIds 复制到 view.itemIds
for _, view := range av.Views {
if 0 < len(view.ItemIDs) {
continue
}
switch view.LayoutType {
case LayoutTypeTable:
if nil != view.Table {
view.ItemIDs = view.Table.RowIDs
}
case LayoutTypeGallery:
if nil != view.Gallery {
view.ItemIDs = view.Gallery.CardIDs
}
}
}
av.Spec = 3
} }
func upgradeSpec2(av *AttributeView) { func upgradeSpec2(av *AttributeView) {
@ -78,7 +105,6 @@ func upgradeSpec2(av *AttributeView) {
} }
av.Spec = 2 av.Spec = 2
logging.LogInfof("av [%s] upgraded to spec [%d]", av.ID, av.Spec)
} }
func upgradeSpec1(av *AttributeView) { func upgradeSpec1(av *AttributeView) {
@ -211,5 +237,4 @@ func upgradeSpec1(av *AttributeView) {
} }
av.Spec = 1 av.Spec = 1
logging.LogInfof("av [%s] upgraded to spec [%d]", av.ID, av.Spec)
} }

View file

@ -110,13 +110,6 @@ func (baseInstanceField *BaseInstanceField) GetID() string {
return baseInstanceField.ID return baseInstanceField.ID
} }
// CollectionLayout 描述了集合布局的接口。
type CollectionLayout interface {
// GetItemIDs 返回集合中所有项目的 ID。
GetItemIDs() []string
}
// Collection 描述了一个集合的接口。 // Collection 描述了一个集合的接口。
// 集合可以是表格、画廊等,包含多个项目。 // 集合可以是表格、画廊等,包含多个项目。
type Collection interface { type Collection interface {

View file

@ -31,11 +31,10 @@ type LayoutGallery struct {
FitImage bool `json:"fitImage"` // 是否适应封面图片大小 FitImage bool `json:"fitImage"` // 是否适应封面图片大小
CardFields []*ViewGalleryCardField `json:"fields"` // 画廊卡片字段 CardFields []*ViewGalleryCardField `json:"fields"` // 画廊卡片字段
CardIDs []string `json:"cardIds"` // 卡片 ID用于自定义排序
}
func (layoutGallery *LayoutGallery) GetItemIDs() (ret []string) { // TODO CardIDs 字段已经废弃,计划于 2026 年 6 月 30 日后删除 https://github.com/siyuan-note/siyuan/issues/15194
return layoutGallery.CardIDs //Deprecated
CardIDs []string `json:"cardIds"` // 卡片 ID用于自定义排序
} }
func NewLayoutGallery() *LayoutGallery { func NewLayoutGallery() *LayoutGallery {

View file

@ -25,11 +25,10 @@ type LayoutTable struct {
*BaseLayout *BaseLayout
Columns []*ViewTableColumn `json:"columns"` // 表格列 Columns []*ViewTableColumn `json:"columns"` // 表格列
RowIDs []string `json:"rowIds"` // 行 ID用于自定义排序
}
func (layoutTable *LayoutTable) GetItemIDs() (ret []string) { // TODO RowIDs 字段已经废弃,计划于 2026 年 6 月 30 日后删除 https://github.com/siyuan-note/siyuan/issues/15194
return layoutTable.RowIDs //Deprecated
RowIDs []string `json:"rowIds"` // 行 ID用于自定义排序
} }
func NewLayoutTable() *LayoutTable { func NewLayoutTable() *LayoutTable {

View file

@ -175,9 +175,6 @@ func ChangeAttrViewLayout(blockID, avID string, layout av.LayoutType) (err error
for _, field := range view.Gallery.CardFields { for _, field := range view.Gallery.CardFields {
view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{BaseField: &av.BaseField{ID: field.ID}}) view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{BaseField: &av.BaseField{ID: field.ID}})
} }
for _, cardID := range view.Gallery.CardIDs {
view.Table.RowIDs = append(view.Table.RowIDs, cardID)
}
} }
case av.LayoutTypeGallery: case av.LayoutTypeGallery:
if view.Name == av.GetAttributeViewI18n("table") { if view.Name == av.GetAttributeViewI18n("table") {
@ -194,9 +191,6 @@ func ChangeAttrViewLayout(blockID, avID string, layout av.LayoutType) (err error
for _, col := range view.Table.Columns { for _, col := range view.Table.Columns {
view.Gallery.CardFields = append(view.Gallery.CardFields, &av.ViewGalleryCardField{BaseField: &av.BaseField{ID: col.ID}}) view.Gallery.CardFields = append(view.Gallery.CardFields, &av.ViewGalleryCardField{BaseField: &av.BaseField{ID: col.ID}})
} }
for _, rowID := range view.Table.RowIDs {
view.Gallery.CardIDs = append(view.Gallery.CardIDs, rowID)
}
} }
} }
@ -469,15 +463,8 @@ func AppendAttributeViewDetachedBlocksWithValues(avID string, blocksValues [][]*
} }
for _, v := range attrView.Views { for _, v := range attrView.Views {
switch v.LayoutType {
case av.LayoutTypeTable:
for _, addingBlockID := range blockIDs { for _, addingBlockID := range blockIDs {
v.Table.RowIDs = append(v.Table.RowIDs, addingBlockID) v.ItemIDs = append(v.ItemIDs, addingBlockID)
}
case av.LayoutTypeGallery:
for _, addingBlockID := range blockIDs {
v.Gallery.CardIDs = append(v.Gallery.CardIDs, addingBlockID)
}
} }
} }
@ -1441,31 +1428,16 @@ func unbindAttributeViewBlock(operation *Operation, tx *Transaction) (err error)
replacedRowID := false replacedRowID := false
for _, v := range attrView.Views { for _, v := range attrView.Views {
switch v.LayoutType { for i, itemID := range v.ItemIDs {
case av.LayoutTypeTable: if itemID == operation.ID {
for i, rowID := range v.Table.RowIDs { v.ItemIDs[i] = operation.NextID
if rowID == operation.ID {
v.Table.RowIDs[i] = operation.NextID
replacedRowID = true replacedRowID = true
break break
} }
} }
if !replacedRowID { if !replacedRowID {
v.Table.RowIDs = append(v.Table.RowIDs, operation.NextID) v.ItemIDs = append(v.ItemIDs, operation.NextID)
}
case av.LayoutTypeGallery:
for i, cardID := range v.Gallery.CardIDs {
if cardID == operation.ID {
v.Gallery.CardIDs[i] = operation.NextID
replacedRowID = true
break
}
}
if !replacedRowID {
v.Gallery.CardIDs = append(v.Gallery.CardIDs, operation.NextID)
}
} }
} }
@ -1977,7 +1949,6 @@ func (tx *Transaction) doDuplicateAttrViewView(operation *Operation) (ret *TxErr
}) })
} }
view.Table.RowIDs = masterView.Table.RowIDs
view.Table.ShowIcon = masterView.Table.ShowIcon view.Table.ShowIcon = masterView.Table.ShowIcon
view.Table.WrapField = masterView.Table.WrapField view.Table.WrapField = masterView.Table.WrapField
case av.LayoutTypeGallery: case av.LayoutTypeGallery:
@ -1992,7 +1963,6 @@ func (tx *Transaction) doDuplicateAttrViewView(operation *Operation) (ret *TxErr
}) })
} }
view.Gallery.CardIDs = masterView.Gallery.CardIDs
view.Gallery.CoverFrom = masterView.Gallery.CoverFrom view.Gallery.CoverFrom = masterView.Gallery.CoverFrom
view.Gallery.CoverFromAssetKeyID = masterView.Gallery.CoverFromAssetKeyID view.Gallery.CoverFromAssetKeyID = masterView.Gallery.CoverFromAssetKeyID
view.Gallery.CardSize = masterView.Gallery.CardSize view.Gallery.CardSize = masterView.Gallery.CardSize
@ -2001,6 +1971,8 @@ func (tx *Transaction) doDuplicateAttrViewView(operation *Operation) (ret *TxErr
view.Gallery.WrapField = masterView.Gallery.WrapField view.Gallery.WrapField = masterView.Gallery.WrapField
} }
view.ItemIDs = masterView.ItemIDs
if err = av.SaveAttributeView(attrView); err != nil { if err = av.SaveAttributeView(attrView); err != nil {
logging.LogErrorf("save attribute view [%s] failed: %s", avID, err) logging.LogErrorf("save attribute view [%s] failed: %s", avID, err)
return &TxErr{code: TxErrWriteAttributeView, msg: err.Error(), id: avID} return &TxErr{code: TxErrWriteAttributeView, msg: err.Error(), id: avID}
@ -2047,16 +2019,10 @@ func addAttrViewView(avID, viewID, blockID string, layout av.LayoutType) (err er
for _, col := range firstView.Table.Columns { for _, col := range firstView.Table.Columns {
view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{BaseField: &av.BaseField{ID: col.ID}}) view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{BaseField: &av.BaseField{ID: col.ID}})
} }
for _, rowID := range firstView.Table.RowIDs {
view.Table.RowIDs = append(view.Table.RowIDs, rowID)
}
case av.LayoutTypeGallery: case av.LayoutTypeGallery:
for _, field := range firstView.Gallery.CardFields { for _, field := range firstView.Gallery.CardFields {
view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{BaseField: &av.BaseField{ID: field.ID}}) view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{BaseField: &av.BaseField{ID: field.ID}})
} }
for _, cardID := range firstView.Gallery.CardIDs {
view.Table.RowIDs = append(view.Table.RowIDs, cardID)
}
} }
case av.LayoutTypeGallery: case av.LayoutTypeGallery:
view = av.NewGalleryView() view = av.NewGalleryView()
@ -2065,16 +2031,10 @@ func addAttrViewView(avID, viewID, blockID string, layout av.LayoutType) (err er
for _, col := range firstView.Table.Columns { for _, col := range firstView.Table.Columns {
view.Gallery.CardFields = append(view.Gallery.CardFields, &av.ViewGalleryCardField{BaseField: &av.BaseField{ID: col.ID}}) view.Gallery.CardFields = append(view.Gallery.CardFields, &av.ViewGalleryCardField{BaseField: &av.BaseField{ID: col.ID}})
} }
for _, rowID := range firstView.Table.RowIDs {
view.Gallery.CardIDs = append(view.Gallery.CardIDs, rowID)
}
case av.LayoutTypeGallery: case av.LayoutTypeGallery:
for _, field := range firstView.Gallery.CardFields { for _, field := range firstView.Gallery.CardFields {
view.Gallery.CardFields = append(view.Gallery.CardFields, &av.ViewGalleryCardField{BaseField: &av.BaseField{ID: field.ID}}) view.Gallery.CardFields = append(view.Gallery.CardFields, &av.ViewGalleryCardField{BaseField: &av.BaseField{ID: field.ID}})
} }
for _, cardID := range firstView.Gallery.CardIDs {
view.Gallery.CardIDs = append(view.Gallery.CardIDs, cardID)
}
} }
default: default:
err = av.ErrWrongLayoutType err = av.ErrWrongLayoutType
@ -2082,6 +2042,7 @@ func addAttrViewView(avID, viewID, blockID string, layout av.LayoutType) (err er
return return
} }
view.ItemIDs = firstView.ItemIDs
attrView.ViewID = viewID attrView.ViewID = viewID
view.ID = viewID view.ID = viewID
attrView.Views = append(attrView.Views, view) attrView.Views = append(attrView.Views, view)
@ -2599,39 +2560,20 @@ func addAttributeViewBlock(now int64, avID, blockID, previousBlockID, addingBloc
} }
for _, v := range attrView.Views { for _, v := range attrView.Views {
switch v.LayoutType {
case av.LayoutTypeTable:
if "" != previousBlockID { if "" != previousBlockID {
changed := false changed := false
for i, id := range v.Table.RowIDs { for i, id := range v.ItemIDs {
if id == previousBlockID { if id == previousBlockID {
v.Table.RowIDs = append(v.Table.RowIDs[:i+1], append([]string{addingBlockID}, v.Table.RowIDs[i+1:]...)...) v.ItemIDs = append(v.ItemIDs[:i+1], append([]string{addingBlockID}, v.ItemIDs[i+1:]...)...)
changed = true changed = true
break break
} }
} }
if !changed { if !changed {
v.Table.RowIDs = append(v.Table.RowIDs, addingBlockID) v.ItemIDs = append(v.ItemIDs, addingBlockID)
} }
} else { } else {
v.Table.RowIDs = append([]string{addingBlockID}, v.Table.RowIDs...) v.ItemIDs = append([]string{addingBlockID}, v.ItemIDs...)
}
case av.LayoutTypeGallery:
if "" != previousBlockID {
changed := false
for i, id := range v.Gallery.CardIDs {
if id == previousBlockID {
v.Gallery.CardIDs = append(v.Gallery.CardIDs[:i+1], append([]string{addingBlockID}, v.Gallery.CardIDs[i+1:]...)...)
changed = true
break
}
}
if !changed {
v.Gallery.CardIDs = append(v.Gallery.CardIDs, addingBlockID)
}
} else {
v.Gallery.CardIDs = append([]string{addingBlockID}, v.Gallery.CardIDs...)
}
} }
} }
@ -2688,12 +2630,7 @@ func removeAttributeViewBlock(srcIDs []string, avID string, tx *Transaction) (er
for _, view := range attrView.Views { for _, view := range attrView.Views {
for _, blockID := range srcIDs { for _, blockID := range srcIDs {
switch view.LayoutType { view.ItemIDs = gulu.Str.RemoveElem(view.ItemIDs, blockID)
case av.LayoutTypeTable:
view.Table.RowIDs = gulu.Str.RemoveElem(view.Table.RowIDs, blockID)
case av.LayoutTypeGallery:
view.Gallery.CardIDs = gulu.Str.RemoveElem(view.Gallery.CardIDs, blockID)
}
} }
} }
@ -3082,51 +3019,27 @@ func sortAttributeViewRow(operation *Operation) (err error) {
var itemID string var itemID string
var idx, previousIndex int var idx, previousIndex int
switch view.LayoutType { for i, id := range view.ItemIDs {
case av.LayoutTypeTable: if id == operation.ID {
for i, r := range view.Table.RowIDs { itemID = id
if r == operation.ID {
itemID = r
idx = i idx = i
break break
} }
} }
if "" == itemID { if "" == itemID {
itemID = operation.ID itemID = operation.ID
view.Table.RowIDs = append(view.Table.RowIDs, itemID) view.ItemIDs = append(view.ItemIDs, itemID)
idx = len(view.Table.RowIDs) - 1 idx = len(view.ItemIDs) - 1
} }
view.Table.RowIDs = append(view.Table.RowIDs[:idx], view.Table.RowIDs[idx+1:]...) view.ItemIDs = append(view.ItemIDs[:idx], view.ItemIDs[idx+1:]...)
for i, r := range view.Table.RowIDs { for i, r := range view.ItemIDs {
if r == operation.PreviousID { if r == operation.PreviousID {
previousIndex = i + 1 previousIndex = i + 1
break break
} }
} }
view.Table.RowIDs = util.InsertElem(view.Table.RowIDs, previousIndex, itemID) view.ItemIDs = util.InsertElem(view.ItemIDs, previousIndex, itemID)
case av.LayoutTypeGallery:
for i, c := range view.Gallery.CardIDs {
if c == operation.ID {
itemID = c
idx = i
break
}
}
if "" == itemID {
itemID = operation.ID
view.Gallery.CardIDs = append(view.Gallery.CardIDs, itemID)
idx = len(view.Gallery.CardIDs) - 1
}
view.Gallery.CardIDs = append(view.Gallery.CardIDs[:idx], view.Gallery.CardIDs[idx+1:]...)
for i, c := range view.Gallery.CardIDs {
if c == operation.PreviousID {
previousIndex = i + 1
break
}
}
view.Gallery.CardIDs = util.InsertElem(view.Gallery.CardIDs, previousIndex, itemID)
}
err = av.SaveAttributeView(attrView) err = av.SaveAttributeView(attrView)
return return
@ -3664,27 +3577,16 @@ func replaceAttributeViewBlock(operation *Operation, tx *Transaction) (err error
replacedRowID := false replacedRowID := false
for _, v := range attrView.Views { for _, v := range attrView.Views {
switch v.LayoutType { for i, itemID := range v.ItemIDs {
case av.LayoutTypeTable: if itemID == operation.PreviousID {
for i, rowID := range v.Table.RowIDs { v.ItemIDs[i] = operation.NextID
if rowID == operation.PreviousID {
v.Table.RowIDs[i] = operation.NextID
replacedRowID = true replacedRowID = true
break break
} }
} }
if !replacedRowID { if !replacedRowID {
v.Table.RowIDs = append(v.Table.RowIDs, operation.NextID) v.ItemIDs = append(v.ItemIDs, operation.NextID)
}
case av.LayoutTypeGallery:
for i, cardID := range v.Gallery.CardIDs {
if cardID == operation.PreviousID {
v.Gallery.CardIDs[i] = operation.NextID
replacedRowID = true
break
}
}
} }
} }

View file

@ -3405,9 +3405,6 @@ func getAttrViewTable(attrView *av.AttributeView, view *av.View, query string) (
for _, field := range view.Gallery.CardFields { for _, field := range view.Gallery.CardFields {
view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{BaseField: &av.BaseField{ID: field.ID}}) view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{BaseField: &av.BaseField{ID: field.ID}})
} }
for _, cardID := range view.Gallery.CardIDs {
view.Table.RowIDs = append(view.Table.RowIDs, cardID)
}
} }
ret = sql.RenderAttributeViewTable(attrView, view, query) ret = sql.RenderAttributeViewTable(attrView, view, query)
return return

View file

@ -619,16 +619,16 @@ func filterByQuery(query string, collection av.Collection) {
} }
// manualSort 处理用户手动排序。 // manualSort 处理用户手动排序。
func manualSort(collectionLayout av.CollectionLayout, collection av.Collection) { func manualSort(view *av.View, collection av.Collection) {
sortRowIDs := map[string]int{} sortItemIDs := map[string]int{}
for i, itemID := range collectionLayout.GetItemIDs() { for i, itemID := range view.ItemIDs {
sortRowIDs[itemID] = i sortItemIDs[itemID] = i
} }
items := collection.GetItems() items := collection.GetItems()
sort.Slice(items, func(i, j int) bool { sort.Slice(items, func(i, j int) bool {
iv := sortRowIDs[items[i].GetID()] iv := sortItemIDs[items[i].GetID()]
jv := sortRowIDs[items[j].GetID()] jv := sortItemIDs[items[j].GetID()]
if iv == jv { if iv == jv {
return items[i].GetID() < items[j].GetID() return items[i].GetID() < items[j].GetID()
} }

View file

@ -143,7 +143,7 @@ func RenderAttributeViewGallery(attrView *av.AttributeView, view *av.View, query
} }
filterByQuery(query, ret) filterByQuery(query, ret)
manualSort(view.Gallery, ret) manualSort(view, ret)
return return
} }

View file

@ -142,6 +142,6 @@ func RenderAttributeViewTable(attrView *av.AttributeView, view *av.View, query s
} }
filterByQuery(query, ret) filterByQuery(query, ret)
manualSort(view.Table, ret) manualSort(view, ret)
return return
} }