fix: AI review loading UX and Gate preview snapshot time filter SQL
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -232,7 +232,7 @@
|
|||||||
.stats-period-block h3{font-size:1rem;color:#dbe4ff;margin-bottom:4px}
|
.stats-period-block h3{font-size:1rem;color:#dbe4ff;margin-bottom:4px}
|
||||||
.stats-period-block .sub{font-size:.78rem;color:#8892b0;margin-bottom:10px;line-height:1.4}
|
.stats-period-block .sub{font-size:.78rem;color:#8892b0;margin-bottom:10px;line-height:1.4}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="/static/instance_theme.css?v=6">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=7">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body data-page="{{ page }}">
|
<body data-page="{{ page }}">
|
||||||
@@ -813,11 +813,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input type="date" id="day_date">
|
<input type="date" id="day_date">
|
||||||
<button type="button" onclick="genDaily()">生成日复盘</button>
|
<button type="button" id="gen-daily-btn" onclick="genDaily()">生成日复盘</button>
|
||||||
<button type="button" onclick="exportDailyBundleMd()" style="background:#1f3a5a">导出当日日复盘MD</button>
|
<button type="button" onclick="exportDailyBundleMd()" style="background:#1f3a5a">导出当日日复盘MD</button>
|
||||||
<input type="date" id="week_start">
|
<input type="date" id="week_start">
|
||||||
<input type="date" id="week_end">
|
<input type="date" id="week_end">
|
||||||
<button type="button" onclick="genWeekly()">生成周复盘</button>
|
<button type="button" id="gen-weekly-btn" onclick="genWeekly()">生成周复盘</button>
|
||||||
<button type="button" onclick="exportWeeklyBundleMd()" style="background:#1f3a5a">导出当周复盘MD</button>
|
<button type="button" onclick="exportWeeklyBundleMd()" style="background:#1f3a5a">导出当周复盘MD</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="ai-result-wrap" id="daily_result_wrap" style="display:none">
|
<div class="ai-result-wrap" id="daily_result_wrap" style="display:none">
|
||||||
@@ -902,7 +902,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/instance_ui.js?v=1"></script>
|
<script src="/static/instance_ui.js?v=1"></script>
|
||||||
<script src="/static/ai_review_render.js?v=1"></script>
|
<script src="/static/ai_review_render.js?v=2"></script>
|
||||||
<script src="/static/form_submit_guard.js?v=2"></script>
|
<script src="/static/form_submit_guard.js?v=2"></script>
|
||||||
<script>
|
<script>
|
||||||
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
||||||
@@ -1233,36 +1233,76 @@ function loadReviews(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function genDaily(){
|
function genDaily(){
|
||||||
|
if(window.AiReviewRender && AiReviewRender.isGenerating && AiReviewRender.isGenerating()) return;
|
||||||
const d = document.getElementById("day_date").value;
|
const d = document.getElementById("day_date").value;
|
||||||
if(!d){alert("请选择日期");return;}
|
if(!d){alert("请选择日期");return;}
|
||||||
|
if(window.AiReviewRender && AiReviewRender.setGenerating){
|
||||||
|
AiReviewRender.setGenerating({
|
||||||
|
wrapId:"daily_result_wrap",
|
||||||
|
elId:"daily_result",
|
||||||
|
btnId:"gen-daily-btn",
|
||||||
|
message:"生成日复盘中,请稍候…(AI 分析可能需要 1~3 分钟)",
|
||||||
|
btnLabel:"日复盘生成中…"
|
||||||
|
});
|
||||||
|
}
|
||||||
fetch("/ai_daily_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`date=${encodeURIComponent(d)}`})
|
fetch("/ai_daily_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`date=${encodeURIComponent(d)}`})
|
||||||
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
||||||
.then(data=>{
|
.then(data=>{
|
||||||
|
if(!data || data.result == null) throw new Error("返回数据为空");
|
||||||
const el=document.getElementById("daily_result");
|
const el=document.getElementById("daily_result");
|
||||||
const wrap=document.getElementById("daily_result_wrap");
|
const wrap=document.getElementById("daily_result_wrap");
|
||||||
setAiReviewMarkdown(el, data.result);
|
setAiReviewMarkdown(el, data.result);
|
||||||
if(wrap){ wrap.style.display="block"; }
|
if(wrap){ wrap.style.display="block"; }
|
||||||
else { el.style.display="block"; }
|
else if(el){ el.style.display="block"; }
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-daily-btn");
|
||||||
loadReviews();
|
loadReviews();
|
||||||
})
|
})
|
||||||
.catch(e=>alert("生成日复盘失败:"+(e.message||e)));
|
.catch(e=>{
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-daily-btn");
|
||||||
|
const el=document.getElementById("daily_result");
|
||||||
|
if(el){
|
||||||
|
el.classList.remove("is-loading","ai-result-md");
|
||||||
|
el.innerText="生成失败,请重试。";
|
||||||
|
}
|
||||||
|
alert("生成日复盘失败:"+(e.message||e));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function genWeekly(){
|
function genWeekly(){
|
||||||
|
if(window.AiReviewRender && AiReviewRender.isGenerating && AiReviewRender.isGenerating()) return;
|
||||||
const s=document.getElementById("week_start").value;
|
const s=document.getElementById("week_start").value;
|
||||||
const e=document.getElementById("week_end").value;
|
const e=document.getElementById("week_end").value;
|
||||||
if(!s || !e){alert("请选择起止日期");return;}
|
if(!s || !e){alert("请选择起止日期");return;}
|
||||||
|
if(window.AiReviewRender && AiReviewRender.setGenerating){
|
||||||
|
AiReviewRender.setGenerating({
|
||||||
|
wrapId:"weekly_result_wrap",
|
||||||
|
elId:"weekly_result",
|
||||||
|
btnId:"gen-weekly-btn",
|
||||||
|
message:"生成周复盘中,请稍候…(AI 分析可能需要 1~3 分钟)",
|
||||||
|
btnLabel:"周复盘生成中…"
|
||||||
|
});
|
||||||
|
}
|
||||||
fetch("/ai_weekly_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`start_date=${encodeURIComponent(s)}&end_date=${encodeURIComponent(e)}`})
|
fetch("/ai_weekly_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`start_date=${encodeURIComponent(s)}&end_date=${encodeURIComponent(e)}`})
|
||||||
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
||||||
.then(data=>{
|
.then(data=>{
|
||||||
|
if(!data || data.result == null) throw new Error("返回数据为空");
|
||||||
const el=document.getElementById("weekly_result");
|
const el=document.getElementById("weekly_result");
|
||||||
const wrap=document.getElementById("weekly_result_wrap");
|
const wrap=document.getElementById("weekly_result_wrap");
|
||||||
setAiReviewMarkdown(el, data.result);
|
setAiReviewMarkdown(el, data.result);
|
||||||
if(wrap){ wrap.style.display="block"; }
|
if(wrap){ wrap.style.display="block"; }
|
||||||
else { el.style.display="block"; }
|
else if(el){ el.style.display="block"; }
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-weekly-btn");
|
||||||
loadReviews();
|
loadReviews();
|
||||||
})
|
})
|
||||||
.catch(e=>alert("生成周复盘失败:"+(e.message||e)));
|
.catch(e=>{
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-weekly-btn");
|
||||||
|
const el=document.getElementById("weekly_result");
|
||||||
|
if(el){
|
||||||
|
el.classList.remove("is-loading","ai-result-md");
|
||||||
|
el.innerText="生成失败,请重试。";
|
||||||
|
}
|
||||||
|
alert("生成周复盘失败:"+(e.message||e));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportDailyBundleMd(){
|
function exportDailyBundleMd(){
|
||||||
|
|||||||
@@ -232,7 +232,7 @@
|
|||||||
.stats-period-block h3{font-size:1rem;color:#dbe4ff;margin-bottom:4px}
|
.stats-period-block h3{font-size:1rem;color:#dbe4ff;margin-bottom:4px}
|
||||||
.stats-period-block .sub{font-size:.78rem;color:#8892b0;margin-bottom:10px;line-height:1.4}
|
.stats-period-block .sub{font-size:.78rem;color:#8892b0;margin-bottom:10px;line-height:1.4}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="/static/instance_theme.css?v=6">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=7">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body data-page="{{ page }}">
|
<body data-page="{{ page }}">
|
||||||
@@ -813,11 +813,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input type="date" id="day_date">
|
<input type="date" id="day_date">
|
||||||
<button type="button" onclick="genDaily()">生成日复盘</button>
|
<button type="button" id="gen-daily-btn" onclick="genDaily()">生成日复盘</button>
|
||||||
<button type="button" onclick="exportDailyBundleMd()" style="background:#1f3a5a">导出当日日复盘MD</button>
|
<button type="button" onclick="exportDailyBundleMd()" style="background:#1f3a5a">导出当日日复盘MD</button>
|
||||||
<input type="date" id="week_start">
|
<input type="date" id="week_start">
|
||||||
<input type="date" id="week_end">
|
<input type="date" id="week_end">
|
||||||
<button type="button" onclick="genWeekly()">生成周复盘</button>
|
<button type="button" id="gen-weekly-btn" onclick="genWeekly()">生成周复盘</button>
|
||||||
<button type="button" onclick="exportWeeklyBundleMd()" style="background:#1f3a5a">导出当周复盘MD</button>
|
<button type="button" onclick="exportWeeklyBundleMd()" style="background:#1f3a5a">导出当周复盘MD</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="ai-result-wrap" id="daily_result_wrap" style="display:none">
|
<div class="ai-result-wrap" id="daily_result_wrap" style="display:none">
|
||||||
@@ -902,7 +902,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/instance_ui.js?v=1"></script>
|
<script src="/static/instance_ui.js?v=1"></script>
|
||||||
<script src="/static/ai_review_render.js?v=1"></script>
|
<script src="/static/ai_review_render.js?v=2"></script>
|
||||||
<script src="/static/form_submit_guard.js?v=2"></script>
|
<script src="/static/form_submit_guard.js?v=2"></script>
|
||||||
<script>
|
<script>
|
||||||
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
||||||
@@ -1233,36 +1233,76 @@ function loadReviews(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function genDaily(){
|
function genDaily(){
|
||||||
|
if(window.AiReviewRender && AiReviewRender.isGenerating && AiReviewRender.isGenerating()) return;
|
||||||
const d = document.getElementById("day_date").value;
|
const d = document.getElementById("day_date").value;
|
||||||
if(!d){alert("请选择日期");return;}
|
if(!d){alert("请选择日期");return;}
|
||||||
|
if(window.AiReviewRender && AiReviewRender.setGenerating){
|
||||||
|
AiReviewRender.setGenerating({
|
||||||
|
wrapId:"daily_result_wrap",
|
||||||
|
elId:"daily_result",
|
||||||
|
btnId:"gen-daily-btn",
|
||||||
|
message:"生成日复盘中,请稍候…(AI 分析可能需要 1~3 分钟)",
|
||||||
|
btnLabel:"日复盘生成中…"
|
||||||
|
});
|
||||||
|
}
|
||||||
fetch("/ai_daily_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`date=${encodeURIComponent(d)}`})
|
fetch("/ai_daily_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`date=${encodeURIComponent(d)}`})
|
||||||
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
||||||
.then(data=>{
|
.then(data=>{
|
||||||
|
if(!data || data.result == null) throw new Error("返回数据为空");
|
||||||
const el=document.getElementById("daily_result");
|
const el=document.getElementById("daily_result");
|
||||||
const wrap=document.getElementById("daily_result_wrap");
|
const wrap=document.getElementById("daily_result_wrap");
|
||||||
setAiReviewMarkdown(el, data.result);
|
setAiReviewMarkdown(el, data.result);
|
||||||
if(wrap){ wrap.style.display="block"; }
|
if(wrap){ wrap.style.display="block"; }
|
||||||
else { el.style.display="block"; }
|
else if(el){ el.style.display="block"; }
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-daily-btn");
|
||||||
loadReviews();
|
loadReviews();
|
||||||
})
|
})
|
||||||
.catch(e=>alert("生成日复盘失败:"+(e.message||e)));
|
.catch(e=>{
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-daily-btn");
|
||||||
|
const el=document.getElementById("daily_result");
|
||||||
|
if(el){
|
||||||
|
el.classList.remove("is-loading","ai-result-md");
|
||||||
|
el.innerText="生成失败,请重试。";
|
||||||
|
}
|
||||||
|
alert("生成日复盘失败:"+(e.message||e));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function genWeekly(){
|
function genWeekly(){
|
||||||
|
if(window.AiReviewRender && AiReviewRender.isGenerating && AiReviewRender.isGenerating()) return;
|
||||||
const s=document.getElementById("week_start").value;
|
const s=document.getElementById("week_start").value;
|
||||||
const e=document.getElementById("week_end").value;
|
const e=document.getElementById("week_end").value;
|
||||||
if(!s || !e){alert("请选择起止日期");return;}
|
if(!s || !e){alert("请选择起止日期");return;}
|
||||||
|
if(window.AiReviewRender && AiReviewRender.setGenerating){
|
||||||
|
AiReviewRender.setGenerating({
|
||||||
|
wrapId:"weekly_result_wrap",
|
||||||
|
elId:"weekly_result",
|
||||||
|
btnId:"gen-weekly-btn",
|
||||||
|
message:"生成周复盘中,请稍候…(AI 分析可能需要 1~3 分钟)",
|
||||||
|
btnLabel:"周复盘生成中…"
|
||||||
|
});
|
||||||
|
}
|
||||||
fetch("/ai_weekly_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`start_date=${encodeURIComponent(s)}&end_date=${encodeURIComponent(e)}`})
|
fetch("/ai_weekly_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`start_date=${encodeURIComponent(s)}&end_date=${encodeURIComponent(e)}`})
|
||||||
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
||||||
.then(data=>{
|
.then(data=>{
|
||||||
|
if(!data || data.result == null) throw new Error("返回数据为空");
|
||||||
const el=document.getElementById("weekly_result");
|
const el=document.getElementById("weekly_result");
|
||||||
const wrap=document.getElementById("weekly_result_wrap");
|
const wrap=document.getElementById("weekly_result_wrap");
|
||||||
setAiReviewMarkdown(el, data.result);
|
setAiReviewMarkdown(el, data.result);
|
||||||
if(wrap){ wrap.style.display="block"; }
|
if(wrap){ wrap.style.display="block"; }
|
||||||
else { el.style.display="block"; }
|
else if(el){ el.style.display="block"; }
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-weekly-btn");
|
||||||
loadReviews();
|
loadReviews();
|
||||||
})
|
})
|
||||||
.catch(e=>alert("生成周复盘失败:"+(e.message||e)));
|
.catch(e=>{
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-weekly-btn");
|
||||||
|
const el=document.getElementById("weekly_result");
|
||||||
|
if(el){
|
||||||
|
el.classList.remove("is-loading","ai-result-md");
|
||||||
|
el.innerText="生成失败,请重试。";
|
||||||
|
}
|
||||||
|
alert("生成周复盘失败:"+(e.message||e));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportDailyBundleMd(){
|
function exportDailyBundleMd(){
|
||||||
|
|||||||
@@ -5573,9 +5573,10 @@ def render_main_page(page="trade"):
|
|||||||
preview_snapshots = []
|
preview_snapshots = []
|
||||||
if page == "records":
|
if page == "records":
|
||||||
try:
|
try:
|
||||||
|
snap_ts = sql_list_time_field("preview_created_at", "snapshot_at")
|
||||||
snap_rows = conn.execute(
|
snap_rows = conn.execute(
|
||||||
f"SELECT * FROM trend_pullback_preview_snapshots WHERE {sql_list_time_field('preview_created_at')} >= ? "
|
f"SELECT * FROM trend_pullback_preview_snapshots WHERE {snap_ts} >= ? "
|
||||||
f"AND {sql_list_time_field('preview_created_at')} <= ? ORDER BY id DESC LIMIT 500",
|
f"AND {snap_ts} <= ? ORDER BY id DESC LIMIT 500",
|
||||||
(start_bj, end_bj),
|
(start_bj, end_bj),
|
||||||
).fetchall()
|
).fetchall()
|
||||||
for sr in snap_rows:
|
for sr in snap_rows:
|
||||||
|
|||||||
@@ -269,7 +269,7 @@
|
|||||||
.stats-split-row{grid-template-columns:1fr}
|
.stats-split-row{grid-template-columns:1fr}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="/static/instance_theme.css?v=6">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=7">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body data-page="{{ page }}">
|
<body data-page="{{ page }}">
|
||||||
@@ -769,11 +769,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input type="date" id="day_date">
|
<input type="date" id="day_date">
|
||||||
<button type="button" onclick="genDaily()">生成日复盘</button>
|
<button type="button" id="gen-daily-btn" onclick="genDaily()">生成日复盘</button>
|
||||||
<button type="button" onclick="exportDailyBundleMd()" style="background:#1f3a5a">导出当日日复盘MD</button>
|
<button type="button" onclick="exportDailyBundleMd()" style="background:#1f3a5a">导出当日日复盘MD</button>
|
||||||
<input type="date" id="week_start">
|
<input type="date" id="week_start">
|
||||||
<input type="date" id="week_end">
|
<input type="date" id="week_end">
|
||||||
<button type="button" onclick="genWeekly()">生成周复盘</button>
|
<button type="button" id="gen-weekly-btn" onclick="genWeekly()">生成周复盘</button>
|
||||||
<button type="button" onclick="exportWeeklyBundleMd()" style="background:#1f3a5a">导出当周复盘MD</button>
|
<button type="button" onclick="exportWeeklyBundleMd()" style="background:#1f3a5a">导出当周复盘MD</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="ai-result-wrap" id="daily_result_wrap" style="display:none">
|
<div class="ai-result-wrap" id="daily_result_wrap" style="display:none">
|
||||||
@@ -871,7 +871,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/instance_ui.js?v=1"></script>
|
<script src="/static/instance_ui.js?v=1"></script>
|
||||||
<script src="/static/ai_review_render.js?v=1"></script>
|
<script src="/static/ai_review_render.js?v=2"></script>
|
||||||
<script src="/static/form_submit_guard.js?v=2"></script>
|
<script src="/static/form_submit_guard.js?v=2"></script>
|
||||||
<script>
|
<script>
|
||||||
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
||||||
@@ -1196,36 +1196,76 @@ function loadReviews(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function genDaily(){
|
function genDaily(){
|
||||||
|
if(window.AiReviewRender && AiReviewRender.isGenerating && AiReviewRender.isGenerating()) return;
|
||||||
const d = document.getElementById("day_date").value;
|
const d = document.getElementById("day_date").value;
|
||||||
if(!d){alert("请选择日期");return;}
|
if(!d){alert("请选择日期");return;}
|
||||||
|
if(window.AiReviewRender && AiReviewRender.setGenerating){
|
||||||
|
AiReviewRender.setGenerating({
|
||||||
|
wrapId:"daily_result_wrap",
|
||||||
|
elId:"daily_result",
|
||||||
|
btnId:"gen-daily-btn",
|
||||||
|
message:"生成日复盘中,请稍候…(AI 分析可能需要 1~3 分钟)",
|
||||||
|
btnLabel:"日复盘生成中…"
|
||||||
|
});
|
||||||
|
}
|
||||||
fetch("/ai_daily_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`date=${encodeURIComponent(d)}`})
|
fetch("/ai_daily_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`date=${encodeURIComponent(d)}`})
|
||||||
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
||||||
.then(data=>{
|
.then(data=>{
|
||||||
|
if(!data || data.result == null) throw new Error("返回数据为空");
|
||||||
const el=document.getElementById("daily_result");
|
const el=document.getElementById("daily_result");
|
||||||
const wrap=document.getElementById("daily_result_wrap");
|
const wrap=document.getElementById("daily_result_wrap");
|
||||||
setAiReviewMarkdown(el, data.result);
|
setAiReviewMarkdown(el, data.result);
|
||||||
if(wrap){ wrap.style.display="block"; }
|
if(wrap){ wrap.style.display="block"; }
|
||||||
else { el.style.display="block"; }
|
else if(el){ el.style.display="block"; }
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-daily-btn");
|
||||||
loadReviews();
|
loadReviews();
|
||||||
})
|
})
|
||||||
.catch(e=>alert("生成日复盘失败:"+(e.message||e)));
|
.catch(e=>{
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-daily-btn");
|
||||||
|
const el=document.getElementById("daily_result");
|
||||||
|
if(el){
|
||||||
|
el.classList.remove("is-loading","ai-result-md");
|
||||||
|
el.innerText="生成失败,请重试。";
|
||||||
|
}
|
||||||
|
alert("生成日复盘失败:"+(e.message||e));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function genWeekly(){
|
function genWeekly(){
|
||||||
|
if(window.AiReviewRender && AiReviewRender.isGenerating && AiReviewRender.isGenerating()) return;
|
||||||
const s=document.getElementById("week_start").value;
|
const s=document.getElementById("week_start").value;
|
||||||
const e=document.getElementById("week_end").value;
|
const e=document.getElementById("week_end").value;
|
||||||
if(!s || !e){alert("请选择起止日期");return;}
|
if(!s || !e){alert("请选择起止日期");return;}
|
||||||
|
if(window.AiReviewRender && AiReviewRender.setGenerating){
|
||||||
|
AiReviewRender.setGenerating({
|
||||||
|
wrapId:"weekly_result_wrap",
|
||||||
|
elId:"weekly_result",
|
||||||
|
btnId:"gen-weekly-btn",
|
||||||
|
message:"生成周复盘中,请稍候…(AI 分析可能需要 1~3 分钟)",
|
||||||
|
btnLabel:"周复盘生成中…"
|
||||||
|
});
|
||||||
|
}
|
||||||
fetch("/ai_weekly_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`start_date=${encodeURIComponent(s)}&end_date=${encodeURIComponent(e)}`})
|
fetch("/ai_weekly_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`start_date=${encodeURIComponent(s)}&end_date=${encodeURIComponent(e)}`})
|
||||||
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
||||||
.then(data=>{
|
.then(data=>{
|
||||||
|
if(!data || data.result == null) throw new Error("返回数据为空");
|
||||||
const el=document.getElementById("weekly_result");
|
const el=document.getElementById("weekly_result");
|
||||||
const wrap=document.getElementById("weekly_result_wrap");
|
const wrap=document.getElementById("weekly_result_wrap");
|
||||||
setAiReviewMarkdown(el, data.result);
|
setAiReviewMarkdown(el, data.result);
|
||||||
if(wrap){ wrap.style.display="block"; }
|
if(wrap){ wrap.style.display="block"; }
|
||||||
else { el.style.display="block"; }
|
else if(el){ el.style.display="block"; }
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-weekly-btn");
|
||||||
loadReviews();
|
loadReviews();
|
||||||
})
|
})
|
||||||
.catch(e=>alert("生成周复盘失败:"+(e.message||e)));
|
.catch(e=>{
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-weekly-btn");
|
||||||
|
const el=document.getElementById("weekly_result");
|
||||||
|
if(el){
|
||||||
|
el.classList.remove("is-loading","ai-result-md");
|
||||||
|
el.innerText="生成失败,请重试。";
|
||||||
|
}
|
||||||
|
alert("生成周复盘失败:"+(e.message||e));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportDailyBundleMd(){
|
function exportDailyBundleMd(){
|
||||||
|
|||||||
@@ -232,7 +232,7 @@
|
|||||||
.stats-period-block h3{font-size:1rem;color:#dbe4ff;margin-bottom:4px}
|
.stats-period-block h3{font-size:1rem;color:#dbe4ff;margin-bottom:4px}
|
||||||
.stats-period-block .sub{font-size:.78rem;color:#8892b0;margin-bottom:10px;line-height:1.4}
|
.stats-period-block .sub{font-size:.78rem;color:#8892b0;margin-bottom:10px;line-height:1.4}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="/static/instance_theme.css?v=6">
|
<link rel="stylesheet" href="/static/instance_theme.css?v=7">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body data-page="{{ page }}">
|
<body data-page="{{ page }}">
|
||||||
@@ -822,11 +822,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input type="date" id="day_date">
|
<input type="date" id="day_date">
|
||||||
<button type="button" onclick="genDaily()">生成日复盘</button>
|
<button type="button" id="gen-daily-btn" onclick="genDaily()">生成日复盘</button>
|
||||||
<button type="button" onclick="exportDailyBundleMd()" style="background:#1f3a5a">导出当日日复盘MD</button>
|
<button type="button" onclick="exportDailyBundleMd()" style="background:#1f3a5a">导出当日日复盘MD</button>
|
||||||
<input type="date" id="week_start">
|
<input type="date" id="week_start">
|
||||||
<input type="date" id="week_end">
|
<input type="date" id="week_end">
|
||||||
<button type="button" onclick="genWeekly()">生成周复盘</button>
|
<button type="button" id="gen-weekly-btn" onclick="genWeekly()">生成周复盘</button>
|
||||||
<button type="button" onclick="exportWeeklyBundleMd()" style="background:#1f3a5a">导出当周复盘MD</button>
|
<button type="button" onclick="exportWeeklyBundleMd()" style="background:#1f3a5a">导出当周复盘MD</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="ai-result-wrap" id="daily_result_wrap" style="display:none">
|
<div class="ai-result-wrap" id="daily_result_wrap" style="display:none">
|
||||||
@@ -911,7 +911,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/instance_ui.js?v=1"></script>
|
<script src="/static/instance_ui.js?v=1"></script>
|
||||||
<script src="/static/ai_review_render.js?v=1"></script>
|
<script src="/static/ai_review_render.js?v=2"></script>
|
||||||
<script src="/static/form_submit_guard.js?v=2"></script>
|
<script src="/static/form_submit_guard.js?v=2"></script>
|
||||||
<script>
|
<script>
|
||||||
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
const JOURNAL_ENTRY_REASON_OPTIONS = {{ entry_reason_options | tojson }};
|
||||||
@@ -1242,36 +1242,76 @@ function loadReviews(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function genDaily(){
|
function genDaily(){
|
||||||
|
if(window.AiReviewRender && AiReviewRender.isGenerating && AiReviewRender.isGenerating()) return;
|
||||||
const d = document.getElementById("day_date").value;
|
const d = document.getElementById("day_date").value;
|
||||||
if(!d){alert("请选择日期");return;}
|
if(!d){alert("请选择日期");return;}
|
||||||
|
if(window.AiReviewRender && AiReviewRender.setGenerating){
|
||||||
|
AiReviewRender.setGenerating({
|
||||||
|
wrapId:"daily_result_wrap",
|
||||||
|
elId:"daily_result",
|
||||||
|
btnId:"gen-daily-btn",
|
||||||
|
message:"生成日复盘中,请稍候…(AI 分析可能需要 1~3 分钟)",
|
||||||
|
btnLabel:"日复盘生成中…"
|
||||||
|
});
|
||||||
|
}
|
||||||
fetch("/ai_daily_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`date=${encodeURIComponent(d)}`})
|
fetch("/ai_daily_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`date=${encodeURIComponent(d)}`})
|
||||||
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
||||||
.then(data=>{
|
.then(data=>{
|
||||||
|
if(!data || data.result == null) throw new Error("返回数据为空");
|
||||||
const el=document.getElementById("daily_result");
|
const el=document.getElementById("daily_result");
|
||||||
const wrap=document.getElementById("daily_result_wrap");
|
const wrap=document.getElementById("daily_result_wrap");
|
||||||
setAiReviewMarkdown(el, data.result);
|
setAiReviewMarkdown(el, data.result);
|
||||||
if(wrap){ wrap.style.display="block"; }
|
if(wrap){ wrap.style.display="block"; }
|
||||||
else { el.style.display="block"; }
|
else if(el){ el.style.display="block"; }
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-daily-btn");
|
||||||
loadReviews();
|
loadReviews();
|
||||||
})
|
})
|
||||||
.catch(e=>alert("生成日复盘失败:"+(e.message||e)));
|
.catch(e=>{
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-daily-btn");
|
||||||
|
const el=document.getElementById("daily_result");
|
||||||
|
if(el){
|
||||||
|
el.classList.remove("is-loading","ai-result-md");
|
||||||
|
el.innerText="生成失败,请重试。";
|
||||||
|
}
|
||||||
|
alert("生成日复盘失败:"+(e.message||e));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function genWeekly(){
|
function genWeekly(){
|
||||||
|
if(window.AiReviewRender && AiReviewRender.isGenerating && AiReviewRender.isGenerating()) return;
|
||||||
const s=document.getElementById("week_start").value;
|
const s=document.getElementById("week_start").value;
|
||||||
const e=document.getElementById("week_end").value;
|
const e=document.getElementById("week_end").value;
|
||||||
if(!s || !e){alert("请选择起止日期");return;}
|
if(!s || !e){alert("请选择起止日期");return;}
|
||||||
|
if(window.AiReviewRender && AiReviewRender.setGenerating){
|
||||||
|
AiReviewRender.setGenerating({
|
||||||
|
wrapId:"weekly_result_wrap",
|
||||||
|
elId:"weekly_result",
|
||||||
|
btnId:"gen-weekly-btn",
|
||||||
|
message:"生成周复盘中,请稍候…(AI 分析可能需要 1~3 分钟)",
|
||||||
|
btnLabel:"周复盘生成中…"
|
||||||
|
});
|
||||||
|
}
|
||||||
fetch("/ai_weekly_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`start_date=${encodeURIComponent(s)}&end_date=${encodeURIComponent(e)}`})
|
fetch("/ai_weekly_review",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`start_date=${encodeURIComponent(s)}&end_date=${encodeURIComponent(e)}`})
|
||||||
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
.then(r=>{ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
||||||
.then(data=>{
|
.then(data=>{
|
||||||
|
if(!data || data.result == null) throw new Error("返回数据为空");
|
||||||
const el=document.getElementById("weekly_result");
|
const el=document.getElementById("weekly_result");
|
||||||
const wrap=document.getElementById("weekly_result_wrap");
|
const wrap=document.getElementById("weekly_result_wrap");
|
||||||
setAiReviewMarkdown(el, data.result);
|
setAiReviewMarkdown(el, data.result);
|
||||||
if(wrap){ wrap.style.display="block"; }
|
if(wrap){ wrap.style.display="block"; }
|
||||||
else { el.style.display="block"; }
|
else if(el){ el.style.display="block"; }
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-weekly-btn");
|
||||||
loadReviews();
|
loadReviews();
|
||||||
})
|
})
|
||||||
.catch(e=>alert("生成周复盘失败:"+(e.message||e)));
|
.catch(e=>{
|
||||||
|
if(window.AiReviewRender && AiReviewRender.clearGenerating) AiReviewRender.clearGenerating("gen-weekly-btn");
|
||||||
|
const el=document.getElementById("weekly_result");
|
||||||
|
if(el){
|
||||||
|
el.classList.remove("is-loading","ai-result-md");
|
||||||
|
el.innerText="生成失败,请重试。";
|
||||||
|
}
|
||||||
|
alert("生成周复盘失败:"+(e.message||e));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportDailyBundleMd(){
|
function exportDailyBundleMd(){
|
||||||
|
|||||||
@@ -92,9 +92,14 @@ def sql_list_time_field(*columns):
|
|||||||
"""
|
"""
|
||||||
SQLite 列表时间窗比较表达式。
|
SQLite 列表时间窗比较表达式。
|
||||||
journal_entries 的 open/close 可能含 'T',直接与 bounds(空格格式)比会误判为超出上界。
|
journal_entries 的 open/close 可能含 'T',直接与 bounds(空格格式)比会误判为超出上界。
|
||||||
|
单列时不用 COALESCE(SQLite 要求 COALESCE 至少 2 个参数)。
|
||||||
"""
|
"""
|
||||||
cols = ", ".join(columns)
|
cols = [c for c in columns if c]
|
||||||
return f"REPLACE(COALESCE({cols}), 'T', ' ')"
|
if not cols:
|
||||||
|
raise ValueError("sql_list_time_field requires at least one column")
|
||||||
|
if len(cols) == 1:
|
||||||
|
return f"REPLACE({cols[0]}, 'T', ' ')"
|
||||||
|
return f"REPLACE(COALESCE({', '.join(cols)}), 'T', ' ')"
|
||||||
|
|
||||||
|
|
||||||
SESSION_KEY_LIST_WIN = "list_win_filter"
|
SESSION_KEY_LIST_WIN = "list_win_filter"
|
||||||
|
|||||||
@@ -109,10 +109,54 @@
|
|||||||
return html.join("\n");
|
return html.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _genBusy = false;
|
||||||
|
|
||||||
|
function setGenerating(opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
_genBusy = true;
|
||||||
|
var wrap = document.getElementById(opts.wrapId);
|
||||||
|
var el = document.getElementById(opts.elId);
|
||||||
|
var btn = opts.btnId ? document.getElementById(opts.btnId) : null;
|
||||||
|
if (wrap) wrap.style.display = "block";
|
||||||
|
if (el) {
|
||||||
|
el.classList.remove("ai-result-md");
|
||||||
|
el.classList.add("is-loading");
|
||||||
|
el.innerHTML = "";
|
||||||
|
el.innerText = opts.message || "生成复盘中,请稍候…";
|
||||||
|
}
|
||||||
|
if (btn) {
|
||||||
|
btn.disabled = true;
|
||||||
|
if (!btn.dataset.aiOrigText) btn.dataset.aiOrigText = btn.textContent;
|
||||||
|
btn.textContent = opts.btnLabel || "生成中…";
|
||||||
|
}
|
||||||
|
if (wrap && wrap.scrollIntoView) {
|
||||||
|
try {
|
||||||
|
wrap.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearGenerating(btnId) {
|
||||||
|
_genBusy = false;
|
||||||
|
var btn = btnId ? document.getElementById(btnId) : null;
|
||||||
|
if (btn) {
|
||||||
|
btn.disabled = false;
|
||||||
|
if (btn.dataset.aiOrigText) {
|
||||||
|
btn.textContent = btn.dataset.aiOrigText;
|
||||||
|
delete btn.dataset.aiOrigText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isGenerating() {
|
||||||
|
return _genBusy;
|
||||||
|
}
|
||||||
|
|
||||||
function setElementMarkdown(el, rawText) {
|
function setElementMarkdown(el, rawText) {
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
var raw = String(rawText || "");
|
var raw = String(rawText || "");
|
||||||
el.dataset.markdownRaw = raw;
|
el.dataset.markdownRaw = raw;
|
||||||
|
el.classList.remove("is-loading");
|
||||||
el.classList.add("ai-result-md");
|
el.classList.add("ai-result-md");
|
||||||
el.innerHTML = renderMarkdown(raw);
|
el.innerHTML = renderMarkdown(raw);
|
||||||
}
|
}
|
||||||
@@ -130,5 +174,8 @@
|
|||||||
renderMarkdown: renderMarkdown,
|
renderMarkdown: renderMarkdown,
|
||||||
setElementMarkdown: setElementMarkdown,
|
setElementMarkdown: setElementMarkdown,
|
||||||
getElementMarkdown: getElementMarkdown,
|
getElementMarkdown: getElementMarkdown,
|
||||||
|
setGenerating: setGenerating,
|
||||||
|
clearGenerating: clearGenerating,
|
||||||
|
isGenerating: isGenerating,
|
||||||
};
|
};
|
||||||
})(typeof window !== "undefined" ? window : this);
|
})(typeof window !== "undefined" ? window : this);
|
||||||
|
|||||||
@@ -601,6 +601,21 @@ html[data-theme="light"] .ai-result {
|
|||||||
color: #1a2838 !important;
|
color: #1a2838 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-result.is-loading {
|
||||||
|
color: #8fc8ff;
|
||||||
|
font-style: italic;
|
||||||
|
animation: ai-review-pulse 1.2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="light"] .ai-result.is-loading {
|
||||||
|
color: #006e9a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ai-review-pulse {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.55; }
|
||||||
|
}
|
||||||
|
|
||||||
html[data-theme="light"] .ai-result-md p,
|
html[data-theme="light"] .ai-result-md p,
|
||||||
html[data-theme="light"] .detail-modal .panel-body.md-review p {
|
html[data-theme="light"] .detail-modal .panel-body.md-review p {
|
||||||
color: #1a2838 !important;
|
color: #1a2838 !important;
|
||||||
|
|||||||
Reference in New Issue
Block a user