@363045841yyt/klinechart 0.8.3 → 0.8.5

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.
Files changed (51) hide show
  1. package/dist/components/BatchStockDialog.vue.d.ts +13 -0
  2. package/dist/components/BatchStockDialog.vue.d.ts.map +1 -0
  3. package/dist/components/CompareSymbolSelector.vue.d.ts.map +1 -1
  4. package/dist/components/Dropdown.vue.d.ts.map +1 -1
  5. package/dist/components/ExportProgressDialog.vue.d.ts +15 -0
  6. package/dist/components/ExportProgressDialog.vue.d.ts.map +1 -0
  7. package/dist/components/IndicatorSelector.vue.d.ts.map +1 -1
  8. package/dist/components/KLineChart.vue.d.ts +5 -9
  9. package/dist/components/KLineChart.vue.d.ts.map +1 -1
  10. package/dist/components/LeftToolbar.vue.d.ts.map +1 -1
  11. package/dist/components/SymbolSelector.vue.d.ts.map +1 -1
  12. package/dist/components/TopToolbar.vue.d.ts.map +1 -1
  13. package/dist/composables/chart/useChartTheme.d.ts +329 -0
  14. package/dist/composables/chart/useChartTheme.d.ts.map +1 -0
  15. package/dist/composables/chart/useDrawingManager.d.ts +86 -0
  16. package/dist/composables/chart/useDrawingManager.d.ts.map +1 -0
  17. package/dist/composables/chart/useIndicatorManager.d.ts +38 -0
  18. package/dist/composables/chart/useIndicatorManager.d.ts.map +1 -0
  19. package/dist/composables/chart/useRangeSelection.d.ts +65 -0
  20. package/dist/composables/chart/useRangeSelection.d.ts.map +1 -0
  21. package/dist/composables/useTeleportedPopup.d.ts +8 -0
  22. package/dist/composables/useTeleportedPopup.d.ts.map +1 -0
  23. package/dist/index.cjs +9 -2
  24. package/dist/index.css +1 -1
  25. package/dist/index.d.cts +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1769 -1090
  29. package/dist/tools/calcRangeOverlayPixel.d.ts +15 -0
  30. package/dist/tools/calcRangeOverlayPixel.d.ts.map +1 -0
  31. package/dist/tools/getKLineIndexByTimestamp.d.ts +4 -0
  32. package/dist/tools/getKLineIndexByTimestamp.d.ts.map +1 -0
  33. package/dist/web-component.d.ts.map +1 -1
  34. package/package.json +1 -1
  35. package/src/components/BatchStockDialog.vue +293 -0
  36. package/src/components/CompareSymbolSelector.vue +35 -8
  37. package/src/components/Dropdown.vue +42 -19
  38. package/src/components/ExportProgressDialog.vue +226 -0
  39. package/src/components/IndicatorSelector.vue +13 -5
  40. package/src/components/KLineChart.vue +329 -399
  41. package/src/components/LeftToolbar.vue +2 -1
  42. package/src/components/SymbolSelector.vue +35 -8
  43. package/src/components/TopToolbar.vue +55 -2
  44. package/src/composables/chart/useChartTheme.ts +86 -0
  45. package/src/composables/chart/useDrawingManager.ts +67 -0
  46. package/src/composables/chart/useIndicatorManager.ts +307 -0
  47. package/src/composables/chart/useRangeSelection.ts +417 -0
  48. package/src/composables/useTeleportedPopup.ts +33 -0
  49. package/src/index.ts +41 -14
  50. package/src/tools/calcRangeOverlayPixel.ts +28 -0
  51. package/src/tools/getKLineIndexByTimestamp.ts +40 -0
