adtec-core-package 3.1.8 → 3.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adtec-core-package",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.9",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -82,6 +82,7 @@
|
|
|
82
82
|
"es-drager": "1.2.11",
|
|
83
83
|
"exceljs": "4.4.0",
|
|
84
84
|
"fast-glob": "3.3.3",
|
|
85
|
+
"fflate": "^0.3.8",
|
|
85
86
|
"file-saver": "2.0.5",
|
|
86
87
|
"hotkeys-js": "4.0.2",
|
|
87
88
|
"jsbarcode": "3.12.3",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<template>
|
|
6
6
|
<Teleport to="body" v-if="model">
|
|
7
7
|
<div
|
|
8
|
-
v-loading="
|
|
8
|
+
v-loading="showOverlayLoading"
|
|
9
9
|
element-loading-text="加载中,请稍后。。。"
|
|
10
10
|
class="file-view-overlay"
|
|
11
11
|
>
|
|
@@ -86,11 +86,16 @@ const isHeaderPreview = computed(() =>
|
|
|
86
86
|
isHeaderPreviewFile(undefined, title.value, url.value),
|
|
87
87
|
)
|
|
88
88
|
|
|
89
|
+
/** 富文本预览由 OfficePreview 自带 loading,避免与 v-loading 双层转圈 */
|
|
90
|
+
const showOverlayLoading = computed(() => loading.value && !isHeaderPreview.value)
|
|
91
|
+
|
|
89
92
|
watch(
|
|
90
93
|
[model, url],
|
|
91
94
|
([visible, fileUrl]) => {
|
|
92
95
|
if (visible && fileUrl) {
|
|
93
|
-
|
|
96
|
+
if (!isHeaderPreview.value) {
|
|
97
|
+
loading.value = true
|
|
98
|
+
}
|
|
94
99
|
previewScale.value = 1
|
|
95
100
|
} else if (!visible) {
|
|
96
101
|
loading.value = false
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
@error="handleError"
|
|
72
72
|
@page-change="previewCurrentPage = $event"
|
|
73
73
|
/>
|
|
74
|
-
<div v-if="isPreviewLoading" class="office-rich-loading">
|
|
74
|
+
<div v-if="isPreviewLoading && !fileSrc" class="office-rich-loading">
|
|
75
75
|
<div class="loading-card">
|
|
76
76
|
<span class="loading-spinner" />
|
|
77
77
|
<p class="loading-title">{{ loadingMessage }}</p>
|
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs'
|
|
44
44
|
import pdfWorker from 'pdfjs-dist/legacy/build/pdf.worker.mjs?url'
|
|
45
45
|
import { searchPdfDocument, type PdfSearchMatch } from '../../utils/pdfSearchUtil'
|
|
46
|
-
import { computePdfDefaultFitScale } from '../../utils/officePreviewUtil.ts'
|
|
46
|
+
import { computePdfDefaultFitScale, buildPdfJsLoadOptions } from '../../utils/officePreviewUtil.ts'
|
|
47
47
|
|
|
48
48
|
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker
|
|
49
49
|
|
|
@@ -667,7 +667,7 @@ const loadPdf = async (src: Blob | ArrayBuffer) => {
|
|
|
667
667
|
const data = await toArrayBuffer(src)
|
|
668
668
|
if (token !== loadToken) return
|
|
669
669
|
|
|
670
|
-
const loadingTask = pdfjsLib.getDocument(
|
|
670
|
+
const loadingTask = pdfjsLib.getDocument(buildPdfJsLoadOptions(data))
|
|
671
671
|
activeTask = loadingTask
|
|
672
672
|
const doc = await loadingTask.promise
|
|
673
673
|
if (token !== loadToken) return
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as XLSX from 'xlsx-js-style'
|
|
2
|
+
import { unzipSync } from 'fflate'
|
|
2
3
|
|
|
3
4
|
export interface ExcelPreviewCellStyle {
|
|
4
5
|
backgroundColor?: string
|
|
@@ -43,7 +44,14 @@ export interface ExcelSearchMatch {
|
|
|
43
44
|
|
|
44
45
|
type ColorStyle = { rgb?: string; theme?: number; tint?: number; indexed?: number }
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
type WorkbookStyles = {
|
|
48
|
+
Fonts?: Array<Record<string, unknown>>
|
|
49
|
+
Fills?: Array<Record<string, unknown>>
|
|
50
|
+
Borders?: Array<Record<string, unknown>>
|
|
51
|
+
CellXf?: Array<Record<string, unknown>>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Excel 默认主题色(Office 2013+,含 accent / hyperlink) */
|
|
47
55
|
const EXCEL_THEME_COLORS: Record<number, string> = {
|
|
48
56
|
0: '#FFFFFF',
|
|
49
57
|
1: '#000000',
|
|
@@ -55,6 +63,68 @@ const EXCEL_THEME_COLORS: Record<number, string> = {
|
|
|
55
63
|
7: '#FFC000',
|
|
56
64
|
8: '#5B9BD5',
|
|
57
65
|
9: '#70AD47',
|
|
66
|
+
10: '#0563C1',
|
|
67
|
+
11: '#954F72',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Excel 标准 indexed 色板(常用前 16 色) */
|
|
71
|
+
const INDEXED_COLORS: Record<number, string> = {
|
|
72
|
+
0: '#000000',
|
|
73
|
+
1: '#FFFFFF',
|
|
74
|
+
2: '#FF0000',
|
|
75
|
+
3: '#00FF00',
|
|
76
|
+
4: '#0000FF',
|
|
77
|
+
5: '#FFFF00',
|
|
78
|
+
6: '#FF00FF',
|
|
79
|
+
7: '#00FFFF',
|
|
80
|
+
8: '#000000',
|
|
81
|
+
9: '#FFFFFF',
|
|
82
|
+
10: '#FF0000',
|
|
83
|
+
11: '#00FF00',
|
|
84
|
+
12: '#0000FF',
|
|
85
|
+
13: '#FFFF00',
|
|
86
|
+
14: '#FF00FF',
|
|
87
|
+
15: '#00FFFF',
|
|
88
|
+
16: '#800000',
|
|
89
|
+
17: '#008000',
|
|
90
|
+
18: '#000080',
|
|
91
|
+
19: '#808000',
|
|
92
|
+
20: '#800080',
|
|
93
|
+
21: '#008080',
|
|
94
|
+
22: '#C0C0C0',
|
|
95
|
+
23: '#808080',
|
|
96
|
+
24: '#9999FF',
|
|
97
|
+
25: '#993366',
|
|
98
|
+
26: '#FFFFCC',
|
|
99
|
+
27: '#CCFFFF',
|
|
100
|
+
28: '#660066',
|
|
101
|
+
29: '#FF8080',
|
|
102
|
+
30: '#0066CC',
|
|
103
|
+
31: '#CCCCFF',
|
|
104
|
+
40: '#00CCFF',
|
|
105
|
+
41: '#CCFFFF',
|
|
106
|
+
42: '#CCFFCC',
|
|
107
|
+
43: '#FFFF99',
|
|
108
|
+
44: '#99CCFF',
|
|
109
|
+
45: '#FF99CC',
|
|
110
|
+
46: '#CC99FF',
|
|
111
|
+
47: '#FFCC99',
|
|
112
|
+
48: '#3366FF',
|
|
113
|
+
49: '#33CCCC',
|
|
114
|
+
50: '#99CC00',
|
|
115
|
+
51: '#FFCC00',
|
|
116
|
+
52: '#FF9900',
|
|
117
|
+
53: '#FF6600',
|
|
118
|
+
54: '#666699',
|
|
119
|
+
55: '#969696',
|
|
120
|
+
56: '#003366',
|
|
121
|
+
57: '#339966',
|
|
122
|
+
58: '#003300',
|
|
123
|
+
59: '#333300',
|
|
124
|
+
60: '#993300',
|
|
125
|
+
61: '#993366',
|
|
126
|
+
62: '#333399',
|
|
127
|
+
63: '#333333',
|
|
58
128
|
}
|
|
59
129
|
|
|
60
130
|
const BORDER_WIDTH: Record<string, string> = {
|
|
@@ -69,6 +139,16 @@ const BORDER_WIDTH: Record<string, string> = {
|
|
|
69
139
|
|
|
70
140
|
const DEFAULT_COL_WIDTH = 72
|
|
71
141
|
|
|
142
|
+
const isOleXls = (buffer: ArrayBuffer) => {
|
|
143
|
+
const sig = new Uint8Array(buffer, 0, 4)
|
|
144
|
+
return sig[0] === 0xd0 && sig[1] === 0xcf && sig[2] === 0x11 && sig[3] === 0xe0
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const isZipXlsx = (buffer: ArrayBuffer) => {
|
|
148
|
+
const sig = new Uint8Array(buffer, 0, 2)
|
|
149
|
+
return sig[0] === 0x50 && sig[1] === 0x4b
|
|
150
|
+
}
|
|
151
|
+
|
|
72
152
|
const hexToRgb = (hex: string) => {
|
|
73
153
|
const normalized = hex.replace('#', '')
|
|
74
154
|
const value =
|
|
@@ -106,8 +186,9 @@ const resolveColor = (color?: ColorStyle): string | undefined => {
|
|
|
106
186
|
if (raw.length === 6) return `#${raw}`
|
|
107
187
|
return undefined
|
|
108
188
|
}
|
|
189
|
+
if (color.indexed != null) return INDEXED_COLORS[color.indexed]
|
|
109
190
|
if (color.theme != null) {
|
|
110
|
-
const base = EXCEL_THEME_COLORS[color.theme] ?? '#
|
|
191
|
+
const base = EXCEL_THEME_COLORS[color.theme] ?? '#000000'
|
|
111
192
|
return color.tint ? applyTint(base, color.tint) : base
|
|
112
193
|
}
|
|
113
194
|
return undefined
|
|
@@ -116,63 +197,64 @@ const resolveColor = (color?: ColorStyle): string | undefined => {
|
|
|
116
197
|
const resolveBorderSide = (side?: { style?: string; color?: ColorStyle }) => {
|
|
117
198
|
if (!side?.style || side.style === 'none') return undefined
|
|
118
199
|
const width = BORDER_WIDTH[side.style] ?? '1px'
|
|
119
|
-
const color = resolveColor(side.color) ?? '#
|
|
200
|
+
const color = resolveColor(side.color) ?? '#000000'
|
|
120
201
|
const lineStyle = side.style === 'dashed' ? 'dashed' : side.style === 'dotted' ? 'dotted' : 'solid'
|
|
121
202
|
return `${width} ${lineStyle} ${color}`
|
|
122
203
|
}
|
|
123
204
|
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
205
|
+
const toNumber = (value: unknown, fallback = 0) => {
|
|
206
|
+
const num = Number(value)
|
|
207
|
+
return Number.isFinite(num) ? num : fallback
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const isTruthy = (value: unknown) => value === true || value === 1 || value === '1'
|
|
211
|
+
|
|
212
|
+
const styleFromParts = (parts: {
|
|
213
|
+
font?: Record<string, unknown>
|
|
214
|
+
fill?: Record<string, unknown>
|
|
215
|
+
border?: Record<string, unknown>
|
|
216
|
+
alignment?: Record<string, unknown>
|
|
217
|
+
}): ExcelPreviewCellStyle | undefined => {
|
|
128
218
|
const css: ExcelPreviewCellStyle = {}
|
|
129
219
|
|
|
130
|
-
const fill =
|
|
220
|
+
const fill = parts.fill
|
|
131
221
|
if (fill && fill.patternType !== 'none') {
|
|
132
|
-
const
|
|
133
|
-
|
|
222
|
+
const fg = fill.fgColor as ColorStyle | undefined
|
|
223
|
+
const bg = fill.bgColor as ColorStyle | undefined
|
|
224
|
+
const background = resolveColor(fg) || resolveColor(bg)
|
|
225
|
+
if (background) css.backgroundColor = background
|
|
134
226
|
}
|
|
135
227
|
|
|
136
|
-
const font =
|
|
137
|
-
bold?: boolean
|
|
138
|
-
italic?: boolean
|
|
139
|
-
underline?: boolean | string
|
|
140
|
-
sz?: number | string
|
|
141
|
-
color?: ColorStyle
|
|
142
|
-
} | undefined
|
|
228
|
+
const font = parts.font
|
|
143
229
|
if (font) {
|
|
144
|
-
if (font.bold) css.fontWeight = 'bold'
|
|
145
|
-
if (font.italic) css.fontStyle = 'italic'
|
|
230
|
+
if (isTruthy(font.bold)) css.fontWeight = 'bold'
|
|
231
|
+
if (isTruthy(font.italic)) css.fontStyle = 'italic'
|
|
146
232
|
if (font.underline) css.textDecoration = 'underline'
|
|
147
233
|
if (font.sz) css.fontSize = `${font.sz}pt`
|
|
148
|
-
const color = resolveColor(font.color)
|
|
234
|
+
const color = resolveColor(font.color as ColorStyle | undefined)
|
|
149
235
|
if (color) css.color = color
|
|
150
236
|
}
|
|
151
237
|
|
|
152
|
-
const alignment =
|
|
153
|
-
horizontal?: string
|
|
154
|
-
vertical?: string
|
|
155
|
-
wrapText?: boolean
|
|
156
|
-
} | undefined
|
|
238
|
+
const alignment = parts.alignment
|
|
157
239
|
if (alignment) {
|
|
158
|
-
|
|
159
|
-
|
|
240
|
+
const horizontal = alignment.horizontal as string | undefined
|
|
241
|
+
if (horizontal && horizontal !== 'general') {
|
|
242
|
+
css.textAlign = horizontal as ExcelPreviewCellStyle['textAlign']
|
|
160
243
|
}
|
|
161
|
-
|
|
244
|
+
const vertical = alignment.vertical as string | undefined
|
|
245
|
+
if (vertical) {
|
|
162
246
|
css.verticalAlign =
|
|
163
|
-
|
|
164
|
-
? 'middle'
|
|
165
|
-
: (alignment.vertical as ExcelPreviewCellStyle['verticalAlign'])
|
|
247
|
+
vertical === 'center' ? 'middle' : (vertical as ExcelPreviewCellStyle['verticalAlign'])
|
|
166
248
|
}
|
|
167
|
-
if (alignment.wrapText) css.whiteSpace = 'pre-wrap'
|
|
249
|
+
if (isTruthy(alignment.wrapText)) css.whiteSpace = 'pre-wrap'
|
|
168
250
|
}
|
|
169
251
|
|
|
170
|
-
const border =
|
|
252
|
+
const border = parts.border
|
|
171
253
|
if (border) {
|
|
172
|
-
const top = resolveBorderSide(border.top)
|
|
173
|
-
const right = resolveBorderSide(border.right)
|
|
174
|
-
const bottom = resolveBorderSide(border.bottom)
|
|
175
|
-
const left = resolveBorderSide(border.left)
|
|
254
|
+
const top = resolveBorderSide(border.top as { style?: string; color?: ColorStyle })
|
|
255
|
+
const right = resolveBorderSide(border.right as { style?: string; color?: ColorStyle })
|
|
256
|
+
const bottom = resolveBorderSide(border.bottom as { style?: string; color?: ColorStyle })
|
|
257
|
+
const left = resolveBorderSide(border.left as { style?: string; color?: ColorStyle })
|
|
176
258
|
if (top) css.borderTop = top
|
|
177
259
|
if (right) css.borderRight = right
|
|
178
260
|
if (bottom) css.borderBottom = bottom
|
|
@@ -182,6 +264,83 @@ const extractCellStyle = (cell?: XLSX.CellObject): ExcelPreviewCellStyle | undef
|
|
|
182
264
|
return Object.keys(css).length > 0 ? css : undefined
|
|
183
265
|
}
|
|
184
266
|
|
|
267
|
+
const resolveXfStyle = (
|
|
268
|
+
styles: WorkbookStyles | undefined,
|
|
269
|
+
xfIndex: number,
|
|
270
|
+
): ExcelPreviewCellStyle | undefined => {
|
|
271
|
+
if (!styles?.CellXf?.length || xfIndex < 0) return undefined
|
|
272
|
+
const xf = styles.CellXf[xfIndex]
|
|
273
|
+
if (!xf) return undefined
|
|
274
|
+
|
|
275
|
+
const fontId = toNumber(xf.fontId ?? xf.fontid, 0)
|
|
276
|
+
const fillId = toNumber(xf.fillId ?? xf.fillid, 0)
|
|
277
|
+
const borderId = toNumber(xf.borderId ?? xf.borderid, 0)
|
|
278
|
+
|
|
279
|
+
return styleFromParts({
|
|
280
|
+
font: styles.Fonts?.[fontId] as Record<string, unknown> | undefined,
|
|
281
|
+
fill: styles.Fills?.[fillId] as Record<string, unknown> | undefined,
|
|
282
|
+
border: styles.Borders?.[borderId] as Record<string, unknown> | undefined,
|
|
283
|
+
alignment: xf.alignment as Record<string, unknown> | undefined,
|
|
284
|
+
})
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** xlsx-js-style 读入后 cell.s 往往只有 fill,字体/边框需用 XML 中的 s 索引关联 CellXf */
|
|
288
|
+
const parseXlsxStyleIndexMaps = (buffer: ArrayBuffer, sheetCount: number) => {
|
|
289
|
+
if (!isZipXlsx(buffer) || sheetCount <= 0) return [] as Map<string, number>[]
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const files = unzipSync(new Uint8Array(buffer))
|
|
293
|
+
const decoder = new TextDecoder('utf-8')
|
|
294
|
+
const maps: Map<string, number>[] = []
|
|
295
|
+
|
|
296
|
+
for (let i = 0; i < sheetCount; i++) {
|
|
297
|
+
const path = `xl/worksheets/sheet${i + 1}.xml`
|
|
298
|
+
const xmlBytes = files[path]
|
|
299
|
+
const map = new Map<string, number>()
|
|
300
|
+
if (xmlBytes) {
|
|
301
|
+
const xml = decoder.decode(xmlBytes)
|
|
302
|
+
const cellTagRe = /<c\b([^>/]*)(?:\/>|>)/g
|
|
303
|
+
let match: RegExpExecArray | null
|
|
304
|
+
while ((match = cellTagRe.exec(xml))) {
|
|
305
|
+
const attrs = match[1]
|
|
306
|
+
const addr = attrs.match(/\br="([^"]+)"/)?.[1]
|
|
307
|
+
const styleIndex = attrs.match(/\bs="(\d+)"/)?.[1]
|
|
308
|
+
if (addr && styleIndex != null) {
|
|
309
|
+
map.set(addr, Number(styleIndex))
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
maps.push(map)
|
|
314
|
+
}
|
|
315
|
+
return maps
|
|
316
|
+
} catch {
|
|
317
|
+
return Array.from({ length: sheetCount }, () => new Map<string, number>())
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const extractCellStyle = (
|
|
322
|
+
cell?: XLSX.CellObject,
|
|
323
|
+
styles?: WorkbookStyles,
|
|
324
|
+
xfIndex?: number,
|
|
325
|
+
): ExcelPreviewCellStyle | undefined => {
|
|
326
|
+
if (styles && xfIndex != null && xfIndex >= 0) {
|
|
327
|
+
const resolved = resolveXfStyle(styles, xfIndex)
|
|
328
|
+
if (resolved) return resolved
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (typeof cell?.s === 'number' && styles) {
|
|
332
|
+
return resolveXfStyle(styles, cell.s)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const rawStyle = cell?.s
|
|
336
|
+
if (!rawStyle || typeof rawStyle !== 'object') return undefined
|
|
337
|
+
|
|
338
|
+
// cell.s 对象通常仅含 fill,作为兜底
|
|
339
|
+
return styleFromParts({
|
|
340
|
+
fill: rawStyle as Record<string, unknown>,
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
|
|
185
344
|
export const cellStyleToCss = (style?: ExcelPreviewCellStyle): Record<string, string> => {
|
|
186
345
|
if (!style) return {}
|
|
187
346
|
const css: Record<string, string> = {}
|
|
@@ -228,13 +387,23 @@ const parseColWidths = (sheet: XLSX.WorkSheet, startCol: number, endCol: number)
|
|
|
228
387
|
|
|
229
388
|
export const parseExcelWorkbook = async (src: Blob | ArrayBuffer): Promise<ExcelPreviewSheet[]> => {
|
|
230
389
|
const buffer = src instanceof Blob ? await src.arrayBuffer() : src
|
|
231
|
-
const workbook = XLSX.read(buffer, {
|
|
232
|
-
|
|
390
|
+
const workbook = XLSX.read(buffer, {
|
|
391
|
+
type: 'array',
|
|
392
|
+
cellDates: true,
|
|
393
|
+
cellStyles: true,
|
|
394
|
+
...(isOleXls(buffer) ? {} : {}),
|
|
395
|
+
})
|
|
396
|
+
const styles = workbook.Styles as WorkbookStyles | undefined
|
|
397
|
+
const styleIndexMaps = isZipXlsx(buffer)
|
|
398
|
+
? parseXlsxStyleIndexMaps(buffer, workbook.SheetNames.length)
|
|
399
|
+
: []
|
|
400
|
+
|
|
401
|
+
return workbook.SheetNames.map((name, sheetIndex) => {
|
|
233
402
|
const sheet = workbook.Sheets[name]
|
|
234
403
|
const range = sheet?.['!ref'] ? XLSX.utils.decode_range(sheet['!ref']) : null
|
|
235
404
|
return {
|
|
236
405
|
name,
|
|
237
|
-
rows: buildSheetRows(sheet),
|
|
406
|
+
rows: buildSheetRows(sheet, styles, styleIndexMaps[sheetIndex]),
|
|
238
407
|
startCol: range?.s.c ?? 0,
|
|
239
408
|
endCol: range?.e.c ?? 0,
|
|
240
409
|
colWidths: range ? parseColWidths(sheet, range.s.c, range.e.c) : {},
|
|
@@ -242,7 +411,11 @@ export const parseExcelWorkbook = async (src: Blob | ArrayBuffer): Promise<Excel
|
|
|
242
411
|
})
|
|
243
412
|
}
|
|
244
413
|
|
|
245
|
-
const buildSheetRows = (
|
|
414
|
+
const buildSheetRows = (
|
|
415
|
+
sheet?: XLSX.WorkSheet,
|
|
416
|
+
styles?: WorkbookStyles,
|
|
417
|
+
styleIndexMap?: Map<string, number>,
|
|
418
|
+
): ExcelPreviewCell[][] => {
|
|
246
419
|
if (!sheet || !sheet['!ref']) return []
|
|
247
420
|
const range = XLSX.utils.decode_range(sheet['!ref'])
|
|
248
421
|
const colWidths = parseColWidths(sheet, range.s.c, range.e.c)
|
|
@@ -268,13 +441,14 @@ const buildSheetRows = (sheet?: XLSX.WorkSheet): ExcelPreviewCell[][] => {
|
|
|
268
441
|
const addr = XLSX.utils.encode_cell({ r, c })
|
|
269
442
|
const cellObj = sheet[addr]
|
|
270
443
|
const merge = mergeStarts.get(`${r},${c}`)
|
|
444
|
+
const xfIndex = styleIndexMap?.get(addr)
|
|
271
445
|
row.push({
|
|
272
446
|
value: formatCellValue(cellObj),
|
|
273
447
|
row: r,
|
|
274
448
|
col: c,
|
|
275
449
|
rowSpan: merge?.rowSpan,
|
|
276
450
|
colSpan: merge?.colSpan,
|
|
277
|
-
style: extractCellStyle(cellObj),
|
|
451
|
+
style: extractCellStyle(cellObj, styles, xfIndex),
|
|
278
452
|
width: colWidths[c],
|
|
279
453
|
})
|
|
280
454
|
}
|
|
@@ -120,3 +120,20 @@ export const isLegacyDocFile = (type?: string, name?: string, fileUrl?: string)
|
|
|
120
120
|
/** 弹层等场景:使用 OfficePreview 内置标题栏(PDF / Word / Excel) */
|
|
121
121
|
export const isHeaderPreviewFile = (type?: string, name?: string, fileUrl?: string) =>
|
|
122
122
|
HEADER_PREVIEW_TYPES.has(toOfficePreviewType(type, name, fileUrl))
|
|
123
|
+
|
|
124
|
+
const pdfAssetBase = () => {
|
|
125
|
+
const base = import.meta.env.BASE_URL || '/'
|
|
126
|
+
return base.endsWith('/') ? base : `${base}/`
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** pdf.js 加载参数:CJK 预览需 cMap;缺嵌入字体时尝试系统字体 */
|
|
130
|
+
export const buildPdfJsLoadOptions = (data: ArrayBuffer) => {
|
|
131
|
+
const assetBase = pdfAssetBase()
|
|
132
|
+
return {
|
|
133
|
+
data,
|
|
134
|
+
useSystemFonts: true,
|
|
135
|
+
cMapUrl: `${assetBase}pdfjs/cmaps/`,
|
|
136
|
+
cMapPacked: true,
|
|
137
|
+
standardFontDataUrl: `${assetBase}pdfjs/standard_fonts/`,
|
|
138
|
+
}
|
|
139
|
+
}
|