Unify key support/resistance monitor type and fix form parity.

Merge 关键阻力位/关键支撑位 into 关键支撑阻力, share key_monitor_form.js across hub and new-tab views, and add hub shortcut to /key_monitor.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-19 08:31:14 +08:00
parent ce172a7cee
commit 073a382d41
15 changed files with 233 additions and 470 deletions
+4 -2
View File
@@ -157,6 +157,7 @@ from key_monitor_lib import (
KEY_DIRECTION_WATCH,
KEY_MONITOR_ALERT_ONLY_TYPES,
KEY_MONITOR_AUTO_TYPES,
KEY_MONITOR_RS_TYPE,
KEY_MONITOR_RS_TYPES,
auto_amp_ok,
auto_confirm_ok,
@@ -7684,6 +7685,7 @@ def add_key():
direction_sel = (d.get("direction") or "").strip().lower()
if mt in KEY_MONITOR_RS_TYPES:
direction_sel = KEY_DIRECTION_WATCH
mt = KEY_MONITOR_RS_TYPE
elif direction_sel not in ("long", "short"):
flash("箱体/收敛突破请选择做多或做空")
return redirect("/key_monitor")
@@ -7723,7 +7725,7 @@ def add_key():
conn = None
flash(
f"当前持仓已达上限({occupied}/{MAX_ACTIVE_POSITIONS}):无法添加「箱体突破 / 收敛突破」。"
"请平仓后再试,或使用「关键阻力位/关键支撑位」(仅单次提醒)。"
"请平仓后再试,或使用「关键支撑阻力」(仅提醒)。"
)
return redirect("/key_monitor")
ex_sym_key = normalize_exchange_symbol(symbol)
@@ -7925,7 +7927,7 @@ def add_key():
extra += f"{time_close_label(tc_h)}"
if mt in KEY_MONITOR_RS_TYPES:
flash(
f"添加成功({symbol} 日成交量排名 {rank}/{total})|阻力/支撑:双向监控上/下沿,"
f"添加成功({symbol} 日成交量排名 {rank}/{total})|关键支撑阻力:双向监控上/下沿,"
f"5m 收盘突破后微信提醒 {KEY_ALERT_MAX_TIMES} 次(间隔 {KEY_ALERT_INTERVAL_MINUTES} 分钟)"
)
else:
+1 -113
View File
@@ -596,8 +596,7 @@
<select name="type" required>
<option value="箱体突破">箱体突破</option>
<option value="收敛突破">收敛突破</option>
<option value="关键阻力">关键阻力</option>
<option value="关键支撑位">关键支撑位</option>
<option value="关键支撑阻力">关键支撑阻力</option>
</select>
<select name="direction" required>
<option value="">方向</option><option value="long">做多</option><option value="short">做空</option>
@@ -1517,120 +1516,9 @@ if(journalForm){
}
}
function syncKeyMonitorFormFields(){
const typeEl = document.querySelector('#key-form [name="type"]');
const dirEl = document.getElementById("key-direction");
const modeEl = document.getElementById("key-sl-tp-mode");
const manualTp = document.getElementById("key-manual-tp");
const beWrap = document.getElementById("key-breakeven-wrap");
if(!typeEl) return;
const t = (typeEl.value || "").trim();
const autoTypes = new Set(["箱体突破","收敛突破"]);
const fibTypes = new Set(["斐波回调0.618","斐波回调0.786"]);
const fbTypes = new Set(["假突破"]);
const teTypes = new Set(["触价开仓"]);
const rsTypes = new Set(["关键阻力位","关键支撑位"]);
const showAuto = autoTypes.has(t);
const showFb = fbTypes.has(t);
const showTe = teTypes.has(t);
const showBe = showAuto || fibTypes.has(t) || showFb || showTe;
const showDir = !rsTypes.has(t);
const upperEl = document.getElementById("key-upper");
const lowerEl = document.getElementById("key-lower");
const fbPriceEl = document.getElementById("key-fb-price");
const teEntryEl = document.getElementById("key-trigger-entry");
const teSlEl = document.getElementById("key-trigger-sl");
const teTpEl = document.getElementById("key-trigger-tp");
if(dirEl){
dirEl.style.display = showDir ? "" : "none";
dirEl.required = showDir;
if(!showDir) dirEl.value = "";
}
if(modeEl) modeEl.style.display = showAuto ? "" : "none";
if(manualTp){
const trend = showAuto && modeEl && modeEl.value === "trend_manual";
manualTp.style.display = trend ? "" : "none";
manualTp.required = !!trend;
}
if(beWrap) beWrap.style.display = showBe ? "inline-flex" : "none";
if(window.TimeCloseUI) TimeCloseUI.syncKeyTimeCloseVisibility(showBe);
const hideBounds = showFb || showTe;
if(upperEl){
upperEl.style.display = hideBounds ? "none" : "";
upperEl.required = !hideBounds;
if(hideBounds) upperEl.value = "";
}
if(lowerEl){
lowerEl.style.display = hideBounds ? "none" : "";
lowerEl.required = !hideBounds;
if(hideBounds) lowerEl.value = "";
}
if(fbPriceEl){
fbPriceEl.style.display = showFb ? "" : "none";
fbPriceEl.required = showFb;
if(!showFb) fbPriceEl.value = "";
fbPriceEl.placeholder = (dirEl && dirEl.value === "short") ? "高点(阻力)" : ((dirEl && dirEl.value === "long") ? "低点(支撑)" : "做空填高点/做多填低点");
}
[teEntryEl, teSlEl, teTpEl].forEach((el)=>{
if(!el) return;
el.style.display = showTe ? "" : "none";
el.required = showTe;
if(!showTe) el.value = "";
});
}
const keyTypeSel = document.querySelector('#key-form [name="type"]');
const keyModeSel = document.getElementById("key-sl-tp-mode");
const keyDirSel = document.getElementById("key-direction");
if(keyTypeSel) keyTypeSel.addEventListener("change", syncKeyMonitorFormFields);
if(keyModeSel) keyModeSel.addEventListener("change", syncKeyMonitorFormFields);
if(keyDirSel) keyDirSel.addEventListener("change", syncKeyMonitorFormFields);
syncKeyMonitorFormFields();
if(window.TimeCloseUI){
TimeCloseUI.bindTimeCloseForm("key-time-close-cb", "key-time-close-hours", "key-time-close-wrap");
TimeCloseUI.bindTimeCloseForm("order-time-close-cb", "order-time-close-hours", "order-time-close-wrap");
}
const keyForm = document.getElementById("key-form");
if(keyForm){
keyForm.addEventListener("submit", (e)=>{
e.preventDefault();
if(window.FormSubmitGuard && FormSubmitGuard.isLocked(keyForm)) return;
const symbolEl = keyForm.querySelector('[name="symbol"]');
const symbol = (symbolEl ? symbolEl.value : "").trim();
if(!symbol){
alert("请先输入交易对");
return;
}
const typeVal = (keyForm.querySelector('[name="type"]') || {}).value || "";
if(typeVal === "假突破"){
if(window.FormSubmitGuard) FormSubmitGuard.nativeSubmitOnce(keyForm, "提交中…");
else keyForm.submit();
return;
}
if(window.FormSubmitGuard) FormSubmitGuard.lock(keyForm, "校验排名中…");
fetch(`/api/symbol_liquidity_rank?symbol=${encodeURIComponent(symbol)}`)
.then(r=>r.json().then(d=>({status:r.status, data:d})))
.then(({status,data})=>{
if(status >= 400 || !data.ok){
alert((data && data.msg) || "日成交量排名读取失败");
if(window.FormSubmitGuard) FormSubmitGuard.unlock(keyForm);
return;
}
const rankMax = data.rank_max || 30;
if(!data.in_top30){
alert(`${data.symbol} 当前日成交量排名 ${data.rank}/${data.total},不在前${rankMax},已拦截。`);
if(window.FormSubmitGuard) FormSubmitGuard.unlock(keyForm);
return;
}
if(window.FormSubmitGuard) FormSubmitGuard.nativeSubmitOnce(keyForm, "提交中…");
else keyForm.submit();
})
.catch(()=>{
alert("日成交量排名检查失败,请稍后重试");
if(window.FormSubmitGuard) FormSubmitGuard.unlock(keyForm);
});
});
}
// 复盘/AI列表:初次进入页面后再异步刷新一次,避免浏览器 bfcache/重定向后仍显示旧缓存
setTimeout(() => {
if(document.getElementById("journal-list")) loadJournals();