diff --git a/kernel/av/av.go b/kernel/av/av.go
index bf6bfe173..71431bca7 100644
--- a/kernel/av/av.go
+++ b/kernel/av/av.go
@@ -203,8 +203,8 @@ type View struct {
// GroupCalc 描述了分组计算规则和结果的结构。
type GroupCalc struct {
- Field string `json:"field"` // 字段 ID
- FieldCalc `json:"calc"` // 计算规则和结果
+ Field string `json:"field"` // 字段 ID
+ FieldCalc *FieldCalc `json:"calc"` // 计算规则和结果
}
// LayoutType 描述了视图布局类型。
@@ -267,15 +267,6 @@ func NewGalleryView() (ret *View) {
// Viewable 描述了视图的接口。
type Viewable interface {
- // Filter 根据视图中设置的过滤器进行过滤。
- Filter(attrView *AttributeView)
-
- // Sort 根据视图中设置的排序规则进行排序。
- Sort(attrView *AttributeView)
-
- // Calc 根据视图中设置的计算规则进行计算。
- Calc()
-
// GetType 获取视图的布局类型。
GetType() LayoutType
@@ -284,6 +275,24 @@ type Viewable interface {
// SetGroups 设置视图分组列表。
SetGroups(viewables []Viewable)
+
+ // SetGroupCalc 设置视图分组计算规则和结果。
+ SetGroupCalc(group *GroupCalc)
+
+ // GetGroupCalc 获取视图分组计算规则和结果。
+ GetGroupCalc() *GroupCalc
+
+ // SetGroupName 设置分组名称。
+ SetGroupName(name string)
+
+ // SetGroupFolded 设置分组是否折叠。
+ SetGroupFolded(folded bool)
+
+ // SetGroupHidden 设置分组是否隐藏。
+ SetGroupHidden(hidden bool)
+
+ // SetGroupDefault 设置分组是否为默认分组。
+ SetGroupDefault(defaulted bool)
}
func NewAttributeView(id string) (ret *AttributeView) {
diff --git a/kernel/av/calc.go b/kernel/av/calc.go
index 012e9a0e7..95a81113d 100644
--- a/kernel/av/calc.go
+++ b/kernel/av/calc.go
@@ -16,6 +16,13 @@
package av
+import (
+ "math"
+ "sort"
+
+ "github.com/siyuan-note/siyuan/kernel/util"
+)
+
// FieldCalc 描述了字段计算操作和结果的结构。
type FieldCalc struct {
Operator CalcOperator `json:"operator"` // 计算操作符
@@ -47,3 +54,1794 @@ const (
CalcOperatorPercentChecked CalcOperator = "Percent checked"
CalcOperatorPercentUnchecked CalcOperator = "Percent unchecked"
)
+
+func Calc(viewable Viewable) {
+ collection := viewable.(Collection)
+ for i, field := range collection.GetFields() {
+ calc := field.GetCalc()
+ if nil == calc || CalcOperatorNone == calc.Operator {
+ continue
+ }
+
+ switch field.GetType() {
+ case KeyTypeBlock:
+ CalcFieldBlock(collection, field, i)
+ case KeyTypeText:
+ CalcFieldText(collection, field, i)
+ case KeyTypeNumber:
+ CalcFieldNumber(collection, field, i)
+ case KeyTypeDate:
+ CalcFieldDate(collection, field, i)
+ case KeyTypeSelect:
+ CalcFieldSelect(collection, field, i)
+ case KeyTypeMSelect:
+ CalcFieldMSelect(collection, field, i)
+ case KeyTypeURL:
+ CalcFieldURL(collection, field, i)
+ case KeyTypeEmail:
+ CalcFieldEmail(collection, field, i)
+ case KeyTypePhone:
+ CalcFieldPhone(collection, field, i)
+ case KeyTypeMAsset:
+ CalcFieldMAsset(collection, field, i)
+ case KeyTypeTemplate:
+ CalcFieldTemplate(collection, field, i)
+ case KeyTypeCreated:
+ CalcFieldCreated(collection, field, i)
+ case KeyTypeUpdated:
+ CalcFieldUpdated(collection, field, i)
+ case KeyTypeCheckbox:
+ CalcFieldCheckbox(collection, field, i)
+ case KeyTypeRelation:
+ CalcFieldRelation(collection, field, i)
+ case KeyTypeRollup:
+ CalcFieldRollup(collection, field, i)
+ }
+ }
+}
+
+func CalcFieldTemplate(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ if !uniqueValues[values[fieldIndex].Template.Content] {
+ uniqueValues[values[fieldIndex].Template.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Template || "" == values[fieldIndex].Template.Content {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Template || "" == values[fieldIndex].Template.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ if !uniqueValues[values[fieldIndex].Template.Content] {
+ uniqueValues[values[fieldIndex].Template.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorSum:
+ sum := 0.0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
+ sum += val
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(sum, field.GetNumberFormat())}
+ case CalcOperatorAverage:
+ sum := 0.0
+ count := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
+ sum += val
+ count++
+ }
+ }
+ if 0 != count {
+ calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), field.GetNumberFormat())}
+ }
+ case CalcOperatorMedian:
+ calcValues := []float64{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
+ calcValues = append(calcValues, val)
+ }
+ }
+ sort.Float64s(calcValues)
+ if len(calcValues) > 0 {
+ if len(calcValues)%2 == 0 {
+ calc.Result = &Value{Number: NewFormattedValueNumber((calcValues[len(calcValues)/2-1]+calcValues[len(calcValues)/2])/2, field.GetNumberFormat())}
+ } else {
+ calc.Result = &Value{Number: NewFormattedValueNumber(calcValues[len(calcValues)/2], field.GetNumberFormat())}
+ }
+ }
+ case CalcOperatorMin:
+ minVal := math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
+ if val < minVal {
+ minVal = val
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(minVal, field.GetNumberFormat())}
+ }
+ case CalcOperatorMax:
+ maxVal := -math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
+ if val > maxVal {
+ maxVal = val
+ }
+ }
+ }
+ if -math.MaxFloat64 != maxVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, field.GetNumberFormat())}
+ }
+ case CalcOperatorRange:
+ minVal := math.MaxFloat64
+ maxVal := -math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
+ val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
+ if val < minVal {
+ minVal = val
+ }
+ if val > maxVal {
+ maxVal = val
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, field.GetNumberFormat())}
+ }
+ }
+}
+
+func CalcFieldMAsset(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
+ countValues += len(values[fieldIndex].MAsset)
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
+ for _, sel := range values[fieldIndex].MAsset {
+ if _, ok := uniqueValues[sel.Content]; !ok {
+ uniqueValues[sel.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].MAsset || 0 == len(values[fieldIndex].MAsset) {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].MAsset || 0 == len(values[fieldIndex].MAsset) {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
+ for _, sel := range values[fieldIndex].MAsset {
+ if _, ok := uniqueValues[sel.Content]; !ok {
+ uniqueValues[sel.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldMSelect(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
+ countValues += len(values[fieldIndex].MSelect)
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
+ for _, sel := range values[fieldIndex].MSelect {
+ if _, ok := uniqueValues[sel.Content]; !ok {
+ uniqueValues[sel.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].MSelect || 0 == len(values[fieldIndex].MSelect) {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].MSelect || 0 == len(values[fieldIndex].MSelect) {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
+ for _, sel := range values[fieldIndex].MSelect {
+ if _, ok := uniqueValues[sel.Content]; !ok {
+ uniqueValues[sel.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldSelect(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
+ if _, ok := uniqueValues[values[fieldIndex].MSelect[0].Content]; !ok {
+ uniqueValues[values[fieldIndex].MSelect[0].Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].MSelect || 1 > len(values[fieldIndex].MSelect) || nil == values[fieldIndex].MSelect[0] || "" == values[fieldIndex].MSelect[0].Content {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].MSelect || 1 > len(values[fieldIndex].MSelect) || nil == values[fieldIndex].MSelect[0] || "" == values[fieldIndex].MSelect[0].Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
+ if _, ok := uniqueValues[values[fieldIndex].MSelect[0].Content]; !ok {
+ uniqueValues[values[fieldIndex].MSelect[0].Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldDate(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
+ if _, ok := uniqueValues[values[fieldIndex].Date.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[values[fieldIndex].Date.Content] = true
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Date || !values[fieldIndex].Date.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Date || !values[fieldIndex].Date.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
+ if _, ok := uniqueValues[values[fieldIndex].Date.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[values[fieldIndex].Date.Content] = true
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorEarliest:
+ earliest := int64(0)
+ var isNotTime, hasEndDate bool
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
+ if 0 == earliest || earliest > values[fieldIndex].Date.Content {
+ earliest = values[fieldIndex].Date.Content
+ isNotTime = values[fieldIndex].Date.IsNotTime
+ hasEndDate = values[fieldIndex].Date.HasEndDate
+ }
+ }
+ }
+ if 0 != earliest {
+ calc.Result = &Value{Date: NewFormattedValueDate(earliest, 0, DateFormatNone, isNotTime, hasEndDate)}
+ }
+ case CalcOperatorLatest:
+ latest := int64(0)
+ var isNotTime, hasEndDate bool
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
+ if 0 == latest || latest < values[fieldIndex].Date.Content {
+ latest = values[fieldIndex].Date.Content
+ isNotTime = values[fieldIndex].Date.IsNotTime
+ hasEndDate = values[fieldIndex].Date.HasEndDate
+ }
+ }
+ }
+ if 0 != latest {
+ calc.Result = &Value{Date: NewFormattedValueDate(latest, 0, DateFormatNone, isNotTime, hasEndDate)}
+ }
+ case CalcOperatorRange:
+ earliest := int64(0)
+ latest := int64(0)
+ var isNotTime, hasEndDate bool
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
+ if 0 == earliest || earliest > values[fieldIndex].Date.Content {
+ earliest = values[fieldIndex].Date.Content
+ isNotTime = values[fieldIndex].Date.IsNotTime
+ hasEndDate = values[fieldIndex].Date.HasEndDate
+ }
+ if 0 == latest || latest < values[fieldIndex].Date.Content {
+ latest = values[fieldIndex].Date.Content
+ isNotTime = values[fieldIndex].Date.IsNotTime
+ hasEndDate = values[fieldIndex].Date.HasEndDate
+ }
+ }
+ }
+ if 0 != earliest && 0 != latest {
+ calc.Result = &Value{Date: NewFormattedValueDate(earliest, latest, DateFormatDuration, isNotTime, hasEndDate)}
+ }
+ }
+}
+
+func CalcFieldNumber(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[float64]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ if !uniqueValues[values[fieldIndex].Number.Content] {
+ uniqueValues[values[fieldIndex].Number.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Number || !values[fieldIndex].Number.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Number || !values[fieldIndex].Number.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[float64]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ if !uniqueValues[values[fieldIndex].Number.Content] {
+ uniqueValues[values[fieldIndex].Number.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorSum:
+ sum := 0.0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ sum += values[fieldIndex].Number.Content
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(sum, field.GetNumberFormat())}
+ case CalcOperatorAverage:
+ sum := 0.0
+ count := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ sum += values[fieldIndex].Number.Content
+ count++
+ }
+ }
+ if 0 != count {
+ calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), field.GetNumberFormat())}
+ }
+ case CalcOperatorMedian:
+ calcValues := []float64{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ calcValues = append(calcValues, values[fieldIndex].Number.Content)
+ }
+ }
+ sort.Float64s(calcValues)
+ if len(calcValues) > 0 {
+ if len(calcValues)%2 == 0 {
+ calc.Result = &Value{Number: NewFormattedValueNumber((calcValues[len(calcValues)/2-1]+calcValues[len(calcValues)/2])/2, field.GetNumberFormat())}
+ } else {
+ calc.Result = &Value{Number: NewFormattedValueNumber(calcValues[len(calcValues)/2], field.GetNumberFormat())}
+ }
+ }
+ case CalcOperatorMin:
+ minVal := math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ if values[fieldIndex].Number.Content < minVal {
+ minVal = values[fieldIndex].Number.Content
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(minVal, field.GetNumberFormat())}
+ }
+ case CalcOperatorMax:
+ maxVal := -math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ if values[fieldIndex].Number.Content > maxVal {
+ maxVal = values[fieldIndex].Number.Content
+ }
+ }
+ }
+ if -math.MaxFloat64 != maxVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, field.GetNumberFormat())}
+ }
+ case CalcOperatorRange:
+ minVal := math.MaxFloat64
+ maxVal := -math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
+ if values[fieldIndex].Number.Content < minVal {
+ minVal = values[fieldIndex].Number.Content
+ }
+ if values[fieldIndex].Number.Content > maxVal {
+ maxVal = values[fieldIndex].Number.Content
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, field.GetNumberFormat())}
+ }
+ }
+}
+
+func CalcFieldText(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
+ if !uniqueValues[values[fieldIndex].Text.Content] {
+ uniqueValues[values[fieldIndex].Text.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Text || "" == values[fieldIndex].Text.Content {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Text || "" == values[fieldIndex].Text.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
+ if !uniqueValues[values[fieldIndex].Text.Content] {
+ uniqueValues[values[fieldIndex].Text.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldURL(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
+ if !uniqueValues[values[fieldIndex].URL.Content] {
+ uniqueValues[values[fieldIndex].URL.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].URL || "" == values[fieldIndex].URL.Content {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].URL || "" == values[fieldIndex].URL.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
+ if !uniqueValues[values[fieldIndex].URL.Content] {
+ uniqueValues[values[fieldIndex].URL.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldEmail(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
+ if !uniqueValues[values[fieldIndex].Email.Content] {
+ uniqueValues[values[fieldIndex].Email.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Email || "" == values[fieldIndex].Email.Content {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Email || "" == values[fieldIndex].Email.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
+ if !uniqueValues[values[fieldIndex].Email.Content] {
+ uniqueValues[values[fieldIndex].Email.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldPhone(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
+ if !uniqueValues[values[fieldIndex].Phone.Content] {
+ uniqueValues[values[fieldIndex].Phone.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Phone || "" == values[fieldIndex].Phone.Content {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Phone || "" == values[fieldIndex].Phone.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
+ if !uniqueValues[values[fieldIndex].Phone.Content] {
+ uniqueValues[values[fieldIndex].Phone.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldBlock(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
+ if !uniqueValues[values[fieldIndex].Block.Content] {
+ uniqueValues[values[fieldIndex].Block.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Block || "" == values[fieldIndex].Block.Content {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Block || "" == values[fieldIndex].Block.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
+ if !uniqueValues[values[fieldIndex].Block.Content] {
+ uniqueValues[values[fieldIndex].Block.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldCreated(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
+ if _, ok := uniqueValues[values[fieldIndex].Created.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[values[fieldIndex].Created.Content] = true
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Created {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Created {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
+ if _, ok := uniqueValues[values[fieldIndex].Created.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[values[fieldIndex].Created.Content] = true
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorEarliest:
+ earliest := int64(0)
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
+ if 0 == earliest || earliest > values[fieldIndex].Created.Content {
+ earliest = values[fieldIndex].Created.Content
+ }
+ }
+ }
+ if 0 != earliest {
+ calc.Result = &Value{Created: NewFormattedValueCreated(earliest, 0, CreatedFormatNone)}
+ }
+ case CalcOperatorLatest:
+ latest := int64(0)
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
+ if 0 == latest || latest < values[fieldIndex].Created.Content {
+ latest = values[fieldIndex].Created.Content
+ }
+ }
+ }
+ if 0 != latest {
+ calc.Result = &Value{Created: NewFormattedValueCreated(latest, 0, CreatedFormatNone)}
+ }
+ case CalcOperatorRange:
+ earliest := int64(0)
+ latest := int64(0)
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
+ if 0 == earliest || earliest > values[fieldIndex].Created.Content {
+ earliest = values[fieldIndex].Created.Content
+ }
+ if 0 == latest || latest < values[fieldIndex].Created.Content {
+ latest = values[fieldIndex].Created.Content
+ }
+ }
+ }
+ if 0 != earliest && 0 != latest {
+ calc.Result = &Value{Created: NewFormattedValueCreated(earliest, latest, CreatedFormatDuration)}
+ }
+ }
+}
+
+func CalcFieldUpdated(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
+ if _, ok := uniqueValues[values[fieldIndex].Updated.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[values[fieldIndex].Updated.Content] = true
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Updated || !values[fieldIndex].Updated.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Updated || !values[fieldIndex].Updated.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
+ if _, ok := uniqueValues[values[fieldIndex].Updated.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[values[fieldIndex].Updated.Content] = true
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorEarliest:
+ earliest := int64(0)
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
+ if 0 == earliest || earliest > values[fieldIndex].Updated.Content {
+ earliest = values[fieldIndex].Updated.Content
+ }
+ }
+ }
+ if 0 != earliest {
+ calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, 0, UpdatedFormatNone)}
+ }
+ case CalcOperatorLatest:
+ latest := int64(0)
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
+ if 0 == latest || latest < values[fieldIndex].Updated.Content {
+ latest = values[fieldIndex].Updated.Content
+ }
+ }
+ }
+ if 0 != latest {
+ calc.Result = &Value{Updated: NewFormattedValueUpdated(latest, 0, UpdatedFormatNone)}
+ }
+ case CalcOperatorRange:
+ earliest := int64(0)
+ latest := int64(0)
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
+ if 0 == earliest || earliest > values[fieldIndex].Updated.Content {
+ earliest = values[fieldIndex].Updated.Content
+ }
+ if 0 == latest || latest < values[fieldIndex].Updated.Content {
+ latest = values[fieldIndex].Updated.Content
+ }
+ }
+ }
+ if 0 != earliest && 0 != latest {
+ calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, latest, UpdatedFormatDuration)}
+ }
+ }
+}
+
+func CalcFieldCheckbox(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorChecked:
+ countChecked := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Checkbox && values[fieldIndex].Checkbox.Checked {
+ countChecked++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked), NumberFormatNone)}
+ case CalcOperatorUnchecked:
+ countUnchecked := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Checkbox && !values[fieldIndex].Checkbox.Checked {
+ countUnchecked++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked), NumberFormatNone)}
+ case CalcOperatorPercentChecked:
+ countChecked := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Checkbox && values[fieldIndex].Checkbox.Checked {
+ countChecked++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUnchecked:
+ countUnchecked := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Checkbox && !values[fieldIndex].Checkbox.Checked {
+ countUnchecked++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldRelation(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Relation {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Relation {
+ for _, id := range values[fieldIndex].Relation.BlockIDs {
+ if !uniqueValues[id] {
+ uniqueValues[id] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Relation || 0 == len(values[fieldIndex].Relation.BlockIDs) {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Relation && 0 < len(values[fieldIndex].Relation.BlockIDs) {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Relation || 0 == len(values[fieldIndex].Relation.BlockIDs) {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Relation && 0 < len(values[fieldIndex].Relation.BlockIDs) {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Relation {
+ for _, id := range values[fieldIndex].Relation.BlockIDs {
+ if !uniqueValues[id] {
+ uniqueValues[id] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ }
+}
+
+func CalcFieldRollup(collection Collection, field Field, fieldIndex int) {
+ calc := field.GetCalc()
+ switch calc.Operator {
+ case CalcOperatorCountAll:
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup {
+ countValues++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup {
+ for _, content := range values[fieldIndex].Rollup.Contents {
+ if !uniqueValues[content.String(true)] {
+ uniqueValues[content.String(true)] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Rollup || 0 == len(values[fieldIndex].Rollup.Contents) {
+ countEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
+ countNotEmpty++
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil == values[fieldIndex] || nil == values[fieldIndex].Rollup || 0 == len(values[fieldIndex].Rollup.Contents) {
+ countEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup {
+ for _, content := range values[fieldIndex].Rollup.Contents {
+ if !uniqueValues[content.String(true)] {
+ uniqueValues[content.String(true)] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ if 0 < len(collection.GetItems()) {
+ calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
+ }
+ case CalcOperatorSum:
+ sum := 0.0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
+ for _, content := range values[fieldIndex].Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ sum += val
+ }
+ }
+ }
+ calc.Result = &Value{Number: NewFormattedValueNumber(sum, field.GetNumberFormat())}
+ case CalcOperatorAverage:
+ sum := 0.0
+ count := 0
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
+ for _, content := range values[fieldIndex].Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ sum += val
+ count++
+ }
+ }
+ }
+ if 0 != count {
+ calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), field.GetNumberFormat())}
+ }
+ case CalcOperatorMedian:
+ calcValues := []float64{}
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
+ for _, content := range values[fieldIndex].Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ calcValues = append(calcValues, val)
+ }
+ }
+ }
+ sort.Float64s(calcValues)
+ if 0 < len(calcValues) {
+ if 0 == len(calcValues)%2 {
+ calc.Result = &Value{Number: NewFormattedValueNumber((calcValues[len(calcValues)/2-1]+calcValues[len(calcValues)/2])/2, field.GetNumberFormat())}
+ } else {
+ calc.Result = &Value{Number: NewFormattedValueNumber(calcValues[len(calcValues)/2], field.GetNumberFormat())}
+ }
+ }
+ case CalcOperatorMin:
+ minVal := math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
+ for _, content := range values[fieldIndex].Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ if val < minVal {
+ minVal = val
+ }
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(minVal, field.GetNumberFormat())}
+ }
+ case CalcOperatorMax:
+ maxVal := -math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
+ for _, content := range values[fieldIndex].Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ if val > maxVal {
+ maxVal = val
+ }
+ }
+ }
+ }
+ if -math.MaxFloat64 != maxVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, field.GetNumberFormat())}
+ }
+ case CalcOperatorRange:
+ minVal := math.MaxFloat64
+ maxVal := -math.MaxFloat64
+ for _, item := range collection.GetItems() {
+ values := item.GetValues()
+ if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
+ for _, content := range values[fieldIndex].Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ if val < minVal {
+ minVal = val
+ }
+ if val > maxVal {
+ maxVal = val
+ }
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
+ calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, field.GetNumberFormat())}
+ }
+ }
+}
diff --git a/kernel/av/filter.go b/kernel/av/filter.go
index 5545f548d..207593823 100644
--- a/kernel/av/filter.go
+++ b/kernel/av/filter.go
@@ -76,6 +76,58 @@ const (
FilterOperatorIsFalse FilterOperator = "Is false"
)
+func Filter(viewable Viewable, attrView *AttributeView) {
+ collection := viewable.(Collection)
+ filters := collection.GetFilters()
+ if 1 > len(filters) {
+ return
+ }
+
+ var colIndexes []int
+ for _, f := range filters {
+ for i, c := range collection.GetFields() {
+ if c.GetID() == f.Column {
+ colIndexes = append(colIndexes, i)
+ break
+ }
+ }
+ }
+
+ var items []Item
+ attrViewCache := map[string]*AttributeView{}
+ attrViewCache[attrView.ID] = attrView
+ for _, item := range collection.GetItems() {
+ pass := true
+ values := item.GetValues()
+ for j, index := range colIndexes {
+ operator := filters[j].Operator
+
+ if nil == values[index] {
+ if FilterOperatorIsNotEmpty == operator {
+ pass = false
+ } else if FilterOperatorIsEmpty == operator {
+ pass = true
+ break
+ }
+
+ if KeyTypeText != values[index].Type {
+ pass = false
+ }
+ break
+ }
+
+ if !values[index].Filter(filters[j], attrView, item.GetID(), &attrViewCache) {
+ pass = false
+ break
+ }
+ }
+ if pass {
+ items = append(items, item)
+ }
+ }
+ collection.SetItems(items)
+}
+
func (value *Value) Filter(filter *ViewFilter, attrView *AttributeView, rowID string, attrViewCache *map[string]*AttributeView) bool {
if nil == filter || (nil == filter.Value && nil == filter.RelativeDate) {
return true
diff --git a/kernel/av/layout.go b/kernel/av/layout.go
index 8ea45a24c..a8d9e1d25 100644
--- a/kernel/av/layout.go
+++ b/kernel/av/layout.go
@@ -16,8 +16,6 @@
package av
-import "sort"
-
// BaseLayout 描述了布局的基础结构。
type BaseLayout struct {
Spec int `json:"spec"` // 布局格式版本
@@ -38,10 +36,11 @@ type BaseLayout struct {
// BaseField 描述了字段的基础结构。
type BaseField struct {
- ID string `json:"id"` // 字段 ID
- Wrap bool `json:"wrap"` // 是否换行
- Hidden bool `json:"hidden"` // 是否隐藏
- Desc string `json:"desc,omitempty"` // 字段描述
+ ID string `json:"id"` // 字段 ID
+ Wrap bool `json:"wrap"` // 是否换行
+ Hidden bool `json:"hidden"` // 是否隐藏
+ Desc string `json:"desc,omitempty"` // 字段描述
+ Calc *FieldCalc `json:"calc,omitempty"` // 计算规则
}
// BaseValue 描述了字段值的基础结构。
@@ -67,8 +66,32 @@ type BaseInstance struct {
Folded bool `json:"folded,omitempty"` // 是否折叠
Hidden bool `json:"hidden,omitempty"` // 是否隐藏
- Groups []Viewable `json:"groups,omitempty"` // 分组实例列表
- GroupCalc *GroupCalc `json:"groupCalc,omitempty"` // 分组计算规则和结果
+ Groups []Viewable `json:"groups,omitempty"` // 分组实例列表
+ GroupCalc *GroupCalc `json:"groupCalc,omitempty"` // 分组计算规则和结果
+ GroupName string `json:"groupName,omitempty"` // 分组名称
+ GroupFolded bool `json:"groupFolded,omitempty"` // 分组是否折叠
+ GroupHidden bool `json:"groupHidden,omitempty"` // 分组是否隐藏
+ GroupDefault bool `json:"groupDefault,omitempty"` // 是否为默认分组
+}
+
+func NewViewBaseInstance(view *View) *BaseInstance {
+ return &BaseInstance{
+ ID: view.ID,
+ Icon: view.Icon,
+ Name: view.Name,
+ Desc: view.Desc,
+ HideAttrViewName: view.HideAttrViewName,
+ Filters: view.Filters,
+ Sorts: view.Sorts,
+ Group: view.Group,
+ GroupCalc: view.GroupCalc,
+ GroupName: view.GroupName,
+ GroupFolded: view.GroupFolded,
+ GroupHidden: view.GroupHidden,
+ GroupDefault: view.GroupDefault,
+ ShowIcon: view.Table.ShowIcon,
+ WrapField: view.Table.WrapField,
+ }
}
func (baseInstance *BaseInstance) GetSorts() []*ViewSort {
@@ -83,19 +106,44 @@ func (baseInstance *BaseInstance) SetGroups(viewables []Viewable) {
baseInstance.Groups = viewables
}
+func (baseInstance *BaseInstance) SetGroupCalc(group *GroupCalc) {
+ baseInstance.GroupCalc = group
+}
+
+func (baseInstance *BaseInstance) GetGroupCalc() *GroupCalc {
+ return baseInstance.GroupCalc
+}
+
+func (baseInstance *BaseInstance) SetGroupName(name string) {
+ baseInstance.GroupName = name
+}
+
+func (baseInstance *BaseInstance) SetGroupFolded(folded bool) {
+ baseInstance.GroupFolded = folded
+}
+
+func (baseInstance *BaseInstance) SetGroupHidden(hidden bool) {
+ baseInstance.GroupHidden = hidden
+}
+
+func (baseInstance *BaseInstance) SetGroupDefault(defaulted bool) {
+ baseInstance.GroupDefault = defaulted
+}
+
func (baseInstance *BaseInstance) GetID() string {
return baseInstance.ID
}
// BaseInstanceField 描述了实例字段的基础结构。
type BaseInstanceField struct {
- ID string `json:"id"` // ID
- Name string `json:"name"` // 名称
- Type KeyType `json:"type"` // 类型
- Icon string `json:"icon"` // 图标
- Wrap bool `json:"wrap"` // 是否换行
- Hidden bool `json:"hidden"` // 是否隐藏
- Desc string `json:"desc"` // 描述
+ ID string `json:"id"` // ID
+ Name string `json:"name"` // 名称
+ Type KeyType `json:"type"` // 类型
+ Icon string `json:"icon"` // 图标
+ Wrap bool `json:"wrap"` // 是否换行
+ Hidden bool `json:"hidden"` // 是否隐藏
+ Desc string `json:"desc"` // 描述
+ Calc *FieldCalc `json:"calc"` // 计算规则和结果
// 以下是某些字段类型的特有属性
@@ -111,6 +159,22 @@ func (baseInstanceField *BaseInstanceField) GetID() string {
return baseInstanceField.ID
}
+func (baseInstanceField *BaseInstanceField) GetCalc() *FieldCalc {
+ return baseInstanceField.Calc
+}
+
+func (baseInstanceField *BaseInstanceField) SetCalc(calc *FieldCalc) {
+ baseInstanceField.Calc = calc
+}
+
+func (baseInstanceField *BaseInstanceField) GetType() KeyType {
+ return baseInstanceField.Type
+}
+
+func (baseInstanceField *BaseInstanceField) GetNumberFormat() NumberFormat {
+ return baseInstanceField.NumberFormat
+}
+
// Collection 描述了一个集合的接口。
// 集合可以是表格、卡片等,包含多个项目。
type Collection interface {
@@ -124,6 +188,9 @@ type Collection interface {
// GetFields 返回集合的所有字段。
GetFields() []Field
+ // GetField 返回指定 ID 的字段。
+ GetField(id string) (ret Field)
+
// GetSorts 返回集合的排序规则。
GetSorts() []*ViewSort
@@ -136,6 +203,18 @@ type Field interface {
// GetID 返回字段的 ID。
GetID() string
+
+ // GetType 返回字段的类型。
+ GetType() KeyType
+
+ // GetCalc 返回字段的计算规则和结果。
+ GetCalc() *FieldCalc
+
+ // SetCalc 设置字段的计算规则和结果。
+ SetCalc(*FieldCalc)
+
+ // GetNumberFormat 返回数字字段的格式化设置。
+ GetNumberFormat() NumberFormat
}
// Item 描述了一个项目的接口。
@@ -154,169 +233,3 @@ type Item interface {
// GetID 返回项目的 ID。
GetID() string
}
-
-func sort0(collection Collection, attrView *AttributeView) {
- sorts := collection.GetSorts()
- if 1 > len(sorts) {
- return
- }
-
- type FieldIndexSort struct {
- Index int
- Order SortOrder
- }
-
- var fieldIndexSorts []*FieldIndexSort
- for _, s := range sorts {
- for i, c := range collection.GetFields() {
- if c.GetID() == s.Column {
- fieldIndexSorts = append(fieldIndexSorts, &FieldIndexSort{Index: i, Order: s.Order})
- break
- }
- }
- }
-
- items := collection.GetItems()
- editedValItems := map[string]bool{}
- for i, item := range items {
- for _, fieldIndexSort := range fieldIndexSorts {
- val := items[i].GetValues()[fieldIndexSort.Index]
- if KeyTypeCheckbox == val.Type {
- if block := item.GetBlockValue(); nil != block && block.IsEdited() {
- // 如果主键编辑过,则勾选框也算作编辑过,参与排序 https://github.com/siyuan-note/siyuan/issues/11016
- editedValItems[item.GetID()] = true
- break
- }
- }
-
- if val.IsEdited() {
- // 如果该卡片某字段的值已经编辑过,则该卡片可参与排序
- editedValItems[item.GetID()] = true
- break
- }
- }
- }
-
- // 将未编辑的卡片和已编辑的卡片分开排序
- var uneditedItems, editedItems []Item
- for _, item := range items {
- if _, ok := editedValItems[item.GetID()]; ok {
- editedItems = append(editedItems, item)
- } else {
- uneditedItems = append(uneditedItems, item)
- }
- }
-
- sort.Slice(uneditedItems, func(i, j int) bool {
- val1 := uneditedItems[i].GetBlockValue()
- if nil == val1 {
- return true
- }
- val2 := uneditedItems[j].GetBlockValue()
- if nil == val2 {
- return false
- }
- return val1.CreatedAt < val2.CreatedAt
- })
-
- sort.Slice(editedItems, func(i, j int) bool {
- sorted := true
- for _, fieldIndexSort := range fieldIndexSorts {
- val1 := editedItems[i].GetValues()[fieldIndexSort.Index]
- val2 := editedItems[j].GetValues()[fieldIndexSort.Index]
- 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 fieldIndexSort.Order == SortOrderAsc {
- return 0 > result
- }
- return 0 < result
- }
-
- if !sorted {
- key1 := editedItems[i].GetBlockValue()
- if nil == key1 {
- return false
- }
- key2 := editedItems[j].GetBlockValue()
- if nil == key2 {
- return false
- }
- return key1.CreatedAt < key2.CreatedAt
- }
- return false
- })
-
- // 将包含未编辑的卡片放在最后
- collection.SetItems(append(editedItems, uneditedItems...))
- if 1 > len(collection.GetItems()) {
- collection.SetItems([]Item{})
- }
-}
-
-func filter0(collection Collection, attrView *AttributeView) {
- filters := collection.GetFilters()
- if 1 > len(filters) {
- return
- }
-
- var colIndexes []int
- for _, f := range filters {
- for i, c := range collection.GetFields() {
- if c.GetID() == f.Column {
- colIndexes = append(colIndexes, i)
- break
- }
- }
- }
-
- var items []Item
- attrViewCache := map[string]*AttributeView{}
- attrViewCache[attrView.ID] = attrView
- for _, item := range collection.GetItems() {
- pass := true
- values := item.GetValues()
- for j, index := range colIndexes {
- operator := filters[j].Operator
-
- if nil == values[index] {
- if FilterOperatorIsNotEmpty == operator {
- pass = false
- } else if FilterOperatorIsEmpty == operator {
- pass = true
- break
- }
-
- if KeyTypeText != values[index].Type {
- pass = false
- }
- break
- }
-
- if !values[index].Filter(filters[j], attrView, item.GetID(), &attrViewCache) {
- pass = false
- break
- }
- }
- if pass {
- items = append(items, item)
- }
- }
- collection.SetItems(items)
-}
diff --git a/kernel/av/layout_gallery.go b/kernel/av/layout_gallery.go
index c30fbe42f..c83411f04 100644
--- a/kernel/av/layout_gallery.go
+++ b/kernel/av/layout_gallery.go
@@ -173,14 +173,15 @@ func (gallery *Gallery) GetFields() (ret []Field) {
return ret
}
+func (gallery *Gallery) GetField(id string) Field {
+ for _, field := range gallery.Fields {
+ if field.ID == id {
+ return field
+ }
+ }
+ return nil
+}
+
func (gallery *Gallery) GetType() LayoutType {
return LayoutTypeGallery
}
-
-func (gallery *Gallery) Sort(attrView *AttributeView) {
- sort0(gallery, attrView)
-}
-
-func (gallery *Gallery) Filter(attrView *AttributeView) {
- filter0(gallery, attrView)
-}
diff --git a/kernel/av/layout_gallery_calc.go b/kernel/av/layout_gallery_calc.go
deleted file mode 100644
index cb83abca4..000000000
--- a/kernel/av/layout_gallery_calc.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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 .
-
-package av
-
-func (gallery *Gallery) Calc() {
- // 卡片视图不支持计算
-}
diff --git a/kernel/av/layout_table.go b/kernel/av/layout_table.go
index f1b26d67b..afb9bc82b 100644
--- a/kernel/av/layout_table.go
+++ b/kernel/av/layout_table.go
@@ -63,9 +63,8 @@ type Table struct {
type TableColumn struct {
*BaseInstanceField
- Pin bool `json:"pin"` // 是否固定
- Width string `json:"width"` // 列宽度
- Calc *FieldCalc `json:"calc"` // 计算规则和结果
+ Pin bool `json:"pin"` // 是否固定
+ Width string `json:"width"` // 列宽度
}
// TableRow 描述了表格实例行的结构。
@@ -150,18 +149,15 @@ func (table *Table) GetFields() (ret []Field) {
return ret
}
+func (table *Table) GetField(id string) Field {
+ 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) {
- sort0(table, attrView)
-}
-
-func (table *Table) Filter(attrView *AttributeView) {
- filter0(table, attrView)
-}
diff --git a/kernel/av/layout_table_calc.go b/kernel/av/layout_table_calc.go
deleted file mode 100644
index 6542d6d3a..000000000
--- a/kernel/av/layout_table_calc.go
+++ /dev/null
@@ -1,1665 +0,0 @@
-// 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 .
-
-package av
-
-import (
- "math"
- "sort"
-
- "github.com/siyuan-note/siyuan/kernel/util"
-)
-
-func (table *Table) Calc() {
- for i, col := range table.Columns {
- if nil == col.Calc {
- continue
- }
-
- if CalcOperatorNone == col.Calc.Operator {
- continue
- }
-
- switch col.Type {
- case KeyTypeBlock:
- table.calcColBlock(col, i)
- case KeyTypeText:
- table.calcColText(col, i)
- case KeyTypeNumber:
- table.calcColNumber(col, i)
- case KeyTypeDate:
- table.calcColDate(col, i)
- case KeyTypeSelect:
- table.calcColSelect(col, i)
- case KeyTypeMSelect:
- table.calcColMSelect(col, i)
- case KeyTypeURL:
- table.calcColURL(col, i)
- case KeyTypeEmail:
- table.calcColEmail(col, i)
- case KeyTypePhone:
- table.calcColPhone(col, i)
- case KeyTypeMAsset:
- table.calcColMAsset(col, i)
- case KeyTypeTemplate:
- table.calcColTemplate(col, i)
- case KeyTypeCreated:
- table.calcColCreated(col, i)
- case KeyTypeUpdated:
- table.calcColUpdated(col, i)
- case KeyTypeCheckbox:
- table.calcColCheckbox(col, i)
- case KeyTypeRelation:
- table.calcColRelation(col, i)
- case KeyTypeRollup:
- table.calcColRollup(col, i)
- }
- }
-}
-
-func (table *Table) calcColTemplate(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Template.Content] {
- uniqueValues[row.Cells[colIndex].Value.Template.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Template || "" == row.Cells[colIndex].Value.Template.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Template || "" == row.Cells[colIndex].Value.Template.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Template.Content] {
- uniqueValues[row.Cells[colIndex].Value.Template.Content] = true
- countUniqueValues++
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorSum:
- sum := 0.0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- sum += val
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
- case CalcOperatorAverage:
- sum := 0.0
- count := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- sum += val
- count++
- }
- }
- if 0 != count {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
- }
- case CalcOperatorMedian:
- values := []float64{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- values = append(values, val)
- }
- }
- sort.Float64s(values)
- if len(values) > 0 {
- if len(values)%2 == 0 {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
- } else {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
- }
- }
- case CalcOperatorMin:
- minVal := math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- if val < minVal {
- minVal = val
- }
- }
- }
- if math.MaxFloat64 != minVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
- }
- case CalcOperatorMax:
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- if val > maxVal {
- maxVal = val
- }
- }
- }
- if -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
- }
- case CalcOperatorRange:
- minVal := math.MaxFloat64
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- if val < minVal {
- minVal = val
- }
- if val > maxVal {
- maxVal = val
- }
- }
- }
- if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
- }
- }
-}
-
-func (table *Table) calcColMAsset(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- countValues += len(row.Cells[colIndex].Value.MAsset)
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- for _, sel := range row.Cells[colIndex].Value.MAsset {
- if _, ok := uniqueValues[sel.Content]; !ok {
- uniqueValues[sel.Content] = true
- countUniqueValues++
- }
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MAsset || 0 == len(row.Cells[colIndex].Value.MAsset) {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MAsset || 0 == len(row.Cells[colIndex].Value.MAsset) {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- for _, sel := range row.Cells[colIndex].Value.MAsset {
- if _, ok := uniqueValues[sel.Content]; !ok {
- uniqueValues[sel.Content] = true
- countUniqueValues++
- }
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColMSelect(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- countValues += len(row.Cells[colIndex].Value.MSelect)
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- for _, sel := range row.Cells[colIndex].Value.MSelect {
- if _, ok := uniqueValues[sel.Content]; !ok {
- uniqueValues[sel.Content] = true
- countUniqueValues++
- }
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 0 == len(row.Cells[colIndex].Value.MSelect) {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 0 == len(row.Cells[colIndex].Value.MSelect) {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- for _, sel := range row.Cells[colIndex].Value.MSelect {
- if _, ok := uniqueValues[sel.Content]; !ok {
- uniqueValues[sel.Content] = true
- countUniqueValues++
- }
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColSelect(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.MSelect[0].Content]; !ok {
- uniqueValues[row.Cells[colIndex].Value.MSelect[0].Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 1 > len(row.Cells[colIndex].Value.MSelect) || nil == row.Cells[colIndex].Value.MSelect[0] || "" == row.Cells[colIndex].Value.MSelect[0].Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 1 > len(row.Cells[colIndex].Value.MSelect) || nil == row.Cells[colIndex].Value.MSelect[0] || "" == row.Cells[colIndex].Value.MSelect[0].Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.MSelect[0].Content]; !ok {
- uniqueValues[row.Cells[colIndex].Value.MSelect[0].Content] = true
- countUniqueValues++
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColDate(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Date.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Date.Content] = true
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Date || !row.Cells[colIndex].Value.Date.IsNotEmpty {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Date || !row.Cells[colIndex].Value.Date.IsNotEmpty {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Date.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Date.Content] = true
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorEarliest:
- earliest := int64(0)
- var isNotTime, hasEndDate bool
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Date.Content {
- earliest = row.Cells[colIndex].Value.Date.Content
- isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
- hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
- }
- }
- }
- if 0 != earliest {
- col.Calc.Result = &Value{Date: NewFormattedValueDate(earliest, 0, DateFormatNone, isNotTime, hasEndDate)}
- }
- case CalcOperatorLatest:
- latest := int64(0)
- var isNotTime, hasEndDate bool
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if 0 == latest || latest < row.Cells[colIndex].Value.Date.Content {
- latest = row.Cells[colIndex].Value.Date.Content
- isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
- hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
- }
- }
- }
- if 0 != latest {
- col.Calc.Result = &Value{Date: NewFormattedValueDate(latest, 0, DateFormatNone, isNotTime, hasEndDate)}
- }
- case CalcOperatorRange:
- earliest := int64(0)
- latest := int64(0)
- var isNotTime, hasEndDate bool
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Date.Content {
- earliest = row.Cells[colIndex].Value.Date.Content
- isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
- hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
- }
- if 0 == latest || latest < row.Cells[colIndex].Value.Date.Content {
- latest = row.Cells[colIndex].Value.Date.Content
- isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
- hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
- }
- }
- }
- if 0 != earliest && 0 != latest {
- col.Calc.Result = &Value{Date: NewFormattedValueDate(earliest, latest, DateFormatDuration, isNotTime, hasEndDate)}
- }
- }
-}
-
-func (table *Table) calcColNumber(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[float64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if !uniqueValues[row.Cells[colIndex].Value.Number.Content] {
- uniqueValues[row.Cells[colIndex].Value.Number.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Number || !row.Cells[colIndex].Value.Number.IsNotEmpty {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Number || !row.Cells[colIndex].Value.Number.IsNotEmpty {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[float64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if !uniqueValues[row.Cells[colIndex].Value.Number.Content] {
- uniqueValues[row.Cells[colIndex].Value.Number.Content] = true
- countUniqueValues++
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorSum:
- sum := 0.0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- sum += row.Cells[colIndex].Value.Number.Content
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
- case CalcOperatorAverage:
- sum := 0.0
- count := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- sum += row.Cells[colIndex].Value.Number.Content
- count++
- }
- }
- if 0 != count {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
- }
- case CalcOperatorMedian:
- values := []float64{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- values = append(values, row.Cells[colIndex].Value.Number.Content)
- }
- }
- sort.Float64s(values)
- if len(values) > 0 {
- if len(values)%2 == 0 {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
- } else {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
- }
- }
- case CalcOperatorMin:
- minVal := math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if row.Cells[colIndex].Value.Number.Content < minVal {
- minVal = row.Cells[colIndex].Value.Number.Content
- }
- }
- }
- if math.MaxFloat64 != minVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
- }
- case CalcOperatorMax:
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if row.Cells[colIndex].Value.Number.Content > maxVal {
- maxVal = row.Cells[colIndex].Value.Number.Content
- }
- }
- }
- if -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
- }
- case CalcOperatorRange:
- minVal := math.MaxFloat64
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if row.Cells[colIndex].Value.Number.Content < minVal {
- minVal = row.Cells[colIndex].Value.Number.Content
- }
- if row.Cells[colIndex].Value.Number.Content > maxVal {
- maxVal = row.Cells[colIndex].Value.Number.Content
- }
- }
- }
- if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
- }
- }
-}
-
-func (table *Table) calcColText(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Text.Content] {
- uniqueValues[row.Cells[colIndex].Value.Text.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Text || "" == row.Cells[colIndex].Value.Text.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Text || "" == row.Cells[colIndex].Value.Text.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Text.Content] {
- uniqueValues[row.Cells[colIndex].Value.Text.Content] = true
- countUniqueValues++
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColURL(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- if !uniqueValues[row.Cells[colIndex].Value.URL.Content] {
- uniqueValues[row.Cells[colIndex].Value.URL.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.URL || "" == row.Cells[colIndex].Value.URL.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.URL || "" == row.Cells[colIndex].Value.URL.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- if !uniqueValues[row.Cells[colIndex].Value.URL.Content] {
- uniqueValues[row.Cells[colIndex].Value.URL.Content] = true
- countUniqueValues++
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColEmail(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Email.Content] {
- uniqueValues[row.Cells[colIndex].Value.Email.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Email || "" == row.Cells[colIndex].Value.Email.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Email || "" == row.Cells[colIndex].Value.Email.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Email.Content] {
- uniqueValues[row.Cells[colIndex].Value.Email.Content] = true
- countUniqueValues++
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColPhone(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Phone.Content] {
- uniqueValues[row.Cells[colIndex].Value.Phone.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Phone || "" == row.Cells[colIndex].Value.Phone.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Phone || "" == row.Cells[colIndex].Value.Phone.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Phone.Content] {
- uniqueValues[row.Cells[colIndex].Value.Phone.Content] = true
- countUniqueValues++
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColBlock(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Block.Content] {
- uniqueValues[row.Cells[colIndex].Value.Block.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Block || "" == row.Cells[colIndex].Value.Block.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Block || "" == row.Cells[colIndex].Value.Block.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Block.Content] {
- uniqueValues[row.Cells[colIndex].Value.Block.Content] = true
- countUniqueValues++
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColCreated(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Created.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Created.Content] = true
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Created {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Created {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Created.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Created.Content] = true
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorEarliest:
- earliest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Created.Content {
- earliest = row.Cells[colIndex].Value.Created.Content
- }
- }
- }
- if 0 != earliest {
- col.Calc.Result = &Value{Created: NewFormattedValueCreated(earliest, 0, CreatedFormatNone)}
- }
- case CalcOperatorLatest:
- latest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if 0 == latest || latest < row.Cells[colIndex].Value.Created.Content {
- latest = row.Cells[colIndex].Value.Created.Content
- }
- }
- }
- if 0 != latest {
- col.Calc.Result = &Value{Created: NewFormattedValueCreated(latest, 0, CreatedFormatNone)}
- }
- case CalcOperatorRange:
- earliest := int64(0)
- latest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Created.Content {
- earliest = row.Cells[colIndex].Value.Created.Content
- }
- if 0 == latest || latest < row.Cells[colIndex].Value.Created.Content {
- latest = row.Cells[colIndex].Value.Created.Content
- }
- }
- }
- if 0 != earliest && 0 != latest {
- col.Calc.Result = &Value{Created: NewFormattedValueCreated(earliest, latest, CreatedFormatDuration)}
- }
- }
-}
-
-func (table *Table) calcColUpdated(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Updated.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Updated.Content] = true
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Updated || !row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Updated || !row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Updated.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Updated.Content] = true
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorEarliest:
- earliest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Updated.Content {
- earliest = row.Cells[colIndex].Value.Updated.Content
- }
- }
- }
- if 0 != earliest {
- col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, 0, UpdatedFormatNone)}
- }
- case CalcOperatorLatest:
- latest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if 0 == latest || latest < row.Cells[colIndex].Value.Updated.Content {
- latest = row.Cells[colIndex].Value.Updated.Content
- }
- }
- }
- if 0 != latest {
- col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(latest, 0, UpdatedFormatNone)}
- }
- case CalcOperatorRange:
- earliest := int64(0)
- latest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Updated.Content {
- earliest = row.Cells[colIndex].Value.Updated.Content
- }
- if 0 == latest || latest < row.Cells[colIndex].Value.Updated.Content {
- latest = row.Cells[colIndex].Value.Updated.Content
- }
- }
- }
- if 0 != earliest && 0 != latest {
- col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, latest, UpdatedFormatDuration)}
- }
- }
-}
-
-func (table *Table) calcColCheckbox(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorChecked:
- countChecked := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && row.Cells[colIndex].Value.Checkbox.Checked {
- countChecked++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked), NumberFormatNone)}
- case CalcOperatorUnchecked:
- countUnchecked := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && !row.Cells[colIndex].Value.Checkbox.Checked {
- countUnchecked++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked), NumberFormatNone)}
- case CalcOperatorPercentChecked:
- countChecked := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && row.Cells[colIndex].Value.Checkbox.Checked {
- countChecked++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUnchecked:
- countUnchecked := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && !row.Cells[colIndex].Value.Checkbox.Checked {
- countUnchecked++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColRelation(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation {
- for _, id := range row.Cells[colIndex].Value.Relation.BlockIDs {
- if !uniqueValues[id] {
- uniqueValues[id] = true
- countUniqueValues++
- }
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Relation || 0 == len(row.Cells[colIndex].Value.Relation.BlockIDs) {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation && 0 < len(row.Cells[colIndex].Value.Relation.BlockIDs) {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Relation || 0 == len(row.Cells[colIndex].Value.Relation.BlockIDs) {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation && 0 < len(row.Cells[colIndex].Value.Relation.BlockIDs) {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation {
- for _, id := range row.Cells[colIndex].Value.Relation.BlockIDs {
- if !uniqueValues[id] {
- uniqueValues[id] = true
- countUniqueValues++
- }
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- if !uniqueValues[content.String(true)] {
- uniqueValues[content.String(true)] = true
- countUniqueValues++
- }
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Rollup || 0 == len(row.Cells[colIndex].Value.Rollup.Contents) {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Rollup || 0 == len(row.Cells[colIndex].Value.Rollup.Contents) {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- if !uniqueValues[content.String(true)] {
- uniqueValues[content.String(true)] = true
- countUniqueValues++
- }
- }
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorSum:
- sum := 0.0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- sum += val
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
- case CalcOperatorAverage:
- sum := 0.0
- count := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- sum += val
- count++
- }
- }
- }
- if 0 != count {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
- }
- case CalcOperatorMedian:
- values := []float64{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- values = append(values, val)
- }
- }
- }
- sort.Float64s(values)
- if 0 < len(values) {
- if 0 == len(values)%2 {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
- } else {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
- }
- }
- case CalcOperatorMin:
- minVal := math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- if val < minVal {
- minVal = val
- }
- }
- }
- }
- if math.MaxFloat64 != minVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
- }
- case CalcOperatorMax:
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- if val > maxVal {
- maxVal = val
- }
- }
- }
- }
- if -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
- }
- case CalcOperatorRange:
- minVal := math.MaxFloat64
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- if val < minVal {
- minVal = val
- }
- if val > maxVal {
- maxVal = val
- }
- }
- }
- }
- if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
- }
- }
-}
diff --git a/kernel/av/sort.go b/kernel/av/sort.go
index 5cef4f83f..56ca2eaa2 100644
--- a/kernel/av/sort.go
+++ b/kernel/av/sort.go
@@ -18,6 +18,7 @@ package av
import (
"bytes"
+ "sort"
"strings"
"time"
@@ -37,6 +38,122 @@ const (
SortOrderDesc SortOrder = "DESC"
)
+func Sort(viewable Viewable, attrView *AttributeView) {
+ collection := viewable.(Collection)
+ sorts := collection.GetSorts()
+ if 1 > len(sorts) {
+ return
+ }
+
+ type FieldIndexSort struct {
+ Index int
+ Order SortOrder
+ }
+
+ var fieldIndexSorts []*FieldIndexSort
+ for _, s := range sorts {
+ for i, c := range collection.GetFields() {
+ if c.GetID() == s.Column {
+ fieldIndexSorts = append(fieldIndexSorts, &FieldIndexSort{Index: i, Order: s.Order})
+ break
+ }
+ }
+ }
+
+ items := collection.GetItems()
+ editedValItems := map[string]bool{}
+ for i, item := range items {
+ for _, fieldIndexSort := range fieldIndexSorts {
+ val := items[i].GetValues()[fieldIndexSort.Index]
+ if KeyTypeCheckbox == val.Type {
+ if block := item.GetBlockValue(); nil != block && block.IsEdited() {
+ // 如果主键编辑过,则勾选框也算作编辑过,参与排序 https://github.com/siyuan-note/siyuan/issues/11016
+ editedValItems[item.GetID()] = true
+ break
+ }
+ }
+
+ if val.IsEdited() {
+ // 如果该卡片某字段的值已经编辑过,则该卡片可参与排序
+ editedValItems[item.GetID()] = true
+ break
+ }
+ }
+ }
+
+ // 将未编辑的卡片和已编辑的卡片分开排序
+ var uneditedItems, editedItems []Item
+ for _, item := range items {
+ if _, ok := editedValItems[item.GetID()]; ok {
+ editedItems = append(editedItems, item)
+ } else {
+ uneditedItems = append(uneditedItems, item)
+ }
+ }
+
+ sort.Slice(uneditedItems, func(i, j int) bool {
+ val1 := uneditedItems[i].GetBlockValue()
+ if nil == val1 {
+ return true
+ }
+ val2 := uneditedItems[j].GetBlockValue()
+ if nil == val2 {
+ return false
+ }
+ return val1.CreatedAt < val2.CreatedAt
+ })
+
+ sort.Slice(editedItems, func(i, j int) bool {
+ sorted := true
+ for _, fieldIndexSort := range fieldIndexSorts {
+ val1 := editedItems[i].GetValues()[fieldIndexSort.Index]
+ val2 := editedItems[j].GetValues()[fieldIndexSort.Index]
+ 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 fieldIndexSort.Order == SortOrderAsc {
+ return 0 > result
+ }
+ return 0 < result
+ }
+
+ if !sorted {
+ key1 := editedItems[i].GetBlockValue()
+ if nil == key1 {
+ return false
+ }
+ key2 := editedItems[j].GetBlockValue()
+ if nil == key2 {
+ return false
+ }
+ return key1.CreatedAt < key2.CreatedAt
+ }
+ return false
+ })
+
+ // 将包含未编辑的卡片放在最后
+ collection.SetItems(append(editedItems, uneditedItems...))
+ if 1 > len(collection.GetItems()) {
+ collection.SetItems([]Item{})
+ }
+}
+
func (value *Value) Compare(other *Value, attrView *AttributeView) int {
switch value.Type {
case KeyTypeBlock:
diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go
index 711b87080..9f65285d7 100644
--- a/kernel/model/attribute_view.go
+++ b/kernel/model/attribute_view.go
@@ -1316,9 +1316,74 @@ func renderViewableInstance(viewable av.Viewable, view *av.View, attrView *av.At
return
}
- viewable.Filter(attrView)
- viewable.Sort(attrView)
- viewable.Calc()
+ av.Filter(viewable, attrView)
+ av.Sort(viewable, attrView)
+ av.Calc(viewable)
+
+ if groupCalc := viewable.GetGroupCalc(); nil != groupCalc {
+ if groupCalcKey, _ := attrView.GetKey(groupCalc.Field); nil != groupCalcKey {
+ collection := viewable.(av.Collection)
+ var calcResult *av.GroupCalc
+ field := collection.GetField(groupCalcKey.ID)
+ if nil != field {
+ if calc := field.GetCalc(); nil != calc && field.GetID() == groupCalcKey.ID {
+ // 直接使用字段计算结果
+ calcResult = &av.GroupCalc{Field: groupCalcKey.ID, FieldCalc: calc}
+ }
+
+ if nil == calcResult {
+ for i, f := range collection.GetFields() {
+ if f.GetID() != groupCalcKey.ID {
+ continue
+ }
+
+ field.SetCalc(groupCalc.FieldCalc)
+
+ switch field.GetType() {
+ case av.KeyTypeBlock:
+ av.CalcFieldBlock(collection, field, i)
+ case av.KeyTypeText:
+ av.CalcFieldText(collection, field, i)
+ case av.KeyTypeNumber:
+ av.CalcFieldNumber(collection, field, i)
+ case av.KeyTypeDate:
+ av.CalcFieldDate(collection, field, i)
+ case av.KeyTypeSelect:
+ av.CalcFieldSelect(collection, field, i)
+ case av.KeyTypeMSelect:
+ av.CalcFieldMSelect(collection, field, i)
+ case av.KeyTypeURL:
+ av.CalcFieldURL(collection, field, i)
+ case av.KeyTypeEmail:
+ av.CalcFieldEmail(collection, field, i)
+ case av.KeyTypePhone:
+ av.CalcFieldPhone(collection, field, i)
+ case av.KeyTypeMAsset:
+ av.CalcFieldMAsset(collection, field, i)
+ case av.KeyTypeTemplate:
+ av.CalcFieldTemplate(collection, field, i)
+ case av.KeyTypeCreated:
+ av.CalcFieldCreated(collection, field, i)
+ case av.KeyTypeUpdated:
+ av.CalcFieldUpdated(collection, field, i)
+ case av.KeyTypeCheckbox:
+ av.CalcFieldCheckbox(collection, field, i)
+ case av.KeyTypeRelation:
+ av.CalcFieldRelation(collection, field, i)
+ case av.KeyTypeRollup:
+ av.CalcFieldRollup(collection, field, i)
+ }
+ break
+ }
+
+ calcResult = &av.GroupCalc{Field: groupCalcKey.ID, FieldCalc: field.GetCalc()}
+ field.SetCalc(nil)
+ }
+ }
+
+ viewable.SetGroupCalc(calcResult)
+ }
+ }
// 分页
switch viewable.GetType() {
@@ -1368,8 +1433,8 @@ func GetCurrentAttributeViewImages(avID, viewID, query string) (ret []string, er
}
table := getAttrViewTable(attrView, view, query)
- table.Filter(attrView)
- table.Sort(attrView)
+ av.Filter(table, attrView)
+ av.Sort(table, attrView)
for _, row := range table.Rows {
for _, cell := range row.Cells {
@@ -2480,8 +2545,8 @@ func addAttributeViewBlock(now int64, avID, blockID, previousBlockID, addingBloc
if nil != view && 0 < len(view.Filters) && !ignoreFillFilter {
viewable := sql.RenderView(view, attrView, "")
- viewable.Filter(attrView)
- viewable.Sort(attrView)
+ av.Filter(viewable, attrView)
+ av.Sort(viewable, attrView)
collection := viewable.(av.Collection)
items := collection.GetItems()
diff --git a/kernel/model/export.go b/kernel/model/export.go
index 4ba5065c9..ccf92e8ba 100644
--- a/kernel/model/export.go
+++ b/kernel/model/export.go
@@ -83,8 +83,8 @@ func ExportAv2CSV(avID, blockID string) (zipPath string, err error) {
table := getAttrViewTable(attrView, view, "")
// 遵循视图过滤和排序规则 Use filtering and sorting of current view settings when exporting database blocks https://github.com/siyuan-note/siyuan/issues/10474
- table.Filter(attrView)
- table.Sort(attrView)
+ av.Filter(table, attrView)
+ av.Sort(table, attrView)
exportFolder := filepath.Join(util.TempDir, "export", "csv", name)
if err = os.MkdirAll(exportFolder, 0755); err != nil {
@@ -2499,8 +2499,8 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold, avHiddenCol bool,
table := getAttrViewTable(attrView, view, "")
// 遵循视图过滤和排序规则 Use filtering and sorting of current view settings when exporting database blocks https://github.com/siyuan-note/siyuan/issues/10474
- table.Filter(attrView)
- table.Sort(attrView)
+ av.Filter(table, attrView)
+ av.Sort(table, attrView)
var aligns []int
for range table.Columns {
diff --git a/kernel/sql/av_gallery.go b/kernel/sql/av_gallery.go
index 895c07728..ac5886907 100644
--- a/kernel/sql/av_gallery.go
+++ b/kernel/sql/av_gallery.go
@@ -20,18 +20,7 @@ import (
func RenderAttributeViewGallery(attrView *av.AttributeView, view *av.View, query string) (ret *av.Gallery) {
ret = &av.Gallery{
- BaseInstance: &av.BaseInstance{
- ID: view.ID,
- Icon: view.Icon,
- Name: view.Name,
- Desc: view.Desc,
- HideAttrViewName: view.HideAttrViewName,
- Filters: view.Filters,
- Sorts: view.Sorts,
- Group: view.Group,
- ShowIcon: view.Gallery.ShowIcon,
- WrapField: view.Gallery.WrapField,
- },
+ BaseInstance: av.NewViewBaseInstance(view),
CoverFrom: view.Gallery.CoverFrom,
CoverFromAssetKeyID: view.Gallery.CoverFromAssetKeyID,
CardAspectRatio: view.Gallery.CardAspectRatio,
@@ -59,6 +48,7 @@ func RenderAttributeViewGallery(attrView *av.AttributeView, view *av.View, query
Wrap: field.Wrap,
Hidden: field.Hidden,
Desc: key.Desc,
+ Calc: field.Calc,
Options: key.Options,
NumberFormat: key.NumberFormat,
Template: key.Template,
diff --git a/kernel/sql/av_table.go b/kernel/sql/av_table.go
index c6a77456a..cda7cfc7a 100644
--- a/kernel/sql/av_table.go
+++ b/kernel/sql/av_table.go
@@ -24,20 +24,9 @@ import (
func RenderAttributeViewTable(attrView *av.AttributeView, view *av.View, query string) (ret *av.Table) {
ret = &av.Table{
- BaseInstance: &av.BaseInstance{
- ID: view.ID,
- Icon: view.Icon,
- Name: view.Name,
- Desc: view.Desc,
- HideAttrViewName: view.HideAttrViewName,
- Filters: view.Filters,
- Sorts: view.Sorts,
- Group: view.Group,
- ShowIcon: view.Table.ShowIcon,
- WrapField: view.Table.WrapField,
- },
- Columns: []*av.TableColumn{},
- Rows: []*av.TableRow{},
+ BaseInstance: av.NewViewBaseInstance(view),
+ Columns: []*av.TableColumn{},
+ Rows: []*av.TableRow{},
}
// 组装列
@@ -58,6 +47,7 @@ func RenderAttributeViewTable(attrView *av.AttributeView, view *av.View, query s
Wrap: col.Wrap,
Hidden: col.Hidden,
Desc: key.Desc,
+ Calc: col.Calc,
Options: key.Options,
NumberFormat: key.NumberFormat,
Template: key.Template,
@@ -67,7 +57,6 @@ func RenderAttributeViewTable(attrView *av.AttributeView, view *av.View, query s
},
Width: col.Width,
Pin: col.Pin,
- Calc: col.Calc,
})
}