refactor: establish standalone application boundary
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
function meaningfulNumber(value) {
|
||||
return value !== null && value !== undefined && value !== "" && Number.isFinite(Number(value));
|
||||
}
|
||||
async function openStock(code, fallback = null) {
|
||||
closeStockPreview();
|
||||
const pools = [state.dashboard?.limits || [], state.dashboard?.broken || [], state.dashboard?.down_limits || []];
|
||||
const row = pools.flat().find((item) => String(item.code) === String(code)) || fallback || { code, name: "--", sector: "其他" };
|
||||
state.activeStock = row;
|
||||
state.stockDetail = null;
|
||||
state.stockDetailIntraday = null;
|
||||
state.stockDetailChartMode = "daily";
|
||||
const requestSequence = ++state.stockDetailRequestSequence;
|
||||
syncDetailChartButtons("stock", "daily");
|
||||
setText("detailCode", row.code);
|
||||
setText("detailName", row.name);
|
||||
setText("detailPrice", formatNumber(row.price, 2));
|
||||
setText("detailChange", `${signed(row.change)}%`);
|
||||
const changeElement = document.querySelector("#detailChange");
|
||||
changeElement.className = changeClass(row.change);
|
||||
setText("detailStreak", row.status === "涨停" ? streakLabel(row.streak) : row.status || "--");
|
||||
setText("detailReason", row.reason || "--");
|
||||
setText("detailSector", row.sector || "其他");
|
||||
setText("detailFirst", row.first_time || "--");
|
||||
setText("detailLast", row.last_time || "--");
|
||||
setText("detailOpen", `${number(row.open_times)} 次`);
|
||||
setText("detailTurnover", `${formatNumber(row.turnover_rate, 2)}%`);
|
||||
setText("detailAmount", `${formatNumber(row.amount_billion, 2)} 亿`);
|
||||
setText("detailSeal", `${formatNumber(row.seal_amount_million, 0)} 万`);
|
||||
setText("chartSource", "正在加载行情");
|
||||
setText("flowNet", "--");
|
||||
setText("flowLarge", "--");
|
||||
setText("flowMedium", "--");
|
||||
setText("flowSmall", "--");
|
||||
document.querySelector("#reasonInput").value = row.reason || "";
|
||||
document.querySelector("#stockNoteContent").value = "";
|
||||
document.querySelector("#stockNotePlan").value = "";
|
||||
renderEmptyState("stockNotes", "正在加载笔记");
|
||||
updateWatchButton();
|
||||
openModalDialog(elements.stockDialog);
|
||||
clearPriceChart("正在加载日 K 数据");
|
||||
try {
|
||||
const query = new URLSearchParams({ trade_date: elements.tradeDate.value });
|
||||
const payload = await apiRequest(`/api/stock/${encodeURIComponent(code)}?${query}`);
|
||||
if (requestSequence !== state.stockDetailRequestSequence) return;
|
||||
state.stockDetail = payload;
|
||||
const stock = payload.stock || {};
|
||||
state.activeStock = { ...row, name: stock.name || row.name, sector: stock.industry || row.sector };
|
||||
setText("detailName", stock.name || row.name);
|
||||
setText("detailPrice", formatNumber(stock.price || row.price, 2));
|
||||
setText("detailChange", `${signed(stock.change ?? row.change)}%`);
|
||||
renderMoneyflow(payload.moneyflow || {});
|
||||
renderStockNotes(payload.notes || []);
|
||||
updateWatchButton();
|
||||
if (state.stockDetailChartMode === "daily") {
|
||||
setText("chartSource", `日 K 行情 · ${payload.prices.length} 个交易日`);
|
||||
requestAnimationFrame(() => drawPriceChart(payload.prices || []));
|
||||
}
|
||||
} catch (error) {
|
||||
if (requestSequence !== state.stockDetailRequestSequence) return;
|
||||
setText("chartSource", "行情加载失败");
|
||||
if (state.stockDetailChartMode === "daily") clearPriceChart(error.message || "行情加载失败");
|
||||
showToast(error.message || "个股详情加载失败");
|
||||
}
|
||||
}
|
||||
|
||||
async function selectStockDetailChart(mode) {
|
||||
const selected = mode === "intraday" ? "intraday" : "daily";
|
||||
state.stockDetailChartMode = selected;
|
||||
syncDetailChartButtons("stock", selected);
|
||||
if (selected === "daily") {
|
||||
const prices = state.stockDetail?.prices || [];
|
||||
setText("chartSource", prices.length ? `日 K 行情 · ${prices.length} 个交易日` : "正在加载行情");
|
||||
if (prices.length) requestAnimationFrame(() => drawPriceChart(prices));
|
||||
else clearPriceChart("正在加载日 K 数据");
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.stockDetailIntraday) {
|
||||
renderStockDetailIntraday(state.stockDetailIntraday);
|
||||
return;
|
||||
}
|
||||
const code = String(state.activeStock?.code || "");
|
||||
if (!/^\d{6}$/.test(code)) return;
|
||||
const requestSequence = state.stockDetailRequestSequence;
|
||||
setText("chartSource", "正在加载分时");
|
||||
clearPriceChart("正在加载分时数据");
|
||||
try {
|
||||
const params = new URLSearchParams({ type: "stock", id: code });
|
||||
const payload = await apiRequest(`/api/chart/intraday?${params}`);
|
||||
if (requestSequence !== state.stockDetailRequestSequence) return;
|
||||
state.stockDetailIntraday = payload;
|
||||
if (state.stockDetailChartMode === "intraday") renderStockDetailIntraday(payload);
|
||||
} catch (error) {
|
||||
if (requestSequence !== state.stockDetailRequestSequence || state.stockDetailChartMode !== "intraday") return;
|
||||
setText("chartSource", "分时暂不可用");
|
||||
clearPriceChart(error.message || "分时行情暂不可用");
|
||||
}
|
||||
}
|
||||
|
||||
function renderStockDetailIntraday(payload) {
|
||||
const points = payload.points || [];
|
||||
if (!points.length) {
|
||||
setText("chartSource", "分时暂不可用");
|
||||
clearPriceChart("分时行情暂不可用");
|
||||
return;
|
||||
}
|
||||
setText("chartSource", `分时 · ${payload.meta?.trade_date || "--"}`);
|
||||
requestAnimationFrame(() => {
|
||||
if (state.stockDetailChartMode !== "intraday") return;
|
||||
drawIntradayCanvas(elements.priceChart, points, [], payload.meta?.previous_close);
|
||||
});
|
||||
}
|
||||
|
||||
function openActiveStockInHeaven() {
|
||||
const code = state.activeStock?.code;
|
||||
if (!/^\d{6}$/.test(String(code || ""))) return;
|
||||
elements.stockDialog.close();
|
||||
state.heavenPanel = "trend";
|
||||
state.heavenManualData = null;
|
||||
const input = document.querySelector("#heavenStockInput");
|
||||
input.value = code;
|
||||
openView("heavenView");
|
||||
selectHeavenPanel("trend", true);
|
||||
}
|
||||
Reference in New Issue
Block a user