@@ -0,0 +1,226 @@
1
+ <template>
2
+ <Teleport :to="teleportTarget">
3
+ <Transition name="overlay">
4
+ <div v-if="progress" class="export-overlay">
5
+ <Transition name="modal">
6
+ <div class="export-modal" @click.stop>
7
+ <div class="export-header">
8
+ <span class="export-title">导出数据</span>
9
+ <button class="export-close-btn" @click="emit('close')">
10
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
11
+ <path d="M18 6L6 18M6 6l12 12" />
12
+ </svg>
13
+ </button>
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>
32
+ </div>
33
+ </Transition>
34
+ </Teleport>
35
+ </template>
36
+
37
+ <script setup lang="ts">
38
+ import { computed } from 'vue'
39
+ import { useFullscreenTeleportTarget } from '../composables/useFullscreenTeleportTarget'
40
+
41
+ const props = defineProps<{
42
+ progress: { current: number; total: number; label: string } | null
43
+ }>()
44
+
45
+ const emit = defineEmits<{
46
+ close: []
47
+ }>()
48
+
49
+ const teleportTarget = useFullscreenTeleportTarget()
50
+
51
+ const pct = computed(() => {
52
+ if (!props.progress || props.progress.total <= 0) return 0
53
+ return Math.min(100, Math.round((props.progress.current / props.progress.total) * 100))
54
+ })
55
+ </script>
56
+
57
+ <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
+ .export-body {
127
+ padding: 16px 20px 24px;
128
+ display: flex;
129
+ flex-direction: column;
130
+ gap: 10px;
131
+ }
132
+
133
+ .export-label {
134
+ font-size: 13px;
135
+ color: var(--klc-color-axis-text);
136
+ line-height: 1.4;
137
+ white-space: nowrap;
138
+ overflow: hidden;
139
+ text-overflow: ellipsis;
140
+ }
141
+
142
+ .export-bar-track {
143
+ width: 100%;
144
+ height: 6px;
145
+ background: var(--klc-color-grid-major);
146
+ border-radius: 999px;
147
+ overflow: hidden;
148
+ }
149
+
150
+ .export-bar-fill {
151
+ height: 100%;
152
+ background: var(--klc-color-foreground);
153
+ border-radius: 999px;
154
+ transition: width 0.25s ease;
155
+ }
156
+
157
+ .export-counter {
158
+ font-size: 12px;
159
+ color: var(--klc-color-axis-text);
160
+ text-align: right;
161
+ font-variant-numeric: tabular-nums;
162
+ }
163
+
164
+ .export-done-btn {
165
+ display: flex;
166
+ align-items: center;
167
+ justify-content: center;
168
+ height: 32px;
169
+ padding: 0 20px;
170
+ border-radius: 7px;
171
+ font-size: 13px;
172
+ font-weight: 500;
173
+ cursor: pointer;
174
+ border: 1px solid transparent;
175
+ background: var(--klc-color-foreground);
176
+ border-color: var(--klc-color-foreground);
177
+ color: var(--klc-color-background);
178
+ align-self: center;
179
+ transition:
180
+ background 0.15s,
181
+ box-shadow 0.15s,
182
+ transform 0.15s;
183
+ line-height: 1;
184
+ white-space: nowrap;
185
+ }
186
+
187
+ .export-done-btn:hover {
188
+ background: var(--klc-color-foreground);
189
+ border-color: var(--klc-color-foreground);
190
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
191
+ transform: translateY(-1px);
192
+ }
193
+
194
+ .export-done-btn:active {
195
+ transform: translateY(0);
196
+ box-shadow: none;
197
+ }
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
+ </style>
@@ -219,6 +219,8 @@ import {
219
219
  allIndicators,
220
220
  findIndicator,
221
221
  type Indicator,
222
+ loadBuiltinIndicators,
223
+ isBuiltinIndicatorsLoaded,
222
224
  } from '@363045841yyt/klinechart-core/controllers'
223
225
 
224
226
  const props = defineProps<{
@@ -233,7 +235,7 @@ const emit = defineEmits<{
233
235
  }>()
234
236
 
235
237
  // ── 将 Indicator[] 转换为 IndicatorDefinition[] ──
236
- function toIndicatorDefinitions(source: typeof allIndicators): IndicatorDefinition[] {
238
+ function toIndicatorDefinitions(source: Indicator[]): IndicatorDefinition[] {
237
239
  return source.map((i) => ({
238
240
  id: i.id,
239
241
  label: i.label,
@@ -253,9 +255,7 @@ function toIndicatorDefinitions(source: typeof allIndicators): IndicatorDefiniti
253
255
  }
254
256
 
255
257
  // ── Controller ──
256
- const controller = createIndicatorSelectorController({
257
- catalog: toIndicatorDefinitions(allIndicators),
258
- })
258
+ const controller = createIndicatorSelectorController()
259
259
 
260
260
  // ── 从 Controller Signal 桥接的 Vue 响应式状态 ──
261
261
  const menuOpen = coreSignalToVueRef(controller.menuOpen)
@@ -267,7 +267,15 @@ const hasSearchResults = computed(
267
267
  () => filteredMain.value.length > 0 || filteredSub.value.length > 0,
268
268
  )
269
269
 
270
- const catalogLen = controller.catalog.peek().length
270
+ const catalog = coreSignalToVueRef(controller.catalog)
271
+ const catalogLen = computed(() => catalog.value.length)
272
+
273
+ onMounted(async () => {
274
+ if (!isBuiltinIndicatorsLoaded()) {
275
+ await loadBuiltinIndicators()
276
+ }
277
+ controller.catalog.set(toIndicatorDefinitions(allIndicators()))
278
+ })
271
279
 
272
280
  // ── 本地 UI 状态(非 Controller 管理的纯 UI 状态) ──
273
281
  const paramsVisible = ref(false)