feat(HEL-90): P2b 验收五条整改 + 夜间黑字排查
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -1076,7 +1076,7 @@
|
||||
|
||||
.m-chart-card {
|
||||
padding: 8px 6px;
|
||||
height: var(--mobile-chart-height);
|
||||
height: var(--mobile-chart-height-compact);
|
||||
}
|
||||
|
||||
.m-chart-card svg {
|
||||
@@ -1148,18 +1148,18 @@
|
||||
|
||||
.m-sent-metrics {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
gap: 6px;
|
||||
margin-top: 12px;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.m-sent-metric {
|
||||
flex: 1;
|
||||
min-width: 72px;
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 8px;
|
||||
padding: 8px 6px;
|
||||
border-radius: 6px;
|
||||
background: var(--surface-muted);
|
||||
}
|
||||
@@ -1167,18 +1167,31 @@
|
||||
.m-sent-metric span {
|
||||
font-size: var(--font-size-aux);
|
||||
color: var(--text-tertiary);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.m-sent-metric b {
|
||||
font-size: var(--font-size-card-title);
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.m-sent-up b { color: var(--market-up); }
|
||||
.m-sent-warn b { color: var(--warning); }
|
||||
.m-sent-down b { color: var(--market-down); }
|
||||
|
||||
@media (max-width: 359px) {
|
||||
.m-sent-metrics { gap: 4px; }
|
||||
.m-sent-metric { padding: 8px 4px; }
|
||||
.m-sent-metric span { font-size: 10.5px; }
|
||||
.m-sent-metric b { font-size: 14px; }
|
||||
}
|
||||
|
||||
.m-sent-advice {
|
||||
margin-top: 10px;
|
||||
font-size: var(--font-size-label);
|
||||
@@ -1337,12 +1350,14 @@
|
||||
.m-ladder-tier-count {
|
||||
font-size: var(--font-size-label);
|
||||
color: var(--text-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.m-ladder-rate {
|
||||
margin-left: auto;
|
||||
flex: 0 0 auto;
|
||||
font-size: var(--font-size-aux);
|
||||
color: var(--text-tertiary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.m-ladder-stocks {
|
||||
@@ -1426,15 +1441,24 @@
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.m-ladder-more {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
.m-ladder-fold {
|
||||
margin-left: auto;
|
||||
flex: 0 0 auto;
|
||||
min-height: 32px;
|
||||
padding: 0 2px;
|
||||
border: 0;
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
background: transparent;
|
||||
color: var(--action);
|
||||
font-size: var(--font-size-label);
|
||||
font-size: var(--font-size-aux);
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
transition: transform var(--motion-press-release) var(--ease-press);
|
||||
}
|
||||
|
||||
.m-ladder-fold:active {
|
||||
transform: scale(0.94);
|
||||
transition-duration: var(--motion-press);
|
||||
}
|
||||
|
||||
.m-rate-list {
|
||||
@@ -1512,16 +1536,17 @@
|
||||
}
|
||||
|
||||
.m-rotation-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.m-rotation-chip {
|
||||
display: inline-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 10px;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border-strong);
|
||||
background: var(--surface);
|
||||
@@ -1536,14 +1561,28 @@
|
||||
background: var(--surface-hover);
|
||||
}
|
||||
|
||||
.m-rotation-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.m-rotation-chip strong {
|
||||
font-size: var(--font-size-label);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.m-rotation-chip small {
|
||||
font-size: var(--font-size-aux);
|
||||
color: var(--text-secondary);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.m-rotation-chip.heat-strong {
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
--mobile-safe-bottom: env(safe-area-inset-bottom, 0px);
|
||||
--mobile-page-padding: 12px;
|
||||
--mobile-chart-height: 240px;
|
||||
--mobile-chart-height-compact: 168px;
|
||||
--mobile-table-row-height: 44px;
|
||||
--mobile-table-header-height: 40px;
|
||||
--mobile-icon-cell: 78px;
|
||||
|
||||
+53
-20
@@ -372,7 +372,7 @@
|
||||
}
|
||||
|
||||
const head = ordered.map(function (col, i) {
|
||||
const sortable = sortableColumn(col);
|
||||
const sortable = !(opts && opts.noSort) && sortableColumn(col);
|
||||
let extraCls = "";
|
||||
let extraAttrs = "";
|
||||
let indicator = "";
|
||||
@@ -813,7 +813,7 @@
|
||||
}
|
||||
|
||||
function sentimentTrendChart(rows) {
|
||||
const W = 360, H = 240, padL = 8, padR = 30, padT = 12, padB = 22;
|
||||
const W = 360, H = 168, padL = 8, padR = 30, padT = 10, padB = 20;
|
||||
const pw = W - padL - padR;
|
||||
const ph = H - padT - padB;
|
||||
if (!rows.length) return emptyChart("暂无情绪历史数据");
|
||||
@@ -927,7 +927,7 @@
|
||||
return raw.slice().reverse().map(function (r) {
|
||||
return Object.assign({}, r, { trade_date: displayCompactDate(r.trade_date) });
|
||||
});
|
||||
}, {});
|
||||
}, { noSort: true });
|
||||
}
|
||||
|
||||
function sentMetric(label, valueHtml, tone) {
|
||||
@@ -951,6 +951,7 @@
|
||||
|
||||
function loadLadder() {
|
||||
const seq = nextSeq();
|
||||
Object.keys(expandedLadder).forEach(function (level) { delete expandedLadder[level]; });
|
||||
const date = state.requestedDate;
|
||||
global.MobileAPI.request("/api/dashboard?trade_date=" + encodeURIComponent(date)).then(function (payload) {
|
||||
if (seq !== state.seq) return;
|
||||
@@ -974,6 +975,7 @@
|
||||
const rateHtml = level > 1 && count ? '<span class="m-ladder-rate">较' + (level - 1) + "板 " + rate + "%</span>" : "";
|
||||
|
||||
let stocksHtml = "";
|
||||
let foldBtn = "";
|
||||
if (gap) {
|
||||
stocksHtml = '<div class="m-ladder-gap">' + (level >= maxLevel ? "断层 · " + escapeHtml(label) + "及以上空缺" : "该层暂时空缺") + "</div>";
|
||||
} else {
|
||||
@@ -995,15 +997,16 @@
|
||||
"<small>" + escapeHtml(s.first_time && s.first_time !== "--" ? s.first_time : "时间待校正") + " · " + escapeHtml(amount) + "</small></span>" +
|
||||
"</button>";
|
||||
}).join("");
|
||||
const remaining = !expanded && cap && stocks.length > cap ? stocks.length - cap : 0;
|
||||
if (remaining) {
|
||||
stocksHtml += '<button class="m-ladder-more" type="button" data-ladder-expand="' + level + '">展开剩余 ' + remaining + " 只</button>";
|
||||
if (cap && stocks.length > cap) {
|
||||
const remaining = stocks.length - cap;
|
||||
foldBtn = '<button class="m-ladder-fold" type="button" data-ladder-expand="' + level + '">' +
|
||||
(expanded ? "收起 \u25b4" : "展开剩余 " + remaining + " 只 \u25be") + "</button>";
|
||||
}
|
||||
}
|
||||
|
||||
return '<section class="m-ladder-tier' + (gap ? " is-gap" : "") + '">' +
|
||||
'<div class="m-ladder-tier-head"><span class="m-ladder-tier-level" style="color:' + color + '">' + escapeHtml(label) + "</span>" +
|
||||
'<span class="m-ladder-tier-count">' + count + " 只</span>" + rateHtml + "</div>" +
|
||||
'<span class="m-ladder-tier-count">' + count + " 只</span>" + rateHtml + foldBtn + "</div>" +
|
||||
'<div class="m-ladder-stocks">' + stocksHtml + "</div></section>";
|
||||
}
|
||||
|
||||
@@ -1019,7 +1022,6 @@
|
||||
ladders.forEach(function (g) { groupMap[number(g.level)] = g; });
|
||||
const yesterday = dash.yesterday_limits || [];
|
||||
const prevMax = yesterday.reduce(function (m, r) { return Math.max(m, number(r.prior_streak)); }, 0);
|
||||
const spaceStocks = (groupMap[maxLevel] || {}).stocks || [];
|
||||
const spaceChange = prevMax && maxLevel < prevMax ? "较昨日 " + prevMax + " 板 ↓ 压缩"
|
||||
: prevMax && maxLevel > prevMax ? "较昨日 " + prevMax + " 板 ↑ 抬升" : "高度与昨日接近";
|
||||
const spaceNote = maxLevel >= 5 ? "高位梯队仍有辨识度,重点看承接。"
|
||||
@@ -1027,7 +1029,6 @@
|
||||
|
||||
const apexHtml = '<div class="m-apex">' +
|
||||
'<div class="m-apex-head"><span>空间板</span><strong>' + (maxLevel ? maxLevel + " 板" : "--") + "</strong><em>" + escapeHtml(spaceChange) + "</em></div>" +
|
||||
'<p>' + (spaceStocks.length ? spaceStocks.map(function (s) { return "<b>" + escapeHtml(s.name) + "</b>(" + escapeHtml(s.sector || "其他") + ")"; }).join(" · ") : "暂无空间板") + "</p>" +
|
||||
"<small>" + escapeHtml(spaceNote) + "</small></div>";
|
||||
|
||||
const tiers = [];
|
||||
@@ -1082,8 +1083,10 @@
|
||||
const heat = strength >= 90 ? "strong" : strength >= 70 ? "warm" : "mild";
|
||||
return '<button class="m-rotation-chip ' + heat + '" type="button" data-rotation-sector="' + escapeHtml(sector.name) + '" data-rotation-date="' + escapeHtml(day.trade_date) + '">' +
|
||||
'<span class="m-rotation-rank rank-' + Math.min(number(sector.rank), 4) + '">' + number(sector.rank) + "</span>" +
|
||||
'<span class="m-rotation-copy">' +
|
||||
"<strong>" + escapeHtml(sector.name) + "</strong>" +
|
||||
"<small>" + number(sector.count) + " 家 · " + formatNumber(number(sector.strength), 0) + "</small>" +
|
||||
"</span>" +
|
||||
"</button>";
|
||||
}).join("");
|
||||
return '<section class="m-rotation-day' + (day.trade_date === latestDate ? " is-latest" : "") + '">' +
|
||||
@@ -1586,30 +1589,60 @@
|
||||
|
||||
function bindSheetDrag(root) {
|
||||
const sheet = root.querySelector(".m-sheet");
|
||||
const backdrop = root.querySelector(".m-sheet-backdrop");
|
||||
const handle = root.querySelector(".m-sheet-handle");
|
||||
if (!sheet || !handle) return;
|
||||
const head = root.querySelector(".m-sheet-head");
|
||||
if (!sheet) return;
|
||||
let startY = 0;
|
||||
let startT = 0;
|
||||
let dragging = false;
|
||||
handle.addEventListener("touchstart", function (event) {
|
||||
|
||||
function begin(event) {
|
||||
if (event.target && event.target.closest(".m-sheet-close")) return;
|
||||
dragging = true;
|
||||
startY = event.touches[0].clientY;
|
||||
startY = event.clientY;
|
||||
startT = Date.now();
|
||||
sheet.style.transition = "none";
|
||||
}, { passive: true });
|
||||
handle.addEventListener("touchmove", function (event) {
|
||||
if (backdrop) backdrop.style.transition = "none";
|
||||
if (event.currentTarget && event.currentTarget.setPointerCapture) {
|
||||
try { event.currentTarget.setPointerCapture(event.pointerId); } catch (e) { /* noop */ }
|
||||
}
|
||||
}
|
||||
|
||||
function move(event) {
|
||||
if (!dragging) return;
|
||||
const dy = event.touches[0].clientY - startY;
|
||||
if (dy > 0) sheet.style.transform = "translateY(" + dy + "px)";
|
||||
}, { passive: true });
|
||||
handle.addEventListener("touchend", function (event) {
|
||||
const dy = event.clientY - startY;
|
||||
if (dy > 0) {
|
||||
sheet.style.transform = "translateY(" + dy + "px)";
|
||||
if (backdrop) {
|
||||
const ratio = Math.min(1, dy / sheet.offsetHeight);
|
||||
backdrop.style.opacity = String(Math.max(0, 1 - ratio));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function end(event) {
|
||||
if (!dragging) return;
|
||||
dragging = false;
|
||||
sheet.style.transition = "";
|
||||
const dy = event.changedTouches[0].clientY - startY;
|
||||
if (dy > sheet.offsetHeight / 3) {
|
||||
if (backdrop) { backdrop.style.opacity = ""; backdrop.style.transition = ""; }
|
||||
const dy = event.clientY - startY;
|
||||
const dt = Date.now() - startT;
|
||||
const velocity = dt > 0 ? dy / dt : 0;
|
||||
if (dy >= sheet.offsetHeight * 0.25 || (velocity >= 0.5 && dy >= 40)) {
|
||||
closeSheet();
|
||||
} else {
|
||||
sheet.style.transform = "";
|
||||
}
|
||||
}
|
||||
|
||||
[handle, head].forEach(function (grip) {
|
||||
if (!grip) return;
|
||||
grip.style.touchAction = "none";
|
||||
grip.addEventListener("pointerdown", begin);
|
||||
grip.addEventListener("pointermove", move);
|
||||
grip.addEventListener("pointerup", end);
|
||||
grip.addEventListener("pointercancel", end);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user