adtec-core-package 3.1.5 → 3.1.7
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/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/adtec-core-package/adtec-core-package.css +1 -0
- package/adtec-core-package/adtec-core-package.js +41216 -0
- package/adtec-core-package/adtec-core-package.umd.cjs +87 -0
- package/adtec-core-package/favicon.ico +0 -0
- package/package.json +4 -2
- package/src/api/DocumentApi.ts +11 -1
- package/src/components/upload/DocxJsViewer.vue +286 -0
- package/src/components/upload/ExcelJsViewer.vue +270 -0
- package/src/components/upload/FileView.vue +104 -160
- package/src/components/upload/FileViewComponents.vue +2 -1
- package/src/components/upload/OfficePreview.vue +479 -0
- package/src/components/upload/OfficePreviewHeaderBar.vue +315 -0
- package/src/components/upload/OfficePreviewToolbar.vue +203 -0
- package/src/components/upload/PdfJsViewer.vue +920 -0
- package/src/utils/docxPreviewUtil.ts +108 -0
- package/src/utils/excelPreviewUtil.ts +101 -0
- package/src/utils/officePreviewUtil.ts +122 -0
- package/src/utils/pdfSearchUtil.ts +127 -0
- package/src/utils/toSameOriginFileUrl.ts +14 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="office-preview-root" :class="{ 'is-rich-preview': isRichPreview }">
|
|
3
|
+
<template v-if="isRichPreview">
|
|
4
|
+
<office-preview-header-bar
|
|
5
|
+
v-if="showHeader"
|
|
6
|
+
:title="headerTitle"
|
|
7
|
+
:zoom="scale"
|
|
8
|
+
:current-page="previewCurrentPage"
|
|
9
|
+
:total-pages="previewTotalPages"
|
|
10
|
+
:search-query="searchQuery"
|
|
11
|
+
:search-index="searchMatchIndex"
|
|
12
|
+
:search-total="searchMatchTotal"
|
|
13
|
+
:show-search="showSearch"
|
|
14
|
+
:show-page-nav="showPageNav"
|
|
15
|
+
:show-zoom="showZoom"
|
|
16
|
+
:show-download="showDownload"
|
|
17
|
+
:show-refresh="showRefresh"
|
|
18
|
+
:show-fullscreen="showFullscreen"
|
|
19
|
+
:show-close="showClose"
|
|
20
|
+
:fullscreen="fullscreen"
|
|
21
|
+
:download-loading="downloadLoading"
|
|
22
|
+
:min-zoom="MIN_OFFICE_ZOOM"
|
|
23
|
+
:max-zoom="MAX_RICH_PREVIEW_ZOOM"
|
|
24
|
+
@zoom-in="zoomIn"
|
|
25
|
+
@zoom-out="zoomOut"
|
|
26
|
+
@zoom-reset="resetZoom"
|
|
27
|
+
@download="emit('download')"
|
|
28
|
+
@refresh="emit('refresh')"
|
|
29
|
+
@toggle-fullscreen="emit('toggle-fullscreen')"
|
|
30
|
+
@close="emit('close')"
|
|
31
|
+
@page-prev="goPrevPage"
|
|
32
|
+
@page-next="goNextPage"
|
|
33
|
+
@search="handleSearch"
|
|
34
|
+
@search-clear="handleSearchClear"
|
|
35
|
+
@search-prev="goPrevSearchMatch"
|
|
36
|
+
@search-next="goNextSearchMatch"
|
|
37
|
+
/>
|
|
38
|
+
<div class="office-rich-wrap">
|
|
39
|
+
<pdf-js-viewer
|
|
40
|
+
v-if="officeType === 'pdf' || previewAsPdf"
|
|
41
|
+
ref="pdfViewerRef"
|
|
42
|
+
:src="fileSrc"
|
|
43
|
+
:scale="scale"
|
|
44
|
+
class="office-rich-viewer"
|
|
45
|
+
@loaded="handleRendered"
|
|
46
|
+
@error="handleError"
|
|
47
|
+
@page-change="previewCurrentPage = $event"
|
|
48
|
+
/>
|
|
49
|
+
<excel-js-viewer
|
|
50
|
+
v-else-if="officeType === 'excel'"
|
|
51
|
+
ref="excelViewerRef"
|
|
52
|
+
:src="fileSrc"
|
|
53
|
+
:scale="scale"
|
|
54
|
+
class="office-rich-viewer"
|
|
55
|
+
@loaded="handleRendered"
|
|
56
|
+
@error="handleError"
|
|
57
|
+
@page-change="previewCurrentPage = $event"
|
|
58
|
+
/>
|
|
59
|
+
<docx-js-viewer
|
|
60
|
+
v-else-if="officeType === 'docx' && !previewAsPdf"
|
|
61
|
+
ref="docxViewerRef"
|
|
62
|
+
:src="fileSrc"
|
|
63
|
+
:scale="scale"
|
|
64
|
+
:file-name="fileName"
|
|
65
|
+
:file-type="fileType"
|
|
66
|
+
:file-url="url"
|
|
67
|
+
class="office-rich-viewer"
|
|
68
|
+
@loaded="handleRendered"
|
|
69
|
+
@error="handleError"
|
|
70
|
+
@page-change="previewCurrentPage = $event"
|
|
71
|
+
/>
|
|
72
|
+
<div v-if="isPreviewLoading" class="office-rich-loading">
|
|
73
|
+
<div class="loading-card">
|
|
74
|
+
<span class="loading-spinner" />
|
|
75
|
+
<p class="loading-title">{{ loadingMessage }}</p>
|
|
76
|
+
<p v-if="headerTitle" class="loading-sub">{{ headerTitle }}</p>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</template>
|
|
81
|
+
<div v-else-if="isUnsupportedType" class="unsupported-preview">
|
|
82
|
+
<el-empty :description="unsupportedMessage">
|
|
83
|
+
<el-button v-if="showDownload" type="primary" @click="emit('download')">
|
|
84
|
+
下载文件
|
|
85
|
+
</el-button>
|
|
86
|
+
</el-empty>
|
|
87
|
+
</div>
|
|
88
|
+
<pre v-else-if="officeType === 'txt'" class="txt-preview">{{ txtContent }}</pre>
|
|
89
|
+
</div>
|
|
90
|
+
</template>
|
|
91
|
+
<script setup lang="ts">
|
|
92
|
+
import { computed, ref, watch, nextTick } from 'vue'
|
|
93
|
+
import { ElMessage } from 'element-plus'
|
|
94
|
+
import request from '../../utils/AxiosConfig'
|
|
95
|
+
import documentApi from '../../api/DocumentApi'
|
|
96
|
+
import frameworkUtils from '../../utils/FrameworkUtils'
|
|
97
|
+
import { toSameOriginFileUrl } from '../../utils/toSameOriginFileUrl'
|
|
98
|
+
import OfficePreviewHeaderBar from './OfficePreviewHeaderBar.vue'
|
|
99
|
+
import PdfJsViewer from './PdfJsViewer.vue'
|
|
100
|
+
import ExcelJsViewer from './ExcelJsViewer.vue'
|
|
101
|
+
import DocxJsViewer from './DocxJsViewer.vue'
|
|
102
|
+
import {
|
|
103
|
+
type OfficePreviewType,
|
|
104
|
+
clampRichPreviewZoom,
|
|
105
|
+
isSupportedPreviewType,
|
|
106
|
+
isLegacyDocFile,
|
|
107
|
+
MAX_RICH_PREVIEW_ZOOM,
|
|
108
|
+
MIN_OFFICE_ZOOM,
|
|
109
|
+
toOfficePreviewType,
|
|
110
|
+
OFFICE_ZOOM_STEP,
|
|
111
|
+
} from '../../utils/officePreviewUtil.ts'
|
|
112
|
+
|
|
113
|
+
const props = withDefaults(
|
|
114
|
+
defineProps<{
|
|
115
|
+
url: string
|
|
116
|
+
fileId?: string
|
|
117
|
+
fileName?: string
|
|
118
|
+
fileType?: string
|
|
119
|
+
showHeader?: boolean
|
|
120
|
+
showSearch?: boolean
|
|
121
|
+
showPageNav?: boolean
|
|
122
|
+
showZoom?: boolean
|
|
123
|
+
showDownload?: boolean
|
|
124
|
+
showRefresh?: boolean
|
|
125
|
+
showFullscreen?: boolean
|
|
126
|
+
showClose?: boolean
|
|
127
|
+
fullscreen?: boolean
|
|
128
|
+
downloadLoading?: boolean
|
|
129
|
+
}>(),
|
|
130
|
+
{
|
|
131
|
+
showHeader: true,
|
|
132
|
+
showSearch: true,
|
|
133
|
+
showPageNav: true,
|
|
134
|
+
showZoom: true,
|
|
135
|
+
showDownload: false,
|
|
136
|
+
showRefresh: false,
|
|
137
|
+
showFullscreen: false,
|
|
138
|
+
showClose: false,
|
|
139
|
+
fullscreen: false,
|
|
140
|
+
downloadLoading: false,
|
|
141
|
+
},
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
const scale = defineModel<number>('scale', { default: 1 })
|
|
145
|
+
|
|
146
|
+
const emit = defineEmits<{
|
|
147
|
+
loaded: []
|
|
148
|
+
error: [err?: unknown]
|
|
149
|
+
download: []
|
|
150
|
+
refresh: []
|
|
151
|
+
'toggle-fullscreen': []
|
|
152
|
+
close: []
|
|
153
|
+
}>()
|
|
154
|
+
|
|
155
|
+
const fileSrc = ref<Blob | ArrayBuffer>()
|
|
156
|
+
const txtContent = ref('')
|
|
157
|
+
const previewAsPdf = ref(false)
|
|
158
|
+
const pdfViewerRef = ref<InstanceType<typeof PdfJsViewer> | null>(null)
|
|
159
|
+
const excelViewerRef = ref<InstanceType<typeof ExcelJsViewer> | null>(null)
|
|
160
|
+
const docxViewerRef = ref<InstanceType<typeof DocxJsViewer> | null>(null)
|
|
161
|
+
const previewCurrentPage = ref(1)
|
|
162
|
+
const previewTotalPages = ref(0)
|
|
163
|
+
const searchQuery = ref('')
|
|
164
|
+
const searchMatchIndex = ref(-1)
|
|
165
|
+
const searchMatchTotal = ref(0)
|
|
166
|
+
const isPreviewLoading = ref(false)
|
|
167
|
+
const loadingPhase = ref<'fetch' | 'open'>('fetch')
|
|
168
|
+
|
|
169
|
+
type RichViewer = {
|
|
170
|
+
totalPages?: number
|
|
171
|
+
scrollToPage?: (page: number) => Promise<void>
|
|
172
|
+
runSearch?: (query: string) => Promise<{ total: number; index: number } | undefined>
|
|
173
|
+
clearSearch?: () => void
|
|
174
|
+
gotoSearchMatch?: (direction: 1 | -1) => Promise<{ total: number; index: number } | undefined>
|
|
175
|
+
refitLayout?: () => void
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const loadingMessage = computed(() =>
|
|
179
|
+
loadingPhase.value === 'fetch' ? '正在获取文档,请稍候…' : '正在打开文档,请稍候…',
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
const officeType = computed<OfficePreviewType>(() =>
|
|
183
|
+
toOfficePreviewType(props.fileType, props.fileName, props.url),
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
const isLegacyDoc = computed(() =>
|
|
187
|
+
isLegacyDocFile(props.fileType, props.fileName, props.url),
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
const isRichPreview = computed(
|
|
191
|
+
() =>
|
|
192
|
+
officeType.value === 'pdf' ||
|
|
193
|
+
officeType.value === 'excel' ||
|
|
194
|
+
officeType.value === 'docx',
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
const isUnsupportedType = computed(
|
|
198
|
+
() => !!officeType.value && !isSupportedPreviewType(officeType.value),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
const unsupportedMessage = computed(() => {
|
|
202
|
+
const ext = officeType.value || '未知'
|
|
203
|
+
return `暂不支持在线预览 ${ext} 格式,请下载后查看`
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
const headerTitle = computed(() => props.fileName || '')
|
|
207
|
+
|
|
208
|
+
const activeViewer = computed<RichViewer | null>(() => {
|
|
209
|
+
if (officeType.value === 'pdf' || previewAsPdf.value) return pdfViewerRef.value
|
|
210
|
+
if (officeType.value === 'excel') return excelViewerRef.value
|
|
211
|
+
if (officeType.value === 'docx') return docxViewerRef.value
|
|
212
|
+
return null
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
const resetPreview = () => {
|
|
216
|
+
fileSrc.value = undefined
|
|
217
|
+
txtContent.value = ''
|
|
218
|
+
previewAsPdf.value = false
|
|
219
|
+
scale.value = 1
|
|
220
|
+
previewCurrentPage.value = 1
|
|
221
|
+
previewTotalPages.value = 0
|
|
222
|
+
searchQuery.value = ''
|
|
223
|
+
searchMatchIndex.value = -1
|
|
224
|
+
searchMatchTotal.value = 0
|
|
225
|
+
isPreviewLoading.value = false
|
|
226
|
+
loadingPhase.value = 'fetch'
|
|
227
|
+
pdfViewerRef.value?.clearSearch()
|
|
228
|
+
excelViewerRef.value?.clearSearch()
|
|
229
|
+
docxViewerRef.value?.clearSearch()
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const loadPreview = async () => {
|
|
233
|
+
if (!props.url || !officeType.value) {
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
if (isUnsupportedType.value) {
|
|
237
|
+
isPreviewLoading.value = false
|
|
238
|
+
emit('loaded')
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
isPreviewLoading.value = true
|
|
242
|
+
loadingPhase.value = 'fetch'
|
|
243
|
+
try {
|
|
244
|
+
if (isLegacyDoc.value) {
|
|
245
|
+
if (!props.fileId) {
|
|
246
|
+
isPreviewLoading.value = false
|
|
247
|
+
ElMessage.warning('无法预览该 .doc 文件,请下载后查看')
|
|
248
|
+
emit('loaded')
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
loadingPhase.value = 'open'
|
|
252
|
+
const pdfBlob = await documentApi.previewWordAsPdf(props.fileId)
|
|
253
|
+
previewAsPdf.value = true
|
|
254
|
+
fileSrc.value = pdfBlob
|
|
255
|
+
return
|
|
256
|
+
}
|
|
257
|
+
const res = await request<Blob>({
|
|
258
|
+
url: toSameOriginFileUrl(props.url),
|
|
259
|
+
method: 'get',
|
|
260
|
+
responseType: 'blob',
|
|
261
|
+
})
|
|
262
|
+
if (officeType.value === 'txt') {
|
|
263
|
+
txtContent.value = await res.data.text()
|
|
264
|
+
isPreviewLoading.value = false
|
|
265
|
+
emit('loaded')
|
|
266
|
+
} else {
|
|
267
|
+
loadingPhase.value = 'open'
|
|
268
|
+
fileSrc.value = res.data
|
|
269
|
+
}
|
|
270
|
+
} catch (err) {
|
|
271
|
+
isPreviewLoading.value = false
|
|
272
|
+
frameworkUtils.messageError(err)
|
|
273
|
+
emit('error', err)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const handleRendered = async () => {
|
|
278
|
+
await nextTick()
|
|
279
|
+
previewTotalPages.value = Number(activeViewer.value?.totalPages ?? 0)
|
|
280
|
+
isPreviewLoading.value = false
|
|
281
|
+
emit('loaded')
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const handleError = (err?: unknown) => {
|
|
285
|
+
isPreviewLoading.value = false
|
|
286
|
+
emit('error', err)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const zoomIn = () => {
|
|
290
|
+
scale.value = clampRichPreviewZoom(scale.value + OFFICE_ZOOM_STEP)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const zoomOut = () => {
|
|
294
|
+
scale.value = clampRichPreviewZoom(scale.value - OFFICE_ZOOM_STEP)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const resetZoom = () => {
|
|
298
|
+
scale.value = 1
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const goPrevPage = () => {
|
|
302
|
+
void activeViewer.value?.scrollToPage?.(previewCurrentPage.value - 1)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const goNextPage = () => {
|
|
306
|
+
void activeViewer.value?.scrollToPage?.(previewCurrentPage.value + 1)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const handleSearch = async (query: string) => {
|
|
310
|
+
searchQuery.value = query
|
|
311
|
+
if (!query) {
|
|
312
|
+
handleSearchClear()
|
|
313
|
+
return
|
|
314
|
+
}
|
|
315
|
+
const result = await activeViewer.value?.runSearch?.(query)
|
|
316
|
+
if (!result || result.total === 0) {
|
|
317
|
+
searchMatchIndex.value = -1
|
|
318
|
+
searchMatchTotal.value = 0
|
|
319
|
+
ElMessage.warning('未找到匹配内容')
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
searchMatchIndex.value = result.index
|
|
323
|
+
searchMatchTotal.value = result.total
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const handleSearchClear = () => {
|
|
327
|
+
searchQuery.value = ''
|
|
328
|
+
searchMatchIndex.value = -1
|
|
329
|
+
searchMatchTotal.value = 0
|
|
330
|
+
activeViewer.value?.clearSearch?.()
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const goPrevSearchMatch = async () => {
|
|
334
|
+
const result = await activeViewer.value?.gotoSearchMatch?.(-1)
|
|
335
|
+
if (!result) return
|
|
336
|
+
searchMatchIndex.value = result.index
|
|
337
|
+
searchMatchTotal.value = result.total
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const goNextSearchMatch = async () => {
|
|
341
|
+
const result = await activeViewer.value?.gotoSearchMatch?.(1)
|
|
342
|
+
if (!result) return
|
|
343
|
+
searchMatchIndex.value = result.index
|
|
344
|
+
searchMatchTotal.value = result.total
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
watch(
|
|
348
|
+
() => [props.url, props.fileName, props.fileType] as const,
|
|
349
|
+
([fileUrl]) => {
|
|
350
|
+
resetPreview()
|
|
351
|
+
if (fileUrl) {
|
|
352
|
+
loadPreview()
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
{ immediate: true },
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
watch(
|
|
359
|
+
() => props.fullscreen,
|
|
360
|
+
() => {
|
|
361
|
+
void nextTick(() => {
|
|
362
|
+
activeViewer.value?.refitLayout?.()
|
|
363
|
+
})
|
|
364
|
+
},
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
defineExpose({
|
|
368
|
+
zoomIn,
|
|
369
|
+
zoomOut,
|
|
370
|
+
resetZoom,
|
|
371
|
+
officeType,
|
|
372
|
+
})
|
|
373
|
+
</script>
|
|
374
|
+
<style scoped lang="scss">
|
|
375
|
+
.office-preview-root {
|
|
376
|
+
width: 100%;
|
|
377
|
+
height: 100%;
|
|
378
|
+
min-height: 0;
|
|
379
|
+
overflow: auto;
|
|
380
|
+
background: #f5f5f5;
|
|
381
|
+
|
|
382
|
+
&.is-rich-preview {
|
|
383
|
+
display: flex;
|
|
384
|
+
flex-direction: column;
|
|
385
|
+
overflow: hidden;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.office-rich-viewer {
|
|
390
|
+
flex: 1;
|
|
391
|
+
width: 100%;
|
|
392
|
+
min-height: 0;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.office-rich-wrap {
|
|
396
|
+
position: relative;
|
|
397
|
+
flex: 1;
|
|
398
|
+
width: 100%;
|
|
399
|
+
min-height: 0;
|
|
400
|
+
display: flex;
|
|
401
|
+
flex-direction: column;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.office-rich-loading {
|
|
405
|
+
position: absolute;
|
|
406
|
+
inset: 0;
|
|
407
|
+
z-index: 3;
|
|
408
|
+
display: flex;
|
|
409
|
+
align-items: center;
|
|
410
|
+
justify-content: center;
|
|
411
|
+
background: #f5f5f5;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.loading-card {
|
|
415
|
+
display: flex;
|
|
416
|
+
flex-direction: column;
|
|
417
|
+
align-items: center;
|
|
418
|
+
gap: 12px;
|
|
419
|
+
padding: 28px 36px;
|
|
420
|
+
border-radius: 12px;
|
|
421
|
+
background: #fff;
|
|
422
|
+
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.loading-spinner {
|
|
426
|
+
width: 36px;
|
|
427
|
+
height: 36px;
|
|
428
|
+
border: 3px solid #e5e7eb;
|
|
429
|
+
border-top-color: #409eff;
|
|
430
|
+
border-radius: 50%;
|
|
431
|
+
animation: office-preview-spin 0.9s linear infinite;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.loading-title {
|
|
435
|
+
margin: 0;
|
|
436
|
+
font-size: 14px;
|
|
437
|
+
font-weight: 600;
|
|
438
|
+
color: #374151;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.loading-sub {
|
|
442
|
+
margin: 0;
|
|
443
|
+
max-width: 280px;
|
|
444
|
+
font-size: 12px;
|
|
445
|
+
color: #9ca3af;
|
|
446
|
+
text-align: center;
|
|
447
|
+
white-space: nowrap;
|
|
448
|
+
overflow: hidden;
|
|
449
|
+
text-overflow: ellipsis;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
@keyframes office-preview-spin {
|
|
453
|
+
to {
|
|
454
|
+
transform: rotate(360deg);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.txt-preview {
|
|
459
|
+
height: 100%;
|
|
460
|
+
margin: 0;
|
|
461
|
+
padding: 16px;
|
|
462
|
+
overflow: auto;
|
|
463
|
+
text-align: left;
|
|
464
|
+
white-space: pre-wrap;
|
|
465
|
+
word-break: break-word;
|
|
466
|
+
background: #fff;
|
|
467
|
+
font-size: 14px;
|
|
468
|
+
line-height: 1.6;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.unsupported-preview {
|
|
472
|
+
display: flex;
|
|
473
|
+
align-items: center;
|
|
474
|
+
justify-content: center;
|
|
475
|
+
height: 100%;
|
|
476
|
+
min-height: 240px;
|
|
477
|
+
background: #fff;
|
|
478
|
+
}
|
|
479
|
+
</style>
|