From 51feb991b83159bc4b7e1c74abf41cb882d9ec40 Mon Sep 17 00:00:00 2001 From: Seven Date: Sun, 28 Dec 2025 17:59:40 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E8=A7=86=E5=9B=BE=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=88=90=E4=BA=A4?= =?UTF-8?q?=E9=87=8F=E6=95=B0=E6=8D=AE=E6=94=AF=E6=8C=81=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=94=A8=E6=88=B7=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auto-imports.d.ts | 2 +- src/composables/useTradingView.ts | 63 +++++- src/ui/tabs/index.vue | 15 +- src/views/market/index.vue | 25 ++- src/views/system-settings/outlet.vue | 10 +- src/views/trade-settings/my-issues/outlet.vue | 9 +- src/views/trade/index.vue | 185 ++++++++---------- src/views/user-settings/outlet.vue | 2 +- 8 files changed, 172 insertions(+), 139 deletions(-) diff --git a/auto-imports.d.ts b/auto-imports.d.ts index cd777b1..e077f5d 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -358,7 +358,7 @@ declare global { export type { ThemeMode } from './src/composables/useTheme' import('./src/composables/useTheme') // @ts-ignore - export type { Series, TData, WeightChartOptions, TradingViewData, TradingViewOptions } from './src/composables/useTradingView' + export type { Series, TData, WeightChartOptions, TradingViewData, VolumeData, TradingViewOptions } from './src/composables/useTradingView' import('./src/composables/useTradingView') // @ts-ignore export type { HapticsOptions } from './src/composables/useVibrate' diff --git a/src/composables/useTradingView.ts b/src/composables/useTradingView.ts index 565160f..4b16ca1 100644 --- a/src/composables/useTradingView.ts +++ b/src/composables/useTradingView.ts @@ -1,5 +1,5 @@ import type { Awaitable } from "@vueuse/core"; -import type { ChartOptions, DeepPartial, IChartApi, ISeriesApi, LayoutOptions, SeriesDataItemTypeMap, SeriesType } from "lightweight-charts"; +import type { ChartOptions, DeepPartial, HistogramData, IChartApi, ISeriesApi, LayoutOptions, SeriesDataItemTypeMap, SeriesType, Time } from "lightweight-charts"; import type { ThemeMode } from "./useTheme"; import { AreaSeries, BarSeries, BaselineSeries, CandlestickSeries, ColorType, createChart, HistogramSeries, LineSeries } from "lightweight-charts"; import { cloneDeep, mergeWith } from "lodash-es"; @@ -12,12 +12,19 @@ export type WeightChartOptions = DeepPartial; export type TradingViewData = (() => Awaitable) | MaybeRefOrGetter; +export interface VolumeData extends HistogramData { + value: number; + color?: string; +} + export interface TradingViewOptions { theme?: ThemeMode; type?: T; data?: TradingViewData; + volumeData?: MaybeRefOrGetter; weightChartOptions?: MaybeRefOrGetter; autosize?: boolean; + showVolume?: boolean; } const lightThemeLayout: Partial = { @@ -34,11 +41,13 @@ const initializeOptions: Required = { theme: "dark", type: "Candlestick", data: [], + volumeData: [], weightChartOptions: { width: 400, height: 300, }, autosize: true, + showVolume: true, }; function getChartSeriesDefinition(type: Series) { @@ -68,6 +77,7 @@ export function useTradingView(target: MaybeRefOrGetter, opt const chartSeriesDefinition = getChartSeriesDefinition(opts.type); const chartEl = ref(null); const series = ref | null>(null); + const volumeSeries = ref | null>(null); function fitContent() { chart.value?.timeScale().fitContent(); @@ -103,6 +113,13 @@ export function useTradingView(target: MaybeRefOrGetter, opt } } + function setVolumeData(data: MaybeRefOrGetter) { + if (!volumeSeries.value) + return; + const volumeData = toValue(data); + volumeSeries.value.setData(volumeData); + } + function changeTheme(theme: ThemeMode) { if (!chart.value) return; @@ -115,11 +132,43 @@ export function useTradingView(target: MaybeRefOrGetter, opt if (!el) return; chartEl.value = el; - chart.value = createChart(el, toValue(opts.weightChartOptions)); - series.value = chart.value.addSeries(chartSeriesDefinition); + + const chartOptions = toValue(opts.weightChartOptions); + chart.value = createChart(el, chartOptions); + series.value = chart.value.addSeries(chartSeriesDefinition, { + priceFormat: { + type: "price", + precision: 1, + }, + }); + + // 添加成交量副图 + if (opts.showVolume) { + volumeSeries.value = chart.value.addSeries(HistogramSeries, { + priceFormat: { + type: "volume", + }, + priceScaleId: "", // 设置为右侧价格轴 + }); + + // 配置成交量图表在底部 + chart.value.priceScale("").applyOptions({ + scaleMargins: { + top: 0.8, + bottom: 0, + }, + }); + + // 设置成交量数据 + if (opts.volumeData) { + setVolumeData(opts.volumeData); + } + } + watch(isDark, (dark) => { changeTheme(dark ? "dark" : "light"); }, { immediate: true }); + setData(opts.data); fitContent(); @@ -129,6 +178,12 @@ export function useTradingView(target: MaybeRefOrGetter, opt }, { deep: true }); } + if (isRef(opts.volumeData)) { + watch(opts.volumeData, (newData) => { + setVolumeData(newData); + }, { deep: true }); + } + if (opts.autosize) { useTimeoutFn(() => { resize(); @@ -149,5 +204,5 @@ export function useTradingView(target: MaybeRefOrGetter, opt chart.value.applyOptions(newOptions); }, { deep: true }); - return { chart, series, fitContent, resize }; + return { chart, series, volumeSeries, fitContent, resize, setVolumeData }; } diff --git a/src/ui/tabs/index.vue b/src/ui/tabs/index.vue index 708f0f3..839bd90 100644 --- a/src/ui/tabs/index.vue +++ b/src/ui/tabs/index.vue @@ -337,7 +337,7 @@ const stickyStyle = computed(() => { /* 导航包装器 */ .ui-tabs__nav-wrapper { - @apply relative; + @apply relative w-fit mb-4; } /* Sticky 布局 */ @@ -374,7 +374,7 @@ const stickyStyle = computed(() => { } .ui-tabs__nav--segment { - @apply gap-1 p-1 rounded-lg; + @apply gap-1 p-1 rounded-full; background-color: var(--ion-color-light, #f8f9fa); } @@ -427,11 +427,12 @@ const stickyStyle = computed(() => { /* Segment 类型 */ .ui-tab--segment { - @apply px-3 py-2 rounded-md; + @apply px-3 py-2 rounded-full; } .ui-tab--segment.ui-tab--active { background-color: var(--ui-tabs-background); + color: var(--ui-tabs-text, "black"); box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); @@ -448,7 +449,11 @@ const stickyStyle = computed(() => { } .ui-tab--small.ui-tab--segment { - @apply px-2 py-1; + @apply px-5 py-1; +} + +.ui-tab--medium.ui-tab--segment { + @apply px-8 py-1; } .ui-tab--large { @@ -461,7 +466,7 @@ const stickyStyle = computed(() => { } .ui-tab--large.ui-tab--segment { - @apply px-4 py-3; + @apply px-8 py-3; } /* Tab Label */ diff --git a/src/views/market/index.vue b/src/views/market/index.vue index c3d38bc..b42210d 100644 --- a/src/views/market/index.vue +++ b/src/views/market/index.vue @@ -73,13 +73,13 @@ onBeforeMount(() => { - - - - + { - diff --git a/src/views/system-settings/outlet.vue b/src/views/system-settings/outlet.vue index a1d8845..b612ab2 100644 --- a/src/views/system-settings/outlet.vue +++ b/src/views/system-settings/outlet.vue @@ -2,15 +2,7 @@ diff --git a/src/views/trade-settings/my-issues/outlet.vue b/src/views/trade-settings/my-issues/outlet.vue index 9c88551..bb3d43c 100644 --- a/src/views/trade-settings/my-issues/outlet.vue +++ b/src/views/trade-settings/my-issues/outlet.vue @@ -1,16 +1,9 @@ diff --git a/src/views/trade/index.vue b/src/views/trade/index.vue index 60b1a54..23d4d8c 100644 --- a/src/views/trade/index.vue +++ b/src/views/trade/index.vue @@ -1,34 +1,87 @@ - diff --git a/src/views/user-settings/outlet.vue b/src/views/user-settings/outlet.vue index dc05d54..349276a 100644 --- a/src/views/user-settings/outlet.vue +++ b/src/views/user-settings/outlet.vue @@ -8,7 +8,7 @@ 用户设置 - +