Skip to content

Commit

Permalink
支持多维表
Browse files Browse the repository at this point in the history
  • Loading branch information
sumneko committed Jul 23, 2024
1 parent 9dc2a4a commit 6297973
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 7 deletions.
69 changes: 66 additions & 3 deletions src/editorTable/excel/excel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import * as vscode from 'vscode';
import * as y3 from 'y3-helper';

type Cells = Record<string, string>;

export type Table = Record<string | number, Record<string, string>>;
type TableKey = string | number;
export type Table = Record<TableKey, Record<string, string>>;
export type MultiTable = Record<TableKey, Record<string, string[]>>;

export class Sheet {
constructor(private sheet: exceljs.Worksheet) {
Expand Down Expand Up @@ -46,7 +47,7 @@ export class Sheet {
count++;
}
}
if (count * 2 > this.sheet.rowCount) {
if (count * 4 > this.sheet.rowCount) {
colPart = col.letter;
colIndex = i;
break;
Expand Down Expand Up @@ -124,6 +125,68 @@ export class Sheet {
},
});
}


/**
* 已某个单元格为锚点,创建一个key-value[]的多维表格。
* 与 `makeTable` 不同,可以一个对象可以保存多行的数据。
* 如果不提供参数,会自动猜测一个合适的位置。
* @param offset 锚点位置,如 `"B2"`
*/
public makeMultiTable(offset?: string): MultiTable {
if (!offset) {
offset = this.guessTableOffset();
if (!offset) {
throw new Error('无法猜测出锚点位置,请手动指定锚点');
}
}
const cell = this.sheet.getCell(offset);
const row = cell.row as any as number;
const col = cell.col as any as number;
const titleRow = this.sheet.getRow(row);
const titles: string[] = [];
for (let c = col; c <= this.sheet.columnCount; c++) {
const cell = titleRow.getCell(c);
const title = cell.toString();
titles[c] = title ? title : (cell.address.match(/[A-Z]+/)?.[0] ?? c.toString());
}

let table: MultiTable = {};
let current: Record<string, string[]> | undefined;

const mergeIntoCurrent = (row: exceljs.Row) => {
if (!current) {
return;
}
for (let c = col; c <= this.sheet.columnCount; c++) {
const title = titles[c];
current[title] ??= [];
current[title].push(row.getCell(c).toString());
}
};

for (let r = row + 1; r <= this.sheet.rowCount; r++) {
const row = this.sheet.getRow(r);
const key = row.getCell(col).toString();
if (key) {
current = {};
table[key] = current;
}
mergeIntoCurrent(row);
}

return new Proxy(table, {
set: () => {
throw new Error('这是只读表!');
},
get: (target, key) => {
if (typeof key === 'symbol') {
return {};
}
return target[key] ?? {};
},
});
}
}

export class Excel {
Expand Down
4 changes: 1 addition & 3 deletions src/editorTable/excel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ let baseDir: vscode.Uri;
* @returns
*/
export async function loadFile(path: vscode.Uri | string, sheetName?: number | string) {
if (typeof path === 'string') {
path = vscode.Uri.parse(path);
}
path = getUri(path);
const exc = new excel.Excel();
const suc = await exc.loadFile(path);
if (!suc) {
Expand Down
44 changes: 43 additions & 1 deletion template/plugin/y3-helper.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,9 @@ declare module 'y3-helper/editorTable/excel/excel' {
import * as exceljs from 'exceljs';
import * as vscode from 'vscode';
type Cells = Record<string, string>;
export type Table = Record<string | number, Record<string, string>>;
type TableKey = string | number;
export type Table = Record<TableKey, Record<string, string>>;
export type MultiTable = Record<TableKey, Record<string, string[]>>;
export class Sheet {
constructor(sheet: exceljs.Worksheet);
/**
Expand All @@ -459,6 +461,13 @@ declare module 'y3-helper/editorTable/excel/excel' {
* @param offset 锚点位置,如 `"B2"`
*/
makeTable(offset?: string): Table;
/**
* 已某个单元格为锚点,创建一个key-value[]的多维表格。
* 与 `makeTable` 不同,可以一个对象可以保存多行的数据。
* 如果不提供参数,会自动猜测一个合适的位置。
* @param offset 锚点位置,如 `"B2"`
*/
makeMultiTable(offset?: string): MultiTable;
}
export class Excel {
/**
Expand Down Expand Up @@ -544,6 +553,21 @@ declare module 'y3-helper/editorTable/excel/rule' {
* @returns
*/
readonly number: (title: string, defaultValue?: number | undefined) => ReaderRule<number>;
/**
* 将值视为布尔值。
* @param title 列标题
* @param defaultValue 默认值,如果不传表示不做修改(使用物编里原来的值)。
* @returns
*/
readonly boolean: (title: string, defaultValue?: boolean | undefined) => ReaderRule<boolean>;
/**
* 将值视为数组。如果设置了 `default`,则会用默认值填充数组。
* @param title 列标题
* @param separator 分割符
* @param converter 数组中的每一项还会调用此函数再转换一次
* @returns
*/
readonly string: (title: string, defaultValue?: string | undefined) => ReaderRule<string>;
/**
* 将值视为数组。如果设置了 `default`,则会用默认值填充数组。
* @param title 列标题
Expand All @@ -564,6 +588,20 @@ declare module 'y3-helper/editorTable/excel/rule' {
* @returns
*/
readonly number: (defaultValue?: number | undefined) => AsRule<number>;
/**
* 将值视为字符串。
* @param value 值
* @param defaultValue 默认值,如果不传表示不做修改(使用物编里原来的值)。
* @returns
*/
readonly string: (defaultValue?: string | undefined) => AsRule<string>;
/**
* 将值视为布尔值。
* @param value 值
* @param defaultValue 默认值,如果不传表示不做修改(使用物编里原来的值)。
* @returns
*/
readonly boolean: (defaultValue?: boolean | undefined) => AsRule<boolean>;
/**
* 将值视为数组。如果设置了 `default`,则会用默认值填充数组。
* @param title 列标题
Expand Down Expand Up @@ -592,6 +630,10 @@ declare module 'y3-helper/editorTable/excel/rule' {
* 对象从哪个模板上继承。如果不提供,或是与`key`相同则使用默认模板。
*/
template?: string;
/**
* 是否强制创建对象。默认情况下会优先使用已有对象,保留对象已有的数据。
*/
overwrite?: boolean;
/**
* 定义一个根据excel字段的生成规则
* @param title excel中的列标题
Expand Down

0 comments on commit 6297973

Please sign in to comment.