Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(copy): 修复刷选复制行列头时, 数值单元格未格式化 & 存在省略号时未复制原始值 #2410

Merged
merged 1 commit into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 143 additions & 8 deletions packages/s2-core/__tests__/unit/utils/export/copy-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,80 @@ describe('Tree Table Core Data Process', () => {
总计 26193 23516 49709 12321 16838"
`);
});

it('should copy normal data with header for custom field name', () => {
s2.setOptions({
interaction: {
copyWithHeader: true,
},
});
s2.setDataCfg({
meta: [
{
field: 'number',
name: '数量',
},
],
});
s2.render();

setSelectedVisibleCell();

expect(getSelectedData(s2)).toMatchInlineSnapshot(`
" 家具 家具 家具 办公用品 办公用品
桌子 沙发 小计 笔 纸张
数量 数量 数量 数量
浙江省 18375 14043 32418 4826 5854
浙江省 7789 5343 13132 945 1343
浙江省 2367 632 2999 1304 1354
浙江省 3877 7234 11111 1145 1523
浙江省 4342 834 5176 1432 1634
四川省 7818 9473 17291 7495 10984
四川省 1723 2451 4174 2335 4004
四川省 1822 2244 4066 245 3077
四川省 1943 2333 4276 2457 3551
四川省 2330 2445 4775 2458 352
总计 26193 23516 49709 12321 16838"
`);
});

it('should copy normal data with header for custom field formatter if enable copyWithFormat', () => {
s2.setOptions({
interaction: {
copyWithHeader: true,
copyWithFormat: true,
},
});
s2.setDataCfg({
meta: [
{
field: 'number',
name: '数量',
formatter: (value) => `${value}-@`,
},
],
});
s2.render();

setSelectedVisibleCell();

expect(getSelectedData(s2)).toMatchInlineSnapshot(`
" 家具 家具 家具 办公用品 办公用品
桌子 沙发 小计 笔 纸张
数量 数量 数量 数量
浙江省 18375-@ 14043-@ 32418 4826-@ 5854-@
浙江省 7789-@ 5343-@ 13132 945-@ 1343-@
浙江省 2367-@ 632-@ 2999 1304-@ 1354-@
浙江省 3877-@ 7234-@ 11111 1145-@ 1523-@
浙江省 4342-@ 834-@ 5176 1432-@ 1634-@
四川省 7818-@ 9473-@ 17291 7495-@ 10984-@
四川省 1723-@ 2451-@ 4174 2335-@ 4004-@
四川省 1822-@ 2244-@ 4066 245-@ 3077-@
四川省 1943-@ 2333-@ 4276 2457-@ 3551-@
四川省 2330-@ 2445-@ 4775 2458-@ 352-@
总计 26193-@ 23516-@ 49709 12321-@ 16838-@"
`);
});
});

describe('List Table getCopyData', () => {
Expand Down Expand Up @@ -1114,6 +1188,7 @@ describe('Pivot Table getBrushHeaderCopyable', () => {
});

const s2 = new PivotSheet(getContainer(), dataCfg, options);

beforeEach(() => {
s2.render();
});
Expand Down Expand Up @@ -1141,6 +1216,37 @@ describe('Pivot Table getBrushHeaderCopyable', () => {
`);
});

test('should copy all original row data in grid mode if contains text ellipses', () => {
s2.setOptions({
style: {
rowCfg: {
// 展示省略号
width: 10,
},
},
});
const cells = s2.interaction.getAllRowHeaderCells();

s2.interaction.changeState({
cells: map(cells, getCellMeta),
stateName: InteractionStateName.SELECTED,
onUpdateCells: (root) => {
root.updateCells(root.getAllRowHeaderCells());
},
});

expect(getSelectedData(s2)).toMatchInlineSnapshot(`
"浙江省 杭州市
浙江省 绍兴市
浙江省 宁波市
浙江省 舟山市
四川省 成都市
四川省 绵阳市
四川省 南充市
四川省 乐山市"
`);
});

