fix(通知): 新建/编辑弹窗缺「保存/关闭」整条操作栏(点进去出不来、也存不了)
用户报:新建 webhook 弹窗**没有关闭按钮**——点进去不想建就出不来了(只能刷新页面)。 顺着查发现更严重的一处:**底部操作栏整个漏了**——「创建/保存」「预览」「取消」全都没有, 只是靠"以为有保存按钮所以先点开看看"才没被立刻发现:其实填完也提交不了。 修(static/admin/notify.js + monitor.html): - 弹窗顶部加「✕ 关闭」,底部加「创建/保存 · 预览请求体 · 取消」操作栏 - 四条关闭路径都可用:✕ / 取消 / **Esc** / **点空白处**(overlay 的 onclick) 同批复核出的其它问题: - 通配订阅区被我上一版写成永远隐藏(`display:none` 且没人改回来)→ 恢复可见 (任何格式都适用,标签补成「通配订阅(可选,任何格式都适用)」) - `_notifyFormatChanged` 里残留 `(f === 'json' || true)` 的无意义判断 → 清掉 - 工具条上一个 input 写了**两个 style 属性**(后者会被浏览器忽略)→ 合并成一个 复核方式(这次全部**走页面按钮**,不再只测接口): - UI 全流程 13 项:四条关闭路径 + 底部按钮存在 + 页面创建(列出/打码 URL/事件数) + 编辑回填与改名 + 发送测试(假接收端真收到)+ 页面删除,无 JS 报错 - 通配订阅 6 项:区可见 / 非法通配被拒 / 芯片渲染 / 保存后列出 / 编辑回填 / 清理 - 接口边界 10 项:提交打码 URL 不覆盖真实值、只传 enabled 的局部更新、非法模板被拒、 预览字节数、limit 非法值兜底、404 分支、未登录被挡 教训:交付物是界面时,自测必须走界面点一遍——上一轮我用接口建的 webhook, 把「按钮不存在」整类问题漏掉了。
This commit is contained in:
+21
-5
@@ -107,8 +107,11 @@ function openNotifyModal(id){
|
||||
const box = document.getElementById('notify-modal-box');
|
||||
if(!box) return;
|
||||
box.innerHTML =
|
||||
'<div style="font-size:15px;font-weight:700;margin-bottom:12px">'
|
||||
+ (id ? '编辑 Webhook' : '新建 Webhook') + '</div>'
|
||||
'<div style="display:flex;align-items:center;margin-bottom:12px">'
|
||||
+ '<div style="font-size:15px;font-weight:700;flex:1">'
|
||||
+ (id ? '编辑 Webhook' : '新建 Webhook') + '</div>'
|
||||
+ '<button class="btn btn-xs" title="关闭(不保存)" onclick="closeNotifyModal()">✕ 关闭</button>'
|
||||
+ '</div>'
|
||||
+ '<div class="form-row">'
|
||||
+ '<div class="form-group"><label>名称</label>'
|
||||
+ '<input id="nf-name" class="form-control" value="' + esc(h.name || '') + '" placeholder="如:运维群"></div>'
|
||||
@@ -136,7 +139,7 @@ function openNotifyModal(id){
|
||||
+ '带 <b>★</b> 的是建议开启的。也可以直接写通配(如 <code>task.*</code>)——在下面的芯片框里加。</div>'
|
||||
+ '<div id="nf-events" style="max-height:260px;overflow-y:auto;border:1px solid var(--border);border-radius:8px;padding:10px"></div>'
|
||||
+ '</div>'
|
||||
+ '<div class="form-group" id="nf-pattern-wrap" style="display:none"><label>通配订阅</label>'
|
||||
+ '<div class="form-group" id="nf-pattern-wrap"><label>通配订阅(可选,任何格式都适用)</label>'
|
||||
+ '<div id="nf-patterns" style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:6px"></div>'
|
||||
+ '<div style="display:flex;gap:6px"><input id="nf-pattern-input" class="form-control" placeholder="task.* 或 device.* 或 *">'
|
||||
+ '<button class="btn" onclick="addNotifyPattern()">添加</button></div></div>'
|
||||
@@ -147,6 +150,13 @@ function openNotifyModal(id){
|
||||
+ '<code>{"text":"{{markdown}}"}</code></div></div>'
|
||||
+ '<div class="form-group">'
|
||||
+ '<label>预览</label><div id="nf-preview" class="help">点「预览请求体」看真实会发出去的内容与字节数。</div>'
|
||||
+ '</div>'
|
||||
// 底部操作栏(缺了它就只能靠刷新页面逃出去)
|
||||
+ '<div style="display:flex;gap:8px;align-items:center;margin-top:16px;padding-top:12px;border-top:1px solid var(--border)">'
|
||||
+ '<button class="btn btn-primary" onclick="saveNotifyHook()">' + (id ? '保存' : '创建') + '</button>'
|
||||
+ '<button class="btn" onclick="previewNotifyHook()">预览请求体</button>'
|
||||
+ '<button class="btn" onclick="closeNotifyModal()">取消</button>'
|
||||
+ '<span class="help" style="margin-left:auto">Esc 或点空白处也能关</span>'
|
||||
+ '</div>';
|
||||
box.querySelector('#nf-body').value = h.body_template || '';
|
||||
renderEventTree(checked);
|
||||
@@ -157,12 +167,18 @@ function openNotifyModal(id){
|
||||
|
||||
function _notifyFormatChanged(){
|
||||
const f = (document.getElementById('nf-format') || {}).value;
|
||||
// 只有「通用 JSON」才需要自定义请求体模板
|
||||
const bodyWrap = document.getElementById('nf-body-wrap');
|
||||
if(bodyWrap) bodyWrap.style.display = (f === 'json') ? 'block' : 'none';
|
||||
const patWrap = document.getElementById('nf-pattern-wrap');
|
||||
if(patWrap) patWrap.style.display = (f === 'json' || true) ? 'block' : 'none';
|
||||
}
|
||||
|
||||
// Esc 关闭弹窗(点空白处关闭在 overlay 的 onclick 上)
|
||||
document.addEventListener('keydown', function(ev){
|
||||
if(ev.key !== 'Escape') return;
|
||||
const ov = document.getElementById('notify-modal-overlay');
|
||||
if(ov && ov.style.display !== 'none') closeNotifyModal();
|
||||
});
|
||||
|
||||
function renderEventTree(checked){
|
||||
const box = document.getElementById('nf-events');
|
||||
if(!box) return;
|
||||
|
||||
@@ -1169,9 +1169,10 @@ body{background:var(--bg);font-family:var(--body);color:var(--text);font-size:14
|
||||
<input type="checkbox" id="notify-global" onchange="toggleNotifyGlobal(this)"> 启用通知
|
||||
</label>
|
||||
<span class="text-muted" style="font-size:11.5px">默认聚合
|
||||
<input type="number" id="notify-agg" min="0" max="600" style="width:56px"
|
||||
class="form-control" style="display:inline-block"> 秒 ·
|
||||
限流 <input type="number" id="notify-rate" min="0" max="60" style="width:56px" class="form-control"> 条/分
|
||||
<input type="number" id="notify-agg" min="0" max="600" class="form-control"
|
||||
style="width:64px;display:inline-block"> 秒 ·
|
||||
限流 <input type="number" id="notify-rate" min="0" max="60" class="form-control"
|
||||
style="width:64px;display:inline-block"> 条/分
|
||||
<button class="btn btn-xs" onclick="saveNotifyGlobal()">保存默认</button>
|
||||
</span>
|
||||
</div>
|
||||
@@ -1193,7 +1194,8 @@ body{background:var(--bg);font-family:var(--body);color:var(--text);font-size:14
|
||||
</div>
|
||||
|
||||
<!-- 通知:编辑弹窗(内容由 static/admin/notify.js 渲染) -->
|
||||
<div id="notify-modal-overlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:1340;align-items:flex-start;justify-content:center;overflow-y:auto;padding:30px 0">
|
||||
<div id="notify-modal-overlay" onclick="if(event.target===this)closeNotifyModal()"
|
||||
style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:1340;align-items:flex-start;justify-content:center;overflow-y:auto;padding:30px 0">
|
||||
<div id="notify-modal-box" style="background:#fff;border-radius:14px;padding:20px;width:760px;max-width:94vw;margin:auto"></div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user