dsh-xueqiu 1.7.2 → 1.8.0
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 +1 -0
- package/README.md +2 -0
- package/dynamic/client.js +26 -4
- package/package.json +1 -1
- package/src/client/index.js +26 -4
package/README.en.md
CHANGED
|
@@ -121,6 +121,7 @@ The data layer is defended in depth — safe to leave open for hours:
|
|
|
121
121
|
|
|
122
122
|
## Changelog
|
|
123
123
|
|
|
124
|
+
- **1.8.0** (2025-08-19) — Pro polish: tabular-nums everywhere (no column jitter), red/green percent chips, and price-change flash animation on watchlist rows.
|
|
124
125
|
- **1.7.2** (2025-08-19) — News tab pagination: scroll-to-bottom or "load earlier" fetches older items (max_id cursor, deduped); refresh resets to the latest page.
|
|
125
126
|
- **1.7.1** (2025-08-19) — Fix static install (`dsh plugin add`) crashing `dsh web` startup: dual-mode RPC (harness.handle for dynamic runs, a loopback+same-origin fenced `/xq-rpc` webServer route for static installs) and a proper `__ModuleLoader__` CJS client bundle.
|
|
126
127
|
- **1.7.0** (2025-08-19) — Hidden-tab polling pause + CN/HK/US market session hints.
|
package/README.md
CHANGED
|
@@ -151,6 +151,8 @@ dsh-xueqiu/
|
|
|
151
151
|
|
|
152
152
|
## 📋 更新日志
|
|
153
153
|
|
|
154
|
+
- **1.8.0**(2025-08-19)
|
|
155
|
+
- 专业感升级三件套:全界面等宽数字(tabular-nums,价格跳动不抖列);涨跌幅色块 chip(红涨/绿跌半透明底,扫一眼定位);自选行价格变动闪烁动画(涨红闪/跌绿闪,0.8s 渐隐)。
|
|
154
156
|
- **1.7.2**(2025-08-19)
|
|
155
157
|
- 新增:快讯 tab 翻页——滚动到底或点「加载更早」自动加载历史快讯(max_id 游标,自动去重),「刷新」重置回最新一页。
|
|
156
158
|
- **1.7.1**(2025-08-19)
|
package/dynamic/client.js
CHANGED
|
@@ -41,6 +41,17 @@ return {
|
|
|
41
41
|
'.xq-up{color:var(--dsw-alias-state-error-primary);}\n' +
|
|
42
42
|
'.xq-down{color:var(--dsw-alias-state-success-primary);}\n' +
|
|
43
43
|
'.xq-flat{color:var(--dsw-alias-label-secondary);}\n' +
|
|
44
|
+
// 专业感三件套:①等宽数字 ②涨跌幅色块 ③价格闪烁
|
|
45
|
+
'.xq-dock,.xq-badge,.xq-ticker{font-variant-numeric:tabular-nums;}\n' +
|
|
46
|
+
'.xq-pct-chip{display:inline-block;min-width:52px;text-align:center;padding:1px 6px;border-radius:5px;font-size:11.5px;font-weight:600;}\n' +
|
|
47
|
+
'.xq-pct-chip.xq-up{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent);}\n' +
|
|
48
|
+
'.xq-pct-chip.xq-down{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent);}\n' +
|
|
49
|
+
'.xq-pct-chip.xq-flat{background:var(--dsw-alias-bg-layer-2);}\n' +
|
|
50
|
+
'.xq-idx-pct.xq-pct-chip{min-width:46px;padding:0 5px;font-size:10.5px;}\n' +
|
|
51
|
+
'@keyframes xq-flash-up{0%{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 18%, transparent);}100%{background:transparent;}}\n' +
|
|
52
|
+
'@keyframes xq-flash-down{0%{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 18%, transparent);}100%{background:transparent;}}\n' +
|
|
53
|
+
'.xq-flash-up{animation:xq-flash-up .8s ease-out;}\n' +
|
|
54
|
+
'.xq-flash-down{animation:xq-flash-down .8s ease-out;}\n' +
|
|
44
55
|
'.xq-grid{display:grid;gap:0;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;overflow:hidden;margin-bottom:8px;}\n' +
|
|
45
56
|
'.xq-grid-hd,.xq-grid-row{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr 84px;align-items:center;}\n' +
|
|
46
57
|
'.xq-grid-hd{font-size:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);padding:5px 8px;}\n' +
|
|
@@ -459,6 +470,9 @@ return {
|
|
|
459
470
|
function XueqiuPanel() {
|
|
460
471
|
const [watchlist, setWatchlist] = React.useState([])
|
|
461
472
|
const [quotes, setQuotes] = React.useState([])
|
|
473
|
+
// 价格闪烁:记录上一价与变化方向(symbol -> 1|-1),行渲染时挂一次性动画类
|
|
474
|
+
const prevPrices = React.useRef({})
|
|
475
|
+
const [flashDir, setFlashDir] = React.useState({})
|
|
462
476
|
const [indices, setIndices] = React.useState([])
|
|
463
477
|
const [hot, setHot] = React.useState([])
|
|
464
478
|
const [hotMarket, setHotMarket] = React.useState('cn')
|
|
@@ -495,7 +509,15 @@ return {
|
|
|
495
509
|
setErr('')
|
|
496
510
|
if (!wl.length) return
|
|
497
511
|
return call('quote', { symbols: wl }).then(function (data) {
|
|
498
|
-
|
|
512
|
+
const list = (data && data.list) || []
|
|
513
|
+
const dirs = {}
|
|
514
|
+
list.forEach(function (q) {
|
|
515
|
+
const prev = prevPrices.current[q.symbol]
|
|
516
|
+
if (prev !== undefined && q.current !== prev) dirs[q.symbol] = q.current > prev ? 1 : -1
|
|
517
|
+
prevPrices.current[q.symbol] = q.current
|
|
518
|
+
})
|
|
519
|
+
if (Object.keys(dirs).length) setFlashDir(dirs)
|
|
520
|
+
setQuotes(list)
|
|
499
521
|
})
|
|
500
522
|
}).catch(function (e) {
|
|
501
523
|
setErr(String((e && e.message) || e))
|
|
@@ -689,7 +711,7 @@ return {
|
|
|
689
711
|
el('div', { key: 'n', className: 'xq-idx-name' }, q.name),
|
|
690
712
|
el('div', { key: 'r', className: 'xq-idx-row' }, [
|
|
691
713
|
el('span', { key: 'c', className: 'xq-idx-cur ' + colorOf(q.percent) }, fmt(q.current)),
|
|
692
|
-
el('span', { key: 'p', className: 'xq-idx-pct ' + colorOf(q.percent) }, fmtPct(q.percent))
|
|
714
|
+
el('span', { key: 'p', className: 'xq-idx-pct xq-pct-chip ' + colorOf(q.percent) }, fmtPct(q.percent))
|
|
693
715
|
])
|
|
694
716
|
])
|
|
695
717
|
})
|
|
@@ -699,8 +721,8 @@ return {
|
|
|
699
721
|
el('div', { key: 'a', className: 'xq-name' }, q.name),
|
|
700
722
|
el('div', { key: 'b', className: 'xq-sub' }, q.symbol)
|
|
701
723
|
]),
|
|
702
|
-
el('div', { key: 'c', className: colorOf(q.percent) }, fmt(q.current)),
|
|
703
|
-
el('div', { key: 'p', className: colorOf(q.percent) }, fmtPct(q.percent)),
|
|
724
|
+
el('div', { key: 'c', className: colorOf(q.percent) + (flashDir[q.symbol] === 1 ? ' xq-flash-up' : flashDir[q.symbol] === -1 ? ' xq-flash-down' : '') }, fmt(q.current)),
|
|
725
|
+
el('div', { key: 'p' }, el('span', { key: 'pp', className: 'xq-pct-chip ' + colorOf(q.percent) }, fmtPct(q.percent))),
|
|
704
726
|
el('div', { key: 'v', className: 'xq-sub' }, fmtVol(q.volume)),
|
|
705
727
|
el('div', { key: 'a2', className: 'xq-actions' }, [
|
|
706
728
|
el('button', { key: 'd', className: 'xq-btn-mini', onClick: function (e) { e.stopPropagation(); openDetail(q.symbol) } }, '详情'),
|
package/package.json
CHANGED
package/src/client/index.js
CHANGED
|
@@ -60,6 +60,17 @@ exports.default = {
|
|
|
60
60
|
'.xq-up{color:var(--dsw-alias-state-error-primary);}\n' +
|
|
61
61
|
'.xq-down{color:var(--dsw-alias-state-success-primary);}\n' +
|
|
62
62
|
'.xq-flat{color:var(--dsw-alias-label-secondary);}\n' +
|
|
63
|
+
// 专业感三件套:①等宽数字 ②涨跌幅色块 ③价格闪烁
|
|
64
|
+
'.xq-dock,.xq-badge,.xq-ticker{font-variant-numeric:tabular-nums;}\n' +
|
|
65
|
+
'.xq-pct-chip{display:inline-block;min-width:52px;text-align:center;padding:1px 6px;border-radius:5px;font-size:11.5px;font-weight:600;}\n' +
|
|
66
|
+
'.xq-pct-chip.xq-up{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent);}\n' +
|
|
67
|
+
'.xq-pct-chip.xq-down{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent);}\n' +
|
|
68
|
+
'.xq-pct-chip.xq-flat{background:var(--dsw-alias-bg-layer-2);}\n' +
|
|
69
|
+
'.xq-idx-pct.xq-pct-chip{min-width:46px;padding:0 5px;font-size:10.5px;}\n' +
|
|
70
|
+
'@keyframes xq-flash-up{0%{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 18%, transparent);}100%{background:transparent;}}\n' +
|
|
71
|
+
'@keyframes xq-flash-down{0%{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 18%, transparent);}100%{background:transparent;}}\n' +
|
|
72
|
+
'.xq-flash-up{animation:xq-flash-up .8s ease-out;}\n' +
|
|
73
|
+
'.xq-flash-down{animation:xq-flash-down .8s ease-out;}\n' +
|
|
63
74
|
'.xq-grid{display:grid;gap:0;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;overflow:hidden;margin-bottom:8px;}\n' +
|
|
64
75
|
'.xq-grid-hd,.xq-grid-row{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr 84px;align-items:center;}\n' +
|
|
65
76
|
'.xq-grid-hd{font-size:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);padding:5px 8px;}\n' +
|
|
@@ -478,6 +489,9 @@ exports.default = {
|
|
|
478
489
|
function XueqiuPanel() {
|
|
479
490
|
const [watchlist, setWatchlist] = React.useState([])
|
|
480
491
|
const [quotes, setQuotes] = React.useState([])
|
|
492
|
+
// 价格闪烁:记录上一价与变化方向(symbol -> 1|-1),行渲染时挂一次性动画类
|
|
493
|
+
const prevPrices = React.useRef({})
|
|
494
|
+
const [flashDir, setFlashDir] = React.useState({})
|
|
481
495
|
const [indices, setIndices] = React.useState([])
|
|
482
496
|
const [hot, setHot] = React.useState([])
|
|
483
497
|
const [hotMarket, setHotMarket] = React.useState('cn')
|
|
@@ -514,7 +528,15 @@ exports.default = {
|
|
|
514
528
|
setErr('')
|
|
515
529
|
if (!wl.length) return
|
|
516
530
|
return call('quote', { symbols: wl }).then(function (data) {
|
|
517
|
-
|
|
531
|
+
const list = (data && data.list) || []
|
|
532
|
+
const dirs = {}
|
|
533
|
+
list.forEach(function (q) {
|
|
534
|
+
const prev = prevPrices.current[q.symbol]
|
|
535
|
+
if (prev !== undefined && q.current !== prev) dirs[q.symbol] = q.current > prev ? 1 : -1
|
|
536
|
+
prevPrices.current[q.symbol] = q.current
|
|
537
|
+
})
|
|
538
|
+
if (Object.keys(dirs).length) setFlashDir(dirs)
|
|
539
|
+
setQuotes(list)
|
|
518
540
|
})
|
|
519
541
|
}).catch(function (e) {
|
|
520
542
|
setErr(String((e && e.message) || e))
|
|
@@ -708,7 +730,7 @@ exports.default = {
|
|
|
708
730
|
el('div', { key: 'n', className: 'xq-idx-name' }, q.name),
|
|
709
731
|
el('div', { key: 'r', className: 'xq-idx-row' }, [
|
|
710
732
|
el('span', { key: 'c', className: 'xq-idx-cur ' + colorOf(q.percent) }, fmt(q.current)),
|
|
711
|
-
el('span', { key: 'p', className: 'xq-idx-pct ' + colorOf(q.percent) }, fmtPct(q.percent))
|
|
733
|
+
el('span', { key: 'p', className: 'xq-idx-pct xq-pct-chip ' + colorOf(q.percent) }, fmtPct(q.percent))
|
|
712
734
|
])
|
|
713
735
|
])
|
|
714
736
|
})
|
|
@@ -718,8 +740,8 @@ exports.default = {
|
|
|
718
740
|
el('div', { key: 'a', className: 'xq-name' }, q.name),
|
|
719
741
|
el('div', { key: 'b', className: 'xq-sub' }, q.symbol)
|
|
720
742
|
]),
|
|
721
|
-
el('div', { key: 'c', className: colorOf(q.percent) }, fmt(q.current)),
|
|
722
|
-
el('div', { key: 'p', className: colorOf(q.percent) }, fmtPct(q.percent)),
|
|
743
|
+
el('div', { key: 'c', className: colorOf(q.percent) + (flashDir[q.symbol] === 1 ? ' xq-flash-up' : flashDir[q.symbol] === -1 ? ' xq-flash-down' : '') }, fmt(q.current)),
|
|
744
|
+
el('div', { key: 'p' }, el('span', { key: 'pp', className: 'xq-pct-chip ' + colorOf(q.percent) }, fmtPct(q.percent))),
|
|
723
745
|
el('div', { key: 'v', className: 'xq-sub' }, fmtVol(q.volume)),
|
|
724
746
|
el('div', { key: 'a2', className: 'xq-actions' }, [
|
|
725
747
|
el('button', { key: 'd', className: 'xq-btn-mini', onClick: function (e) { e.stopPropagation(); openDetail(q.symbol) } }, '详情'),
|