@363045841yyt/klinechart 0.8.5 → 0.8.6
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/README.md +6 -1
- package/dist/components/BaseModal.vue.d.ts +54 -0
- package/dist/components/BaseModal.vue.d.ts.map +1 -0
- package/dist/components/BatchStockDialog.vue.d.ts.map +1 -1
- package/dist/components/ChartSettingsDialog.vue.d.ts.map +1 -1
- package/dist/components/ColorPresetPanel.vue.d.ts +4 -1
- package/dist/components/ColorPresetPanel.vue.d.ts.map +1 -1
- package/dist/components/DrawingStyleToolbar.vue.d.ts.map +1 -1
- package/dist/components/ExportProgressDialog.vue.d.ts.map +1 -1
- package/dist/components/IndicatorParams.vue.d.ts.map +1 -1
- package/dist/components/IndicatorSelector.vue.d.ts.map +1 -1
- package/dist/components/KLineChart.vue.d.ts.map +1 -1
- package/dist/components/RangeSelectionExport.vue.d.ts +23 -0
- package/dist/components/RangeSelectionExport.vue.d.ts.map +1 -0
- package/dist/components/common/CanvasToolbar.vue.d.ts +14 -0
- package/dist/components/common/CanvasToolbar.vue.d.ts.map +1 -0
- package/dist/components/common/CanvasToolbarStack.vue.d.ts +14 -0
- package/dist/components/common/CanvasToolbarStack.vue.d.ts.map +1 -0
- package/dist/composables/chart/useRangeSelection.d.ts +1 -0
- package/dist/composables/chart/useRangeSelection.d.ts.map +1 -1
- package/dist/composables/useTeleportedPopup.d.ts.map +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.css +1 -1
- package/dist/index.js +1293 -1215
- package/dist/web-component.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/BaseModal.vue +292 -0
- package/src/components/BatchStockDialog.vue +15 -180
- package/src/components/ChartSettingsDialog.vue +248 -405
- package/src/components/ColorPresetPanel.vue +58 -106
- package/src/components/CompareSymbolSelector.vue +2 -2
- package/src/components/DrawingStyleToolbar.vue +33 -72
- package/src/components/ExportProgressDialog.vue +25 -133
- package/src/components/IndicatorParams.vue +194 -321
- package/src/components/IndicatorSelector.vue +188 -405
- package/src/components/KLineChart.vue +34 -138
- package/src/components/LeftToolbar.vue +1 -1
- package/src/components/RangeSelectionExport.vue +117 -0
- package/src/components/SymbolSelector.vue +2 -2
- package/src/components/common/CanvasToolbar.vue +70 -0
- package/src/components/common/CanvasToolbarStack.vue +32 -0
- package/src/composables/chart/useRangeSelection.ts +7 -0
- package/src/composables/useTeleportedPopup.ts +15 -2
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<div class="
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{{ option.label }}
|
|
14
|
-
</button>
|
|
15
|
-
</div>
|
|
16
|
-
<button type="button" class="color-reset-btn" @click="resetCurrentThemeColors">
|
|
17
|
-
重置颜色
|
|
2
|
+
<div class="color-preset-container">
|
|
3
|
+
<div class="theme-tabs" role="tablist" aria-label="颜色主题">
|
|
4
|
+
<button
|
|
5
|
+
v-for="option in themeOptions"
|
|
6
|
+
:key="option.value"
|
|
7
|
+
type="button"
|
|
8
|
+
class="theme-tab"
|
|
9
|
+
:class="{ active: editingTheme === option.value }"
|
|
10
|
+
@click="editingTheme = option.value"
|
|
11
|
+
>
|
|
12
|
+
{{ option.label }}
|
|
18
13
|
</button>
|
|
19
14
|
</div>
|
|
15
|
+
|
|
16
|
+
<!-- 颜色分组列表 -->
|
|
20
17
|
<template v-for="group in colorPresetGroups" :key="group.group">
|
|
21
18
|
<div class="color-group-label">{{ group.label }}</div>
|
|
22
19
|
<div class="color-grid">
|
|
23
20
|
<label v-for="item in group.items" :key="item.key" class="color-item">
|
|
24
|
-
<span>{{ item.label }}</span>
|
|
21
|
+
<span class="color-item-text">{{ item.label }}</span>
|
|
25
22
|
<input
|
|
26
23
|
type="color"
|
|
27
24
|
class="color-input"
|
|
@@ -105,30 +102,27 @@ function resetCurrentThemeColors(): void {
|
|
|
105
102
|
delete nextColorSettings[editingTheme.value]
|
|
106
103
|
emit('update:colorPresetSettings', nextColorSettings)
|
|
107
104
|
}
|
|
105
|
+
|
|
106
|
+
defineExpose({ resetCurrentThemeColors })
|
|
108
107
|
</script>
|
|
109
108
|
|
|
110
109
|
<style scoped>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
display: grid;
|
|
114
|
-
grid-template-columns: 1fr auto;
|
|
115
|
-
align-items: center;
|
|
116
|
-
gap: 8px;
|
|
117
|
-
margin-bottom: 4px;
|
|
110
|
+
.color-preset-container {
|
|
111
|
+
padding: 4px 0;
|
|
118
112
|
}
|
|
119
113
|
|
|
120
|
-
/* ── 主题切换 ── */
|
|
121
114
|
.theme-tabs {
|
|
122
|
-
display:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
115
|
+
display: flex;
|
|
116
|
+
gap: 4px;
|
|
117
|
+
padding: 4px;
|
|
118
|
+
margin-bottom: 12px;
|
|
126
119
|
border: 1px solid var(--klc-color-border-button);
|
|
127
120
|
border-radius: 8px;
|
|
128
121
|
background: var(--klc-color-grid-minor);
|
|
129
122
|
}
|
|
130
123
|
|
|
131
124
|
.theme-tab {
|
|
125
|
+
flex: 1;
|
|
132
126
|
height: 28px;
|
|
133
127
|
border: none;
|
|
134
128
|
border-radius: 6px;
|
|
@@ -137,149 +131,107 @@ function resetCurrentThemeColors(): void {
|
|
|
137
131
|
font-size: 12px;
|
|
138
132
|
font-weight: 500;
|
|
139
133
|
cursor: pointer;
|
|
140
|
-
transition:
|
|
141
|
-
|
|
142
|
-
color 0.18s ease,
|
|
143
|
-
box-shadow 0.18s ease;
|
|
134
|
+
transition: all 0.18s ease;
|
|
135
|
+
white-space: nowrap;
|
|
144
136
|
}
|
|
145
137
|
|
|
146
138
|
.theme-tab:not(.active):hover {
|
|
147
139
|
color: var(--klc-color-foreground);
|
|
148
|
-
background: color-mix(in srgb, var(--klc-color-
|
|
140
|
+
background: color-mix(in srgb, var(--klc-color-background) 60%, transparent);
|
|
149
141
|
}
|
|
150
142
|
|
|
151
143
|
.theme-tab.active {
|
|
152
|
-
background: var(--klc-color-tag-bg-white);
|
|
153
144
|
color: var(--klc-color-foreground);
|
|
154
145
|
font-weight: 600;
|
|
155
|
-
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
156
146
|
}
|
|
157
147
|
|
|
158
|
-
/* ──
|
|
159
|
-
.color-
|
|
160
|
-
|
|
161
|
-
padding: 0 14px;
|
|
162
|
-
border: 1px solid var(--klc-color-axis-line);
|
|
163
|
-
border-radius: 8px;
|
|
164
|
-
background: var(--klc-color-tag-bg-white);
|
|
148
|
+
/* ── 分组标签 ── */
|
|
149
|
+
.color-group-label {
|
|
150
|
+
margin: 18px 0 6px;
|
|
165
151
|
color: var(--klc-color-axis-text);
|
|
166
152
|
font-size: 12px;
|
|
167
153
|
font-weight: 500;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
transition:
|
|
171
|
-
background 0.18s ease,
|
|
172
|
-
border-color 0.18s ease,
|
|
173
|
-
color 0.18s ease,
|
|
174
|
-
box-shadow 0.18s ease;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
.color-reset-btn:hover {
|
|
178
|
-
border-color: var(--klc-color-axis-text);
|
|
179
|
-
background: var(--klc-color-background);
|
|
180
|
-
color: var(--klc-color-foreground);
|
|
181
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
.color-reset-btn:active {
|
|
185
|
-
background: var(--klc-color-tag-bg-hover);
|
|
186
|
-
box-shadow: none;
|
|
154
|
+
letter-spacing: 0.3px;
|
|
155
|
+
line-height: 1;
|
|
187
156
|
}
|
|
188
157
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
margin: 6px 0 6px;
|
|
192
|
-
color: var(--klc-color-axis-text);
|
|
193
|
-
font-size: 12px;
|
|
194
|
-
font-weight: 600;
|
|
195
|
-
line-height: 1.3;
|
|
158
|
+
.color-group-label:first-of-type {
|
|
159
|
+
margin-top: 0;
|
|
196
160
|
}
|
|
197
161
|
|
|
198
162
|
/* ── 颜色网格 ── */
|
|
199
163
|
.color-grid {
|
|
200
164
|
display: grid;
|
|
201
165
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
202
|
-
gap:
|
|
166
|
+
gap: 4px;
|
|
203
167
|
}
|
|
204
168
|
|
|
205
|
-
/* ── 颜色条目 ── */
|
|
169
|
+
/* ── 颜色条目 (扁平化样式) ── */
|
|
206
170
|
.color-item {
|
|
207
171
|
display: flex;
|
|
208
172
|
align-items: center;
|
|
209
173
|
justify-content: space-between;
|
|
210
174
|
gap: 8px;
|
|
211
|
-
min-height:
|
|
212
|
-
padding:
|
|
213
|
-
border:
|
|
214
|
-
|
|
215
|
-
background: var(--klc-color-background);
|
|
175
|
+
min-height: 40px;
|
|
176
|
+
padding: 8px 12px;
|
|
177
|
+
border-radius: 6px;
|
|
178
|
+
background: transparent;
|
|
216
179
|
color: var(--klc-color-foreground);
|
|
217
|
-
font-size:
|
|
218
|
-
line-height: 1.3;
|
|
180
|
+
font-size: 13px;
|
|
219
181
|
cursor: pointer;
|
|
220
|
-
transition:
|
|
221
|
-
border-color 0.18s ease,
|
|
222
|
-
background 0.18s ease,
|
|
223
|
-
box-shadow 0.18s ease;
|
|
182
|
+
transition: background 0.15s ease;
|
|
224
183
|
}
|
|
225
184
|
|
|
226
185
|
.color-item:hover {
|
|
227
|
-
|
|
228
|
-
background: var(--klc-color-tag-bg-hover);
|
|
229
|
-
box-shadow: 0 1px 4px color-mix(in srgb, var(--klc-color-foreground) 6%, transparent);
|
|
186
|
+
background: var(--klc-color-grid-minor);
|
|
230
187
|
}
|
|
231
188
|
|
|
232
|
-
.color-item
|
|
189
|
+
.color-item-text {
|
|
233
190
|
min-width: 0;
|
|
234
191
|
overflow: hidden;
|
|
235
192
|
text-overflow: ellipsis;
|
|
236
193
|
white-space: nowrap;
|
|
237
194
|
user-select: none;
|
|
195
|
+
line-height: 1.4;
|
|
238
196
|
}
|
|
239
197
|
|
|
240
|
-
/* ── 颜色输入 ── */
|
|
198
|
+
/* ── 颜色输入 (无边框圆角矩形) ── */
|
|
241
199
|
.color-input {
|
|
242
200
|
flex: 0 0 auto;
|
|
243
201
|
width: 26px;
|
|
244
202
|
height: 26px;
|
|
245
203
|
padding: 0;
|
|
246
|
-
border: 1px solid var(--klc-color-
|
|
204
|
+
border: 1px solid var(--klc-color-border-button);
|
|
247
205
|
border-radius: 6px;
|
|
248
206
|
background: transparent;
|
|
249
207
|
cursor: pointer;
|
|
250
|
-
transition:
|
|
251
|
-
|
|
252
|
-
box-shadow 0.18s ease;
|
|
208
|
+
transition: transform 0.15s ease;
|
|
209
|
+
overflow: hidden;
|
|
253
210
|
}
|
|
254
211
|
|
|
255
212
|
.color-input:hover {
|
|
256
|
-
|
|
257
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--klc-color-foreground) 6%, transparent);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
.color-input:focus-visible {
|
|
261
|
-
outline: none;
|
|
262
|
-
border-color: var(--klc-color-axis-text);
|
|
263
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--klc-color-foreground) 10%, transparent);
|
|
213
|
+
transform: scale(1.1);
|
|
264
214
|
}
|
|
265
215
|
|
|
266
216
|
.color-input::-webkit-color-swatch-wrapper {
|
|
267
|
-
padding:
|
|
217
|
+
padding: 0;
|
|
268
218
|
}
|
|
269
219
|
|
|
270
220
|
.color-input::-webkit-color-swatch {
|
|
271
221
|
border: none;
|
|
272
|
-
border-radius:
|
|
222
|
+
border-radius: 6px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.color-input::-moz-color-swatch {
|
|
226
|
+
border: none;
|
|
227
|
+
border-radius: 6px;
|
|
273
228
|
}
|
|
274
229
|
|
|
275
230
|
/* ── 响应式 ── */
|
|
276
231
|
@media (max-width: 480px) {
|
|
277
232
|
.color-preset-tools {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
.color-reset-btn {
|
|
282
|
-
width: 100%;
|
|
233
|
+
flex-direction: column;
|
|
234
|
+
align-items: stretch;
|
|
283
235
|
}
|
|
284
236
|
|
|
285
237
|
.color-grid {
|
|
@@ -332,12 +332,12 @@ onBeforeUnmount(() => document.removeEventListener('mousedown', onDocumentClick)
|
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
.compare-popover {
|
|
335
|
-
z-index:
|
|
335
|
+
z-index: 110;
|
|
336
336
|
width: min(360px, calc(100vw - 24px));
|
|
337
337
|
padding: 14px;
|
|
338
338
|
border: 1px solid var(--klc-color-border-button);
|
|
339
339
|
border-radius: 3px;
|
|
340
|
-
background: var(--klc-color-
|
|
340
|
+
background: var(--klc-color-background);
|
|
341
341
|
color: var(--klc-color-foreground);
|
|
342
342
|
|
|
343
343
|
box-sizing: border-box;
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
class="
|
|
4
|
-
@pointerdown.stop
|
|
5
|
-
@pointermove.stop
|
|
6
|
-
@pointerup.stop
|
|
7
|
-
>
|
|
8
|
-
<div class="toolbar-item color-item" title="颜色">
|
|
2
|
+
<CanvasToolbar>
|
|
3
|
+
<div class="color-item" title="颜色">
|
|
9
4
|
<span class="color-swatch" :style="{ background: drawing.style.stroke ?? '#2962ff' }"></span>
|
|
10
5
|
<input
|
|
11
6
|
type="color"
|
|
@@ -31,20 +26,35 @@
|
|
|
31
26
|
@update:model-value="onLineStyleChange($event as 'solid' | 'dashed' | 'dotted')"
|
|
32
27
|
/>
|
|
33
28
|
|
|
34
|
-
<button
|
|
35
|
-
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
class="toolbar-btn toolbar-btn--delete"
|
|
32
|
+
title="删除"
|
|
33
|
+
@click="$emit('delete')"
|
|
34
|
+
>
|
|
35
|
+
<svg
|
|
36
|
+
class="delete-icon"
|
|
37
|
+
viewBox="0 0 24 24"
|
|
38
|
+
fill="none"
|
|
39
|
+
stroke="currentColor"
|
|
40
|
+
stroke-width="2"
|
|
41
|
+
stroke-linecap="round"
|
|
42
|
+
stroke-linejoin="round"
|
|
43
|
+
aria-hidden="true"
|
|
44
|
+
>
|
|
36
45
|
<path d="M3 6h18" />
|
|
37
46
|
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
|
|
38
47
|
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
|
|
39
48
|
</svg>
|
|
40
49
|
</button>
|
|
41
|
-
</
|
|
50
|
+
</CanvasToolbar>
|
|
42
51
|
</template>
|
|
43
52
|
|
|
44
53
|
<script setup lang="ts">
|
|
45
54
|
import { onMounted, onUnmounted } from 'vue'
|
|
46
55
|
import type { DrawingObject, DrawingStyle } from '@363045841yyt/klinechart-core/plugin'
|
|
47
56
|
import Dropdown from './Dropdown.vue'
|
|
57
|
+
import CanvasToolbar from './common/CanvasToolbar.vue'
|
|
48
58
|
|
|
49
59
|
const widthOptions = [
|
|
50
60
|
{ label: '1px', value: '1' },
|
|
@@ -92,46 +102,29 @@ function onLineStyleChange(style: 'solid' | 'dashed' | 'dotted') {
|
|
|
92
102
|
</script>
|
|
93
103
|
|
|
94
104
|
<style scoped>
|
|
95
|
-
.
|
|
96
|
-
position:
|
|
97
|
-
left: 50%;
|
|
98
|
-
top: 8px;
|
|
99
|
-
transform: translateX(-50%);
|
|
100
|
-
display: flex;
|
|
101
|
-
align-items: center;
|
|
102
|
-
gap: 6px;
|
|
103
|
-
padding: 4px 8px;
|
|
104
|
-
height: 32px;
|
|
105
|
-
background: color-mix(in srgb, var(--klc-color-tag-bg-white) 88%, transparent);
|
|
106
|
-
backdrop-filter: blur(8px);
|
|
107
|
-
-webkit-backdrop-filter: blur(8px);
|
|
108
|
-
border: 1px solid var(--klc-color-border-button);
|
|
109
|
-
border-radius: 6px;
|
|
110
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
|
|
111
|
-
z-index: 100;
|
|
112
|
-
user-select: none;
|
|
113
|
-
pointer-events: auto;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.toolbar-item {
|
|
105
|
+
.color-item {
|
|
106
|
+
position: relative;
|
|
117
107
|
display: inline-flex;
|
|
118
108
|
align-items: center;
|
|
119
109
|
justify-content: center;
|
|
110
|
+
width: 26px;
|
|
111
|
+
height: 26px;
|
|
112
|
+
border-radius: 4px;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
transition: background 0.15s ease;
|
|
120
115
|
}
|
|
121
116
|
|
|
122
|
-
.color-item {
|
|
123
|
-
|
|
124
|
-
width: 24px;
|
|
125
|
-
height: 24px;
|
|
117
|
+
.color-item:hover {
|
|
118
|
+
background: var(--klc-color-grid-minor);
|
|
126
119
|
}
|
|
127
120
|
|
|
128
121
|
.color-swatch {
|
|
129
122
|
display: block;
|
|
130
|
-
width:
|
|
131
|
-
height:
|
|
132
|
-
border: 1px solid
|
|
123
|
+
width: 16px;
|
|
124
|
+
height: 16px;
|
|
125
|
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
133
126
|
border-radius: 4px;
|
|
134
|
-
|
|
127
|
+
pointer-events: none;
|
|
135
128
|
}
|
|
136
129
|
|
|
137
130
|
.color-input {
|
|
@@ -142,36 +135,4 @@ function onLineStyleChange(style: 'solid' | 'dashed' | 'dotted') {
|
|
|
142
135
|
width: 100%;
|
|
143
136
|
height: 100%;
|
|
144
137
|
}
|
|
145
|
-
|
|
146
|
-
.toolbar-btn {
|
|
147
|
-
display: inline-flex;
|
|
148
|
-
align-items: center;
|
|
149
|
-
justify-content: center;
|
|
150
|
-
width: 24px;
|
|
151
|
-
height: 24px;
|
|
152
|
-
padding: 0;
|
|
153
|
-
border: 1px solid transparent;
|
|
154
|
-
border-radius: 4px;
|
|
155
|
-
background: transparent;
|
|
156
|
-
color: var(--klc-color-axis-text);
|
|
157
|
-
cursor: pointer;
|
|
158
|
-
transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
.toolbar-btn:hover {
|
|
162
|
-
border-color: var(--klc-color-axis-line);
|
|
163
|
-
background: var(--klc-color-grid-minor);
|
|
164
|
-
color: var(--klc-color-foreground);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
.delete-btn:hover {
|
|
168
|
-
color: #dc2626;
|
|
169
|
-
border-color: #fca5a5;
|
|
170
|
-
background: #fef2f2;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
.delete-icon {
|
|
174
|
-
width: 14px;
|
|
175
|
-
height: 14px;
|
|
176
|
-
}
|
|
177
138
|
</style>
|
|
@@ -1,42 +1,34 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
</div>
|
|
15
|
-
<div class="export-body">
|
|
16
|
-
<div class="export-label">{{ progress.label }}</div>
|
|
17
|
-
<div class="export-bar-track">
|
|
18
|
-
<div
|
|
19
|
-
class="export-bar-fill"
|
|
20
|
-
:style="{ width: pct + '%' }"
|
|
21
|
-
/>
|
|
22
|
-
</div>
|
|
23
|
-
<div class="export-counter">{{ progress.current }} / {{ progress.total }}</div>
|
|
24
|
-
<button
|
|
25
|
-
v-if="progress.current === progress.total"
|
|
26
|
-
class="export-done-btn"
|
|
27
|
-
@click="emit('close')"
|
|
28
|
-
>完成</button>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
</Transition>
|
|
2
|
+
<BaseModal
|
|
3
|
+
title="导出数据"
|
|
4
|
+
:show="!!progress"
|
|
5
|
+
:z-index="1100"
|
|
6
|
+
:close-on-overlay="false"
|
|
7
|
+
footer-align="center"
|
|
8
|
+
@close="emit('close')"
|
|
9
|
+
>
|
|
10
|
+
<div class="export-body">
|
|
11
|
+
<div class="export-label">{{ progress?.label }}</div>
|
|
12
|
+
<div class="export-bar-track">
|
|
13
|
+
<div class="export-bar-fill" :style="{ width: pct + '%' }" />
|
|
32
14
|
</div>
|
|
33
|
-
|
|
34
|
-
|
|
15
|
+
<div class="export-counter">{{ progress?.current ?? 0 }} / {{ progress?.total ?? 0 }}</div>
|
|
16
|
+
</div>
|
|
17
|
+
<template #footer>
|
|
18
|
+
<button
|
|
19
|
+
v-if="progress && progress.current === progress.total"
|
|
20
|
+
class="export-done-btn"
|
|
21
|
+
@click="emit('close')"
|
|
22
|
+
>
|
|
23
|
+
完成
|
|
24
|
+
</button>
|
|
25
|
+
</template>
|
|
26
|
+
</BaseModal>
|
|
35
27
|
</template>
|
|
36
28
|
|
|
37
29
|
<script setup lang="ts">
|
|
38
30
|
import { computed } from 'vue'
|
|
39
|
-
import
|
|
31
|
+
import BaseModal from './BaseModal.vue'
|
|
40
32
|
|
|
41
33
|
const props = defineProps<{
|
|
42
34
|
progress: { current: number; total: number; label: string } | null
|
|
@@ -46,8 +38,6 @@ const emit = defineEmits<{
|
|
|
46
38
|
close: []
|
|
47
39
|
}>()
|
|
48
40
|
|
|
49
|
-
const teleportTarget = useFullscreenTeleportTarget()
|
|
50
|
-
|
|
51
41
|
const pct = computed(() => {
|
|
52
42
|
if (!props.progress || props.progress.total <= 0) return 0
|
|
53
43
|
return Math.min(100, Math.round((props.progress.current / props.progress.total) * 100))
|
|
@@ -55,76 +45,7 @@ const pct = computed(() => {
|
|
|
55
45
|
</script>
|
|
56
46
|
|
|
57
47
|
<style scoped>
|
|
58
|
-
.export-overlay {
|
|
59
|
-
position: fixed;
|
|
60
|
-
inset: 0;
|
|
61
|
-
background: rgba(0, 0, 0, 0.3);
|
|
62
|
-
backdrop-filter: blur(4px);
|
|
63
|
-
padding: 24px;
|
|
64
|
-
display: flex;
|
|
65
|
-
align-items: center;
|
|
66
|
-
justify-content: center;
|
|
67
|
-
z-index: 1100;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.export-modal {
|
|
71
|
-
background: var(--klc-color-tag-bg-white);
|
|
72
|
-
border: 1px solid var(--klc-color-border-button);
|
|
73
|
-
border-radius: 10px;
|
|
74
|
-
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.15);
|
|
75
|
-
min-width: 320px;
|
|
76
|
-
max-width: 380px;
|
|
77
|
-
width: min(88vw, 380px);
|
|
78
|
-
overflow: hidden;
|
|
79
|
-
display: flex;
|
|
80
|
-
flex-direction: column;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
.export-header {
|
|
84
|
-
display: flex;
|
|
85
|
-
justify-content: space-between;
|
|
86
|
-
align-items: center;
|
|
87
|
-
padding: 14px 18px 0 20px;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.export-title {
|
|
91
|
-
font-size: 15px;
|
|
92
|
-
font-weight: 600;
|
|
93
|
-
color: var(--klc-color-foreground);
|
|
94
|
-
line-height: 1.35;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.export-close-btn {
|
|
98
|
-
background: var(--klc-color-tag-bg-white);
|
|
99
|
-
border: 1px solid var(--klc-color-border-button);
|
|
100
|
-
border-radius: 7px;
|
|
101
|
-
width: 30px;
|
|
102
|
-
height: 30px;
|
|
103
|
-
display: flex;
|
|
104
|
-
align-items: center;
|
|
105
|
-
justify-content: center;
|
|
106
|
-
cursor: pointer;
|
|
107
|
-
color: var(--klc-color-axis-text);
|
|
108
|
-
transition:
|
|
109
|
-
background 0.15s,
|
|
110
|
-
color 0.15s,
|
|
111
|
-
border-color 0.15s;
|
|
112
|
-
padding: 0;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
.export-close-btn:hover {
|
|
116
|
-
background: var(--klc-color-tag-bg-hover);
|
|
117
|
-
color: var(--klc-color-foreground);
|
|
118
|
-
border-color: var(--klc-color-axis-line);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
.export-close-btn svg {
|
|
122
|
-
width: 14px;
|
|
123
|
-
height: 14px;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
48
|
.export-body {
|
|
127
|
-
padding: 16px 20px 24px;
|
|
128
49
|
display: flex;
|
|
129
50
|
flex-direction: column;
|
|
130
51
|
gap: 10px;
|
|
@@ -175,7 +96,6 @@ const pct = computed(() => {
|
|
|
175
96
|
background: var(--klc-color-foreground);
|
|
176
97
|
border-color: var(--klc-color-foreground);
|
|
177
98
|
color: var(--klc-color-background);
|
|
178
|
-
align-self: center;
|
|
179
99
|
transition:
|
|
180
100
|
background 0.15s,
|
|
181
101
|
box-shadow 0.15s,
|
|
@@ -195,32 +115,4 @@ const pct = computed(() => {
|
|
|
195
115
|
transform: translateY(0);
|
|
196
116
|
box-shadow: none;
|
|
197
117
|
}
|
|
198
|
-
|
|
199
|
-
.overlay-enter-active,
|
|
200
|
-
.overlay-leave-active {
|
|
201
|
-
transition: opacity 0.2s ease;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
.overlay-enter-from,
|
|
205
|
-
.overlay-leave-to {
|
|
206
|
-
opacity: 0;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.modal-enter-active {
|
|
210
|
-
transition: all 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.modal-leave-active {
|
|
214
|
-
transition: all 0.16s ease-in;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
.modal-enter-from {
|
|
218
|
-
opacity: 0;
|
|
219
|
-
transform: scale(0.96) translateY(-10px);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.modal-leave-to {
|
|
223
|
-
opacity: 0;
|
|
224
|
-
transform: scale(0.98) translateY(8px);
|
|
225
|
-
}
|
|
226
118
|
</style>
|