siyuan/kernel/av/layout_table.go

291 lines
6.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package av
import (
"sort"
"github.com/88250/lute/ast"
)
// LayoutTable 描述了表格布局的结构。
type LayoutTable struct {
*BaseLayout
Columns []*ViewTableColumn `json:"columns"` // 表格列
RowIDs []string `json:"rowIds"` // 行 ID用于自定义排序
}
func NewLayoutTable() *LayoutTable {
return &LayoutTable{
BaseLayout: &BaseLayout{
Spec: 0,
ID: ast.NewNodeID(),
Filters: []*ViewFilter{},
Sorts: []*ViewSort{},
PageSize: TableViewDefaultPageSize,
},
}
}
// ViewTableColumn 描述了表格列的结构。
type ViewTableColumn struct {
ID string `json:"id"` // 列 ID
Wrap bool `json:"wrap"` // 是否换行
Hidden bool `json:"hidden"` // 是否隐藏
Pin bool `json:"pin"` // 是否固定
Width string `json:"width"` // 列宽度
Desc string `json:"desc,omitempty"` // 列描述
Calc *ColumnCalc `json:"calc,omitempty"` // 计算
}
// Table 描述了表格实例的结构。
type Table struct {
*BaseInstance
Columns []*TableColumn `json:"columns"` // 表格列
Rows []*TableRow `json:"rows"` // 表格行
RowCount int `json:"rowCount"` // 表格总行数
}
// TableColumn 描述了表格实例列的结构。
type TableColumn struct {
*BaseInstanceField
Wrap bool `json:"wrap"` // 是否换行
Pin bool `json:"pin"` // 是否固定
Width string `json:"width"` // 列宽度
Calc *ColumnCalc `json:"calc"` // 计算
}
// TableRow 描述了表格实例行的结构。
type TableRow struct {
ID string `json:"id"` // 行 ID
Cells []*TableCell `json:"cells"` // 行单元格
}
// TableCell 描述了表格实例单元格的结构。
type TableCell struct {
*BaseValue
Color string `json:"color"` // 单元格颜色
BgColor string `json:"bgColor"` // 单元格背景颜色
}
func (row *TableRow) GetID() string {
return row.ID
}
func (row *TableRow) GetBlockValue() (ret *Value) {
for _, cell := range row.Cells {
if KeyTypeBlock == cell.ValueType {
ret = cell.Value
break
}
}
return
}
func (row *TableRow) GetValue(keyID string) (ret *Value) {
for _, cell := range row.Cells {
if nil != cell.Value && keyID == cell.Value.KeyID {
ret = cell.Value
break
}
}
return
}
func (table *Table) GetColumn(id string) *TableColumn {
for _, column := range table.Columns {
if column.ID == id {
return column
}
}
return nil
}
func (*Table) GetType() LayoutType {
return LayoutTypeTable
}
func (table *Table) GetID() string {
return table.ID
}
func (table *Table) Sort(attrView *AttributeView) {
if 1 > len(table.Sorts) {
return
}
type ColIndexSort struct {
Index int
Order SortOrder
}
var colIndexSorts []*ColIndexSort
for _, s := range table.Sorts {
for i, c := range table.Columns {
if c.ID == s.Column {
colIndexSorts = append(colIndexSorts, &ColIndexSort{Index: i, Order: s.Order})
break
}
}
}
editedValRows := map[string]bool{}
for i, row := range table.Rows {
for _, colIndexSort := range colIndexSorts {
val := table.Rows[i].Cells[colIndexSort.Index].Value
if KeyTypeCheckbox == val.Type {
if block := row.GetBlockValue(); nil != block && block.IsEdited() {
// 如果主键编辑过,则勾选框也算作编辑过,参与排序 https://github.com/siyuan-note/siyuan/issues/11016
editedValRows[row.ID] = true
break
}
}
if val.IsEdited() {
// 如果该行某列的值已经编辑过,则该行可参与排序
editedValRows[row.ID] = true
break
}
}
}
// 将未编辑的行和已编辑的行分开排序
var uneditedRows, editedRows []*TableRow
for _, row := range table.Rows {
if _, ok := editedValRows[row.ID]; ok {
editedRows = append(editedRows, row)
} else {
uneditedRows = append(uneditedRows, row)
}
}
sort.Slice(uneditedRows, func(i, j int) bool {
val1 := uneditedRows[i].GetBlockValue()
if nil == val1 {
return true
}
val2 := uneditedRows[j].GetBlockValue()
if nil == val2 {
return false
}
return val1.CreatedAt < val2.CreatedAt
})
sort.Slice(editedRows, func(i, j int) bool {
sorted := true
for _, colIndexSort := range colIndexSorts {
val1 := editedRows[i].Cells[colIndexSort.Index].Value
val2 := editedRows[j].Cells[colIndexSort.Index].Value
if nil == val1 || val1.IsEmpty() {
if nil != val2 && !val2.IsEmpty() {
return false
}
sorted = false
continue
} else {
if nil == val2 || val2.IsEmpty() {
return true
}
}
result := val1.Compare(val2, attrView)
if 0 == result {
sorted = false
continue
}
sorted = true
if colIndexSort.Order == SortOrderAsc {
return 0 > result
}
return 0 < result
}
if !sorted {
key1 := editedRows[i].GetBlockValue()
if nil == key1 {
return false
}
key2 := editedRows[j].GetBlockValue()
if nil == key2 {
return false
}
return key1.CreatedAt < key2.CreatedAt
}
return false
})
// 将包含未编辑的行放在最后
table.Rows = append(editedRows, uneditedRows...)
if 1 > len(table.Rows) {
table.Rows = []*TableRow{}
}
}
func (table *Table) Filter(attrView *AttributeView) {
if 1 > len(table.Filters) {
return
}
var colIndexes []int
for _, f := range table.Filters {
for i, c := range table.Columns {
if c.ID == f.Column {
colIndexes = append(colIndexes, i)
break
}
}
}
rows := []*TableRow{}
attrViewCache := map[string]*AttributeView{}
attrViewCache[attrView.ID] = attrView
for _, row := range table.Rows {
pass := true
for j, index := range colIndexes {
operator := table.Filters[j].Operator
if nil == row.Cells[index].Value {
if FilterOperatorIsNotEmpty == operator {
pass = false
} else if FilterOperatorIsEmpty == operator {
pass = true
break
}
if KeyTypeText != row.Cells[index].ValueType {
pass = false
}
break
}
if !row.Cells[index].Value.Filter(table.Filters[j], attrView, row.ID, &attrViewCache) {
pass = false
break
}
}
if pass {
rows = append(rows, row)
}
}
table.Rows = rows
}