adtec-core-package 3.1.6 → 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.
@@ -0,0 +1,315 @@
1
+ <template>
2
+ <div class="office-preview-header">
3
+ <div v-if="title" class="header-title" :title="title">{{ title }}</div>
4
+
5
+ <div v-if="showSearch" class="header-search">
6
+ <el-input
7
+ v-model="searchText"
8
+ class="search-input"
9
+ clearable
10
+ placeholder="搜索文档内容"
11
+ @keyup.enter="emitSearch"
12
+ @clear="emit('search-clear')"
13
+ >
14
+ <template #prefix>
15
+ <el-icon><Search /></el-icon>
16
+ </template>
17
+ </el-input>
18
+ <span v-if="searchTotal > 0" class="search-count">{{ searchIndex + 1 }}/{{ searchTotal }}</span>
19
+ <button
20
+ v-if="searchTotal > 0"
21
+ class="toolbar-btn"
22
+ type="button"
23
+ title="上一处"
24
+ @click="emit('search-prev')"
25
+ >
26
+ <el-icon><ArrowUp /></el-icon>
27
+ </button>
28
+ <button
29
+ v-if="searchTotal > 0"
30
+ class="toolbar-btn"
31
+ type="button"
32
+ title="下一处"
33
+ @click="emit('search-next')"
34
+ >
35
+ <el-icon><ArrowDown /></el-icon>
36
+ </button>
37
+ </div>
38
+
39
+ <div class="header-actions">
40
+ <template v-if="showPageNav && totalPages > 0">
41
+ <button class="toolbar-btn" type="button" title="上一页" :disabled="currentPage <= 1" @click="emit('page-prev')">
42
+ <el-icon><ArrowLeft /></el-icon>
43
+ </button>
44
+ <span class="page-label">{{ currentPage }} / {{ totalPages }}</span>
45
+ <button
46
+ class="toolbar-btn"
47
+ type="button"
48
+ title="下一页"
49
+ :disabled="currentPage >= totalPages"
50
+ @click="emit('page-next')"
51
+ >
52
+ <el-icon><ArrowRight /></el-icon>
53
+ </button>
54
+ <span class="toolbar-divider" />
55
+ </template>
56
+
57
+ <template v-if="showZoom">
58
+ <button class="toolbar-btn" type="button" title="缩小" :disabled="zoom <= minZoom" @click="emit('zoom-out')">
59
+ <el-icon><ZoomOut /></el-icon>
60
+ </button>
61
+ <span class="zoom-label">{{ zoomPercent }}%</span>
62
+ <button class="toolbar-btn" type="button" title="放大" :disabled="zoom >= maxZoom" @click="emit('zoom-in')">
63
+ <el-icon><ZoomIn /></el-icon>
64
+ </button>
65
+ <button class="toolbar-btn" type="button" title="重置缩放" @click="emit('zoom-reset')">
66
+ <el-icon><RefreshRight /></el-icon>
67
+ </button>
68
+ <span class="toolbar-divider" />
69
+ </template>
70
+
71
+ <button
72
+ v-if="showDownload"
73
+ class="toolbar-btn"
74
+ type="button"
75
+ title="下载"
76
+ :disabled="downloadLoading"
77
+ @click="emit('download')"
78
+ >
79
+ <el-icon v-if="downloadLoading" class="is-loading"><Loading /></el-icon>
80
+ <el-icon v-else><Download /></el-icon>
81
+ </button>
82
+
83
+ <button v-if="showRefresh" class="toolbar-btn" type="button" title="刷新附件" @click="emit('refresh')">
84
+ <el-icon><Refresh /></el-icon>
85
+ </button>
86
+
87
+ <button
88
+ v-if="showFullscreen"
89
+ class="toolbar-btn"
90
+ type="button"
91
+ :title="fullscreen ? '退出全屏' : '全屏'"
92
+ @click="emit('toggle-fullscreen')"
93
+ >
94
+ <el-icon><Close v-if="fullscreen" /><FullScreen v-else /></el-icon>
95
+ </button>
96
+
97
+ <button
98
+ v-if="showClose"
99
+ class="toolbar-btn toolbar-btn--close"
100
+ type="button"
101
+ title="关闭"
102
+ @click="emit('close')"
103
+ >
104
+ <el-icon><Close /></el-icon>
105
+ </button>
106
+ </div>
107
+ </div>
108
+ </template>
109
+
110
+ <script setup lang="ts">
111
+ import {
112
+ ArrowDown,
113
+ ArrowLeft,
114
+ ArrowRight,
115
+ ArrowUp,
116
+ Close,
117
+ Download,
118
+ FullScreen,
119
+ Loading,
120
+ Refresh,
121
+ RefreshRight,
122
+ Search,
123
+ ZoomIn,
124
+ ZoomOut,
125
+ } from '@element-plus/icons-vue'
126
+ import { ElIcon, ElInput } from 'element-plus'
127
+ import { computed, ref, watch } from 'vue'
128
+ import { MAX_PDF_ZOOM, MIN_OFFICE_ZOOM } from '../../utils/officePreviewUtil.ts'
129
+
130
+ const props = withDefaults(
131
+ defineProps<{
132
+ title?: string
133
+ zoom?: number
134
+ currentPage?: number
135
+ totalPages?: number
136
+ searchQuery?: string
137
+ searchIndex?: number
138
+ searchTotal?: number
139
+ showSearch?: boolean
140
+ showPageNav?: boolean
141
+ showZoom?: boolean
142
+ showDownload?: boolean
143
+ showRefresh?: boolean
144
+ showFullscreen?: boolean
145
+ showClose?: boolean
146
+ fullscreen?: boolean
147
+ downloadLoading?: boolean
148
+ minZoom?: number
149
+ maxZoom?: number
150
+ }>(),
151
+ {
152
+ title: '',
153
+ zoom: 1,
154
+ currentPage: 1,
155
+ totalPages: 0,
156
+ searchQuery: '',
157
+ searchIndex: -1,
158
+ searchTotal: 0,
159
+ showSearch: true,
160
+ showPageNav: true,
161
+ showZoom: true,
162
+ showDownload: false,
163
+ showRefresh: false,
164
+ showFullscreen: false,
165
+ showClose: false,
166
+ fullscreen: false,
167
+ downloadLoading: false,
168
+ minZoom: MIN_OFFICE_ZOOM,
169
+ maxZoom: MAX_PDF_ZOOM,
170
+ },
171
+ )
172
+
173
+ const emit = defineEmits<{
174
+ 'zoom-in': []
175
+ 'zoom-out': []
176
+ 'zoom-reset': []
177
+ download: []
178
+ refresh: []
179
+ 'toggle-fullscreen': []
180
+ close: []
181
+ 'page-prev': []
182
+ 'page-next': []
183
+ search: [query: string]
184
+ 'search-clear': []
185
+ 'search-prev': []
186
+ 'search-next': []
187
+ }>()
188
+
189
+ const searchText = ref(props.searchQuery)
190
+ const zoomPercent = computed(() => Math.round(props.zoom * 100))
191
+
192
+ watch(
193
+ () => props.searchQuery,
194
+ (value) => {
195
+ searchText.value = value
196
+ },
197
+ )
198
+
199
+ const emitSearch = () => {
200
+ emit('search', searchText.value.trim())
201
+ }
202
+ </script>
203
+
204
+ <style scoped lang="scss">
205
+ .office-preview-header {
206
+ display: flex;
207
+ align-items: center;
208
+ gap: 12px;
209
+ min-height: 44px;
210
+ padding: 6px 12px;
211
+ background: #fff;
212
+ border-bottom: 1px solid #e5e7eb;
213
+ flex-shrink: 0;
214
+ }
215
+
216
+ .header-title {
217
+ max-width: 180px;
218
+ font-size: 13px;
219
+ font-weight: 600;
220
+ color: #374151;
221
+ white-space: nowrap;
222
+ overflow: hidden;
223
+ text-overflow: ellipsis;
224
+ flex-shrink: 0;
225
+ }
226
+
227
+ .header-search {
228
+ display: flex;
229
+ align-items: center;
230
+ gap: 4px;
231
+ flex: 1;
232
+ min-width: 0;
233
+ }
234
+
235
+ .search-input {
236
+ flex: 1;
237
+ min-width: 120px;
238
+ max-width: 360px;
239
+ }
240
+
241
+ .search-count {
242
+ min-width: 48px;
243
+ font-size: 12px;
244
+ color: #6b7280;
245
+ text-align: center;
246
+ }
247
+
248
+ .header-actions {
249
+ display: inline-flex;
250
+ align-items: center;
251
+ gap: 2px;
252
+ margin-left: auto;
253
+ flex-shrink: 0;
254
+ }
255
+
256
+ .toolbar-btn {
257
+ display: inline-flex;
258
+ align-items: center;
259
+ justify-content: center;
260
+ width: 32px;
261
+ height: 32px;
262
+ padding: 0;
263
+ border: none;
264
+ border-radius: 8px;
265
+ background: transparent;
266
+ color: #4b5563;
267
+ cursor: pointer;
268
+ transition: background-color 0.2s ease, color 0.2s ease;
269
+
270
+ &:hover:not(:disabled) {
271
+ background: #f3f4f6;
272
+ color: #111827;
273
+ }
274
+
275
+ &:disabled {
276
+ color: #d1d5db;
277
+ cursor: not-allowed;
278
+ }
279
+
280
+ &--close:hover:not(:disabled) {
281
+ background: #fee2e2;
282
+ color: #dc2626;
283
+ }
284
+ }
285
+
286
+ .zoom-label,
287
+ .page-label {
288
+ min-width: 52px;
289
+ text-align: center;
290
+ font-size: 12px;
291
+ font-weight: 600;
292
+ color: #374151;
293
+ user-select: none;
294
+ }
295
+
296
+ .toolbar-divider {
297
+ width: 1px;
298
+ height: 20px;
299
+ margin: 0 4px;
300
+ background: #e5e7eb;
301
+ }
302
+
303
+ .is-loading {
304
+ animation: rotating 1.2s linear infinite;
305
+ }
306
+
307
+ @keyframes rotating {
308
+ from {
309
+ transform: rotate(0deg);
310
+ }
311
+ to {
312
+ transform: rotate(360deg);
313
+ }
314
+ }
315
+ </style>
@@ -0,0 +1,203 @@
1
+ <template>
2
+ <div class="office-preview-toolbar">
3
+ <template v-if="showZoom">
4
+ <button
5
+ class="toolbar-btn"
6
+ type="button"
7
+ title="缩小"
8
+ :disabled="zoom <= minZoom"
9
+ @click="$emit('zoom-out')"
10
+ >
11
+ <el-icon><ZoomOut /></el-icon>
12
+ </button>
13
+ <span class="zoom-label">{{ zoomPercent }}%</span>
14
+ <button
15
+ class="toolbar-btn"
16
+ type="button"
17
+ title="放大"
18
+ :disabled="zoom >= maxZoom"
19
+ @click="$emit('zoom-in')"
20
+ >
21
+ <el-icon><ZoomIn /></el-icon>
22
+ </button>
23
+ <button class="toolbar-btn" type="button" title="重置缩放" @click="$emit('zoom-reset')">
24
+ <el-icon><RefreshRight /></el-icon>
25
+ </button>
26
+ <span class="toolbar-divider" />
27
+ </template>
28
+
29
+ <button
30
+ v-if="showDownload"
31
+ class="toolbar-btn"
32
+ type="button"
33
+ title="下载"
34
+ :disabled="downloadLoading"
35
+ @click="$emit('download')"
36
+ >
37
+ <el-icon v-if="downloadLoading" class="is-loading"><Loading /></el-icon>
38
+ <el-icon v-else><Download /></el-icon>
39
+ </button>
40
+
41
+ <button
42
+ v-if="showRefresh"
43
+ class="toolbar-btn"
44
+ type="button"
45
+ title="刷新附件"
46
+ @click="$emit('refresh')"
47
+ >
48
+ <el-icon><Refresh /></el-icon>
49
+ </button>
50
+
51
+ <button
52
+ v-if="showFullscreen"
53
+ class="toolbar-btn"
54
+ type="button"
55
+ :title="fullscreen ? '退出全屏' : '全屏'"
56
+ @click="$emit('toggle-fullscreen')"
57
+ >
58
+ <el-icon><Close v-if="fullscreen" /><FullScreen v-else /></el-icon>
59
+ </button>
60
+
61
+ <button
62
+ v-if="showClose"
63
+ class="toolbar-btn toolbar-btn--close"
64
+ type="button"
65
+ title="关闭"
66
+ @click="$emit('close')"
67
+ >
68
+ <el-icon><Close /></el-icon>
69
+ </button>
70
+ </div>
71
+ </template>
72
+
73
+ <script setup lang="ts">
74
+ import {
75
+ Close,
76
+ Download,
77
+ FullScreen,
78
+ Loading,
79
+ Refresh,
80
+ RefreshRight,
81
+ ZoomIn,
82
+ ZoomOut,
83
+ } from '@element-plus/icons-vue'
84
+ import { ElIcon } from 'element-plus'
85
+ import { computed } from 'vue'
86
+ import { MAX_OFFICE_ZOOM, MIN_OFFICE_ZOOM } from '../../utils/officePreviewUtil.ts'
87
+
88
+ const props = withDefaults(
89
+ defineProps<{
90
+ zoom?: number
91
+ showZoom?: boolean
92
+ showDownload?: boolean
93
+ showRefresh?: boolean
94
+ showFullscreen?: boolean
95
+ showClose?: boolean
96
+ fullscreen?: boolean
97
+ downloadLoading?: boolean
98
+ minZoom?: number
99
+ maxZoom?: number
100
+ }>(),
101
+ {
102
+ zoom: 1,
103
+ showZoom: false,
104
+ showDownload: false,
105
+ showRefresh: false,
106
+ showFullscreen: false,
107
+ showClose: false,
108
+ fullscreen: false,
109
+ downloadLoading: false,
110
+ minZoom: MIN_OFFICE_ZOOM,
111
+ maxZoom: MAX_OFFICE_ZOOM,
112
+ },
113
+ )
114
+
115
+ defineEmits<{
116
+ 'zoom-in': []
117
+ 'zoom-out': []
118
+ 'zoom-reset': []
119
+ download: []
120
+ refresh: []
121
+ 'toggle-fullscreen': []
122
+ close: []
123
+ }>()
124
+
125
+ const zoomPercent = computed(() => Math.round(props.zoom * 100))
126
+ </script>
127
+
128
+ <style scoped lang="scss">
129
+ .office-preview-toolbar {
130
+ display: inline-flex;
131
+ align-items: center;
132
+ gap: 2px;
133
+ padding: 4px 8px;
134
+ border-radius: 10px;
135
+ background: rgba(255, 255, 255, 0.96);
136
+ border: 1px solid rgba(0, 0, 0, 0.06);
137
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
138
+ backdrop-filter: blur(8px);
139
+ }
140
+
141
+ .toolbar-btn {
142
+ display: inline-flex;
143
+ align-items: center;
144
+ justify-content: center;
145
+ width: 32px;
146
+ height: 32px;
147
+ padding: 0;
148
+ border: none;
149
+ border-radius: 8px;
150
+ background: transparent;
151
+ color: #4b5563;
152
+ cursor: pointer;
153
+ transition: background-color 0.2s ease, color 0.2s ease;
154
+
155
+ &:hover:not(:disabled) {
156
+ background: #f3f4f6;
157
+ color: #111827;
158
+ }
159
+
160
+ &:disabled {
161
+ color: #d1d5db;
162
+ cursor: not-allowed;
163
+ }
164
+
165
+ &--close {
166
+ color: #6b7280;
167
+
168
+ &:hover:not(:disabled) {
169
+ background: #fee2e2;
170
+ color: #dc2626;
171
+ }
172
+ }
173
+ }
174
+
175
+ .zoom-label {
176
+ min-width: 44px;
177
+ text-align: center;
178
+ font-size: 12px;
179
+ font-weight: 600;
180
+ color: #374151;
181
+ user-select: none;
182
+ }
183
+
184
+ .toolbar-divider {
185
+ width: 1px;
186
+ height: 20px;
187
+ margin: 0 4px;
188
+ background: #e5e7eb;
189
+ }
190
+
191
+ .is-loading {
192
+ animation: rotating 1.2s linear infinite;
193
+ }
194
+
195
+ @keyframes rotating {
196
+ from {
197
+ transform: rotate(0deg);
198
+ }
199
+ to {
200
+ transform: rotate(360deg);
201
+ }
202
+ }
203
+ </style>