KevinChen 发表于 2022-11-12 22:24:43

【SpreadJS v16.0 新特性预览】支持表格分层数据及树形展示

SpreadJS V16 新增了对分层数据的支持,并且可以根据用户提供的分层数据自动生成对应的树形表格。


对分层数据的支持是在 SpreadJS 的 DataManager 中实现的,并通过集算表进行展示和交互。
相关信息请了解集算表相关特性:
https://demo.grapecity.com.cn/spreadjs/SpreadJSTutorial/features/table-sheet/overview/purejs

分层数据源类型:

1. 记录具有id和parentId的属性:

<div>[
{ id: 1, parentId: -1 },
{ id: 2, parentId: -1 },
{ id: 3, parentId:1 },
{ id: 4, parentId:1 },
{ id: 5, parentId:2 }
]</div>

2. 记录有属性表示层级,层级由记录的顺序确定,每条记录都可以有这个属性作为主键:


<div>[
{ name: 'USA', level: -1, id: 1 },
{ name: 'Texas', level: 0, id: 2 },
{ name: 'Houston', level: 1, id: 3 },
{ name: 'California', level: 0, id: 4 },
{ name: 'San Francisco', level: 1, id: 5 },
{ name: 'Los Angeles', level: 1, id: 6 },
]</div>

3. 记录有属性表示分层子级,记录一直是没有根记录的树数据,每个子级都可以有该属性作为主键:


<div>[
    {
      name: 'USA',
      children: [
            {
                name: 'Texas',
                children: [
                  {
                        name: 'Houston',
                  }
                ]
            }
      ]
    }
]</div>

4. 记录有主键,键可以通过自定义函数解析为层次结构:


<div>[
{ id: '1' },
{ id: '2' },
{ id: '1.1' },
{ id: '1.1.1' },
{ id: '2.1' }
]</div>

分层数据源配置
1. 数据源选项可以配置分层选项:

<div>interface GC.Data.IDataSourceOption {
    //others options...
    schema?: {
      hierarchy: GC.Data.IHierarchyOption // define whether the data source is hierarchical
      //others options...
    }
}
interface GC.Data.IHierarchyOption {
type: 'Parent' | 'ChildrenPath' | 'Level' | 'Custom', // the hierarchy type
column: string // the hierarachy key that will help to build the hierarchical data
outlineColumn?: string | GC.Data.IHierarchyOutlineColumnOptions; // the options for self-defined outline
summaryFields: GC.Data.IHierarchySummaryFieldCollection // define the formulas for the fields
parse: (options: GC.Data.IHierarchyCustomParseOptions) => any; // parse the primary key of the custom hierarchy type to the parent key
unparse?: (options: GC.Data.IHierarchyCustomUnparseOptions) => any; // build the primary key of the custom hierarchy type
}
interface GC.Data.IHierarchySummaryFieldCollection {
    : string; // the key is the field name, and the value is the formula
}
interface GC.Data.IHierarchyCustomParseOptions {
data: any,
index: number,
}
interface GC.Data.IHierarchyCustomUnparseOptions {
data: any,
index: number,
parentData: any
}
interface GC.Data.IOutlineColumnOptions {
    showCheckBox?: boolean;
    showImage?: boolean;
    images?: string[];
    showIndicator?: boolean;
    expandIndicator?: string;
    collapseIndicator?: string;
}
interface GC.Data.IHierarchyOutlineColumnOptions {
    value: string; // specify the column name that will be outline column
    showCheckBox?: boolean;
    showImage?: boolean;
    images?: string[];
    showIndicator?: boolean;
    expandIndicator?: string;
    collapseIndicator?: string;
}
interface GC.Data.IColumn {
//other options...
// the rowOrder in the dataType is used for the ordering the records, the value of the column should be a number,
// it's used by the data manager when moving or inserting
// it's better to hide the column for the end user
dataType?: "string" | "number" | "boolean" | "object" | "array" | "date" | "rowOrder";
outlineColumn?: boolean | GC.Data.IOutlineColumnOptions // indicates the column be an outline column or the outline column options, and there should be only one outline column in the columns
}
</div>
<div>var taskTable = dataManager.addTable("Tasks", {
    remote: { ... },
    schema: {
      hierarchy: {
          type: 'Parent',
          column: 'TaskParentId',
      },
      columns: {
          TaskName: {dataName: 'name' },
          TaskId: { dataName: 'id', isPrimaryKey: true }, // using primary key to indicate the hierarchy id
          TaskParentId: { dataName: 'parentId' },
          TaskRowOrder: { dataName: 'rowOrder', dataType: "rowOrder" }, // optional property for inserting and moving up/down
      }
    }
});

