From 99c75a7f696ca1bb70fa756f22faf449bb676f6c Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 8 Feb 2026 14:17:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9A=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E8=96=84=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/OrderBook.vue | 56 +++++++++++++++++++--------- src/views/TradeDetail.vue | 72 ++++++++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 29 deletions(-) diff --git a/src/components/OrderBook.vue b/src/components/OrderBook.vue index 2d10881..6410947 100644 --- a/src/components/OrderBook.vue +++ b/src/components/OrderBook.vue @@ -22,6 +22,7 @@
+
PRICE
SHARES
TOTAL
@@ -321,12 +322,18 @@ const maxBidsTotal = computed(() => { .order-list-header { display: flex; - justify-content: space-between; + align-items: center; + gap: 12px; padding: 8px 0; border-bottom: none; margin-bottom: 8px; } +.order-list-header-spacer { + flex: 1; + min-width: 0; +} + .order-list-header-price, .order-list-header-shares, .order-list-header-total { @@ -338,18 +345,22 @@ const maxBidsTotal = computed(() => { .order-list-header-price { width: 80px; + flex-shrink: 0; } .order-list-header-shares { - flex: 1; + width: 100px; + flex-shrink: 0; text-align: right; } .order-list-header-total { width: 100px; + flex-shrink: 0; text-align: right; } + .asks-label, .bids-label { font-size: 12px; @@ -378,11 +389,10 @@ const maxBidsTotal = computed(() => { gap: 12px; } -/* 深度图:固定宽度,进度条长度表示深度比例,不占满整行 */ +/* 深度条占据左侧剩余空间 */ .order-progress { - flex: 0 0 auto; - width: 120px; - min-width: 120px; + flex: 1; + min-width: 0; } .asks-price { @@ -432,38 +442,50 @@ const maxBidsTotal = computed(() => { color: #666666; } -/* Responsive Adjustments */ +/* Responsive Adjustments - 手机端缩小右侧列宽,让深度条占用更多空间 */ @media (max-width: 600px) { .order-book-content { padding: 8px 12px; - gap: 12px; + gap: 8px; + } + + .order-list-header { + gap: 8px; } .order-progress { - width: 80px; - min-width: 80px; + min-width: 0; + } + + .order-item { + gap: 8px; } .order-list-header-price { - width: 60px; + width: 48px; + } + + .order-list-header-shares { + width: 56px; } .order-list-header-total { - width: 80px; + width: 52px; } .order-price { - width: 60px; - font-size: 13px; + width: 48px; + font-size: 12px; } .order-shares { - font-size: 13px; + width: 56px; + font-size: 12px; } .order-total { - width: 80px; - font-size: 13px; + width: 52px; + font-size: 12px; } } diff --git a/src/views/TradeDetail.vue b/src/views/TradeDetail.vue index 1c01c93..5371cb0 100644 --- a/src/views/TradeDetail.vue +++ b/src/views/TradeDetail.vue @@ -170,8 +170,47 @@ const currentChance = computed(() => { const lineColor = '#2563eb' -function buildOption(chartData: [number, number][]) { +const MOBILE_BREAKPOINT = 600 + +function buildOption(chartData: [number, number][], containerWidth?: number) { const lastIndex = chartData.length - 1 + const width = containerWidth ?? chartContainerRef.value?.clientWidth ?? 400 + const isMobile = width < MOBILE_BREAKPOINT + + // 手机端:计算时间范围,减少 X 轴标签数量并缩短格式,避免重叠 + const xAxisConfig: Record = { + type: 'time', + axisLine: { lineStyle: { color: '#e5e7eb' } }, + axisLabel: { + color: '#6b7280', + fontSize: isMobile ? 10 : 11, + }, + axisTick: { show: false }, + splitLine: { show: false }, + } + + if (isMobile && chartData.length >= 2) { + const times = chartData.map((d) => d[0]) + const minTime = Math.min(...times) + const maxTime = Math.max(...times) + const span = maxTime - minTime + // 只显示约 4 个时间点,避免挤在一起 + xAxisConfig.axisLabel = { + ...(xAxisConfig.axisLabel as object), + interval: Math.max(span / 4, 60 * 1000), + formatter: (value: number) => { + const d = new Date(value) + const h = d.getHours() + const m = d.getMinutes() + if (span >= 24 * 60 * 60 * 1000) { + return `${d.getMonth() + 1}/${d.getDate()}` + } + return `${h}:${m.toString().padStart(2, '0')}` + }, + rotate: -25, + } + } + return { animation: false, tooltip: { @@ -193,14 +232,14 @@ function buildOption(chartData: [number, number][]) { }, axisPointer: { animation: false }, }, - grid: { left: 16, right: 48, top: 16, bottom: 28, containLabel: false }, - xAxis: { - type: 'time', - axisLine: { lineStyle: { color: '#e5e7eb' } }, - axisLabel: { color: '#6b7280', fontSize: 11 }, - axisTick: { show: false }, - splitLine: { show: false }, + grid: { + left: 16, + right: 48, + top: 16, + bottom: isMobile ? 44 : 28, + containLabel: false, }, + xAxis: xAxisConfig, yAxis: { type: 'value', position: 'right', @@ -234,12 +273,14 @@ function initChart() { if (!chartContainerRef.value) return data.value = generateData(selectedTimeRange.value) chartInstance = echarts.init(chartContainerRef.value) - chartInstance.setOption(buildOption(data.value)) + const w = chartContainerRef.value.clientWidth + chartInstance.setOption(buildOption(data.value, w)) } function updateChartData() { data.value = generateData(selectedTimeRange.value) - if (chartInstance) chartInstance.setOption(buildOption(data.value), { replaceMerge: ['series'] }) + const w = chartContainerRef.value?.clientWidth + if (chartInstance) chartInstance.setOption(buildOption(data.value, w), { replaceMerge: ['series'] }) } function selectTimeRange(range: string) { @@ -269,7 +310,8 @@ function startDynamicUpdate() { list.push([nextT, Math.round(nextVal * 10) / 10]) const max = getMaxPoints(selectedTimeRange.value) data.value = list.slice(-max) - if (chartInstance) chartInstance.setOption(buildOption(data.value), { replaceMerge: ['series'] }) + const w = chartContainerRef.value?.clientWidth + if (chartInstance) chartInstance.setOption(buildOption(data.value, w), { replaceMerge: ['series'] }) }, 3000) } @@ -282,7 +324,13 @@ function stopDynamicUpdate() { watch(selectedTimeRange, () => updateChartData()) -const handleResize = () => chartInstance?.resize() +const handleResize = () => { + if (!chartInstance || !chartContainerRef.value) return + chartInstance.resize() + chartInstance.setOption(buildOption(data.value, chartContainerRef.value.clientWidth), { + replaceMerge: ['series'], + }) +} onMounted(() => { initChart()