dsh-xueqiu 1.22.2 → 1.22.4
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.
- package/README.en.md +2 -0
- package/README.md +6 -0
- package/dynamic/client.js +20 -4
- package/package.json +1 -1
- package/src/client/index.js +20 -4
package/README.en.md
CHANGED
|
@@ -135,6 +135,8 @@ The data layer is defended in depth — safe to leave open for hours:
|
|
|
135
135
|
|
|
136
136
|
## Changelog
|
|
137
137
|
|
|
138
|
+
- **1.22.4** (2026-08-26) — **Fix: switching to the minute tab crashed the whole panel** (1.22.3 regression). The double-click-to-latest cleanup used `boxRef.current.removeEventListener`, but React clears refs before running effect cleanup on unmount, so `boxRef.current` was null → TypeError → the `conversation.input.dock` slot crashed entirely, leaving only the mini badge with no way back in. Now the node is captured in a closure inside the effect. Regression-tested: K-line↔minute 4 toggle rounds + collapse/badge-reopen/re-enter detail, 0 errors.
|
|
139
|
+
- **1.22.3** (2026-08-26) — **Fix: K-line OHLC legend permanently drawn over the candles**. KLineChart v10 defaults `candle.tooltip.showRule` to `'always'`, painting time/OHLC/volume in the candle pane's top-left corner at all times (pixel-scan measured 1394 text pixels covering candles from y=23). Changed to `'follow_cross'` (shown on crosshair hover, like Xueqiu) — the indicator tooltip had been disabled but the candle's own legend was missed. Also: the chart footer promised "double-click to return to latest" but no dblclick handler existed (verified: after left-drag loaded 999 bars, double-click did nothing) — now wired to `chart.scrollToRealTime()` (verified: visible range 132→430-500). Minor: K-line date label now includes the year (a 500-bar daily range showed "08-26 ~ 08-24", reading like time travel across two years); the detail-page hero price/change now follows the quote's actual decimal digits (HK 00700 previously 440.40 → 440.4).
|
|
138
140
|
- **1.22.2** (2026-08-24) — **Fix: MA / avg-price lines landed in sub-panes instead of overlaying the main chart**. KLineChart v10's `createIndicator('MA')` opens a new pane by default — MAs were not on the candle pane (squeezed to 72px) and the minute chart's avg/prev-close lived in their own sub-pane. The fix passes `{ name, paneId: 'candle_pane' }` to explicitly overlay the main pane (pane id confirmed from engine source). Result: candlestick pane at 173px with MA5/10/30/60 overlaid (volume remains the only sub-pane); minute chart is a single pane with price + avg + prev-close overlaid, matching Xueqiu's layout. Also a Xueqiu-inspired detail-page restyle: hero quote header (large red/green price + change + pct), lighter 16-stat grid (tinted cards, tabular numerals), accent bar on card titles, theme-tinted active states for mode/period buttons, chart height 264→300px, harmonized 4-color MA palette, and high/low duplicate price marks disabled.
|
|
139
141
|
- **1.22.1** (2026-08-24) — chore: drop peerDependencies to silence install warnings; static smoke script falls back to local `npx dsh` (dsh not on PATH under prepublishOnly).
|
|
140
142
|
- **1.22.0** (2026-08-24) — **K-line / minute charts migrated to the KLineChart v10 engine** (canvas rendering, built-in light/dark theming): candles + volume + MA overlays + crosshair legend across 7 periods (5m/15m/30m/60m/day/week/month); wheel zoom, drag pan, and auto-fetch of earlier history on left-drag (500 bars per fetch); minute chart as a price-colored area with avg line and prev-close baseline.
|
package/README.md
CHANGED
|
@@ -190,6 +190,12 @@ dsh-xueqiu/
|
|
|
190
190
|
|
|
191
191
|
## 📋 更新日志
|
|
192
192
|
|
|
193
|
+
- **1.22.4**(2026-08-26)
|
|
194
|
+
- 修复:**切分时整个面板崩溃消失**(1.22.3 回归)。双击回最新的清理函数里用了 `boxRef.current.removeEventListener`,但 React 卸载组件时先清 ref 再跑 effect 清理,此时 `boxRef.current` 已是 null → 抛 TypeError → `conversation.input.dock` 槽位整体崩溃,只剩自选股小徽章且无法重开。改为 effect 内闭包捕获节点。回归:K线↔分时来回 4 轮 + 收起/徽章重开/再进详情,0 报错。
|
|
195
|
+
- **1.22.3**(2026-08-26)
|
|
196
|
+
- 修复:**K线 OHLC 图例常驻压蜡烛**。KLineChart v10 默认 `candle.tooltip.showRule: 'always'` 把 time/open/high/low/close/volume 永久画在蜡烛区左上角(像素级实测 1394 个文字像素自 y=23 起覆盖蜡烛)。改为 `follow_cross`(十字光标悬停才显示,与雪球一致),此前只关了指标 tooltip 漏了蜡烛自身的。
|
|
197
|
+
- 修复:**"双击回最新"标签承诺无实现**。图表下方文案写了"双击回最新"但代码没有 dblclick 处理(实测左拖加载 999 根后双击无反应)。现监听容器 dblclick → `chart.scrollToRealTime()`(实测可视区 132→430-500 回到最新)。
|
|
198
|
+
- 细节:K线日期标签补年份(500 根日K时"08-26 ~ 08-24"像时间倒流,实际跨两年;现显示"2024-08-02 ~ 2026-08-25");详情页 hero 现价/涨跌额按现价实际小数位显示(港股 00700 此前 440.40 → 440.4)。
|
|
193
199
|
- **1.22.2**(2026-08-24)
|
|
194
200
|
- 修复:**K线均线 / 分时均价误落附图**。KLineChart v10 的 `createIndicator('MA')` 默认给指标新开 pane——均线不在蜡烛主图上(主图被挤到 72px),分时均价/昨收也在独立附图。须传 `{ name, paneId: 'candle_pane' }` 显式叠加到主图(pane id 从引擎源码确认)。修复后:K线主图 173px 蜡烛+MA5/10/30/60 叠加、附图仅成交量;分时只剩一张主图(分时曲线+均价+昨收全部叠加),与雪球布局一致。
|
|
195
201
|
- 样式:**详情页参考雪球重排版**——顶部行情主标题(大号红/绿现价 + 涨跌额 + 涨跌幅,如 `1304.66 +31.83 +2.50%`);16 格 stat 卡片更轻盈(浅底/圆角/等宽数字/标签次要色);卡片标题左侧主题色强调条;K线/分时与周期按钮选中态改主题色 tint 填充;K线画布 264→300px;MA 均线和谐四色(蓝/橙/紫/青);关闭最高/最低点重复标注(消除窄图顶部杂乱数字)。
|
package/dynamic/client.js
CHANGED
|
@@ -232,7 +232,7 @@ return {
|
|
|
232
232
|
if (!ts) return ''
|
|
233
233
|
const d = new Date(Number(ts))
|
|
234
234
|
function p(n) { return n < 10 ? '0' + n : String(n) }
|
|
235
|
-
return p(d.getMonth() + 1) + '-' + p(d.getDate())
|
|
235
|
+
return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate())
|
|
236
236
|
}
|
|
237
237
|
function fmtFullDay(ts) {
|
|
238
238
|
if (!ts) return ''
|
|
@@ -355,6 +355,8 @@ return {
|
|
|
355
355
|
upBorderColor: pal.up, downBorderColor: pal.down, noChangeBorderColor: pal.text,
|
|
356
356
|
upWickColor: pal.up, downWickColor: pal.down, noChangeWickColor: pal.text
|
|
357
357
|
},
|
|
358
|
+
// OHLC 图例:十字光标悬停才显示(v10 默认 always 常驻左上角,压蜡烛且与坐标轴数值重复)
|
|
359
|
+
tooltip: { showRule: 'follow_cross' },
|
|
358
360
|
priceMark: {
|
|
359
361
|
// 关闭最高/最低点重复标注(窄图时易与坐标轴重叠成杂乱数字),保留最新价标
|
|
360
362
|
high: { show: false }, low: { show: false },
|
|
@@ -476,7 +478,15 @@ return {
|
|
|
476
478
|
chart.createIndicator({ name: 'MA', paneId: 'candle_pane' })
|
|
477
479
|
chart.createIndicator('VOL')
|
|
478
480
|
chart.setOffsetRightDistance(16)
|
|
479
|
-
|
|
481
|
+
// 双击回最新(标签文案承诺过;kline v10 自带 dblclick 仅做空十字,需手动 scrollToRealTime)
|
|
482
|
+
const box = boxRef.current
|
|
483
|
+
const onDbl = function () { try { chart.scrollToRealTime() } catch (e) { /* 忽略 */ } }
|
|
484
|
+
box.addEventListener('dblclick', onDbl)
|
|
485
|
+
return function () {
|
|
486
|
+
// 卸载清理时 boxRef.current 已被 React 置 null(切 tab 触发,曾致槽位整体崩溃),须闭包捕获节点
|
|
487
|
+
try { box.removeEventListener('dblclick', onDbl) } catch (e) { /* 忽略 */ }
|
|
488
|
+
h.dispose()
|
|
489
|
+
}
|
|
480
490
|
}, [])
|
|
481
491
|
|
|
482
492
|
if (noLib) return klcNoLib()
|
|
@@ -1022,8 +1032,14 @@ return {
|
|
|
1022
1032
|
])
|
|
1023
1033
|
})
|
|
1024
1034
|
// 行情主标题:现价 + 涨跌额 + 涨跌幅(参考雪球 ¥18.23 +0.14 +0.77% 层级)
|
|
1035
|
+
// 精度取现价自身小数位(港交所 1 位等),涨跌额同精度
|
|
1036
|
+
const qDigits = (function () {
|
|
1037
|
+
const m = String(q.current == null ? '' : q.current).split('.')
|
|
1038
|
+
const d = m[1] ? m[1].length : 0
|
|
1039
|
+
return Math.max(2, Math.min(4, d))
|
|
1040
|
+
})()
|
|
1025
1041
|
const chgRaw = (q.current != null && q.last_close != null) ? (Number(q.current) - Number(q.last_close)) : null
|
|
1026
|
-
const chgStr = (chgRaw != null && isFinite(chgRaw)) ? (chgRaw > 0 ? '+' + fmt(chgRaw) : (chgRaw < 0 ? '-' + fmt(Math.abs(chgRaw)) :
|
|
1042
|
+
const chgStr = (chgRaw != null && isFinite(chgRaw)) ? (chgRaw > 0 ? '+' + fmt(chgRaw, qDigits) : (chgRaw < 0 ? '-' + fmt(Math.abs(chgRaw), qDigits) : fmt(0, qDigits))) : ''
|
|
1027
1043
|
const priceCls = colorOf(q.percent)
|
|
1028
1044
|
return el('div', null, [
|
|
1029
1045
|
el('div', { key: 'h', className: 'xq-detail-head' }, [
|
|
@@ -1032,7 +1048,7 @@ return {
|
|
|
1032
1048
|
el('span', { key: 'c', className: 'xq-detail-code' }, view),
|
|
1033
1049
|
el('span', { key: 'sp', className: 'xq-spacer' }),
|
|
1034
1050
|
el('div', { key: 'px', className: 'xq-detail-price' }, [
|
|
1035
|
-
el('span', { key: 'cur', className: 'xq-detail-cur ' + priceCls }, fmt(q.current)),
|
|
1051
|
+
el('span', { key: 'cur', className: 'xq-detail-cur ' + priceCls }, fmt(q.current, qDigits)),
|
|
1036
1052
|
el('span', { key: 'dl', className: 'xq-detail-delta' }, [
|
|
1037
1053
|
chgStr ? el('span', { key: 'chg', className: 'xq-detail-chg ' + priceCls }, chgStr) : null,
|
|
1038
1054
|
el('span', { key: 'pct', className: 'xq-detail-pct ' + priceCls }, fmtPct(q.percent))
|
package/package.json
CHANGED
package/src/client/index.js
CHANGED
|
@@ -263,7 +263,7 @@ exports.default = {
|
|
|
263
263
|
if (!ts) return ''
|
|
264
264
|
const d = new Date(Number(ts))
|
|
265
265
|
function p(n) { return n < 10 ? '0' + n : String(n) }
|
|
266
|
-
return p(d.getMonth() + 1) + '-' + p(d.getDate())
|
|
266
|
+
return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate())
|
|
267
267
|
}
|
|
268
268
|
function fmtFullDay(ts) {
|
|
269
269
|
if (!ts) return ''
|
|
@@ -386,6 +386,8 @@ exports.default = {
|
|
|
386
386
|
upBorderColor: pal.up, downBorderColor: pal.down, noChangeBorderColor: pal.text,
|
|
387
387
|
upWickColor: pal.up, downWickColor: pal.down, noChangeWickColor: pal.text
|
|
388
388
|
},
|
|
389
|
+
// OHLC 图例:十字光标悬停才显示(v10 默认 always 常驻左上角,压蜡烛且与坐标轴数值重复)
|
|
390
|
+
tooltip: { showRule: 'follow_cross' },
|
|
389
391
|
priceMark: {
|
|
390
392
|
// 关闭最高/最低点重复标注(窄图时易与坐标轴重叠成杂乱数字),保留最新价标
|
|
391
393
|
high: { show: false }, low: { show: false },
|
|
@@ -507,7 +509,15 @@ exports.default = {
|
|
|
507
509
|
chart.createIndicator({ name: 'MA', paneId: 'candle_pane' })
|
|
508
510
|
chart.createIndicator('VOL')
|
|
509
511
|
chart.setOffsetRightDistance(16)
|
|
510
|
-
|
|
512
|
+
// 双击回最新(标签文案承诺过;kline v10 自带 dblclick 仅做空十字,需手动 scrollToRealTime)
|
|
513
|
+
const box = boxRef.current
|
|
514
|
+
const onDbl = function () { try { chart.scrollToRealTime() } catch (e) { /* 忽略 */ } }
|
|
515
|
+
box.addEventListener('dblclick', onDbl)
|
|
516
|
+
return function () {
|
|
517
|
+
// 卸载清理时 boxRef.current 已被 React 置 null(切 tab 触发,曾致槽位整体崩溃),须闭包捕获节点
|
|
518
|
+
try { box.removeEventListener('dblclick', onDbl) } catch (e) { /* 忽略 */ }
|
|
519
|
+
h.dispose()
|
|
520
|
+
}
|
|
511
521
|
}, [])
|
|
512
522
|
|
|
513
523
|
if (noLib) return klcNoLib()
|
|
@@ -1053,8 +1063,14 @@ exports.default = {
|
|
|
1053
1063
|
])
|
|
1054
1064
|
})
|
|
1055
1065
|
// 行情主标题:现价 + 涨跌额 + 涨跌幅(参考雪球 ¥18.23 +0.14 +0.77% 层级)
|
|
1066
|
+
// 精度取现价自身小数位(港交所 1 位等),涨跌额同精度
|
|
1067
|
+
const qDigits = (function () {
|
|
1068
|
+
const m = String(q.current == null ? '' : q.current).split('.')
|
|
1069
|
+
const d = m[1] ? m[1].length : 0
|
|
1070
|
+
return Math.max(2, Math.min(4, d))
|
|
1071
|
+
})()
|
|
1056
1072
|
const chgRaw = (q.current != null && q.last_close != null) ? (Number(q.current) - Number(q.last_close)) : null
|
|
1057
|
-
const chgStr = (chgRaw != null && isFinite(chgRaw)) ? (chgRaw > 0 ? '+' + fmt(chgRaw) : (chgRaw < 0 ? '-' + fmt(Math.abs(chgRaw)) :
|
|
1073
|
+
const chgStr = (chgRaw != null && isFinite(chgRaw)) ? (chgRaw > 0 ? '+' + fmt(chgRaw, qDigits) : (chgRaw < 0 ? '-' + fmt(Math.abs(chgRaw), qDigits) : fmt(0, qDigits))) : ''
|
|
1058
1074
|
const priceCls = colorOf(q.percent)
|
|
1059
1075
|
return el('div', null, [
|
|
1060
1076
|
el('div', { key: 'h', className: 'xq-detail-head' }, [
|
|
@@ -1063,7 +1079,7 @@ exports.default = {
|
|
|
1063
1079
|
el('span', { key: 'c', className: 'xq-detail-code' }, view),
|
|
1064
1080
|
el('span', { key: 'sp', className: 'xq-spacer' }),
|
|
1065
1081
|
el('div', { key: 'px', className: 'xq-detail-price' }, [
|
|
1066
|
-
el('span', { key: 'cur', className: 'xq-detail-cur ' + priceCls }, fmt(q.current)),
|
|
1082
|
+
el('span', { key: 'cur', className: 'xq-detail-cur ' + priceCls }, fmt(q.current, qDigits)),
|
|
1067
1083
|
el('span', { key: 'dl', className: 'xq-detail-delta' }, [
|
|
1068
1084
|
chgStr ? el('span', { key: 'chg', className: 'xq-detail-chg ' + priceCls }, chgStr) : null,
|
|
1069
1085
|
el('span', { key: 'pct', className: 'xq-detail-pct ' + priceCls }, fmtPct(q.percent))
|