From b6b9e9148c731a587df140e1fb0c5059c2ed4bc4 Mon Sep 17 00:00:00 2001 From: hz4th_coder Date: Sun, 16 Aug 2026 19:51:32 +0800 Subject: [PATCH] =?UTF-8?q?UI=20=E4=BC=98=E5=8C=96:=20Markdown=20=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=BC=80=E5=85=B3=E7=A7=BB=E5=85=A5=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E8=A1=8C=20+=20=E5=88=86=E9=A1=B5=E6=8E=A7=E4=BB=B6=E9=A1=B6?= =?UTF-8?q?=E9=83=A8=E5=A4=8D=E5=88=B6/=E6=AF=8F=E9=A1=B5=E6=9D=A1?= =?UTF-8?q?=E6=95=B0=E5=8F=AF=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 任务详情弹窗: 📝 Markdown/原文 切换开关移到「任务指令」「产出物」标题右侧 (标题左、开关右, flex 布局, 不再挤占文本区域宽度) - 运行日志/告警中心: 分页控件顶部底部各一份; 新增每页条数选择(10/20/50/100), 改条数自动回到第1页, 顶部/底部跳页双向同步 --- static/app.js | 59 ++++++++++++++++++++++++++++++++---------------- static/style.css | 6 ++++- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/static/app.js b/static/app.js index 3cf208e..c85d6be 100644 --- a/static/app.js +++ b/static/app.js @@ -102,10 +102,13 @@ function mdToHtml(md) { /* ---------- Markdown 区块(带 原文/Markdown 切换,默认 Markdown) ---------- */ const mdRaw = {}; // id -> {md: bool, text: string} -function mdBlock(id, text, cls = '') { +function mdToggleBtn(id) { + // 切换开关:放入区块标题行右侧(由调用方放到 .sec-title 内) + return ``; +} +function mdBody(id, text, cls = '') { mdRaw[id] = {md: true, text: text || ''}; - return `
-
${mdToHtml(text)}
`; + return `
${mdToHtml(text)}
`; } function mdToggle(id) { const rec = mdRaw[id]; @@ -1436,10 +1439,10 @@ async function openTaskDetail(tid) {
创建/更新
${fmtTime(t.created_at)} / ${fmtTime(t.updated_at)}
截止
${t.deadline || '—'}
-
任务指令
- ${mdBlock('td-desc-' + t.id, t.description || t.title, 'sm')} - ${t.output_text ? `
产出物 v${t.output_version}(${t.output_text.length} 字)
- ${mdBlock('td-out-' + t.id, t.output_text)}` : ''} +
任务指令${mdToggleBtn('td-desc-' + t.id)}
+ ${mdBody('td-desc-' + t.id, t.description || t.title, 'sm')} + ${t.output_text ? `
产出物 v${t.output_version}(${t.output_text.length} 字)${mdToggleBtn('td-out-' + t.id)}
+ ${mdBody('td-out-' + t.id, t.output_text)}` : ''} ${t.error ? `
错误信息
${esc(t.error)}
` : ''}
执行日志
@@ -1839,6 +1842,7 @@ async function pageReports() { /* ---------- 运行日志 ---------- */ let logsState = {page: 1, pageSize: 50, level: '', q: ''}; +window.logsState = logsState; // 供分页组件通过 window[stateVar] 读写 async function pageLogs() { const st = logsState; @@ -1861,9 +1865,10 @@ async function pageLogs() { ${st.q ? `` : ''} + ${pagerHtml(r.page, totalPages, r.total, 'logsState', 'pageLogs', 'top')}
${r.data.map(l => `
${fmtTime(l.created_at)} [任务#${l.task_id} ${esc(l.task_title || '')}] ${esc(l.message)}
`).join('') || '
暂无日志
'}
- ${pagerHtml(r.page, totalPages, r.total, 'logsState', 'pageLogs')}`; + ${pagerHtml(r.page, totalPages, r.total, 'logsState', 'pageLogs', 'bottom')}`; bindPagerGo('logsState', totalPages, 'pageLogs'); const qel = $('#logs-q'); if (qel) qel.addEventListener('keydown', e => { if (e.key === 'Enter') { logsState.q = qel.value.trim(); logsState.page = 1; pageLogs(); } }); @@ -1871,6 +1876,7 @@ async function pageLogs() { /* ---------- 告警中心 ---------- */ let alertsState = {page: 1, pageSize: 20, level: '', type: '', read: ''}; +window.alertsState = alertsState; // 供分页组件通过 window[stateVar] 读写 async function pageAlerts() { const st = alertsState; @@ -1901,13 +1907,14 @@ async function pageAlerts() {
+ ${pagerHtml(r.page, totalPages, r.total, 'alertsState', 'pageAlerts', 'top')}
${r.data.map(a => `
${ALERT_LEVEL[a.level] || 'ℹ️'} ${esc(a.title)} ${a.read ? '' : '未读'}
${esc(a.detail)}
${fmtTime(a.created_at)} · ${esc(a.type)}
`).join('') || '
暂无告警 🎉
'}
- ${pagerHtml(r.page, totalPages, r.total, 'alertsState', 'pageAlerts')}`; + ${pagerHtml(r.page, totalPages, r.total, 'alertsState', 'pageAlerts', 'bottom')}`; bindPagerGo('alertsState', totalPages, 'pageAlerts'); refreshAlertBadge(); } @@ -1920,9 +1927,14 @@ async function readAllAlerts() { toast('已全部标记为已读', 'ok'); pageAlerts(); } -/* ---------- 分页组件(快速定位页数) ---------- */ -function pagerHtml(page, totalPages, total, stateVar, refreshFn) { - if (totalPages <= 1) return total ? `
共 ${total} 条
` : ''; +/* ---------- 分页组件(快速定位页数,顶部/底部各一份 + 每页条数) ---------- */ +function pagerHtml(page, totalPages, total, stateVar, refreshFn, pos = 'bottom') { + const st = window[stateVar] || {}; + const sizes = [10, 20, 50, 100]; + const sizeSel = ``; + if (totalPages <= 1) return total ? `
共 ${total} 条${sizeSel}
` : ''; const pages = []; const add = p => { if (pages[pages.length - 1] !== p && p >= 1 && p <= totalPages) pages.push(p); }; add(1); @@ -1931,27 +1943,36 @@ function pagerHtml(page, totalPages, total, stateVar, refreshFn) { for (let p = lo; p <= hi; p++) add(p); if (hi < totalPages - 1) pages.push('…'); add(totalPages); - return `
+ return `
+ ${sizeSel} 共 ${total} 条 · ${page}/${totalPages} 页 ${pages.map(p => p === '…' ? '' : ``).join('')} - 跳至 + 跳至
`; } -function goPageInput(stateVar, totalPages, refreshFn) { - const v = parseInt($('#pager-go')?.value || ''); +function setPageSize(stateVar, size, refreshFn) { + window[stateVar].pageSize = parseInt(size) || 50; + window[stateVar].page = 1; + window[refreshFn](); +} + +function goPageInput(stateVar, totalPages, refreshFn, pos) { + const el = document.getElementById('pager-go-' + pos); + const v = parseInt(el?.value || ''); if (!v || v < 1 || v > totalPages) return toast(`页码需在 1-${totalPages} 之间`, 'err'); window[stateVar].page = v; window[refreshFn](); } function bindPagerGo(stateVar, totalPages, refreshFn) { - const el = $('#pager-go'); - if (!el) return; - el.addEventListener('keydown', e => { if (e.key === 'Enter') goPageInput(stateVar, totalPages, refreshFn); }); + ['top', 'bottom'].forEach(pos => { + const el = document.getElementById('pager-go-' + pos); + if (el) el.addEventListener('keydown', e => { if (e.key === 'Enter') goPageInput(stateVar, totalPages, refreshFn, pos); }); + }); } /* ---------- 开放 API ---------- */ diff --git a/static/style.css b/static/style.css index d3a55e3..bb4de88 100644 --- a/static/style.css +++ b/static/style.css @@ -139,6 +139,9 @@ tr:hover td{background:var(--panel2)} .filter-bar .fbtn.on.warn-on{background:var(--warn)} .filter-bar .fbtn.on.danger-on{background:var(--danger)} .pager{display:flex;gap:4px;align-items:center;flex-wrap:wrap;margin-top:14px;justify-content:center} +.pager.top{margin-top:0;margin-bottom:14px} +.psize-sel{background:var(--panel2);border:1px solid var(--border);color:var(--text);border-radius:7px;padding:4px 6px;font-size:12px;cursor:pointer;height:30px} +.psize-sel:hover{border-color:var(--accent)} .pager .pbtn{min-width:30px;height:30px;padding:0 8px;border:1px solid var(--border);background:var(--panel2);color:var(--text);border-radius:7px;font-size:12px;cursor:pointer} .pager .pbtn:hover{border-color:var(--accent);color:var(--accent)} .pager .pbtn.cur{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:700} @@ -166,9 +169,10 @@ tr:hover td{background:var(--panel2)} .md-box code{background:var(--panel2);border:1px solid var(--border);border-radius:4px;padding:1px 5px;font-family:ui-monospace,Consolas,monospace;font-size:12px} .md-box pre.md-code code{background:none;border:none;padding:0} .md-box a{color:var(--accent)} -.md-toggle{font-size:11px;float:right} +.md-toggle{font-size:11px;white-space:nowrap} .md-toggle button{border:1px solid var(--border);background:var(--panel2);color:var(--muted);padding:2px 8px;cursor:pointer;font-size:11px;border-radius:5px} .md-toggle button.on{background:var(--accent);color:#fff;border-color:var(--accent)} +.md-title{display:flex;align-items:center;justify-content:space-between;gap:10px} /* V1:tabs / DAG / 告警 / 开关 */ .tabs{display:flex;gap:4px;margin-bottom:16px;border-bottom:1px solid var(--border)}