var taskView = taskTable.addView('TaskView',[
{
    value: 'TaskName', outlineColumn: true // this option indicates the column showing as outline column
}
]);
</div>
<div>var taskTable = dataManager.addTable("Tasks", {
    remote: { ... },
    schema: {
      hierarchy: {
          type: 'Level',
          column: 'TaskLevel',
      },
      columns: {
          TaskName: {dataName: 'name' },
          TaskId: { dataName: 'id', isPrimaryKey: true }, // using primary key to indicate the hierarchy id optionally if exist
          TaskLevel: { dataName: 'level' },
          TaskRowOrder: { dataName: 'rowOrder', dataType: "rowOrder" }, // optional property for inserting and moving up/down
      }
    }
});

var taskView = taskTable.addView('TaskView',[
{
    value: 'TaskName', outlineColumn: true// this option indicates the column showing as outline column
}
]);
</div>
<div>var taskTable = dataManager.addTable("Tasks", {
    remote: { ... },
    schema: {
      hierarchy: {
          type: 'ChildrenPath',
          column: 'TaskChildren',
      },
      columns: {
          TaskName: {dataName: 'name' },
          TaskChildren: { dataName: 'children' },
          // other columns in the child
      }
    }
});
var taskView = taskTable.addView('TaskView',[
{
    value: 'TaskName', outlineColumn: true // this option indicates the column showing as outline column
}
]);
</div>
<div>var taskTable = dataManager.addTable("Tasks", {
    remote: { ... },
    schema: {
      hierarchy: {
          type: 'Custom',
          column: 'TaskId',
          parse: function(options){
            // parse the primary key "1.1.1" to "1.1"
            // the returned value will be treated as parentId
            let seg = options.data.TaskId.split('.');
            return seg.slice(0,seg.length-1).join('.')
          },
          unparse: function(options){
            let parentIds, currentIndex = options.index, parentData = options.parentData, parentKey = parentData && parentData.TaskId;
            if (parentKey) {
            let sp = parentKey.split('.');
            parentIds = sp;
            } else {
            parentIds = [];
            }
            parentIds.push(currentIndex + 1);
            return parentIds.join('.');
          }
      },
      columns: {
          TaskName: {dataName: 'name' },
          TaskId: { dataName: 'id', isPrimaryKey: true }, // using primary key to indicate the hierarchy id optionally
      }
    }
});
var taskView = taskTable.addView('TaskView',[
{
    value: 'TaskName', outlineColumn: true // this option indicates the column showing as outline column
}
]);
</div>




2. 降级记录,将当前记录的 parentId 替换为其上面记录的 id,如果 withChildren 为 true,则当前记录的子级将降低:



<div>    /**
   * Demote the hierarchy data level of the specified row.
   * @param {number} row - The row index.
   * @param {boolean} withChildren - Optional, the children will be demoted with the record by default.
   * @returns {void}
   * @example
   * //This example demote the hierarchy data level by specified index.
   * tableSheet.demoteHierarchyLevel(8);
   */
   function demoteHierarchyLevel(row: number, withChildren?: boolean): void
</div>



