mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-09-22 00:20:47 +02:00
🎨 Database grouping by field https://github.com/siyuan-note/siyuan/issues/10964
This commit is contained in:
parent
759c12be06
commit
cff71aa720
7 changed files with 139 additions and 72 deletions
|
@ -292,10 +292,14 @@ func addAttributeViewBlocks(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
avID := arg["avID"].(string)
|
avID := arg["avID"].(string)
|
||||||
blockID := ""
|
var blockID string
|
||||||
if blockIDArg := arg["blockID"]; nil != blockIDArg {
|
if blockIDArg := arg["blockID"]; nil != blockIDArg {
|
||||||
blockID = blockIDArg.(string)
|
blockID = blockIDArg.(string)
|
||||||
}
|
}
|
||||||
|
var groupID string
|
||||||
|
if groupIDArg := arg["groupID"]; nil != groupIDArg {
|
||||||
|
groupID = groupIDArg.(string)
|
||||||
|
}
|
||||||
var previousID string
|
var previousID string
|
||||||
if nil != arg["previousID"] {
|
if nil != arg["previousID"] {
|
||||||
previousID = arg["previousID"].(string)
|
previousID = arg["previousID"].(string)
|
||||||
|
@ -310,7 +314,7 @@ func addAttributeViewBlocks(c *gin.Context) {
|
||||||
src := v.(map[string]interface{})
|
src := v.(map[string]interface{})
|
||||||
srcs = append(srcs, src)
|
srcs = append(srcs, src)
|
||||||
}
|
}
|
||||||
err := model.AddAttributeViewBlock(nil, srcs, avID, blockID, previousID, ignoreFillFilter)
|
err := model.AddAttributeViewBlock(nil, srcs, avID, blockID, groupID, previousID, ignoreFillFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ret.Code = -1
|
ret.Code = -1
|
||||||
ret.Msg = err.Error()
|
ret.Msg = err.Error()
|
||||||
|
|
|
@ -192,14 +192,31 @@ type View struct {
|
||||||
Gallery *LayoutGallery `json:"gallery,omitempty"` // 卡片布局
|
Gallery *LayoutGallery `json:"gallery,omitempty"` // 卡片布局
|
||||||
ItemIDs []string `json:"itemIds,omitempty"` // 项目 ID 列表,用于维护所有项目
|
ItemIDs []string `json:"itemIds,omitempty"` // 项目 ID 列表,用于维护所有项目
|
||||||
|
|
||||||
Group *ViewGroup `json:"group,omitempty"` // 分组规则
|
Group *ViewGroup `json:"group,omitempty"` // 分组规则
|
||||||
GroupUpdated int64 `json:"groupUpdated"` // 分组规则更新时间戳
|
GroupUpdated int64 `json:"groupUpdated"` // 分组规则更新时间戳
|
||||||
Groups []*View `json:"groups,omitempty"` // 分组视图列表
|
Groups []*View `json:"groups,omitempty"` // 分组视图列表
|
||||||
GroupItemIDs []string `json:"groupItemIds"` // 分组项目 ID 列表,用于维护分组中的所有项目
|
GroupItemIDs []string `json:"groupItemIds"` // 分组项目 ID 列表,用于维护分组中的所有项目
|
||||||
GroupCalc *GroupCalc `json:"groupCalc,omitempty"` // 分组计算规则
|
GroupCalc *GroupCalc `json:"groupCalc,omitempty"` // 分组计算规则
|
||||||
GroupName string `json:"groupName,omitempty"` // 分组名称
|
GroupValue string `json:"groupValue,omitempty"` // 分组值
|
||||||
GroupFolded bool `json:"groupFolded"` // 分组是否折叠
|
GroupFolded bool `json:"groupFolded"` // 分组是否折叠
|
||||||
GroupHidden int `json:"groupHidden"` // 分组是否隐藏,0:显示,1:空白隐藏,2:手动隐藏
|
GroupHidden int `json:"groupHidden"` // 分组是否隐藏,0:显示,1:空白隐藏,2:手动隐藏
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
GroupValueDefault = "_@default@_" // 默认分组值(值为空的默认分组)
|
||||||
|
GroupValueNotInRange = "_@notInRange@_" // 不再范围内的分组值(只有数字类型的分组才可能是该值)
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetGroup 获取指定分组 ID 的分组视图。
|
||||||
|
func (view *View) GetGroup(groupID string) *View {
|
||||||
|
if nil == view.Groups {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, group := range view.Groups {
|
||||||
|
if group.ID == groupID {
|
||||||
|
return group
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupCalc 描述了分组计算规则和结果的结构。
|
// GroupCalc 描述了分组计算规则和结果的结构。
|
||||||
|
@ -283,9 +300,6 @@ type Viewable interface {
|
||||||
// GetGroupCalc 获取视图分组计算规则和结果。
|
// GetGroupCalc 获取视图分组计算规则和结果。
|
||||||
GetGroupCalc() *GroupCalc
|
GetGroupCalc() *GroupCalc
|
||||||
|
|
||||||
// SetGroupName 设置分组名称。
|
|
||||||
SetGroupName(name string)
|
|
||||||
|
|
||||||
// SetGroupFolded 设置分组是否折叠。
|
// SetGroupFolded 设置分组是否折叠。
|
||||||
SetGroupFolded(folded bool)
|
SetGroupFolded(folded bool)
|
||||||
|
|
||||||
|
|
|
@ -866,8 +866,8 @@ func (filter *ViewFilter) GetAffectValue(key *Key, defaultVal *Value) (ret *Valu
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 没有默认值则使用过滤条件的值
|
|
||||||
|
|
||||||
|
// 没有默认值则使用过滤条件的值
|
||||||
switch filter.Value.Type {
|
switch filter.Value.Type {
|
||||||
case KeyTypeBlock:
|
case KeyTypeBlock:
|
||||||
switch filter.Operator {
|
switch filter.Operator {
|
||||||
|
|
|
@ -66,7 +66,6 @@ type BaseInstance struct {
|
||||||
|
|
||||||
Groups []Viewable `json:"groups,omitempty"` // 分组实例列表
|
Groups []Viewable `json:"groups,omitempty"` // 分组实例列表
|
||||||
GroupCalc *GroupCalc `json:"groupCalc,omitempty"` // 分组计算规则和结果
|
GroupCalc *GroupCalc `json:"groupCalc,omitempty"` // 分组计算规则和结果
|
||||||
GroupName string `json:"groupName,omitempty"` // 分组名称
|
|
||||||
GroupFolded bool `json:"groupFolded"` // 分组是否折叠
|
GroupFolded bool `json:"groupFolded"` // 分组是否折叠
|
||||||
GroupHidden int `json:"groupHidden"` // 分组是否隐藏,0:显示,1:空白隐藏,2:手动隐藏
|
GroupHidden int `json:"groupHidden"` // 分组是否隐藏,0:显示,1:空白隐藏,2:手动隐藏
|
||||||
}
|
}
|
||||||
|
@ -91,7 +90,6 @@ func NewViewBaseInstance(view *View) *BaseInstance {
|
||||||
Sorts: view.Sorts,
|
Sorts: view.Sorts,
|
||||||
Group: view.Group,
|
Group: view.Group,
|
||||||
GroupCalc: view.GroupCalc,
|
GroupCalc: view.GroupCalc,
|
||||||
GroupName: view.GroupName,
|
|
||||||
GroupFolded: view.GroupFolded,
|
GroupFolded: view.GroupFolded,
|
||||||
GroupHidden: view.GroupHidden,
|
GroupHidden: view.GroupHidden,
|
||||||
ShowIcon: showIcon,
|
ShowIcon: showIcon,
|
||||||
|
@ -119,10 +117,6 @@ func (baseInstance *BaseInstance) GetGroupCalc() *GroupCalc {
|
||||||
return baseInstance.GroupCalc
|
return baseInstance.GroupCalc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (baseInstance *BaseInstance) SetGroupName(name string) {
|
|
||||||
baseInstance.GroupName = name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (baseInstance *BaseInstance) SetGroupFolded(folded bool) {
|
func (baseInstance *BaseInstance) SetGroupFolded(folded bool) {
|
||||||
baseInstance.GroupFolded = folded
|
baseInstance.GroupFolded = folded
|
||||||
}
|
}
|
||||||
|
|
|
@ -1539,12 +1539,8 @@ func renderAttributeView(attrView *av.AttributeView, blockID, viewID, query stri
|
||||||
// 如果存在分组的话渲染分组视图
|
// 如果存在分组的话渲染分组视图
|
||||||
var groups []av.Viewable
|
var groups []av.Viewable
|
||||||
for _, groupView := range view.Groups {
|
for _, groupView := range view.Groups {
|
||||||
switch groupView.LayoutType {
|
groupView.Filters = view.Filters
|
||||||
case av.LayoutTypeTable:
|
groupView.Sorts = view.Sorts
|
||||||
groupView.Table.Columns = view.Table.Columns
|
|
||||||
case av.LayoutTypeGallery:
|
|
||||||
groupView.Gallery.CardFields = view.Gallery.CardFields
|
|
||||||
}
|
|
||||||
|
|
||||||
groupViewable := sql.RenderView(attrView, groupView, query)
|
groupViewable := sql.RenderView(attrView, groupView, query)
|
||||||
err = renderViewableInstance(groupViewable, view, attrView, page, pageSize)
|
err = renderViewableInstance(groupViewable, view, attrView, page, pageSize)
|
||||||
|
@ -1622,13 +1618,12 @@ func genAttrViewViewGroups(view *av.View, attrView *av.AttributeView) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultGroupName, notInRange = "_@default@_", "_@notInRange@_"
|
|
||||||
var groupName string
|
var groupName string
|
||||||
groupItemsMap := map[string][]av.Item{}
|
groupItemsMap := map[string][]av.Item{}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
value := item.GetValue(group.Field)
|
value := item.GetValue(group.Field)
|
||||||
if value.IsEmpty() {
|
if value.IsEmpty() {
|
||||||
groupName = defaultGroupName
|
groupName = av.GroupValueDefault
|
||||||
groupItemsMap[groupName] = append(groupItemsMap[groupName], item)
|
groupItemsMap[groupName] = append(groupItemsMap[groupName], item)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -1638,16 +1633,16 @@ func genAttrViewViewGroups(view *av.View, attrView *av.AttributeView) {
|
||||||
groupName = value.String(false)
|
groupName = value.String(false)
|
||||||
case av.GroupMethodRangeNum:
|
case av.GroupMethodRangeNum:
|
||||||
if group.Range.NumStart > value.Number.Content || group.Range.NumEnd < value.Number.Content {
|
if group.Range.NumStart > value.Number.Content || group.Range.NumEnd < value.Number.Content {
|
||||||
groupName = notInRange
|
groupName = av.GroupValueNotInRange
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
for rangeEnd <= group.Range.NumEnd && rangeEnd < value.Number.Content {
|
for rangeEnd <= group.Range.NumEnd && rangeEnd <= value.Number.Content {
|
||||||
rangeStart += group.Range.NumStep
|
rangeStart += group.Range.NumStep
|
||||||
rangeEnd += group.Range.NumStep
|
rangeEnd += group.Range.NumStep
|
||||||
}
|
}
|
||||||
|
|
||||||
if rangeStart <= value.Number.Content && rangeEnd >= value.Number.Content {
|
if rangeStart <= value.Number.Content && rangeEnd > value.Number.Content {
|
||||||
groupName = fmt.Sprintf("%s - %s", strconv.FormatFloat(rangeStart, 'f', -1, 64), strconv.FormatFloat(rangeEnd, 'f', -1, 64))
|
groupName = fmt.Sprintf("%s - %s", strconv.FormatFloat(rangeStart, 'f', -1, 64), strconv.FormatFloat(rangeEnd, 'f', -1, 64))
|
||||||
}
|
}
|
||||||
case av.GroupMethodDateDay, av.GroupMethodDateWeek, av.GroupMethodDateMonth, av.GroupMethodDateYear, av.GroupMethodDateRelative:
|
case av.GroupMethodDateDay, av.GroupMethodDateWeek, av.GroupMethodDateMonth, av.GroupMethodDateYear, av.GroupMethodDateRelative:
|
||||||
|
@ -1727,9 +1722,10 @@ func genAttrViewViewGroups(view *av.View, attrView *av.AttributeView) {
|
||||||
v.GroupItemIDs = append(v.GroupItemIDs, item.GetID())
|
v.GroupItemIDs = append(v.GroupItemIDs, item.GetID())
|
||||||
}
|
}
|
||||||
|
|
||||||
if defaultGroupName == name {
|
v.GroupValue = name
|
||||||
|
if av.GroupValueDefault == name {
|
||||||
name = fmt.Sprintf(Conf.language(264), groupKey.Name)
|
name = fmt.Sprintf(Conf.language(264), groupKey.Name)
|
||||||
} else if notInRange == name {
|
} else if av.GroupValueNotInRange == name {
|
||||||
name = fmt.Sprintf(Conf.language(265))
|
name = fmt.Sprintf(Conf.language(265))
|
||||||
}
|
}
|
||||||
v.Name = name
|
v.Name = name
|
||||||
|
@ -2838,14 +2834,14 @@ func setAttributeViewColumnCalc(operation *Operation) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) doInsertAttrViewBlock(operation *Operation) (ret *TxErr) {
|
func (tx *Transaction) doInsertAttrViewBlock(operation *Operation) (ret *TxErr) {
|
||||||
err := AddAttributeViewBlock(tx, operation.Srcs, operation.AvID, operation.BlockID, operation.PreviousID, operation.IgnoreFillFilterVal)
|
err := AddAttributeViewBlock(tx, operation.Srcs, operation.AvID, operation.BlockID, operation.GroupID, operation.PreviousID, operation.IgnoreFillFilterVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}
|
return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddAttributeViewBlock(tx *Transaction, srcs []map[string]interface{}, avID, blockID, previousBlockID string, ignoreFillFilter bool) (err error) {
|
func AddAttributeViewBlock(tx *Transaction, srcs []map[string]interface{}, avID, blockID, groupID, previousBlockID string, ignoreFillFilter bool) (err error) {
|
||||||
slices.Reverse(srcs) // https://github.com/siyuan-note/siyuan/issues/11286
|
slices.Reverse(srcs) // https://github.com/siyuan-note/siyuan/issues/11286
|
||||||
|
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
|
@ -2874,14 +2870,14 @@ func AddAttributeViewBlock(tx *Transaction, srcs []map[string]interface{}, avID,
|
||||||
if nil != src["content"] {
|
if nil != src["content"] {
|
||||||
srcContent = src["content"].(string)
|
srcContent = src["content"].(string)
|
||||||
}
|
}
|
||||||
if avErr := addAttributeViewBlock(now, avID, blockID, previousBlockID, srcID, srcContent, isDetached, ignoreFillFilter, tree, tx); nil != avErr {
|
if avErr := addAttributeViewBlock(now, avID, blockID, groupID, previousBlockID, srcID, srcContent, isDetached, ignoreFillFilter, tree, tx); nil != avErr {
|
||||||
return avErr
|
return avErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func addAttributeViewBlock(now int64, avID, blockID, previousBlockID, addingBlockID, addingBlockContent string, isDetached, ignoreFillFilter bool, tree *parse.Tree, tx *Transaction) (err error) {
|
func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, addingBlockID, addingBlockContent string, isDetached, ignoreFillFilter bool, tree *parse.Tree, tx *Transaction) (err error) {
|
||||||
var node *ast.Node
|
var node *ast.Node
|
||||||
if !isDetached {
|
if !isDetached {
|
||||||
node = treenode.GetNodeInTree(tree, addingBlockID)
|
node = treenode.GetNodeInTree(tree, addingBlockID)
|
||||||
|
@ -2935,17 +2931,14 @@ func addAttributeViewBlock(now int64, avID, blockID, previousBlockID, addingBloc
|
||||||
Block: &av.ValueBlock{ID: addingBlockID, Icon: blockIcon, Content: addingBlockContent, Created: now, Updated: now}}
|
Block: &av.ValueBlock{ID: addingBlockID, Icon: blockIcon, Content: addingBlockContent, Created: now, Updated: now}}
|
||||||
blockValues.Values = append(blockValues.Values, blockValue)
|
blockValues.Values = append(blockValues.Values, blockValue)
|
||||||
|
|
||||||
// 如果存在过滤条件,则将过滤条件应用到新添加的块上
|
view, _ := getAttrViewViewByBlockID(attrView, blockID) // blockID 可能不传,所以这里的 view 可能为空,后面使用需要判空
|
||||||
view, _ := getAttrViewViewByBlockID(attrView, blockID)
|
var nearItem av.Item // 临近项
|
||||||
if nil != view && 0 < len(view.Filters) && !ignoreFillFilter {
|
if nil != view && ((0 < len(view.Filters) && !ignoreFillFilter) || "" != groupID) {
|
||||||
|
// 存在过滤条件或者指定分组视图时,先获取临近项备用
|
||||||
viewable := sql.RenderView(attrView, view, "")
|
viewable := sql.RenderView(attrView, view, "")
|
||||||
av.Filter(viewable, attrView)
|
av.Filter(viewable, attrView)
|
||||||
av.Sort(viewable, attrView)
|
av.Sort(viewable, attrView)
|
||||||
|
items := viewable.(av.Collection).GetItems()
|
||||||
collection := viewable.(av.Collection)
|
|
||||||
items := collection.GetItems()
|
|
||||||
|
|
||||||
var nearItem av.Item
|
|
||||||
if 0 < len(items) {
|
if 0 < len(items) {
|
||||||
if "" != previousBlockID {
|
if "" != previousBlockID {
|
||||||
for _, row := range items {
|
for _, row := range items {
|
||||||
|
@ -2960,19 +2953,26 @@ func addAttributeViewBlock(now int64, avID, blockID, previousBlockID, addingBloc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterKeyIDs := map[string]bool{}
|
||||||
|
if nil != view {
|
||||||
|
for _, f := range view.Filters {
|
||||||
|
filterKeyIDs[f.Column] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果存在过滤条件,则将过滤条件应用到新添加的块上
|
||||||
|
if nil != view && 0 < len(view.Filters) && !ignoreFillFilter {
|
||||||
sameKeyFilterSort := false // 是否在同一个字段上同时存在过滤和排序
|
sameKeyFilterSort := false // 是否在同一个字段上同时存在过滤和排序
|
||||||
if 0 < len(view.Sorts) {
|
if 0 < len(view.Sorts) {
|
||||||
filterKeys, sortKeys := map[string]bool{}, map[string]bool{}
|
sortKeys := map[string]bool{}
|
||||||
for _, f := range view.Filters {
|
|
||||||
filterKeys[f.Column] = true
|
|
||||||
}
|
|
||||||
for _, s := range view.Sorts {
|
for _, s := range view.Sorts {
|
||||||
sortKeys[s.Column] = true
|
sortKeys[s.Column] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for key := range filterKeys {
|
for k := range filterKeyIDs {
|
||||||
if sortKeys[key] {
|
if sortKeys[k] {
|
||||||
sameKeyFilterSort = true
|
sameKeyFilterSort = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -3028,6 +3028,7 @@ func addAttributeViewBlock(now int64, avID, blockID, previousBlockID, addingBloc
|
||||||
bindBlockAv0(tx, avID, node, tree)
|
bindBlockAv0(tx, avID, node, tree)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在所有视图上添加项目
|
||||||
for _, v := range attrView.Views {
|
for _, v := range attrView.Views {
|
||||||
if "" != previousBlockID {
|
if "" != previousBlockID {
|
||||||
changed := false
|
changed := false
|
||||||
|
@ -3046,6 +3047,50 @@ func addAttributeViewBlock(now int64, avID, blockID, previousBlockID, addingBloc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果存在分组条件,则将分组条件应用到新添加的块上
|
||||||
|
groupKey := getViewGroupKey(view, attrView)
|
||||||
|
if nil != view && nil != groupKey {
|
||||||
|
if !filterKeyIDs[groupKey.ID] /* 过滤条件应用过的话就不重复处理了 */ && "" != groupID {
|
||||||
|
if groupView := view.GetGroup(groupID); nil != groupView {
|
||||||
|
if keyValues, _ := attrView.GetKeyValues(groupKey.ID); nil != keyValues {
|
||||||
|
var newValue, defaultVal *av.Value
|
||||||
|
if nil != nearItem {
|
||||||
|
defaultVal = nearItem.GetValue(groupKey.ID)
|
||||||
|
}
|
||||||
|
if nil != defaultVal {
|
||||||
|
newValue = defaultVal.Clone()
|
||||||
|
} else {
|
||||||
|
newValue = av.GetAttributeViewDefaultValue(ast.NewNodeID(), groupKey.ID, blockID, groupKey.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if av.KeyTypeBlock == newValue.Type {
|
||||||
|
// 如果是主键的话前面已经添加过了,这里仅修改内容
|
||||||
|
blockValue.Block.Content = newValue.Block.Content
|
||||||
|
} else {
|
||||||
|
newValue.ID = ast.NewNodeID()
|
||||||
|
newValue.CreatedAt = util.CurrentTimeMillis()
|
||||||
|
newValue.UpdatedAt = newValue.CreatedAt + 1000
|
||||||
|
newValue.KeyID = keyValues.Key.ID
|
||||||
|
newValue.BlockID = addingBlockID
|
||||||
|
newValue.IsDetached = isDetached
|
||||||
|
|
||||||
|
if av.KeyTypeSelect == groupKey.Type || av.KeyTypeMSelect == groupKey.Type {
|
||||||
|
// 因为单选或多选只能按选项分组,并且可能存在空白分组(前面可能找不到临近项) ,所以单选或多选类型的分组字段使用分组值内容对应的选项
|
||||||
|
if opt := groupKey.GetOption(groupView.GroupValue); nil != opt {
|
||||||
|
newValue.MSelect[0].Content = opt.Name
|
||||||
|
newValue.MSelect[0].Color = opt.Color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyValues.Values = append(keyValues.Values, newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regenAttrViewViewGroups(attrView, groupKey.ID)
|
||||||
|
}
|
||||||
|
|
||||||
err = av.SaveAttributeView(attrView)
|
err = av.SaveAttributeView(attrView)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -4428,33 +4473,42 @@ func updateAttributeViewValue(tx *Transaction, attrView *av.AttributeView, keyID
|
||||||
|
|
||||||
func regenAttrViewViewGroups(attrView *av.AttributeView, keyID string) {
|
func regenAttrViewViewGroups(attrView *av.AttributeView, keyID string) {
|
||||||
for _, view := range attrView.Views {
|
for _, view := range attrView.Views {
|
||||||
if nil != view.Group {
|
groupKey := getViewGroupKey(view, attrView)
|
||||||
groupKey, _ := attrView.GetKey(view.Group.Field)
|
if nil == groupKey {
|
||||||
if nil == groupKey {
|
continue
|
||||||
continue
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if av.KeyTypeTemplate != groupKey.Type && view.Group.Field != keyID {
|
if av.KeyTypeTemplate != groupKey.Type && view.Group.Field != keyID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
genAttrViewViewGroups(view, attrView)
|
genAttrViewViewGroups(view, attrView)
|
||||||
|
|
||||||
for _, g := range view.Groups {
|
for _, g := range view.Groups {
|
||||||
if view.Group.HideEmpty {
|
if view.Group.HideEmpty {
|
||||||
if 2 != g.GroupHidden && 1 > len(g.GroupItemIDs) {
|
if 2 != g.GroupHidden && 1 > len(g.GroupItemIDs) {
|
||||||
g.GroupHidden = 1
|
g.GroupHidden = 1
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if 2 != g.GroupHidden {
|
if 2 != g.GroupHidden {
|
||||||
g.GroupHidden = 0
|
g.GroupHidden = 0
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getViewGroupKey(view *av.View, attrView *av.AttributeView) *av.Key {
|
||||||
|
if nil == view.Group {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if "" == view.Group.Field {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret, _ := attrView.GetKey(view.Group.Field)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
func unbindBlockAv(tx *Transaction, avID, blockID string) {
|
func unbindBlockAv(tx *Transaction, avID, blockID string) {
|
||||||
node, tree, err := getNodeByBlockID(tx, blockID)
|
node, tree, err := getNodeByBlockID(tx, blockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -986,7 +986,7 @@ func DuplicateDoc(tree *parse.Tree) {
|
||||||
AddAttributeViewBlock(nil, []map[string]interface{}{{
|
AddAttributeViewBlock(nil, []map[string]interface{}{{
|
||||||
"id": n.ID,
|
"id": n.ID,
|
||||||
"isDetached": false,
|
"isDetached": false,
|
||||||
}}, avID, "", "", false)
|
}}, avID, "", "", "", false)
|
||||||
ReloadAttrView(avID)
|
ReloadAttrView(avID)
|
||||||
}
|
}
|
||||||
return ast.WalkContinue
|
return ast.WalkContinue
|
||||||
|
|
|
@ -1096,7 +1096,7 @@ func (tx *Transaction) doLargeInsert(previousID string) (ret *TxErr) {
|
||||||
AddAttributeViewBlock(tx, []map[string]interface{}{{
|
AddAttributeViewBlock(tx, []map[string]interface{}{{
|
||||||
"id": insertedNode.ID,
|
"id": insertedNode.ID,
|
||||||
"isDetached": false,
|
"isDetached": false,
|
||||||
}}, avID, "", previousID, false)
|
}}, avID, "", "", previousID, false)
|
||||||
ReloadAttrView(avID)
|
ReloadAttrView(avID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1275,7 +1275,7 @@ func (tx *Transaction) doInsert(operation *Operation) (ret *TxErr) {
|
||||||
AddAttributeViewBlock(tx, []map[string]interface{}{{
|
AddAttributeViewBlock(tx, []map[string]interface{}{{
|
||||||
"id": insertedNode.ID,
|
"id": insertedNode.ID,
|
||||||
"isDetached": false,
|
"isDetached": false,
|
||||||
}}, avID, "", previousID, false)
|
}}, avID, "", "", previousID, false)
|
||||||
ReloadAttrView(avID)
|
ReloadAttrView(avID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1692,6 +1692,7 @@ type Operation struct {
|
||||||
BackRelationKeyID string `json:"backRelationKeyID"` // 属性视图关联列回链关联列的 ID
|
BackRelationKeyID string `json:"backRelationKeyID"` // 属性视图关联列回链关联列的 ID
|
||||||
RemoveDest bool `json:"removeDest"` // 属性视图删除关联目标
|
RemoveDest bool `json:"removeDest"` // 属性视图删除关联目标
|
||||||
Layout av.LayoutType `json:"layout"` // 属性视图布局类型
|
Layout av.LayoutType `json:"layout"` // 属性视图布局类型
|
||||||
|
GroupID string `json:"groupID"` // 属性视图分组视图 ID
|
||||||
}
|
}
|
||||||
|
|
||||||
type Transaction struct {
|
type Transaction struct {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue