diff --git a/app/src/protyle/render/av/blockAttr.ts b/app/src/protyle/render/av/blockAttr.ts index d2c324747..892ce2ecd 100644 --- a/app/src/protyle/render/av/blockAttr.ts +++ b/app/src/protyle/render/av/blockAttr.ts @@ -35,6 +35,8 @@ const genAVRollupHTML = (value: IAVCellValue) => { html = value.number.formattedContent || value.number.content.toString(); break; case "date": + case "updated": + case "created": if (value[value.type] && value[value.type].isNotEmpty) { html = dayjs(value[value.type].content).format(value[value.type].isNotTime ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm"); } diff --git a/kernel/av/av.go b/kernel/av/av.go index 17dcbff4e..79c867c1e 100644 --- a/kernel/av/av.go +++ b/kernel/av/av.go @@ -79,6 +79,20 @@ func GetKeyBlockValue(blockKeyValues []*KeyValues) (ret *Value) { return } +func GetValue(keyValues []*KeyValues, keyID, itemID string) (ret *Value) { + for _, kv := range keyValues { + if kv.Key.ID == keyID { + for _, v := range kv.Values { + if v.BlockID == itemID { + ret = v + return + } + } + } + } + return +} + // KeyType 描述了属性视图属性字段的类型。 type KeyType string @@ -565,15 +579,6 @@ func (av *AttributeView) GetCurrentView(viewID string) (ret *View, err error) { return } -func (av *AttributeView) ExistItem(itemID string) bool { - for _, blockVal := range av.GetBlockKeyValues().Values { - if blockVal.BlockID == itemID { - return true - } - } - return false -} - func (av *AttributeView) ExistBoundBlock(nodeID string) bool { for _, blockVal := range av.GetBlockKeyValues().Values { if blockVal.Block.ID == nodeID { diff --git a/kernel/av/filter.go b/kernel/av/filter.go index 3519cec3e..88ebe3e6e 100644 --- a/kernel/av/filter.go +++ b/kernel/av/filter.go @@ -182,7 +182,7 @@ func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, rowID st return false } - value.Rollup.BuildContents(destAv, destKey, relVal, key.Rollup.Calc, nil) + value.Rollup.BuildContents(destAv.KeyValues, destKey, relVal, key.Rollup.Calc, nil) for _, content := range value.Rollup.Contents { switch filter.Operator { case FilterOperatorContains: diff --git a/kernel/av/value.go b/kernel/av/value.go index e3873556f..020c06d46 100644 --- a/kernel/av/value.go +++ b/kernel/av/value.go @@ -796,21 +796,16 @@ type ValueRollup struct { Contents []*Value `json:"contents"` } -func (r *ValueRollup) BuildContents(destAv *AttributeView, destKey *Key, relationVal *Value, calc *RollupCalc, furtherCollection Collection) { +func (r *ValueRollup) BuildContents(keyValues []*KeyValues, destKey *Key, relationVal *Value, calc *RollupCalc, furtherCollection Collection) { r.Contents = nil for _, blockID := range relationVal.Relation.BlockIDs { - destVal := destAv.GetValue(destKey.ID, blockID) + destVal := GetValue(keyValues, destKey.ID, blockID) if nil != furtherCollection && KeyTypeTemplate == destKey.Type { destVal = furtherCollection.GetValue(blockID, destKey.ID) } if nil == destVal { - if destAv.ExistItem(blockID) { // 数据库中存在项目但是字段值不存在是数据未初始化,这里补一个默认值 - destVal = GetAttributeViewDefaultValue(ast.NewNodeID(), destKey.ID, blockID, destKey.Type) - } - if nil == destVal { - continue - } + continue } if KeyTypeNumber == destKey.Type { destVal.Number.Format = destKey.NumberFormat diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 13e6507a6..e87fc2a43 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -1491,8 +1491,7 @@ func GetBlockAttributeViewKeys(nodeID string) (ret []*BlockAttributeViewKeys) { } } - // 渲染自动生成的字段值,比如模板字段、关联字段、汇总字段、创建时间字段和更新时间字段 - // 先处理关联字段、汇总字段、创建时间字段和更新时间字段 + // 先渲染主键、创建时间、更新时间 for _, kv := range keyValues { switch kv.Key.Type { case av.KeyTypeBlock: // 对于主键可能需要填充静态锚文本 Database-bound block primary key supports setting static anchor text https://github.com/siyuan-note/siyuan/issues/10049 @@ -1502,6 +1501,33 @@ func GetBlockAttributeViewKeys(nodeID string) (ret []*BlockAttributeViewKeys) { kv.Values[0].Block.Content = v } } + case av.KeyTypeCreated: + createdStr := nodeID[:len("20060102150405")] + created, parseErr := time.ParseInLocation("20060102150405", createdStr, time.Local) + if nil == parseErr { + kv.Values[0].Created = av.NewFormattedValueCreated(created.UnixMilli(), 0, av.CreatedFormatNone) + kv.Values[0].Created.IsNotEmpty = true + } else { + logging.LogWarnf("parse created [%s] failed: %s", createdStr, parseErr) + kv.Values[0].Created = av.NewFormattedValueCreated(time.Now().UnixMilli(), 0, av.CreatedFormatNone) + } + case av.KeyTypeUpdated: + ial := sql.GetBlockAttrs(nodeID) + updatedStr := ial["updated"] + updated, parseErr := time.ParseInLocation("20060102150405", updatedStr, time.Local) + if nil == parseErr { + kv.Values[0].Updated = av.NewFormattedValueUpdated(updated.UnixMilli(), 0, av.UpdatedFormatNone) + kv.Values[0].Updated.IsNotEmpty = true + } else { + logging.LogWarnf("parse updated [%s] failed: %s", updatedStr, parseErr) + kv.Values[0].Updated = av.NewFormattedValueUpdated(time.Now().UnixMilli(), 0, av.UpdatedFormatNone) + } + } + } + + // 再渲染汇总和关联 + for _, kv := range keyValues { + switch kv.Key.Type { case av.KeyTypeRollup: if nil == kv.Key.Rollup { break @@ -1534,7 +1560,7 @@ func GetBlockAttributeViewKeys(nodeID string) (ret []*BlockAttributeViewKeys) { } } - kv.Values[0].Rollup.BuildContents(destAv, destKey, relVal, kv.Key.Rollup.Calc, furtherCollection) + kv.Values[0].Rollup.BuildContents(keyValues, destKey, relVal, kv.Key.Rollup.Calc, furtherCollection) } } case av.KeyTypeRelation: @@ -1560,31 +1586,10 @@ func GetBlockAttributeViewKeys(nodeID string) (ret []*BlockAttributeViewKeys) { for _, bID := range kv.Values[0].Relation.BlockIDs { kv.Values[0].Relation.Contents = append(kv.Values[0].Relation.Contents, blocks[bID]) } - case av.KeyTypeCreated: - createdStr := nodeID[:len("20060102150405")] - created, parseErr := time.ParseInLocation("20060102150405", createdStr, time.Local) - if nil == parseErr { - kv.Values[0].Created = av.NewFormattedValueCreated(created.UnixMilli(), 0, av.CreatedFormatNone) - kv.Values[0].Created.IsNotEmpty = true - } else { - logging.LogWarnf("parse created [%s] failed: %s", createdStr, parseErr) - kv.Values[0].Created = av.NewFormattedValueCreated(time.Now().UnixMilli(), 0, av.CreatedFormatNone) - } - case av.KeyTypeUpdated: - ial := sql.GetBlockAttrs(nodeID) - updatedStr := ial["updated"] - updated, parseErr := time.ParseInLocation("20060102150405", updatedStr, time.Local) - if nil == parseErr { - kv.Values[0].Updated = av.NewFormattedValueUpdated(updated.UnixMilli(), 0, av.UpdatedFormatNone) - kv.Values[0].Updated.IsNotEmpty = true - } else { - logging.LogWarnf("parse updated [%s] failed: %s", updatedStr, parseErr) - kv.Values[0].Updated = av.NewFormattedValueUpdated(time.Now().UnixMilli(), 0, av.UpdatedFormatNone) - } } } - // 再处理模板字段 + // 最后渲染模板 templateKeys, _ := sql.GetTemplateKeysByResolutionOrder(attrView) var renderTemplateErr error for _, templateKey := range templateKeys { diff --git a/kernel/sql/av.go b/kernel/sql/av.go index b79e71eab..b6283b377 100644 --- a/kernel/sql/av.go +++ b/kernel/sql/av.go @@ -336,6 +336,8 @@ func fillAttributeViewBaseValue(baseValue *av.BaseValue, fieldID, itemID string, func fillAttributeViewAutoGeneratedValues(attrView *av.AttributeView, collection av.Collection, ials map[string]map[string]string, depth *int, renderedAttrViews map[string]*av.AttributeView) { + + // 先渲染主键、创建时间、更新时间 for _, item := range collection.GetItems() { for _, value := range item.GetValues() { itemID := item.GetID() @@ -397,6 +399,7 @@ func fillAttributeViewAutoGeneratedValues(attrView *av.AttributeView, collection } } + // 再渲染汇总和关联 for _, item := range collection.GetItems() { for _, value := range item.GetValues() { itemID := item.GetID() @@ -446,7 +449,7 @@ func fillAttributeViewAutoGeneratedValues(attrView *av.AttributeView, collection } } - value.Rollup.BuildContents(destAv, destKey, relVal, rollupKey.Rollup.Calc, furtherCollection) + value.Rollup.BuildContents(destAv.KeyValues, destKey, relVal, rollupKey.Rollup.Calc, furtherCollection) case av.KeyTypeRelation: // 渲染关联 value.Relation.Contents = nil relKey, _ := attrView.GetKey(value.KeyID)