3. 上移一条记录:
当列的 dataType 为 rowOrder 且列的 value 类型为 number 时,记录可以上下移动。
在层次数据中,向上移动只能在同一父级下的记录之间移动,
当父记录移动时,子记录将移动。

<div>    /**
   * Move the hierarchy data by the specified row up.
   * @param {number} row - The row index.
   * @returns {void}
   * @example
   * //This example move the hierarchy data by specified index up.
   * tableSheet.moveUp(8);
   */
   function moveUp(row: number): void</div>


4. 向下移动一个记录,它与向上移动相同:

    /**
   * Move the hierarchy data by the specified row down.
   * @param {number} row - The row index.
   * @returns {void}
   * @example
   * //This example move the hierarchy data by specified index down.
   * tableSheet.moveDown(8);
   */
   function moveDown(row: number): void



5. 添加记录:
默认情况下,它将在选择位置之前插入一条记录,并且插入的记录应该是选择记录的兄弟。



5.1 选中前添加记录:

<div>    /**
   * Add a new row data before the specified row.
   * @param {number} row - The row index.
   * @param {Object} rowData - The row data.
   * @returns {void}
   * @example
   * //This example adds a new row data before the specified row.
   * tableSheet.addHierarchyItemBefore(8, {id: 8, name: "grapecity"});
   */
   function addHierarchyItemBefore(row: number, rowData: any): void</div>

5.2 选中后添加记录:



<div>    /**
   * Add a new row data after the specified row.
   * @param {number} row - The row index.
   * @param {Object} rowData - The row data.
   * @returns {void}
   * @example
   * //This example adds a new row data after the specified row.
   * tableSheet.addHierarchyItemAfter(8, {id: 8, name: "grapecity"});
   */
   function addHierarchyItemAfter(row: number, rowData: any): void</div>

5.3 在选中的上面添加记录,添加的记录会替换选中记录的位置,选中的记录会是被添加记录的子:

<div>    /**
   * Add a new row data as the parent of the specified row.
   * @param {number} row - The row index.
   * @param {Object} rowData - The row data.
   * @returns {void}
   * @example
   * //This example adds a new row data as the parent of the specified row.
   * tableSheet.addHierarchyItemAbove(8, {id: 8, name: "grapecity"});
   */
   function addHierarchyItemAbove(row: number, rowData: any): void</div>

5.4 在选中的下方添加记录,添加的记录将是选中记录的最后一个子记录:

<div>    /**
   * Add a new row data as the child of the specified row.
   * @param {number} row - The row index.
   * @param {Object} rowData - The row data.
   * @returns {void}
   * @example
   * //This example adds a new row data as the child of the specified row.
   * tableSheet.addHierarchyItemBelow(8, {id: 8, name: "grapecity"});
   */
   function addHierarchyItemBelow(row: number, rowData: any): void</div>
6. 删除一条记录,它会删除子记录和它自己。
7. 展开所有级别:
单击列标题时将显示菜单项。

<div>    /**
   * Expand the all hierarchy levels.
   * @returns {void}
   * @example
   * //This example expand the all hierarchy levels.
   * tableSheet.expandAllHierarchyLevels();
   */
   function expandAllHierarchyLevels(): void
</div>



8. 折叠所有级别:

<div>    /**
   * Collapse the all hierarchy levels.
   * @returns {void}
   * @example
   * //This example collapse the all hierarchy levels.
   * tableSheet.collapseAllHierarchyLevels();
   */
   function collapseAllHierarchyLevels(): void</div>


9. 将记录扩展到指定级别:

单击列标题时会显示菜单,最多支持9级菜单项。

<div>    /**
   * Expand the hierarchy data by specified level.
   * @param {number} level - The level to expand.
   * @returns {void}
   * @example
   * //This example expand the hierarchy data by specified level.
   * tableSheet.expandHierarchyLevel(8);
   */
   function expandHierarchyLevel(level: number): void</div>


10. 切换菜单项的可见性:

提升、降级、上移/下移、前/后/上/下添加、展开/折叠级别的菜单项可以通过选项显示或隐藏:


