From 8d59acabc09d8e12c70a9ea804641630075abf00 Mon Sep 17 00:00:00 2001 From: mianyang <784310601@qq.com> Date: Tue, 5 May 2026 19:03:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BD=8E=E4=BA=8E=20?= =?UTF-8?q?=E5=89=8D=E4=B8=80=E4=BA=A4=E6=98=93=E6=97=A5101%=20=E4=BB=B7?= =?UTF-8?q?=E6=A0=BC=E5=BC=80=E7=9B=98=E9=80=BB=E8=BE=91=E3=80=82=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=B8=8B=E8=BD=BD=E6=96=87=E4=BB=B6=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 3 +- src/api/stock.js | 18 ++ src/router/index.js | 6 + src/views/stock/Analyze.vue | 2 +- src/views/stock/Download.vue | 315 +++++++++++++++++++++++++++++++++ src/views/stock/LimitBoard.vue | 82 ++++++++- 6 files changed, 415 insertions(+), 11 deletions(-) create mode 100644 src/views/stock/Download.vue diff --git a/src/App.vue b/src/App.vue index d2acd5f..855804f 100644 --- a/src/App.vue +++ b/src/App.vue @@ -41,13 +41,14 @@ + + diff --git a/src/views/stock/LimitBoard.vue b/src/views/stock/LimitBoard.vue index bd25d2b..04ac5f7 100644 --- a/src/views/stock/LimitBoard.vue +++ b/src/views/stock/LimitBoard.vue @@ -90,6 +90,7 @@ +
@@ -147,6 +148,14 @@ 开盘 {{ formatPrice(stock.open) }} 前收 {{ formatPrice(stock.previous_close) }}
+
+ 开盘 {{ formatPrice(stock.open) }} + 前收 {{ formatPrice(stock.previous_close) }} + 阈值 {{ formatPrice(stock.open_threshold_price) }} +
@@ -180,6 +189,7 @@ import { fetchTradeCalendar } from "@/composables/useTradeCalendar"; import { getKlineData, getLimitBoardOpenLowerGroups, + getLimitBoardOpenThresholdGroups, getLimitBoardOverview, } from "@/api/stock"; @@ -220,6 +230,17 @@ const openLowerDetail = ref({ }, groups: [], }); +const openThresholdDetail = ref({ + trade_date: "", + previous_trade_date: "", + summary: { + limit_count: 0, + open_within_threshold_count: 0, + open_at_or_above_threshold_count: 0, + threshold_ratio: 1.01, + }, + groups: [], +}); const dialogVisible = ref(false); const dialogTitle = ref(""); @@ -292,6 +313,8 @@ const displayDetailGroups = computed(() => { if (activeDetailTab.value === "sector") return sectorDetailGroups.value; if (activeDetailTab.value === "openLower") return openLowerDisplayGroups.value; + if (activeDetailTab.value === "openThreshold") + return openThresholdDetail.value.groups; return detailGroups.value.map((group) => ({ ...group, key: `board-${group.board_count ?? group.label}`, @@ -313,6 +336,7 @@ const detailModeDescription = computed( board: "按连板高度从高到低展示当日涨停股票。", sector: "按所属行业或板块汇总展示当日涨停股票。", openLower: `仅统计当日涨停且前一交易日也涨停的股票,首二一一红色优先,首板进二板黄色随后,前一交易日 ${openLowerDetail.value.previous_trade_date || "--"}。`, + openThreshold: `仅统计当日涨停且前一交易日也涨停的股票,并按开盘价是否低于前收 101% 分组,前一交易日 ${openThresholdDetail.value.previous_trade_date || "--"}。`, })[activeDetailTab.value], ); const openLowerTabLabel = computed(() => { @@ -379,9 +403,14 @@ const disableDates = (time) => { }; const fetchOverviewPage = async (tradeDate) => { - const [currentOverview, currentOpenLowerGroups] = await Promise.all([ + const [ + currentOverview, + currentOpenLowerGroups, + currentOpenThresholdGroups, + ] = await Promise.all([ getLimitBoardOverview({ trade_date: tradeDate }), getLimitBoardOpenLowerGroups({ trade_date: tradeDate }), + getLimitBoardOpenThresholdGroups({ trade_date: tradeDate }), ]); overview.value = normalizeOverview(currentOverview, tradeDate); @@ -389,6 +418,10 @@ const fetchOverviewPage = async (tradeDate) => { currentOpenLowerGroups, tradeDate, ); + openThresholdDetail.value = normalizeOpenThresholdGroups( + currentOpenThresholdGroups, + tradeDate, + ); strengthSeries.value = overview.value.recent_max_board_stats; detailTradeDate.value = overview.value.trade_date; detailGroups.value = overview.value.groups; @@ -402,10 +435,12 @@ const fetchDetailGroups = async (tradeDate) => { detailLoading.value = true; try { - const [detailOverview, detailOpenLowerGroups] = await Promise.all([ - getLimitBoardOverview({ trade_date: tradeDate }), - getLimitBoardOpenLowerGroups({ trade_date: tradeDate }), - ]); + const [detailOverview, detailOpenLowerGroups, detailOpenThresholdGroups] = + await Promise.all([ + getLimitBoardOverview({ trade_date: tradeDate }), + getLimitBoardOpenLowerGroups({ trade_date: tradeDate }), + getLimitBoardOpenThresholdGroups({ trade_date: tradeDate }), + ]); const normalized = normalizeOverview(detailOverview, tradeDate); detailTradeDate.value = normalized.trade_date; detailGroups.value = normalized.groups; @@ -413,6 +448,10 @@ const fetchDetailGroups = async (tradeDate) => { detailOpenLowerGroups, tradeDate, ); + openThresholdDetail.value = normalizeOpenThresholdGroups( + detailOpenThresholdGroups, + tradeDate, + ); } catch (err) { console.error("刷新涨停分组明细失败", err); } finally { @@ -461,6 +500,28 @@ const normalizeOpenLowerGroups = (data, fallbackTradeDate = "") => ({ : [], }); +const normalizeOpenThresholdGroups = (data, fallbackTradeDate = "") => ({ + trade_date: data?.trade_date || fallbackTradeDate, + previous_trade_date: data?.previous_trade_date || "", + summary: { + limit_count: data?.summary?.limit_count || 0, + open_within_threshold_count: + data?.summary?.open_within_threshold_count || 0, + open_at_or_above_threshold_count: + data?.summary?.open_at_or_above_threshold_count || 0, + threshold_ratio: Number(data?.summary?.threshold_ratio || 1.01), + }, + groups: Array.isArray(data?.groups) + ? data.groups.map((group) => ({ + key: `open-threshold-${group?.key || group?.label || "group"}`, + rawKey: group?.key || "", + label: group?.label || "--", + count: Number(group?.count || 0), + stocks: Array.isArray(group?.stocks) ? group.stocks : [], + })) + : [], +}); + const handleQuery = async () => { if (!selectedDate.value) return; @@ -815,7 +876,7 @@ const openKlineDialog = async (stock) => { }, ], dataZoom: [ - { type: "inside", xAxisIndex: [0, 1], start: 80, end: 100 }, + { type: "inside", xAxisIndex: [0, 1], start: 95, end: 100 }, { show: true, type: "slider", xAxisIndex: [0, 1], top: "90%" }, ], series: [ @@ -1152,7 +1213,8 @@ const openKlineDialog = async (stock) => { .stock-meta, .stock-metrics, .stock-limit-time, -.stock-open-compare { +.stock-open-compare, +.stock-open-threshold { color: #607289; font-size: 13px; } @@ -1166,7 +1228,8 @@ const openKlineDialog = async (stock) => { } .stock-limit-time, -.stock-open-compare { +.stock-open-compare, +.stock-open-threshold { display: flex; align-items: center; justify-content: space-between; @@ -1181,7 +1244,8 @@ const openKlineDialog = async (stock) => { color: #7a8aa1; } -.stock-open-compare span { +.stock-open-compare span, +.stock-open-threshold span { color: #526982; font-weight: 600; }