diff --git a/app/src/protyle/render/av/render.ts b/app/src/protyle/render/av/render.ts index ff26c1341..f0f36245e 100644 --- a/app/src/protyle/render/av/render.ts +++ b/app/src/protyle/render/av/render.ts @@ -136,9 +136,9 @@ style="width: ${index === 0 ? ((parseInt(column.width || "200") + 24) + "px") : } }); tableHTML += `
-
+
-
+
`; // body diff --git a/kernel/av/av.go b/kernel/av/av.go index db829fb95..f434ef777 100644 --- a/kernel/av/av.go +++ b/kernel/av/av.go @@ -91,20 +91,23 @@ type Key struct { // 以下是某些列类型的特有属性 - // 单选/多选列 + // 单选/多选 Options []*SelectOption `json:"options,omitempty"` // 选项列表 - // 数字列 + // 数字 NumberFormat NumberFormat `json:"numberFormat"` // 列数字格式化 - // 模板列 + // 模板 Template string `json:"template"` // 模板内容 - // 关联列 + // 关联 Relation *Relation `json:"relation,omitempty"` // 关联信息 - // 汇总列 + // 汇总 Rollup *Rollup `json:"rollup,omitempty"` // 汇总信息 + + // 日期 + Date *Date `json:"date,omitempty"` // 日期设置 } func NewKey(id, name, icon string, keyType KeyType) *Key { @@ -116,6 +119,10 @@ func NewKey(id, name, icon string, keyType KeyType) *Key { } } +type Date struct { + AutoFillNow bool `json:"autoFillNow"` // 是否自动填充当前时间 The database date field supports filling the current time by default https://github.com/siyuan-note/siyuan/issues/10823 +} + type Rollup struct { RelationKeyID string `json:"relationKeyID"` // 关联列 ID KeyID string `json:"keyID"` // 目标列 ID diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index ce9fa5b1f..d18835b16 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -1184,6 +1184,36 @@ func getRowBlockValue(keyValues []*av.KeyValues) (ret *av.Value) { return } +func (tx *Transaction) doSetAttrViewColDate(operation *Operation) (ret *TxErr) { + err := setAttributeViewColDate(operation) + if nil != err { + return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()} + } + return +} + +func setAttributeViewColDate(operation *Operation) (err error) { + attrView, err := av.ParseAttributeView(operation.AvID) + if nil != err { + return + } + + keyID := operation.ID + key, _ := attrView.GetKey(keyID) + if nil == key || av.KeyTypeDate != key.Type { + return + } + + if nil == key.Date { + key.Date = &av.Date{} + } + + key.Date.AutoFillNow = operation.Data.(bool) + + err = av.SaveAttributeView(attrView) + return +} + func (tx *Transaction) doHideAttrViewName(operation *Operation) (ret *TxErr) { err := hideAttrViewName(operation) if nil != err { @@ -2104,27 +2134,39 @@ func addAttributeViewBlock(avID, blockID, previousBlockID, addingBlockID string, } } + // 处理日期字段默认填充当前创建时间 + // The database date field supports filling the current time by default https://github.com/siyuan-note/siyuan/issues/10823 + for _, keyValues := range attrView.KeyValues { + if av.KeyTypeDate == keyValues.Key.Type && nil != keyValues.Key.Date && keyValues.Key.Date.AutoFillNow { + dateVal := &av.Value{ + ID: ast.NewNodeID(), KeyID: keyValues.Key.ID, BlockID: addingBlockID, Type: av.KeyTypeDate, IsDetached: isDetached, CreatedAt: now, UpdatedAt: now + 1000, + Date: &av.ValueDate{Content: now, IsNotEmpty: true}, + } + keyValues.Values = append(keyValues.Values, dateVal) + } + } + if !isDetached { bindBlockAv0(tx, avID, blockID, node, tree) } - for _, view := range attrView.Views { - switch view.LayoutType { + for _, v := range attrView.Views { + switch v.LayoutType { case av.LayoutTypeTable: if "" != previousBlockID { changed := false - for i, id := range view.Table.RowIDs { + for i, id := range v.Table.RowIDs { if id == previousBlockID { - view.Table.RowIDs = append(view.Table.RowIDs[:i+1], append([]string{addingBlockID}, view.Table.RowIDs[i+1:]...)...) + v.Table.RowIDs = append(v.Table.RowIDs[:i+1], append([]string{addingBlockID}, v.Table.RowIDs[i+1:]...)...) changed = true break } } if !changed { - view.Table.RowIDs = append(view.Table.RowIDs, addingBlockID) + v.Table.RowIDs = append(v.Table.RowIDs, addingBlockID) } } else { - view.Table.RowIDs = append([]string{addingBlockID}, view.Table.RowIDs...) + v.Table.RowIDs = append([]string{addingBlockID}, v.Table.RowIDs...) } } } diff --git a/kernel/model/import.go b/kernel/model/import.go index 48a91e104..641e0cea1 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -149,16 +149,18 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { // 新 ID 保留时间部分,仅修改随机值,避免时间变化导致更新时间早于创建时间 // Keep original creation time when importing .sy.zip https://github.com/siyuan-note/siyuan/issues/9923 - newNodeID := util.TimeFromID(n.ID) + "-" + gulu.Rand.String(7) + newNodeID := util.TimeFromID(n.ID) + "-" + util.RandString(7) blockIDs[n.ID] = newNodeID oldNodeID := n.ID n.ID = newNodeID n.SetIALAttr("id", newNodeID) // 重新指向数据库属性值 - ial := parse.IAL2Map(n.KramdownIAL) - for k, _ := range ial { - if strings.HasPrefix(k, av.NodeAttrNameAvs) { + for _, kv := range n.KramdownIAL { + if 2 > len(kv) { + continue + } + if strings.HasPrefix(kv[0], av.NodeAttrNameAvs) { avBlockIDs[oldNodeID] = newNodeID } } diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index 67882b680..39f480211 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -292,6 +292,8 @@ func performTx(tx *Transaction) (ret *TxErr) { ret = tx.doUpdateAttrViewColRollup(op) case "hideAttrViewName": ret = tx.doHideAttrViewName(op) + case "setAttrViewColDate": + ret = tx.doSetAttrViewColDate(op) } if nil != ret { diff --git a/kernel/model/virutalref.go b/kernel/model/virutalref.go index 72a0f2b2b..668bb204e 100644 --- a/kernel/model/virutalref.go +++ b/kernel/model/virutalref.go @@ -275,7 +275,7 @@ func prepareMarkKeywords(keywords []string) (ret []string) { ret = gulu.Str.RemoveDuplicatedElem(keywords) var tmp []string for _, k := range ret { - if "" != k { + if "" != k && "*" != k { // 提及和虚引排除 * Ignore `*` back mentions and virtual references https://github.com/siyuan-note/siyuan/issues/10873 tmp = append(tmp, k) } } diff --git a/kernel/util/misc.go b/kernel/util/misc.go index 6ef47299f..c339917cf 100644 --- a/kernel/util/misc.go +++ b/kernel/util/misc.go @@ -18,13 +18,31 @@ package util import ( "bytes" + "math/rand" "strconv" "strings" + "time" "unicode" "github.com/88250/lute/html" ) +func init() { + rand.Seed(time.Now().UTC().UnixNano()) +} + +var ( + letter = []rune("abcdefghijklmnopqrstuvwxyz0123456789") +) + +func RandString(length int) string { + b := make([]rune, length) + for i := range b { + b[i] = letter[rand.Intn(len(letter))] + } + return string(b) +} + // InsertElem inserts value at index into a. // 0 <= index <= len(s) func InsertElem[T any](s []T, index int, value T) []T {