<div>interface GC.Spread.Sheets.TableSheet.ITableSheetOptions {
// other properties...
menuItemVisibility?: {
      // the options below be on the row header
      promoteMenuItemVisible?: boolean;
      demoteMenuItemVisible?: boolean;
      // the options below be on the row header
      // and the menu items be enable for the dataType of the column be rowOrder
      moveUpMenuItemVisible?: boolean;
      moveDownMenuItemVisible?: boolean;
      addBeforeMenuItemVisible?: boolean;
      addAfterMenuItemVisible?: boolean;
      addAboveMenuItemVisible?: boolean;
      addBelowMenuItemVisible?: boolean;
      // the options below be on the column header
      expandAllLevelMenuItemVisible?: boolean;
      collapseAllLevelMenuItemVisible?: boolean;
      expandToLevelMenuItemVisible?: boolean;
    };
}

tableSheet.options.menuItemVisibility = {
      promoteMenuItemVisible: true,
      demoteMenuItemVisible: true,
      moveUpMenuItemVisible: true,
      moveDownMenuItemVisible: true,
      addBeforeMenuItemVisible: true,
      addAfterMenuItemVisible: true,
      addAboveMenuItemVisible: true,
      addBelowMenuItemVisible: true,
      expandAllLevelMenuItemVisible: true,
      collapseAllLevelMenuItemVisible: true,
      expandToLevelMenuItemVisible: true,
    }</div>

11. 对层次记录进行排序意味着按级别对记录的任何属性进行排序。

12. 过滤结果将显示父记录及其本身,如果记录有孩子,孩子也会显示。

13. 自定义轮廓列,带有outlineColumn选项的列将在表格中显示轮廓样式,并且只有一列是轮廓:

13.1 . 在架构中:



<div>var taskTable = dataManager.addTable("Tasks", {
    remote: { ... },
    schema: {
      hierarchy: {
          type: 'Parent',
          column: 'TaskParentId',
          outlineColumn: {
            value: 'TaskName', // specify the column name that will be outline column
            showCheckBox: true
            }
      },
      columns: {
          TaskName: {dataName: 'name' },
          TaskId: { dataName: 'id', isPrimaryKey: true }, // using primary key to indicate the hierarchy id
          TaskParentId: { dataName: 'parentId' },
          TaskRowOrder: { dataName: 'rowOrder', dataType: "rowOrder" }, // optional property for inserting and moving up/down
      }
    }
});</div>

13.2. 在视图列中,优先级更高:



<div>var taskTable = dataManager.addTable("Tasks", {
    remote: { ... },
    schema: {
      hierarchy: {
          type: 'Parent',
          column: 'TaskParentId',
          outlineColumn: 'TaskName'
      },
      columns: {
          TaskName: {dataName: 'name' },
          TaskId: { dataName: 'id', isPrimaryKey: true }, // using primary key to indicate the hierarchy id
          TaskParentId: { dataName: 'parentId' },
          TaskRowOrder: { dataName: 'rowOrder', dataType: "rowOrder" }, // optional property for inserting and moving up/down
      }
    }
});

var taskView = taskTable.addView('TaskView',[
{
    value: 'TaskName', outlineColumn: { showCheckBox: true } // this option indicates the column showing as outline column
}
]);</div>

14. 该功能可能与层次结构发生冲突
14.1 . groupBy 不能处理层次结构数据;
14.2. 固定行不能与层次结构数据一起使用;
14.3 . 对于仅影响当前行数据的特征,resetRow 不能很好地处理层次数据,但一些用于层次特征的属性不会受到影响。

层次结构远程接口
在父层级类型中,远程接口和之前一样,
但如果它是级别或子路径层次结构类型,每个远程接口都会将整个记录发送到远程而不被删除,
因为它不能识别插入记录的父记录。
页: [1]
查看完整版本: 【SpreadJS v16.0 新特性预览】支持表格分层数据及树形展示