docs: 固化生成记录详情交互设计 v2 (#65)
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>#65 Admin 生成记录详情交互 v2</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
:root { color-scheme: light; font-family: "Microsoft YaHei", Arial, sans-serif; color: #303133; background: #f3f4f6; }
|
||||
body { margin: 0; min-width: 320px; }
|
||||
button, input, select { font: inherit; }
|
||||
.review-bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 48px; padding: 8px 20px; color: #fff; background: #263445; }
|
||||
.review-bar strong { font-size: 14px; }
|
||||
.review-bar span { color: #d8dee7; font-size: 12px; }
|
||||
.shell { display: grid; grid-template-columns: 188px minmax(0, 1fr); min-height: calc(100vh - 48px); }
|
||||
aside { padding: 18px 12px; color: #d8dee7; background: #304156; }
|
||||
.brand { margin: 0 8px 22px; color: #fff; font-size: 18px; font-weight: 700; }
|
||||
nav div { margin: 4px 0; padding: 10px 12px; font-size: 14px; }
|
||||
nav .active { color: #fff; background: #263445; border-left: 3px solid #409eff; }
|
||||
main { min-width: 0; padding: 20px; overflow: hidden; }
|
||||
.heading, .toolbar { display: flex; align-items: center; gap: 10px; }
|
||||
.heading { justify-content: space-between; margin-bottom: 14px; }
|
||||
h1 { margin: 0 0 5px; font-size: 22px; }
|
||||
.heading p { margin: 0; color: #606266; font-size: 13px; }
|
||||
.btn { min-height: 36px; padding: 0 14px; color: #303133; background: #fff; border: 1px solid #dcdfe6; border-radius: 4px; cursor: pointer; }
|
||||
.btn:hover, .btn:focus-visible { color: #337ecc; border-color: #79bbff; outline: 2px solid transparent; }
|
||||
.toolbar { margin-bottom: 12px; }
|
||||
.toolbar input, .toolbar select { height: 36px; padding: 0 10px; background: #fff; border: 1px solid #dcdfe6; border-radius: 4px; }
|
||||
.toolbar input { width: 290px; }
|
||||
.toolbar select { width: 140px; }
|
||||
.spacer { flex: 1; }
|
||||
.muted { color: #909399; font-size: 13px; }
|
||||
.table-wrap { width: 100%; overflow-x: auto; background: #fff; border: 1px solid #ebeef5; }
|
||||
table { width: 100%; min-width: 920px; border-collapse: collapse; table-layout: fixed; }
|
||||
th, td { height: 48px; padding: 8px 12px; text-align: left; border-right: 1px solid #ebeef5; border-bottom: 1px solid #ebeef5; font-size: 13px; }
|
||||
th { color: #606266; background: #fafafa; font-weight: 600; }
|
||||
tbody tr { cursor: default; }
|
||||
tbody tr:hover { background: #f5f7fa; }
|
||||
.mono { font-family: Consolas, monospace; }
|
||||
.numeric { font-variant-numeric: tabular-nums; }
|
||||
.status { display: inline-block; padding: 3px 9px; border: 1px solid; border-radius: 4px; }
|
||||
.success { color: #529b2e; background: #f0f9eb; border-color: #b3e19d; }
|
||||
.failed { color: #c45656; background: #fef0f0; border-color: #fab6b6; }
|
||||
.view { min-width: 54px; min-height: 32px; padding: 0 10px; color: #337ecc; background: transparent; border: 0; cursor: pointer; }
|
||||
.view:hover, .view:focus-visible { text-decoration: underline; outline: 2px solid #79bbff; outline-offset: 1px; }
|
||||
.backdrop { position: fixed; inset: 48px 0 0; z-index: 20; visibility: hidden; background: rgb(0 0 0 / 28%); opacity: 0; transition: opacity 180ms ease-out; }
|
||||
.backdrop.open { visibility: visible; opacity: 1; }
|
||||
.drawer { position: absolute; top: 0; right: 0; width: min(45vw, 680px); min-width: 480px; height: 100%; padding: 20px; overflow-y: auto; background: #fff; box-shadow: -6px 0 18px rgb(0 0 0 / 14%); transform: translateX(100%); transition: transform 220ms ease-out; }
|
||||
.open .drawer { transform: translateX(0); }
|
||||
.drawer-head { display: flex; align-items: center; gap: 10px; padding-bottom: 14px; border-bottom: 1px solid #ebeef5; }
|
||||
.drawer-head h2 { margin: 0; font-size: 17px; }
|
||||
.close { margin-left: auto; width: 40px; height: 40px; padding: 0; color: #606266; background: transparent; border: 0; font-size: 26px; cursor: pointer; }
|
||||
.close:focus-visible { outline: 2px solid #409eff; }
|
||||
dl { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 0; margin: 16px 0; }
|
||||
dt, dd { margin: 0; padding: 8px 0; border-bottom: 1px solid #f0f2f5; font-size: 13px; }
|
||||
dt { color: #909399; }
|
||||
dd { overflow-wrap: anywhere; }
|
||||
details { margin-top: 14px; padding: 12px 0; border-top: 1px solid #ebeef5; border-bottom: 1px solid #ebeef5; }
|
||||
summary { cursor: pointer; font-size: 14px; font-weight: 600; }
|
||||
pre { max-height: 150px; overflow: auto; white-space: pre-wrap; font-family: inherit; font-size: 13px; }
|
||||
h3 { margin: 20px 0 12px; font-size: 15px; }
|
||||
.timeline { margin: 0; padding: 0 0 0 18px; border-left: 2px solid #dcdfe6; list-style: none; }
|
||||
.timeline li { position: relative; margin: 0 0 18px; padding-left: 12px; font-size: 13px; }
|
||||
.timeline li::before { position: absolute; top: 4px; left: -24px; width: 10px; height: 10px; content: ""; background: #67c23a; border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1px #67c23a; }
|
||||
.timeline small { display: block; margin-top: 4px; color: #909399; }
|
||||
@media (max-width: 860px) {
|
||||
.shell { grid-template-columns: 1fr; }
|
||||
aside { display: none; }
|
||||
main { padding: 14px; }
|
||||
.heading { align-items: flex-start; }
|
||||
.heading p { display: none; }
|
||||
.toolbar { flex-wrap: wrap; }
|
||||
.toolbar input { flex: 1 1 220px; width: auto; }
|
||||
.spacer { display: none; }
|
||||
.drawer { width: min(94vw, 680px); min-width: 0; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="review-bar"><strong>#65 设计证据 v2</strong><span>默认全宽列表 · 双击行或“查看”打开右侧详情</span></div>
|
||||
<div class="shell">
|
||||
<aside><div class="brand">CHORUS ADMIN</div><nav><div>业务配置</div><div class="active">生成记录</div><div>用户管理</div><div>系统管理</div></nav></aside>
|
||||
<main>
|
||||
<header class="heading"><div><h1>生成记录</h1><p>按任务查看渲染 Prompt、错误摘要和每次上游尝试;敏感响应不会在此展示。</p></div><button class="btn" type="button">刷新</button></header>
|
||||
<div class="toolbar"><input aria-label="搜索" placeholder="任务编号 / 用户账号 / 错误码"><select aria-label="状态"><option>全部状态</option><option>成功</option><option>失败</option></select><button class="btn" type="button">重置</button><span class="spacer"></span><span class="muted">显示 4 条</span></div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<colgroup><col style="width:110px"><col style="width:180px"><col style="width:110px"><col style="width:80px"><col style="width:130px"><col style="width:190px"><col style="width:80px"></colgroup>
|
||||
<thead><tr><th>任务编号</th><th>用户账号</th><th>状态</th><th>类型</th><th>总耗时</th><th>创建时间</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr data-id="20"><td class="mono">#20</td><td><strong>test</strong><br><span class="muted">MVP-0 Test User</span></td><td><span class="status success">成功</span></td><td>图片</td><td class="numeric">2分30.3秒</td><td>2026/8/26 10:08:12</td><td><button class="view" type="button">查看</button></td></tr>
|
||||
<tr data-id="19"><td class="mono">#19</td><td><strong>test</strong></td><td><span class="status failed">失败</span></td><td>图片</td><td class="numeric">0.1秒</td><td>2026/8/26 09:52:38</td><td><button class="view" type="button">查看</button></td></tr>
|
||||
<tr data-id="18"><td class="mono">#18</td><td><strong>demo</strong></td><td><span class="status success">成功</span></td><td>文本</td><td class="numeric">18.6秒</td><td>2026/8/26 09:41:06</td><td><button class="view" type="button">查看</button></td></tr>
|
||||
<tr data-id="17"><td class="mono">#17</td><td><strong>demo</strong></td><td><span class="status failed">失败</span></td><td>图片</td><td class="numeric">5分00.0秒</td><td>2026/8/26 09:20:14</td><td><button class="view" type="button">查看</button></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<div id="backdrop" class="backdrop" aria-hidden="true">
|
||||
<section class="drawer" role="dialog" aria-modal="true" aria-labelledby="detail-title">
|
||||
<header class="drawer-head"><h2 id="detail-title">任务 #20</h2><span class="status success">成功</span><button id="close" class="close" type="button" aria-label="关闭详情">×</button></header>
|
||||
<dl><dt>用户账号</dt><dd>test(MVP-0 Test User)</dd><dt>生成类型</dt><dd>图片</dd><dt>Provider 尝试</dt><dd>1</dd><dt>总耗时</dt><dd class="numeric">2分30.3秒</dd><dt>排队耗时</dt><dd class="numeric">0.2秒</dd><dt>处理耗时</dt><dd class="numeric">2分30.1秒</dd><dt>上游耗时</dt><dd class="numeric">2分30.0秒</dd><dt>提交时间</dt><dd>2026/8/26 10:08:12</dd><dt>开始时间</dt><dd>2026/8/26 10:08:12</dd><dt>完成时间</dt><dd>2026/8/26 10:10:42</dd></dl>
|
||||
<details><summary>渲染 Prompt</summary><pre>用于验证详情抽屉层级和长文本换行的示例内容。</pre></details>
|
||||
<h3>尝试记录</h3><ul class="timeline"><li><strong>系统事件 · 任务认领</strong><small>2026/8/26 10:08:12</small></li><li><strong>尝试 1 · 自定义 OpenAI Provider · gpt-image-2</strong><small>成功 · 2分30.0秒 · 2026/8/26 10:08:12</small></li></ul>
|
||||
</section>
|
||||
</div>
|
||||
<script>
|
||||
const backdrop = document.getElementById('backdrop');
|
||||
const closeButton = document.getElementById('close');
|
||||
let returnFocus = null;
|
||||
function openDetail(trigger) {
|
||||
returnFocus = trigger;
|
||||
backdrop.classList.add('open');
|
||||
backdrop.setAttribute('aria-hidden', 'false');
|
||||
closeButton.focus();
|
||||
}
|
||||
function closeDetail() {
|
||||
backdrop.classList.remove('open');
|
||||
backdrop.setAttribute('aria-hidden', 'true');
|
||||
if (returnFocus) returnFocus.focus();
|
||||
}
|
||||
document.querySelectorAll('tbody tr').forEach((row) => {
|
||||
row.addEventListener('dblclick', () => openDetail(row.querySelector('.view')));
|
||||
row.querySelector('.view').addEventListener('click', (event) => openDetail(event.currentTarget));
|
||||
});
|
||||
closeButton.addEventListener('click', closeDetail);
|
||||
backdrop.addEventListener('click', (event) => { if (event.target === backdrop) closeDetail(); });
|
||||
document.addEventListener('keydown', (event) => { if (event.key === 'Escape' && backdrop.classList.contains('open')) closeDetail(); });
|
||||
if (new URLSearchParams(window.location.search).has('open')) openDetail(document.querySelector('.view'));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user