refactor: establish standalone application boundary

This commit is contained in:
leefer
2026-08-03 21:42:25 +08:00
parent cc5fb8d73e
commit e1e76cd51e
324 changed files with 63090 additions and 44743 deletions
File diff suppressed because it is too large Load Diff
+57
View File
@@ -0,0 +1,57 @@
<section id="reviewWorkspaceView" class="workspace-view page redesigned-review-view">
<header class="section-toolbar lad-head review-page-header">
<div class="section-title-group review-page-title">
<h2>我的复盘</h2>
<span class="section-subtitle">复盘日期跟随顶栏日期:<b id="reviewDataDate">--</b> · 自选跟踪、交易记录与明日计划</span>
</div>
<button id="reviewHistoryToggle" class="button review-history-toggle" type="button" aria-expanded="false" aria-controls="reviewHistoryPanel"><i data-lucide="history"></i><span>历史复盘</span></button>
</header>
<div class="review-workspace review-grid">
<div class="review-left-stack">
<section class="workspace-section watchlist-section card">
<div class="workspace-heading card-h review-card-heading">
<div><h3>自选跟踪</h3><span id="watchlistCount" class="review-count-tag">0 只</span></div>
<button id="openWatchlistDialog" class="button review-add-watch" type="button"><i data-lucide="plus"></i><span>添加自选</span></button>
</div>
<div class="table-frame tbl-wrap workspace-table-frame">
<table class="data-table tbl review-watchlist-table">
<thead><tr><th>标记</th><th>股票</th><th>所属板块</th><th class="number num">今日涨幅(%</th><th class="number num">5日涨幅(%</th><th class="number num">竞价关注(分)</th><th>跟踪备注</th><th>操作</th></tr></thead>
<tbody id="watchlistTableBody"></tbody>
</table>
<div id="watchlistEmpty" class="empty-state">从股票详情中添加自选,持续跟踪关键标的</div>
</div>
</section>
<section class="workspace-section trade-journal-section card">
<div class="workspace-heading card-h trade-log-heading review-card-heading">
<div><h3>交易日志</h3><span id="tradeLogCount" class="review-count-tag">0 条</span></div>
<button id="openTradeLogDialog" class="button primary" type="button"><i data-lucide="notebook-pen"></i><span>交易日志</span></button>
</div>
<div id="tradeLogSummary" class="trade-log-summary"></div>
<div class="table-frame tbl-wrap trade-log-table-frame">
<table class="data-table tbl trade-log-table">
<thead><tr><th>日期</th><th>股票</th><th>动作</th><th class="number num">仓位(%</th><th class="number num">盈亏(%</th><th class="number num">盈亏金额(元)</th><th>情绪 / 标签</th><th>交易复核</th><th>操作</th></tr></thead>
<tbody id="tradeLogTableBody"></tbody>
</table>
<div id="tradeLogEmpty" class="empty-state">当前日期暂无交易记录,空仓也值得记录原因</div>
</div>
</section>
</div>
<section class="workspace-section journal-section card">
<div class="workspace-heading card-h review-card-heading">
<h3>每日复盘</h3>
<input id="journalDate" class="date-input" type="date" aria-label="复盘日期">
</div>
<form id="journalForm" class="journal-form">
<label class="form-field journal-summary-field"><span>今日盘面一句话</span><input id="journalSummary" maxlength="500" placeholder="用一句话概括今天最重要的市场特征"></label>
<label class="form-field"><span>今日做对了什么 / 做错了什么</span><textarea id="journalContent" maxlength="5000" placeholder="对照计划与纪律:&#10;· 做对的:&#10;· 做错的:&#10;· 漏掉的信号:"></textarea></label>
<label class="form-field"><span>明日策略</span><textarea id="journalPlan" maxlength="2000" placeholder="记录观察方向、触发条件、计划仓位和风险点"></textarea></label>
<p class="journal-form-hint">不求面面俱到,只记录影响下一次决策的事实。</p>
<div class="dialog-actions"><button class="button primary" type="submit"><i data-lucide="check"></i><span>完成复盘</span></button></div>
</form>
</section>
<section id="reviewHistoryPanel" class="workspace-section notes-history-section card" hidden>
<div class="workspace-heading card-h review-card-heading"><div><h3>最近复盘</h3><span id="notesCount" class="review-count-tag">0 条</span></div><small>按交易日倒序</small></div>
<div id="notesHistory" class="notes-history"><div class="empty-state">暂无复盘记录</div></div>
</section>
</div>
</section>
+51 -4
View File
@@ -1,8 +1,12 @@
let watchlistSearchTimer = null;
let assistantRenderFrame = 0;
window.XiaobaiPageModules.register("review", ["reviewWorkspaceView"], {
bind: bindReviewEvents,
enter: ["loadReview"],
});
/* PRESERVATION-SOURCE-BEGIN app.js:3029-3470 */
async function loadReviewWorkspace() {
try {
const [watchlistPayload, notesPayload, tradesPayload] = await Promise.all([
@@ -445,8 +449,6 @@ async function deleteNote(noteId, compact) {
}
}
/* PRESERVATION-SOURCE-END app.js:3029-3470 */
/* PRESERVATION-SOURCE-BEGIN app.js:7720-7968 */
async function loadAlerts(openDialog = false) {
try {
const query = new URLSearchParams({ status: state.alertFilter, as_of: todayString() });
@@ -696,4 +698,49 @@ function updateAssistantControls() {
});
}
/* PRESERVATION-SOURCE-END app.js:7720-7968 */
function bindReviewEvents() {
document.querySelector("#alertButton").addEventListener("click", openAlerts);
document.querySelector("#assistantButton").addEventListener("click", openReviewAssistant);
document.querySelector("#closeAssistantDialog").addEventListener("click", () => elements.assistantDialog.close());
document.querySelector("#assistantForm").addEventListener("submit", sendAssistantQuestion);
document.querySelector("#stopAssistant").addEventListener("click", stopAssistantResponse);
document.querySelector("#clearAssistantMessages").addEventListener("click", clearAssistantConversation);
document.querySelectorAll("[data-assistant-prompt]").forEach((button) => {
button.addEventListener("click", () => useAssistantPrompt(button.dataset.assistantPrompt));
});
document.querySelector("#closeAlertsDialog").addEventListener("click", () => elements.alertsDialog.close());
document.querySelector("#alertForm").addEventListener("submit", saveAlert);
document.querySelector("#markAllAlertsRead").addEventListener("click", markAllAlertsRead);
document.querySelector("#alertList").addEventListener("click", handleAlertAction);
document.querySelectorAll("[data-alert-filter]").forEach((button) => {
button.addEventListener("click", () => selectAlertFilter(button.dataset.alertFilter));
});
document.querySelector("#journalForm").addEventListener("submit", saveJournal);
document.querySelector("#journalDate").addEventListener("change", populateJournalForm);
document.querySelector("#openWatchlistDialog").addEventListener("click", () => openWatchlistDialog());
document.querySelector("#closeWatchlistDialog").addEventListener("click", closeWatchlistDialog);
document.querySelector("#cancelWatchlistEdit").addEventListener("click", closeWatchlistDialog);
document.querySelector("#changeWatchlistSelection").addEventListener("click", clearWatchlistSelection);
document.querySelector("#watchlistSearchInput").addEventListener("input", scheduleWatchlistSearch);
document.querySelector("#watchlistForm").addEventListener("submit", saveWatchlistFromDialog);
document.querySelector("#watchlistSearchResults").addEventListener("click", handleWatchlistSearchResult);
document.querySelector("#reviewHistoryToggle").addEventListener("click", (event) => {
const panel = document.querySelector("#reviewHistoryPanel");
const expanded = event.currentTarget.getAttribute("aria-expanded") === "true";
event.currentTarget.setAttribute("aria-expanded", String(!expanded));
event.currentTarget.querySelector("span").textContent = expanded ? "历史复盘" : "收起历史";
panel.hidden = expanded;
if (!expanded) panel.scrollIntoView({ behavior: "smooth", block: "nearest" });
});
document.querySelector("#openTradeLogDialog").addEventListener("click", openTradeLogDialog);
document.querySelector("#closeTradeLogDialog").addEventListener("click", closeTradeLogDialog);
document.querySelector("#tradeLogForm").addEventListener("submit", saveTradeLog);
document.querySelector("#cancelTradeEdit").addEventListener("click", closeTradeLogDialog);
elements.tradeLogDialog.addEventListener("close", resetTradeLogForm);
document.querySelector("#tradeLogTableBody").addEventListener("click", handleTradeLogAction);
document.querySelector("#stockNoteForm").addEventListener("submit", saveStockNote);
document.querySelector("#watchStockButton").addEventListener("click", toggleActiveWatchlist);
document.querySelector("#stockHeavenButton").addEventListener("click", openActiveStockInHeaven);
document.querySelector("#stockReminderButton").addEventListener("click", openStockReminder);
}