@363045841yyt/klinechart 0.8.1 → 0.8.2

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.
@@ -1,6 +1,6 @@
1
1
  import { SemanticChartConfig, DataFetcher } from '@363045841yyt/klinechart-core/semantic';
2
2
  declare const KLineChartElement: import('vue').VueElementConstructor<{
3
- semanticConfig: SemanticChartConfig;
3
+ semanticConfig?: SemanticChartConfig;
4
4
  dataFetcher: DataFetcher;
5
5
  yPaddingPx?: number;
6
6
  minKWidth?: number;
@@ -11,6 +11,7 @@ declare const KLineChartElement: import('vue').VueElementConstructor<{
11
11
  zoomLevels?: number;
12
12
  initialZoomLevel?: number;
13
13
  isFullscreen?: boolean;
14
+ timezone?: string;
14
15
  }>;
15
16
  export { KLineChartElement };
16
17
  export default KLineChartElement;
@@ -1 +1 @@
1
- {"version":3,"file":"web-component.d.ts","sourceRoot":"","sources":["../src/web-component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAE9F,QAAA,MAAM,iBAAiB;;;;;;;;;;;;EAErB,CAAA;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA;AAEhC,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"web-component.d.ts","sourceRoot":"","sources":["../src/web-component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAE9F,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;EAErB,CAAA;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA;AAEhC,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@363045841yyt/klinechart",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Vue 3 bindings for @363045841yyt/klinechart-core. Idiomatic composables, SFC components.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <Dropdown
3
+ :model-value="modelValue"
4
+ :options="adjustmentOptions"
5
+ label="复权"
6
+ title="复权方式"
7
+ size="md"
8
+ @update:model-value="emit('update:modelValue', $event as KLineAdjustment)"
9
+ />
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import Dropdown from './Dropdown.vue'
14
+ import type { AdjustType } from '@363045841yyt/klinechart-core/semantic'
15
+
16
+ export type KLineAdjustment = AdjustType
17
+
18
+ const adjustmentOptions: Array<{ label: string; value: KLineAdjustment }> = [
19
+ { label: '前复权', value: 'qfq' },
20
+ { label: '后复权', value: 'hfq' },
21
+ { label: '仅拆股', value: 'splits' },
22
+ { label: '不复权', value: 'none' },
23
+ ]
24
+
25
+ defineProps<{
26
+ modelValue?: string
27
+ }>()
28
+
29
+ const emit = defineEmits<{
30
+ (e: 'update:modelValue', adjust: KLineAdjustment): void
31
+ }>()
32
+ </script>
@@ -3,6 +3,7 @@
3
3
  <TopToolbar
4
4
  :symbol="currentSymbol"
5
5
  :k-line-level="kLineLevel"
6
+ :k-line-adjust="kLineAdjust"
6
7
  :symbol-loading="symbolLoading"
7
8
  :symbol-error="symbolError"
8
9
  :overlay-symbols="overlaySymbols"
@@ -11,6 +12,7 @@
11
12
  @add-overlay-symbol="onAddOverlaySymbol"
12
13
  @remove-overlay-symbol="onRemoveOverlaySymbol"
13
14
  @k-line-level-change="onKLineLevelChange"
15
+ @k-line-adjust-change="onKLineAdjustChange"
14
16
  @toggle-indicator="onToggleIndicator"
15
17
  @symbol-change="onSymbolChange"
16
18
  />
@@ -91,6 +93,8 @@
91
93
  :anchor-placement="tooltipAnchorPlacement"
92
94
  :up-color="tooltipColors.upColor"
93
95
  :down-color="tooltipColors.downColor"
96
+ :timezone="props.timezone"
97
+ :show-time="isIntraday"
94
98
  />
95
99
  <MarkerTooltip
96
100
  v-if="hoveredMarker || hoveredCustomMarker"
@@ -168,8 +172,8 @@ import TopToolbar, { type SymbolItem } from './TopToolbar.vue'
168
172
 
169
173
  const props = withDefaults(
170
174
  defineProps<{
171
- /** 语义化配置(必需,唯一控制源) */
172
- semanticConfig: SemanticChartConfig
175
+ /** 语义化配置(可选,唯一控制源) */
176
+ semanticConfig?: SemanticChartConfig
173
177
 
174
178
  /** 数据获取函数(必需)。框架不绑定数据源,由使用者注入。 */
175
179
  dataFetcher: DataFetcher
@@ -190,6 +194,8 @@ const props = withDefaults(
190
194
  initialZoomLevel?: number
191
195
  /** 是否全屏 */
192
196
  isFullscreen?: boolean
197
+ /** 时区,默认 Asia/Shanghai */
198
+ timezone?: string
193
199
  }>(),
194
200
  {
195
201
  yPaddingPx: 20,
@@ -201,6 +207,7 @@ const props = withDefaults(
201
207
  zoomLevels: 20,
202
208
  initialZoomLevel: 3,
203
209
  isFullscreen: false,
210
+ timezone: 'Asia/Shanghai',
204
211
  },
205
212
  )
206
213
 
@@ -209,9 +216,12 @@ const emit = defineEmits<{
209
216
  (e: 'toggleFullscreen'): void
210
217
  (e: 'themeChange', theme: 'light' | 'dark'): void
211
218
  (e: 'kLineLevelChange', level: string): void
219
+ (e: 'kLineAdjustChange', adjust: 'qfq' | 'hfq' | 'splits' | 'none'): void
212
220
  }>()
213
221
 
214
- const kLineLevel = ref(props.semanticConfig.data.period)
222
+ const kLineLevel = ref(props.semanticConfig?.data?.period ?? 'daily')
223
+ const kLineAdjust = ref(props.semanticConfig?.data?.adjust ?? 'none')
224
+ const isIntraday = computed(() => kLineLevel.value.includes('min'))
215
225
  const currentSymbol = ref('选择商品')
216
226
  const currentSymbolItem = ref<SymbolItem | null>(null)
217
227
  const symbolLoading = ref(false)
@@ -225,6 +235,12 @@ function onKLineLevelChange(level: string) {
225
235
  syncSymbolsToController()
226
236
  }
227
237
 
238
+ function onKLineAdjustChange(adjust: 'qfq' | 'hfq' | 'splits' | 'none') {
239
+ kLineAdjust.value = adjust
240
+ emit('kLineAdjustChange', adjust)
241
+ syncSymbolsToController()
242
+ }
243
+
228
244
  function onSymbolChange(item: SymbolItem) {
229
245
  symbolError.value = false
230
246
  currentSymbol.value = item.code
@@ -253,9 +269,9 @@ function toSymbolSpec(item: SymbolItem): SymbolSpec {
253
269
  exchange: item.exchange,
254
270
  period: kLineLevel.value,
255
271
  source: item.source,
256
- startDate: props.semanticConfig.data.startDate,
257
- endDate: props.semanticConfig.data.endDate,
258
- adjust: props.semanticConfig.data.adjust,
272
+ startDate: props.semanticConfig?.data?.startDate ?? '',
273
+ endDate: props.semanticConfig?.data?.endDate ?? '',
274
+ adjust: kLineAdjust.value,
259
275
  }
260
276
  }
261
277
 
@@ -706,7 +722,7 @@ function clearAllSubPanes(): void {
706
722
  function initIndicatorsFromConfig(): void {
707
723
  const config = props.semanticConfig
708
724
  const c = controller.value
709
- if (!c) return
725
+ if (!config || !c) return
710
726
 
711
727
  const mainIndicators = config.indicators?.main
712
728
  if (mainIndicators) {
@@ -18,12 +18,14 @@ export type KLineLevel =
18
18
  | '15min'
19
19
  | '30min'
20
20
  | '60min'
21
+ | 'daily'
21
22
  | 'weekly'
22
23
  | 'monthly'
23
24
  | 'quarterly'
24
25
  | 'yearly'
25
26
 
26
27
  const kLineLevelOptions: Array<{ label: string; value: KLineLevel }> = [
28
+ { label: '1day', value: 'daily' },
27
29
  { label: '1min', value: '1min' },
28
30
  { label: '5min', value: '5min' },
29
31
  { label: '15min', value: '15min' },
@@ -8,7 +8,7 @@
8
8
  >
9
9
  <div class="kline-tooltip__title">
10
10
  <span v-if="k.stockCode">{{ k.stockCode }}</span>
11
- <span>{{ formatDate(k.timestamp) }}</span>
11
+ <span>{{ formattedDate }}</span>
12
12
  </div>
13
13
  <div class="kline-tooltip__grid">
14
14
  <div class="row">
@@ -51,6 +51,7 @@
51
51
  <script setup lang="ts">
52
52
  import { computed } from 'vue'
53
53
  import type { ComponentPublicInstance } from 'vue'
54
+ import { formatTimestamp } from '@363045841yyt/klinechart-core'
54
55
 
55
56
  export interface KLineData {
56
57
  timestamp: number
@@ -79,9 +80,23 @@ const props = withDefaults(defineProps<{
79
80
  upColor?: string
80
81
  /** 跌的颜色(默认绿跌) */
81
82
  downColor?: string
83
+ /** 时区,默认 Asia/Shanghai */
84
+ timezone?: string
85
+ /** 是否显示时分,默认 false */
86
+ showTime?: boolean
82
87
  }>(), {
83
88
  upColor: '#ef4444',
84
89
  downColor: '#22c55e',
90
+ timezone: 'Asia/Shanghai',
91
+ showTime: false,
92
+ })
93
+
94
+ const formattedDate = computed(() => {
95
+ if (!props.k) return ''
96
+ return formatTimestamp(props.k.timestamp, {
97
+ timeZone: props.timezone,
98
+ showTime: props.showTime,
99
+ })
85
100
  })
86
101
 
87
102
  const useAnchor = computed(() => props.useAnchor === true)
@@ -93,14 +108,6 @@ function onRef(el: Element | ComponentPublicInstance | null) {
93
108
  props.setEl?.(el as HTMLDivElement | null)
94
109
  }
95
110
 
96
- function formatDate(ts: number): string {
97
- const d = new Date(ts)
98
- const y = d.getFullYear()
99
- const m = String(d.getMonth() + 1).padStart(2, '0')
100
- const day = String(d.getDate()).padStart(2, '0')
101
- return `${y}-${m}-${day}`
102
- }
103
-
104
111
  function formatVolume(v: number): string {
105
112
  if (v >= 1e8) return (v / 1e8).toFixed(2) + '亿'
106
113
  if (v >= 1e4) return (v / 1e4).toFixed(2) + '万'
@@ -464,6 +464,8 @@ watch(() => props.symbol, () => {
464
464
  }
465
465
 
466
466
  .symbol-chip__spinner {
467
+ display: inline-block;
468
+ flex-shrink: 0;
467
469
  width: 12px;
468
470
  height: 12px;
469
471
  border: 2px solid var(--klc-color-axis-text);
@@ -20,6 +20,10 @@
20
20
  :model-value="kLineLevel"
21
21
  @update:model-value="emit('kLineLevelChange', $event)"
22
22
  />
23
+ <KLineAdjustmentDropdown
24
+ :model-value="kLineAdjust"
25
+ @update:model-value="emit('kLineAdjustChange', $event)"
26
+ />
23
27
  <button
24
28
  type="button"
25
29
  class="indicator-button"
@@ -36,6 +40,7 @@
36
40
  <script setup lang="ts">
37
41
  import { computed } from 'vue'
38
42
  import KLineLevelDropdown, { type KLineLevel } from './KLineLevelDropdown.vue'
43
+ import KLineAdjustmentDropdown, { type KLineAdjustment } from './KLineAdjustmentDropdown.vue'
39
44
  import SymbolSelector from './SymbolSelector.vue'
40
45
  import CompareSymbolSelector from './CompareSymbolSelector.vue'
41
46
  import type { SymbolItem } from './SymbolSelector.vue'
@@ -45,6 +50,7 @@ export type { SymbolItem }
45
50
  const props = defineProps<{
46
51
  symbol?: string
47
52
  kLineLevel?: string
53
+ kLineAdjust?: string
48
54
  symbols?: SymbolItem[]
49
55
  symbolLoading?: boolean
50
56
  symbolError?: boolean
@@ -57,30 +63,29 @@ const emit = defineEmits<{
57
63
  (e: 'addOverlaySymbol', item: SymbolItem): void
58
64
  (e: 'removeOverlaySymbol', code: string): void
59
65
  (e: 'kLineLevelChange', level: KLineLevel): void
66
+ (e: 'kLineAdjustChange', adjust: KLineAdjustment): void
60
67
  (e: 'toggleIndicator'): void
61
68
  (e: 'symbolChange', symbol: SymbolItem): void
62
69
  }>()
63
70
 
64
71
  const MOCK_SYMBOLS: SymbolItem[] = [
65
72
  // ── TradingView 全球品种 ──
66
- { code: 'XAUUSD', description: '现货黄金', exchange: 'OANDA', source: 'tradingview' },
67
- { code: 'BTCUSDT', description: 'Bitcoin / Tether', exchange: 'BINANCE', source: 'tradingview' },
68
- { code: 'ETHUSDT', description: 'Ethereum / Tether', exchange: 'BINANCE', source: 'tradingview' },
69
- { code: 'EURUSD', description: '欧元/美元', exchange: 'OANDA', source: 'tradingview' },
70
- { code: 'SPX', description: '标普 500 指数', exchange: 'SP', source: 'tradingview' },
71
- { code: 'AAPL', description: 'Apple Inc.', exchange: 'NASDAQ', source: 'tradingview' },
72
- { code: 'TSLA', description: 'Tesla, Inc.', exchange: 'NASDAQ', source: 'tradingview' },
73
- { code: '600519', description: '贵州茅台', exchange: 'SSE', source: 'tradingview' },
74
- { code: '000001', description: '平安银行', exchange: 'SZSE', source: 'tradingview' },
75
- { code: '1810', description: '小米集团', exchange: 'HKEX', source: 'tradingview' },
76
- // ── Baostock A ──
77
- { code: 'sh.600519', description: '贵州茅台', exchange: 'SSE', source: 'baostock' },
78
- { code: 'sh.601360', description: '三六零', exchange: 'SSE', source: 'baostock' },
79
- { code: '000858', description: '五 粮 液', exchange: 'SZSE', source: 'baostock' },
80
- { code: '000001', description: '平安银行', exchange: 'SZSE', source: 'baostock' },
73
+ { code: 'XAUUSD', description: '现货黄金', exchange: 'OANDA', source: 'tradingview' },
74
+ { code: 'BTCUSDT', description: 'Bitcoin / Tether', exchange: 'BINANCE', source: 'tradingview' },
75
+ { code: 'ETHUSDT', description: 'Ethereum / Tether', exchange: 'BINANCE', source: 'tradingview' },
76
+ { code: 'EURUSD', description: '欧元/美元', exchange: 'OANDA', source: 'tradingview' },
77
+ { code: 'SPX', description: '标普 500 指数', exchange: 'SP', source: 'tradingview' },
78
+ { code: 'AAPL', description: 'Apple Inc.', exchange: 'NASDAQ', source: 'tradingview' },
79
+ { code: 'TSLA', description: 'Tesla, Inc.', exchange: 'NASDAQ', source: 'tradingview' },
80
+ { code: '1810', description: '小米集团', exchange: 'HKEX', source: 'tradingview' },
81
+ // ── gotdx A ──
82
+ { code: '600519', description: '贵州茅台', exchange: 'SSE', source: 'gotdx' },
83
+ { code: '601360', description: '三六零', exchange: 'SSE', source: 'gotdx' },
84
+ { code: '000858', description: '五 粮 液', exchange: 'SZSE', source: 'gotdx' },
85
+ { code: '000001', description: '平安银行', exchange: 'SZSE', source: 'gotdx' },
81
86
  // ── Mock ──
82
- { code: 'MOCK-100', description: 'Mock 100 条', exchange: 'MOCK', source: 'mock-100' },
83
- { code: 'MOCK-10000', description: 'Mock 10000 条', exchange: 'MOCK', source: 'mock-10000' },
87
+ { code: 'MOCK-100', description: 'Mock 100 条', exchange: 'MOCK', source: 'mock-100' },
88
+ { code: 'MOCK-10000', description: 'Mock 10000 条', exchange: 'MOCK', source: 'mock-10000' },
84
89
  ]
85
90
 
86
91
  const displaySymbol = computed(() => props.symbol?.trim() ?? '')