Add KOC resource filters and export
This commit is contained in:
@@ -14,6 +14,10 @@ export type RecoveryWorkbookRow = {
|
||||
column: number;
|
||||
image: RecoveryWorkbookImage;
|
||||
}>;
|
||||
hyperlinks?: Array<{
|
||||
column: number;
|
||||
url: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
type WorkbookOptions = {
|
||||
@@ -53,6 +57,15 @@ function safeSheetName(value: string) {
|
||||
return (cleaned || "数据回收").slice(0, 31);
|
||||
}
|
||||
|
||||
function safeHyperlink(value: string) {
|
||||
try {
|
||||
const url = new URL(value);
|
||||
return ["http:", "https:"].includes(url.protocol) ? url.toString() : "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function imageFormat(contentType: string, bytes: Uint8Array) {
|
||||
const normalized = contentType.toLowerCase();
|
||||
if (normalized.includes("png") || (bytes[0] === 0x89 && bytes[1] === 0x50)) {
|
||||
@@ -139,6 +152,15 @@ export function buildRecoveryWorkbook(options: WorkbookOptions) {
|
||||
const imageEntries = options.rows.flatMap((row, rowIndex) =>
|
||||
row.images.map((item) => ({ ...item, row: rowIndex + 1 })),
|
||||
);
|
||||
const hyperlinkEntries = options.rows.flatMap((row, rowIndex) =>
|
||||
(row.hyperlinks ?? [])
|
||||
.map((item) => ({
|
||||
...item,
|
||||
row: rowIndex + 2,
|
||||
url: safeHyperlink(item.url),
|
||||
}))
|
||||
.filter((item) => item.url),
|
||||
);
|
||||
const lastColumn = columnName(Math.max(0, options.headers.length - 1));
|
||||
const lastRow = Math.max(1, options.rows.length + 1);
|
||||
const headerCells = options.headers
|
||||
@@ -148,6 +170,9 @@ export function buildRecoveryWorkbook(options: WorkbookOptions) {
|
||||
.map((row, rowIndex) => {
|
||||
const number = rowIndex + 2;
|
||||
const imageColumns = new Set(row.images.map((item) => item.column));
|
||||
const hyperlinkColumns = new Set(
|
||||
(row.hyperlinks ?? []).map((item) => item.column),
|
||||
);
|
||||
const cells = options.headers
|
||||
.map((_, columnIndex) => {
|
||||
const reference = `${columnName(columnIndex)}${number}`;
|
||||
@@ -157,7 +182,11 @@ export function buildRecoveryWorkbook(options: WorkbookOptions) {
|
||||
}
|
||||
return typeof value === "number"
|
||||
? numberCell(reference, value, 3)
|
||||
: inlineCell(reference, value, 2);
|
||||
: inlineCell(
|
||||
reference,
|
||||
value,
|
||||
hyperlinkColumns.has(columnIndex) ? 5 : 2,
|
||||
);
|
||||
})
|
||||
.join("");
|
||||
const rowHeight = row.images.length > 0 ? IMAGE_ROW_HEIGHT : 42;
|
||||
@@ -199,7 +228,28 @@ export function buildRecoveryWorkbook(options: WorkbookOptions) {
|
||||
.map(([extension, contentType]) => `<Default Extension="${extension}" ContentType="${contentType}"/>`)
|
||||
.join("");
|
||||
const contentTypes = `${XML_HEADER}<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/>${imageContentTypes}<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>${imageEntries.length ? '<Override PartName="/xl/drawings/drawing1.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/>' : ""}<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>`;
|
||||
const worksheet = `${XML_HEADER}<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><dimension ref="A1:${lastColumn}${lastRow}"/><sheetViews><sheetView workbookViewId="0"><pane xSplit="3" ySplit="1" topLeftCell="D2" activePane="bottomRight" state="frozen"/></sheetView></sheetViews><sheetFormatPr defaultRowHeight="18"/><cols>${columns}</cols><sheetData><row r="1" ht="30" customHeight="1">${headerCells}</row>${dataRows}</sheetData><autoFilter ref="A1:${lastColumn}${lastRow}"/>${imageEntries.length ? '<drawing r:id="rId1"/>' : ""}</worksheet>`;
|
||||
const hyperlinkRelationshipOffset = imageEntries.length ? 2 : 1;
|
||||
const hyperlinksXml = hyperlinkEntries.length
|
||||
? `<hyperlinks>${hyperlinkEntries
|
||||
.map(
|
||||
(entry, index) =>
|
||||
`<hyperlink ref="${columnName(entry.column)}${entry.row}" r:id="rId${hyperlinkRelationshipOffset + index}"/>`,
|
||||
)
|
||||
.join("")}</hyperlinks>`
|
||||
: "";
|
||||
const worksheet = `${XML_HEADER}<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><dimension ref="A1:${lastColumn}${lastRow}"/><sheetViews><sheetView workbookViewId="0"><pane xSplit="3" ySplit="1" topLeftCell="D2" activePane="bottomRight" state="frozen"/></sheetView></sheetViews><sheetFormatPr defaultRowHeight="18"/><cols>${columns}</cols><sheetData><row r="1" ht="30" customHeight="1">${headerCells}</row>${dataRows}</sheetData><autoFilter ref="A1:${lastColumn}${lastRow}"/>${hyperlinksXml}${imageEntries.length ? '<drawing r:id="rId1"/>' : ""}</worksheet>`;
|
||||
|
||||
const sheetRelationships = [
|
||||
...(imageEntries.length
|
||||
? [
|
||||
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" Target="../drawings/drawing1.xml"/>',
|
||||
]
|
||||
: []),
|
||||
...hyperlinkEntries.map(
|
||||
(entry, index) =>
|
||||
`<Relationship Id="rId${hyperlinkRelationshipOffset + index}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="${cleanXmlText(entry.url)}" TargetMode="External"/>`,
|
||||
),
|
||||
];
|
||||
|
||||
const files: Record<string, Uint8Array> = {
|
||||
"[Content_Types].xml": strToU8(contentTypes),
|
||||
@@ -208,11 +258,13 @@ export function buildRecoveryWorkbook(options: WorkbookOptions) {
|
||||
"docProps/core.xml": strToU8(`${XML_HEADER}<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:creator>KOC LOOP</dc:creator><cp:lastModifiedBy>KOC LOOP</cp:lastModifiedBy><dcterms:created xsi:type="dcterms:W3CDTF">${new Date().toISOString()}</dcterms:created></cp:coreProperties>`),
|
||||
"xl/workbook.xml": strToU8(`${XML_HEADER}<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets><sheet name="${cleanXmlText(sheetName)}" sheetId="1" r:id="rId1"/></sheets></workbook>`),
|
||||
"xl/_rels/workbook.xml.rels": strToU8(`${XML_HEADER}<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/></Relationships>`),
|
||||
"xl/styles.xml": strToU8(`${XML_HEADER}<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><fonts count="3"><font><sz val="10"/><name val="Arial"/></font><font><b/><color rgb="FFFFFFFF"/><sz val="10"/><name val="Arial"/></font><font><color rgb="FF153B31"/><sz val="10"/><name val="Arial"/></font></fonts><fills count="3"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill><fill><patternFill patternType="solid"><fgColor rgb="FF1F8F6B"/><bgColor indexed="64"/></patternFill></fill></fills><borders count="2"><border><left/><right/><top/><bottom/><diagonal/></border><border><left style="thin"><color rgb="FFDDE5E1"/></left><right style="thin"><color rgb="FFDDE5E1"/></right><top style="thin"><color rgb="FFDDE5E1"/></top><bottom style="thin"><color rgb="FFDDE5E1"/></bottom><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="5"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/><xf numFmtId="0" fontId="1" fillId="2" borderId="1" xfId="0" applyFont="1" applyFill="1" applyBorder="1" applyAlignment="1"><alignment horizontal="center" vertical="center" wrapText="1"/></xf><xf numFmtId="0" fontId="2" fillId="0" borderId="1" xfId="0" applyFont="1" applyBorder="1" applyAlignment="1"><alignment vertical="top" wrapText="1"/></xf><xf numFmtId="0" fontId="2" fillId="0" borderId="1" xfId="0" applyFont="1" applyBorder="1" applyAlignment="1"><alignment horizontal="center" vertical="center"/></xf><xf numFmtId="0" fontId="2" fillId="0" borderId="1" xfId="0" applyFont="1" applyBorder="1" applyAlignment="1"><alignment horizontal="center" vertical="center" wrapText="1"/></xf></cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`),
|
||||
"xl/styles.xml": strToU8(`${XML_HEADER}<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><fonts count="4"><font><sz val="10"/><name val="Arial"/></font><font><b/><color rgb="FFFFFFFF"/><sz val="10"/><name val="Arial"/></font><font><color rgb="FF153B31"/><sz val="10"/><name val="Arial"/></font><font><u/><color rgb="FF1F8F6B"/><sz val="10"/><name val="Arial"/></font></fonts><fills count="3"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill><fill><patternFill patternType="solid"><fgColor rgb="FF1F8F6B"/><bgColor indexed="64"/></patternFill></fill></fills><borders count="2"><border><left/><right/><top/><bottom/><diagonal/></border><border><left style="thin"><color rgb="FFDDE5E1"/></left><right style="thin"><color rgb="FFDDE5E1"/></right><top style="thin"><color rgb="FFDDE5E1"/></top><bottom style="thin"><color rgb="FFDDE5E1"/></bottom><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="6"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/><xf numFmtId="0" fontId="1" fillId="2" borderId="1" xfId="0" applyFont="1" applyFill="1" applyBorder="1" applyAlignment="1"><alignment horizontal="center" vertical="center" wrapText="1"/></xf><xf numFmtId="0" fontId="2" fillId="0" borderId="1" xfId="0" applyFont="1" applyBorder="1" applyAlignment="1"><alignment vertical="top" wrapText="1"/></xf><xf numFmtId="0" fontId="2" fillId="0" borderId="1" xfId="0" applyFont="1" applyBorder="1" applyAlignment="1"><alignment horizontal="center" vertical="center"/></xf><xf numFmtId="0" fontId="2" fillId="0" borderId="1" xfId="0" applyFont="1" applyBorder="1" applyAlignment="1"><alignment horizontal="center" vertical="center" wrapText="1"/></xf><xf numFmtId="0" fontId="3" fillId="0" borderId="1" xfId="0" applyFont="1" applyBorder="1" applyAlignment="1"><alignment vertical="top" wrapText="1"/></xf></cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`),
|
||||
"xl/worksheets/sheet1.xml": strToU8(worksheet),
|
||||
};
|
||||
if (sheetRelationships.length) {
|
||||
files["xl/worksheets/_rels/sheet1.xml.rels"] = strToU8(`${XML_HEADER}<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${sheetRelationships.join("")}</Relationships>`);
|
||||
}
|
||||
if (imageEntries.length) {
|
||||
files["xl/worksheets/_rels/sheet1.xml.rels"] = strToU8(`${XML_HEADER}<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" Target="../drawings/drawing1.xml"/></Relationships>`);
|
||||
files["xl/drawings/drawing1.xml"] = strToU8(drawingXml);
|
||||
files["xl/drawings/_rels/drawing1.xml.rels"] = strToU8(drawingRelationships);
|
||||
imageEntries.forEach((entry, index) => {
|
||||
|
||||
Reference in New Issue
Block a user