test('should copy all col data in grid mode', () => {
const cells = s2.interaction.getAllColHeaderCells();

Expand All @@ -1160,6 +1266,35 @@ describe('Pivot Table getBrushHeaderCopyable', () => {
`);
});

test('should copy all col data in grid mode for custom field meta', () => {
s2.setDataCfg({
meta: [
{
field: 'number',
name: '数量',
},
],
});

s2.render();

const cells = s2.interaction.getAllColHeaderCells();

s2.interaction.changeState({
cells: map(cells, getCellMeta),
stateName: InteractionStateName.SELECTED,
onUpdateCells: (root) => {
root.updateCells(root.getAllColHeaderCells());
},
});

expect(getSelectedData(s2)).toMatchInlineSnapshot(`
"家具 家具 办公用品 办公用品
桌子 沙发 笔 纸张
数量 数量 数量 数量"
`);
});

test('should copy selection row data in grid mode', () => {
const ss = new PivotSheet(
getContainer(),
Expand Down Expand Up @@ -1216,7 +1351,7 @@ describe('Pivot Table getBrushHeaderCopyable', () => {
});

test('should copy selection col data in grid mode', () => {
const ss = new PivotSheet(
const sheet = new PivotSheet(
getContainer(),
assembleDataCfg({
meta: [],
Expand All @@ -1228,37 +1363,37 @@ describe('Pivot Table getBrushHeaderCopyable', () => {
}),
options,
);
ss.render();
sheet.render();

const cells = ss.interaction.getAllColHeaderCells().filter((c) => {
const cells = sheet.interaction.getAllColHeaderCells().filter((c) => {
const meta = c.getMeta();
return (meta.level === 3 || meta.level === 4) && meta.x < 480;
});
ss.interaction.changeState({
sheet.interaction.changeState({
cells: map(cells, getCellMeta),
stateName: InteractionStateName.SELECTED,
onUpdateCells: (root) => {
root.updateCells(root.getAllColHeaderCells());
},
});

expect(getSelectedData(ss)).toMatchInlineSnapshot(`
expect(getSelectedData(sheet)).toMatchInlineSnapshot(`
"桌子 沙发 笔 纸张 桌子
number number number number number"
`);

const cells2 = ss.interaction.getAllColHeaderCells().filter((c) => {
const cells2 = sheet.interaction.getAllColHeaderCells().filter((c) => {
const meta = c.getMeta();
return (meta.level === 0 || meta.level === 1) && meta.x < 480;
});
ss.interaction.changeState({
sheet.interaction.changeState({
cells: map(cells2, getCellMeta),
stateName: InteractionStateName.SELECTED,
onUpdateCells: (root) => {
root.updateCells(root.getAllColHeaderCells());
},
});
expect(getSelectedData(ss)).toMatchInlineSnapshot(`
expect(getSelectedData(sheet)).toMatchInlineSnapshot(`
"浙江省 浙江省
杭州市 绍兴市"
`);
Expand Down
59 changes: 35 additions & 24 deletions packages/s2-core/src/utils/export/copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,33 @@ import {
filter,
forEach,
isEmpty,
isEqual,
isNil,
map,
max,
orderBy,
reduce,
zip,
} from 'lodash';
import type { ColCell, RowCell } from '../../cell';
import type { ColCell, HeaderCell, RowCell } from '../../cell';
import {
type CellMeta,
CellTypes,
CopyType,
EMPTY_PLACEHOLDER,
EXTRA_FIELD,
ID_SEPARATOR,
InteractionStateName,
type RowData,
SERIES_NUMBER_FIELD,
VALUE_FIELD,
type CellMeta,
type RowData,
} from '../../common';
import type { DataType } from '../../data-set/interface';
import type { Node } from '../../facet/layout/node';
import type { SpreadSheet } from '../../sheet-type';
import { copyToClipboard } from '../../utils/export';
import { flattenDeep } from '../data-set-operate';
import { getEmptyPlaceholder } from '../text';
import { getHeaderTotalStatus } from '../dataset/pivot-data-set';
import { getEmptyPlaceholder } from '../text';

export function keyEqualTo(key: string, compareKey: string) {
if (!key || !compareKey) {
Expand Down Expand Up @@ -148,7 +147,7 @@ export const convertString = (v: string) => {
* @param headerId
* @param startLevel 层级
*/
const getHeaderList = (headerId: string, startLevel?: number) => {
const getHeaderMeasureFields = (headerId: string, startLevel?: number) => {
const headerList = headerId.split(ID_SEPARATOR);
if (startLevel) {
return headerList.slice(headerList.length - startLevel);
Expand All @@ -157,6 +156,15 @@ const getHeaderList = (headerId: string, startLevel?: number) => {
return headerList;
};

const getHeaderMeasureFieldNames = (
fields: string[],
spreadsheet: SpreadSheet,
): string[] => {
return map(fields, (field) => {
return spreadsheet.dataSet.getFieldName(field);
});
};

type MatrixTransformer = (data: string[][]) => CopyableItem;

export enum CopyMIMEType {
Expand Down Expand Up @@ -423,8 +431,12 @@ const getPivotWithHeaderCopyData = (
leafRowNodes: Node[],
leafColNodes: Node[],
): Copyable => {
const rowMatrix = map(leafRowNodes, (n) => getHeaderList(n.id));
const colMatrix = zip(...map(leafColNodes, (n) => getHeaderList(n.id)));
const rowMatrix = map(leafRowNodes, (node) =>
getHeaderMeasureFields(node.id),
);
const colMatrix = zip(
...map(leafColNodes, (node) => getHeaderMeasureFields(node.id)),
);
const dataMatrix = getDataMatrix(leafRowNodes, leafColNodes, spreadsheet);
return assembleMatrix(rowMatrix, colMatrix, dataMatrix);
};
Expand Down Expand Up @@ -620,17 +632,23 @@ const getDataWithHeaderMatrix = (
const colMatrix = zip(
...map(cellMetaMatrix[0], (cellMeta) => {
const colId = cellMeta.id.split(EMPTY_PLACEHOLDER)?.[1] ?? '';
return getHeaderList(colId);
return getHeaderMeasureFieldNames(
getHeaderMeasureFields(colId),
spreadsheet,
);
}),
);

const rowMatrix = map(cellMetaMatrix, (cellsMeta) => {
const rowId = cellsMeta[0].id.split(EMPTY_PLACEHOLDER)?.[0] ?? '';
return getHeaderList(rowId);
return getHeaderMeasureFieldNames(
getHeaderMeasureFields(rowId),
spreadsheet,
);
});

const dataMatrix = map(cellMetaMatrix, (cellsMeta) => {
return map(cellsMeta, (it) => format(it, displayData, spreadsheet));
return map(cellsMeta, (meta) => format(meta, displayData, spreadsheet));
});

return assembleMatrix(rowMatrix, colMatrix, dataMatrix);
Expand Down Expand Up @@ -682,25 +700,18 @@ function getTotalCellMatrixId(meta: Node, maxLevel: number) {
}

function getCellMatrix(
lastLevelCells: Array<RowCell | ColCell>,
lastLevelCells: Array<HeaderCell>,
maxLevel: number,
allLevel: Set<number>,
) {
return map(lastLevelCells, (cell: RowCell | ColCell) => {
return map(lastLevelCells, (cell) => {
const meta = cell.getMeta();
const { id, label, isTotals } = meta;
let cellId = id;

if (isTotals) {
cellId = getTotalCellMatrixId(meta, maxLevel);
}
const { id, isTotals, spreadsheet } = meta;
const cellId = isTotals ? getTotalCellMatrixId(meta, maxLevel) : id;

// 将指标维度单元格的标签替换为实际文本
const actualText = cell.getActualText();
const headerList = getHeaderList(cellId, allLevel.size);
return map(headerList, (header) =>
isEqual(header, label) ? actualText : header,
);
const headerFields = getHeaderMeasureFields(cellId, allLevel.size);
return getHeaderMeasureFieldNames(headerFields, spreadsheet);
});
}

Expand Down
2 changes: 2 additions & 0 deletions packages/s2-react/playground/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ export const s2Options: SheetComponentOptions = {
showSeriesNumber: false,
interaction: {
enableCopy: true,
copyWithHeader: true,
copyWithFormat: true,
// 防止 mac 触摸板横向滚动触发浏览器返回, 和移动端下拉刷新
overscrollBehavior: 'none',
brushSelection: {
Expand Down
Loading
Loading