feat: SSO双路径认证 + 端口修正 5176→6176
- 中间件支持 X-Remote-User (SSO) + JWT 双路径 - /api/auth/me 签发 JWT,支持 SSO header 回退 - 退出登录同时清除 SSO cookie - 侧边栏系统设置仅 admin 可见 - package.json 端口 5176→6176 - 跨站点引用端口全部修正
This commit is contained in:
parent
f578198cf9
commit
01a717e8b2
|
|
@ -6,7 +6,7 @@ ASSETS_API_KEY=your-assets-api-key
|
|||
# 允许调用 issue-ai API 的 Key(逗号分隔,支持多个),由 issue-ai 管理界面生成
|
||||
ALLOWED_API_KEYS=your-issue-api-key
|
||||
# NEXT_PUBLIC_ 前缀:构建时内嵌到客户端 JS,云上必须通过 deploy-ai.sh 设置
|
||||
# 本地开发:http://localhost:5177
|
||||
# 本地开发:http://localhost:6177
|
||||
# 云上生产:https://assets.tlyq.ai
|
||||
NEXT_PUBLIC_ASSETS_URL=http://localhost:5177
|
||||
NEXT_PUBLIC_ASSETS_URL=http://localhost:6177
|
||||
NODE_ENV=development
|
||||
|
|
|
|||
|
|
@ -0,0 +1,192 @@
|
|||
<h2>报告预览页</h2>
|
||||
<p class="subtitle">从列表点击报告名称或"预览"按钮进入。右上角按钮根据状态动态切换。</p>
|
||||
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">预览页 — 状态:数据已就绪(待生成文档)</div>
|
||||
<div class="mockup-body">
|
||||
|
||||
<!-- Header -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:16px 0;border-bottom:1px solid #e2e8f0;margin-bottom:20px">
|
||||
<div style="display:flex;align-items:center;gap:16px">
|
||||
<span style="color:#94a3b8;font-size:18px;cursor:pointer">←</span>
|
||||
<div>
|
||||
<h2 style="font-size:22px;font-weight:700;color:#0f172a;margin:0">月报</h2>
|
||||
<span style="font-size:13px;color:#64748b">2026-04-01 ~ 2026-04-30</span>
|
||||
</div>
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#fef3c7;color:#92400e">
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:#f59e0b"></span>
|
||||
数据已就绪
|
||||
</span>
|
||||
</div>
|
||||
<button class="mock-button" style="background:#059669;color:#fff">生成报告文档</button>
|
||||
</div>
|
||||
|
||||
<!-- KPI Row -->
|
||||
<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:20px">
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">工单总数</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0f172a">12</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">已解决</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#059669">10</div>
|
||||
<div style="font-size:11px;color:#94a3b8">83.3%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">整体可用性</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#f59e0b">98.52%</div>
|
||||
<div style="font-size:11px;color:#94a3b8">低于99%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">平均处理时长</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0f172a">240</div>
|
||||
<div style="font-size:11px;color:#94a3b8">分钟</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">进行中</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0369a1">2</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch1 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;margin-bottom:12px">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;color:#fff;border-radius:6px;font-size:12px;font-weight:700">1</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">设备概况</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:32px;padding:16px 20px">
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#dbeafe;display:flex;align-items:center;justify-content:center;font-size:20px">🖥</div>
|
||||
<div><span style="font-size:24px;font-weight:700;color:#0f172a">8</span><span style="font-size:13px;color:#64748b;margin-left:4px">台 GPU 服务器</span></div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#fef3c7;display:flex;align-items:center;justify-content:center;font-size:20px">🗄</div>
|
||||
<div><span style="font-size:24px;font-weight:700;color:#0f172a">3</span><span style="font-size:13px;color:#64748b;margin-left:4px">台 存储服务器</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch2 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;margin-bottom:12px">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#8b5cf6;color:#fff;border-radius:6px;font-size:12px;font-weight:700">2</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">运营数据</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:24px;padding:16px 20px">
|
||||
<div style="font-size:13px;color:#64748b">故障工单 <span style="font-weight:700;color:#d97706;font-size:16px;margin-left:4px">8</span> 件</div>
|
||||
<div style="font-size:13px;color:#64748b">涉及设备 <span style="font-weight:700;color:#0f172a;font-size:16px;margin-left:4px">5</span> 台</div>
|
||||
<div style="font-size:13px;color:#64748b">无故障天数 <span style="font-weight:700;color:#059669;font-size:16px;margin-left:4px">24</span> 天</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch3 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;margin-bottom:12px">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#f59e0b;color:#fff;border-radius:6px;font-size:12px;font-weight:700">3</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">故障分类</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:16px;padding:16px 20px">
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#fff7ed;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#f59e0b">5</div>
|
||||
<div style="font-size:12px;color:#64748b">GPU 故障</div>
|
||||
<div style="width:100%;height:4px;background:#fef3c7;border-radius:2px;margin-top:6px"><div style="width:62.5%;height:100%;background:#f59e0b;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">62.5%</div>
|
||||
</div>
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#fff7ed;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#f59e0b">1</div>
|
||||
<div style="font-size:12px;color:#64748b">存储故障</div>
|
||||
<div style="width:100%;height:4px;background:#fef3c7;border-radius:2px;margin-top:6px"><div style="width:12.5%;height:100%;background:#f59e0b;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">12.5%</div>
|
||||
</div>
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#eff6ff;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#3b82f6">2</div>
|
||||
<div style="font-size:12px;color:#64748b">其他工单</div>
|
||||
<div style="width:100%;height:4px;background:#dbeafe;border-radius:2px;margin-top:6px"><div style="width:25%;height:100%;background:#3b82f6;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">25.0%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch4 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#10b981;color:#fff;border-radius:6px;font-size:12px;font-weight:700">4</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">服务可用性</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding:16px 20px">
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:16px">
|
||||
<span style="font-size:13px;color:#64748b">整体可用性:</span>
|
||||
<span style="font-size:22px;font-weight:700;color:#f59e0b">98.52%</span>
|
||||
</div>
|
||||
<table style="width:100%;font-size:13px;border-collapse:collapse">
|
||||
<thead>
|
||||
<tr style="border-bottom:2px solid #e2e8f0;text-align:left">
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">IP 地址</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">设备类型</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">故障时长</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">可用性</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.35</td>
|
||||
<td style="padding:8px 12px;color:#64748b">GPU</td>
|
||||
<td style="padding:8px 12px;color:#dc2626;font-weight:500">2,160 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#dc2626">95.12%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#fef2f2;color:#dc2626">进行中</span></td>
|
||||
</tr>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.42</td>
|
||||
<td style="padding:8px 12px;color:#64748b">GPU</td>
|
||||
<td style="padding:8px 12px;color:#0f172a">1,440 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#f59e0b">96.78%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#dcfce7;color:#15803d">已恢复</span></td>
|
||||
</tr>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.18</td>
|
||||
<td style="padding:8px 12px;color:#64748b">存储</td>
|
||||
<td style="padding:8px 12px;color:#0f172a">720 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#f59e0b">98.41%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#dcfce7;color:#15803d">已恢复</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:8px">共 3 个 IP 可用性低于 100%,其余设备保持 100% 在线</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 不同状态下的按钮变化 -->
|
||||
<div class="section">
|
||||
<h3>右上角按钮 — 按状态切换</h3>
|
||||
</div>
|
||||
|
||||
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:12px">
|
||||
<div style="background:#fef3c7;border:1px solid #fde68a;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-size:11px;color:#a16207;margin-bottom:6px">数据已就绪</div>
|
||||
<span style="display:inline-block;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;background:#059669;color:#fff">生成报告文档</span>
|
||||
</div>
|
||||
<div style="background:#dbeafe;border:1px solid #bfdbfe;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-size:11px;color:#1e40af;margin-bottom:6px">文档生成中</div>
|
||||
<span style="display:inline-block;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;background:#94a3b8;color:#fff">生成中...</span>
|
||||
</div>
|
||||
<div style="background:#dcfce7;border:1px solid #bbf7d0;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-size:11px;color:#15803d;margin-bottom:6px">已完成</div>
|
||||
<span style="display:inline-block;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;background:#2563eb;color:#fff">⬇ 下载报告</span>
|
||||
</div>
|
||||
<div style="background:#fef2f2;border:1px solid #fecaca;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-size:11px;color:#b91c1c;margin-bottom:6px">生成失败</div>
|
||||
<span style="display:inline-block;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;background:#f59e0b;color:#fff">重新生成</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"type":"server-started","port":50153,"host":"127.0.0.1","url_host":"localhost","url":"http://localhost:50153","screen_dir":"/Users/niuniu/programs/docker/issue-ai/.superpowers/brainstorm/65974-1778137360/content","state_dir":"/Users/niuniu/programs/docker/issue-ai/.superpowers/brainstorm/65974-1778137360/state"}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<h2>报告预览页 — 设计方向</h2>
|
||||
<p class="subtitle">当前页面只展示 4 个数字卡片 + 3 个故障分类卡片。以下三个方向兼顾数据丰富度与视觉提升,各有侧重。</p>
|
||||
|
||||
<div class="options" data-multiselect>
|
||||
<div class="option" data-choice="a" onclick="toggleSelect(this)">
|
||||
<div class="letter">A</div>
|
||||
<div class="content">
|
||||
<h3>仪表盘风格</h3>
|
||||
<p>将预览页做成迷你仪表盘:顶部 KPI 卡片带环比/同比趋势箭头,中间用横向条状图展示故障分类,底部展示服务可用性分布。数据量大但不杂乱,适合快速扫读。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option" data-choice="b" onclick="toggleSelect(this)">
|
||||
<div class="letter">B</div>
|
||||
<div class="content">
|
||||
<h3>摘要 + 详情分区</h3>
|
||||
<p>顶部为摘要区(设备规模 + 核心指标如可用性/SLA/解决率),下方可展开的折叠面板展示故障明细(按分类、按设备、按日期)。信息层级清晰,用户按需深入。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option" data-choice="c" onclick="toggleSelect(this)">
|
||||
<div class="letter">C</div>
|
||||
<div class="content">
|
||||
<h3>单页报告预览</h3>
|
||||
<p>接近真实报告的排版风格:带章节标题(一、设备概况 二、运营数据 三、故障分类 四、服务可用性),每个章节内嵌简表或数据卡片。预览即缩略版报告,视觉专业正式。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>共同增强的数据指标</h3>
|
||||
<p>无论选哪个方向,以下字段都会从 metadata 中新增暴露:</p>
|
||||
</div>
|
||||
|
||||
<div class="pros-cons">
|
||||
<div class="pros">
|
||||
<h4>新增指标</h4>
|
||||
<ul>
|
||||
<li>解决率(已解决 / 故障总数)</li>
|
||||
<li>SLA 达标率</li>
|
||||
<li>平均处理时长</li>
|
||||
<li>故障分类分布(带具体数量)</li>
|
||||
<li>进行中工单数</li>
|
||||
<li>月报独有:设备级最低可用性 IP</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cons">
|
||||
<h4>改动范围</h4>
|
||||
<ul>
|
||||
<li>前后端都需改:metadata 字段扩展 + 预览页 UI 重写</li>
|
||||
<li>旧报告不含新字段,需兼容降级展示</li>
|
||||
<li>周报/月报数据结构不同,需分别处理</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
<h2>报告预览页 — 最终方案</h2>
|
||||
<p class="subtitle">5 KPI + 4 章节全部展开。第 4 章列出所有可用性 < 100% 的 IP。</p>
|
||||
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">完整页面布局 — 月报示例(2026年4月)</div>
|
||||
<div class="mockup-body">
|
||||
|
||||
<!-- Header -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:16px 0;border-bottom:1px solid #e2e8f0;margin-bottom:20px">
|
||||
<div style="display:flex;align-items:center;gap:16px">
|
||||
<span style="color:#94a3b8;font-size:18px">←</span>
|
||||
<div>
|
||||
<h2 style="font-size:22px;font-weight:700;color:#0f172a;margin:0">月报</h2>
|
||||
<span style="font-size:13px;color:#64748b">2026-04-01 ~ 2026-04-30</span>
|
||||
</div>
|
||||
<span style="background:#dcfce7;color:#15803d;padding:2px 10px;border-radius:12px;font-size:12px;font-weight:600">已完成</span>
|
||||
</div>
|
||||
<button class="mock-button">⬇ 下载报告</button>
|
||||
</div>
|
||||
|
||||
<!-- KPI Row -->
|
||||
<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:20px">
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">工单总数</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0f172a">12</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">已解决</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#059669">10</div>
|
||||
<div style="font-size:11px;color:#94a3b8">83.3%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">整体可用性</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#f59e0b">98.52%</div>
|
||||
<div style="font-size:11px;color:#94a3b8">低于99%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">平均处理时长</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0f172a">240</div>
|
||||
<div style="font-size:11px;color:#94a3b8">分钟</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">进行中</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0369a1">2</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chapter Sections — all expanded -->
|
||||
<div style="display:flex;flex-direction:column;gap:12px">
|
||||
|
||||
<!-- Ch1: 设备概况 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;color:#fff;border-radius:6px;font-size:12px;font-weight:700">1</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">设备概况</span>
|
||||
</div>
|
||||
<span style="font-size:20px;color:#94a3b8">▾</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:32px;padding:16px 20px">
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#dbeafe;display:flex;align-items:center;justify-content:center;font-size:20px">🖥</div>
|
||||
<div><span style="font-size:24px;font-weight:700;color:#0f172a">8</span><span style="font-size:13px;color:#64748b;margin-left:4px">台 GPU 服务器</span></div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#fef3c7;display:flex;align-items:center;justify-content:center;font-size:20px">🗄</div>
|
||||
<div><span style="font-size:24px;font-weight:700;color:#0f172a">3</span><span style="font-size:13px;color:#64748b;margin-left:4px">台 存储服务器</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch2: 运营数据 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#8b5cf6;color:#fff;border-radius:6px;font-size:12px;font-weight:700">2</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">运营数据</span>
|
||||
</div>
|
||||
<span style="font-size:20px;color:#94a3b8">▾</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:24px;padding:16px 20px">
|
||||
<div style="font-size:13px;color:#64748b">故障工单 <span style="font-weight:700;color:#d97706;font-size:16px;margin-left:4px">8</span> 件</div>
|
||||
<div style="font-size:13px;color:#64748b">涉及设备 <span style="font-weight:700;color:#0f172a;font-size:16px;margin-left:4px">5</span> 台</div>
|
||||
<div style="font-size:13px;color:#64748b">无故障天数 <span style="font-weight:700;color:#059669;font-size:16px;margin-left:4px">24</span> 天</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch3: 故障分类 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#f59e0b;color:#fff;border-radius:6px;font-size:12px;font-weight:700">3</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">故障分类</span>
|
||||
</div>
|
||||
<span style="font-size:20px;color:#94a3b8">▾</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:16px;padding:16px 20px">
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#fff7ed;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#f59e0b">5</div>
|
||||
<div style="font-size:12px;color:#64748b">GPU 故障</div>
|
||||
<div style="width:100%;height:4px;background:#fef3c7;border-radius:2px;margin-top:6px"><div style="width:62.5%;height:100%;background:#f59e0b;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">62.5%</div>
|
||||
</div>
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#fff7ed;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#f59e0b">1</div>
|
||||
<div style="font-size:12px;color:#64748b">存储故障</div>
|
||||
<div style="width:100%;height:4px;background:#fef3c7;border-radius:2px;margin-top:6px"><div style="width:12.5%;height:100%;background:#f59e0b;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">12.5%</div>
|
||||
</div>
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#eff6ff;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#3b82f6">2</div>
|
||||
<div style="font-size:12px;color:#64748b">其他工单</div>
|
||||
<div style="width:100%;height:4px;background:#dbeafe;border-radius:2px;margin-top:6px"><div style="width:25%;height:100%;background:#3b82f6;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">25.0%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch4: 服务可用性 — 列出所有可用性 <100% 的 IP -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#10b981;color:#fff;border-radius:6px;font-size:12px;font-weight:700">4</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">服务可用性</span>
|
||||
</div>
|
||||
<span style="font-size:20px;color:#94a3b8">▾</span>
|
||||
</div>
|
||||
<div style="padding:16px 20px">
|
||||
<!-- Overall availability banner -->
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:16px">
|
||||
<span style="font-size:13px;color:#64748b">整体可用性:</span>
|
||||
<span style="font-size:22px;font-weight:700;color:#f59e0b">98.52%</span>
|
||||
</div>
|
||||
<!-- IP table -->
|
||||
<table style="width:100%;font-size:13px;border-collapse:collapse">
|
||||
<thead>
|
||||
<tr style="border-bottom:2px solid #e2e8f0;text-align:left">
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">IP 地址</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">设备类型</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">故障时长</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">可用性</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.35</td>
|
||||
<td style="padding:8px 12px;color:#64748b">GPU</td>
|
||||
<td style="padding:8px 12px;color:#dc2626;font-weight:500">2,160 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#dc2626">95.12%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#fef2f2;color:#dc2626">进行中</span></td>
|
||||
</tr>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.42</td>
|
||||
<td style="padding:8px 12px;color:#64748b">GPU</td>
|
||||
<td style="padding:8px 12px;color:#0f172a">1,440 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#f59e0b">96.78%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#dcfce7;color:#15803d">已恢复</span></td>
|
||||
</tr>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.18</td>
|
||||
<td style="padding:8px 12px;color:#64748b">存储</td>
|
||||
<td style="padding:8px 12px;color:#0f172a">720 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#f59e0b">98.41%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#dcfce7;color:#15803d">已恢复</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:8px">共 3 个 IP 可用性低于 100%,其余设备保持 100% 在线</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>方案确认清单</h3>
|
||||
</div>
|
||||
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:16px">
|
||||
<div style="background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;padding:14px">
|
||||
<h4 style="margin:0 0 6px;font-size:14px;color:#15803d">✓ 已定</h4>
|
||||
<ul style="margin:0;padding-left:18px;font-size:13px;color:#166534;line-height:1.8">
|
||||
<li>5 KPI 卡片(工单总数 / 已解决 / 整体可用性 / 平均处理时长 / 进行中)</li>
|
||||
<li>4 章节全部默认展开</li>
|
||||
<li>Ch4 列出所有可用性 <100% 的 IP + 明细表</li>
|
||||
<li>故障分类带占比进度条</li>
|
||||
<li>周报/月报自适应章节内容</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div style="background:#fff7ed;border:1px solid #fed7aa;border-radius:8px;padding:14px">
|
||||
<h4 style="margin:0 0 6px;font-size:14px;color:#c2410c">? 待确认</h4>
|
||||
<ul style="margin:0;padding-left:18px;font-size:13px;color:#7c2d12;line-height:1.8">
|
||||
<li>Ch3 展开后是否需要按 fault_subcategory 二级明细?</li>
|
||||
<li>Ch2 展开后是否需要按日故障统计简表?</li>
|
||||
<li>后端 metadata 需扩展 5-6 个新字段</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
<h2>报告预览页 — 融合方案全景</h2>
|
||||
<p class="subtitle">B(摘要+详情分区)+ C(报告章节结构)。周报/月报共用同一布局,章节内容自适应。</p>
|
||||
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">完整页面布局 — 月报示例(2026年4月)</div>
|
||||
<div class="mockup-body">
|
||||
|
||||
<!-- Header -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:16px 0;border-bottom:1px solid #e2e8f0;margin-bottom:20px">
|
||||
<div style="display:flex;align-items:center;gap:16px">
|
||||
<span style="color:#94a3b8;font-size:18px">←</span>
|
||||
<div>
|
||||
<h2 style="font-size:22px;font-weight:700;color:#0f172a;margin:0">月报</h2>
|
||||
<span style="font-size:13px;color:#64748b">2026-04-01 ~ 2026-04-30</span>
|
||||
</div>
|
||||
<span style="background:#dcfce7;color:#15803d;padding:2px 10px;border-radius:12px;font-size:12px;font-weight:600">已完成</span>
|
||||
</div>
|
||||
<button class="mock-button">⬇ 下载报告</button>
|
||||
</div>
|
||||
|
||||
<!-- KPI Row -->
|
||||
<div style="display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:20px">
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">工单总数</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0f172a">12</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">已解决</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#059669">10</div>
|
||||
<div style="font-size:11px;color:#94a3b8">83.3%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">可用性均值</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#f59e0b">98.52%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">SLA 达标率</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#059669">91.7%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">平均处理时长</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0f172a">240</div>
|
||||
<div style="font-size:11px;color:#94a3b8">分钟</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">进行中</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0369a1">2</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chapter Sections -->
|
||||
<div style="display:flex;flex-direction:column;gap:12px">
|
||||
|
||||
<!-- Ch1: 设备概况 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;color:#fff;border-radius:6px;font-size:12px;font-weight:700">1</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">设备概况</span>
|
||||
</div>
|
||||
<span style="font-size:20px;color:#94a3b8">▾</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:32px;padding:16px 20px">
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#dbeafe;display:flex;align-items:center;justify-content:center;font-size:20px">🖥</div>
|
||||
<div><span style="font-size:24px;font-weight:700;color:#0f172a">8</span><span style="font-size:13px;color:#64748b;margin-left:4px">台 GPU 服务器</span></div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#fef3c7;display:flex;align-items:center;justify-content:center;font-size:20px">🗄</div>
|
||||
<div><span style="font-size:24px;font-weight:700;color:#0f172a">3</span><span style="font-size:13px;color:#64748b;margin-left:4px">台 存储服务器</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch2: 运营数据 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#8b5cf6;color:#fff;border-radius:6px;font-size:12px;font-weight:700">2</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">运营数据</span>
|
||||
</div>
|
||||
<span style="font-size:20px;color:#94a3b8">▸</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:24px;padding:16px 20px">
|
||||
<div style="font-size:13px;color:#64748b">故障工单 <span style="font-weight:700;color:#d97706;font-size:16px;margin-left:4px">8</span> 件</div>
|
||||
<div style="font-size:13px;color:#64748b">涉及设备 <span style="font-weight:700;color:#0f172a;font-size:16px;margin-left:4px">5</span> 台</div>
|
||||
<div style="font-size:13px;color:#64748b">无故障天数 <span style="font-weight:700;color:#059669;font-size:16px;margin-left:4px">24</span> 天</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch3: 故障分类 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#f59e0b;color:#fff;border-radius:6px;font-size:12px;font-weight:700">3</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">故障分类</span>
|
||||
</div>
|
||||
<span style="font-size:20px;color:#94a3b8">▾</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:16px;padding:16px 20px">
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#fff7ed;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#f59e0b">5</div>
|
||||
<div style="font-size:12px;color:#64748b">GPU 故障</div>
|
||||
<div style="width:100%;height:4px;background:#fef3c7;border-radius:2px;margin-top:6px"><div style="width:62.5%;height:100%;background:#f59e0b;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">62.5%</div>
|
||||
</div>
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#fff7ed;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#f59e0b">1</div>
|
||||
<div style="font-size:12px;color:#64748b">存储故障</div>
|
||||
<div style="width:100%;height:4px;background:#fef3c7;border-radius:2px;margin-top:6px"><div style="width:12.5%;height:100%;background:#f59e0b;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">12.5%</div>
|
||||
</div>
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#eff6ff;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#3b82f6">2</div>
|
||||
<div style="font-size:12px;color:#64748b">其他工单</div>
|
||||
<div style="width:100%;height:4px;background:#dbeafe;border-radius:2px;margin-top:6px"><div style="width:25%;height:100%;background:#3b82f6;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">25.0%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch4: 服务可用性 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#10b981;color:#fff;border-radius:6px;font-size:12px;font-weight:700">4</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">服务可用性</span>
|
||||
</div>
|
||||
<span style="font-size:20px;color:#94a3b8">▸</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:16px 20px">
|
||||
<div>
|
||||
<span style="font-size:28px;font-weight:700;color:#f59e0b">98.52%</span>
|
||||
<span style="font-size:13px;color:#64748b;margin-left:6px">整体可用性</span>
|
||||
</div>
|
||||
<div style="font-size:12px;color:#64748b">
|
||||
<span>最低可用 IP:</span>
|
||||
<span style="font-weight:600;color:#dc2626">10.0.0.35</span>
|
||||
<span style="color:#dc2626;font-weight:600;margin-left:4px">(95.12%)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Key features -->
|
||||
<div class="section">
|
||||
<h3>设计要点</h3>
|
||||
</div>
|
||||
|
||||
<div class="pros-cons">
|
||||
<div class="pros">
|
||||
<h4>交互特性</h4>
|
||||
<ul>
|
||||
<li>章节卡片默认全部展开,可折叠</li>
|
||||
<li>折叠态显示摘要数据,不丢失关键信息</li>
|
||||
<li>有数据的章节正常展示,无数据的章节(如无GPU故障)保留卡片但数量为 0</li>
|
||||
<li>周报/月报章节内容自适应(周报无"按IP可用性"明细,改为按日统计)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cons">
|
||||
<h4>待确认</h4>
|
||||
<ul>
|
||||
<li>KPI 行 5-6 个指标是否太多?是否需要精简到 4 个?</li>
|
||||
<li>章节是否默认全部展开,还是默认折叠只显示摘要?</li>
|
||||
<li>故障分类是否需要按 fault_subcategory 二级展开?</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
<h2>报告预览页</h2>
|
||||
<p class="subtitle">从列表点击报告名称或"预览"按钮进入。右上角按钮根据状态动态切换。</p>
|
||||
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">预览页 — 状态:数据已就绪(待生成文档)</div>
|
||||
<div class="mockup-body">
|
||||
|
||||
<!-- Header -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:16px 0;border-bottom:1px solid #e2e8f0;margin-bottom:20px">
|
||||
<div style="display:flex;align-items:center;gap:16px">
|
||||
<span style="color:#94a3b8;font-size:18px;cursor:pointer">←</span>
|
||||
<div>
|
||||
<h2 style="font-size:22px;font-weight:700;color:#0f172a;margin:0">月报</h2>
|
||||
<span style="font-size:13px;color:#64748b">2026-04-01 ~ 2026-04-30</span>
|
||||
</div>
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#fef3c7;color:#92400e">
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:#f59e0b"></span>
|
||||
数据已就绪
|
||||
</span>
|
||||
</div>
|
||||
<button class="mock-button" style="background:#059669;color:#fff">生成报告文档</button>
|
||||
</div>
|
||||
|
||||
<!-- KPI Row -->
|
||||
<div style="display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:20px">
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">工单总数</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0f172a">12</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">已解决</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#059669">10</div>
|
||||
<div style="font-size:11px;color:#94a3b8">83.3%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">整体可用性</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#f59e0b">98.52%</div>
|
||||
<div style="font-size:11px;color:#94a3b8">低于99%</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">平均处理时长</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0f172a">240</div>
|
||||
<div style="font-size:11px;color:#94a3b8">分钟</div>
|
||||
</div>
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px;text-align:center">
|
||||
<div style="font-size:12px;color:#64748b;margin-bottom:4px">进行中</div>
|
||||
<div style="font-size:28px;font-weight:700;color:#0369a1">2</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch1 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;margin-bottom:12px">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#3b82f6;color:#fff;border-radius:6px;font-size:12px;font-weight:700">1</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">设备概况</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:32px;padding:16px 20px">
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#dbeafe;display:flex;align-items:center;justify-content:center;font-size:20px">🖥</div>
|
||||
<div><span style="font-size:24px;font-weight:700;color:#0f172a">8</span><span style="font-size:13px;color:#64748b;margin-left:4px">台 GPU 服务器</span></div>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#fef3c7;display:flex;align-items:center;justify-content:center;font-size:20px">🗄</div>
|
||||
<div><span style="font-size:24px;font-weight:700;color:#0f172a">3</span><span style="font-size:13px;color:#64748b;margin-left:4px">台 存储服务器</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch2 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;margin-bottom:12px">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#8b5cf6;color:#fff;border-radius:6px;font-size:12px;font-weight:700">2</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">运营数据</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:24px;padding:16px 20px">
|
||||
<div style="font-size:13px;color:#64748b">故障工单 <span style="font-weight:700;color:#d97706;font-size:16px;margin-left:4px">8</span> 件</div>
|
||||
<div style="font-size:13px;color:#64748b">涉及设备 <span style="font-weight:700;color:#0f172a;font-size:16px;margin-left:4px">5</span> 台</div>
|
||||
<div style="font-size:13px;color:#64748b">无故障天数 <span style="font-weight:700;color:#059669;font-size:16px;margin-left:4px">24</span> 天</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch3 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;margin-bottom:12px">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#f59e0b;color:#fff;border-radius:6px;font-size:12px;font-weight:700">3</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">故障分类</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:16px;padding:16px 20px">
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#fff7ed;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#f59e0b">5</div>
|
||||
<div style="font-size:12px;color:#64748b">GPU 故障</div>
|
||||
<div style="width:100%;height:4px;background:#fef3c7;border-radius:2px;margin-top:6px"><div style="width:62.5%;height:100%;background:#f59e0b;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">62.5%</div>
|
||||
</div>
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#fff7ed;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#f59e0b">1</div>
|
||||
<div style="font-size:12px;color:#64748b">存储故障</div>
|
||||
<div style="width:100%;height:4px;background:#fef3c7;border-radius:2px;margin-top:6px"><div style="width:12.5%;height:100%;background:#f59e0b;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">12.5%</div>
|
||||
</div>
|
||||
<div style="flex:1;padding:12px;border-radius:8px;background:#eff6ff;text-align:center">
|
||||
<div style="font-size:20px;font-weight:700;color:#3b82f6">2</div>
|
||||
<div style="font-size:12px;color:#64748b">其他工单</div>
|
||||
<div style="width:100%;height:4px;background:#dbeafe;border-radius:2px;margin-top:6px"><div style="width:25%;height:100%;background:#3b82f6;border-radius:2px"></div></div>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:2px">25.0%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ch4 -->
|
||||
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:#f8fafc;border-bottom:1px solid #e2e8f0">
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;background:#10b981;color:#fff;border-radius:6px;font-size:12px;font-weight:700">4</span>
|
||||
<span style="font-size:15px;font-weight:600;color:#1e293b">服务可用性</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding:16px 20px">
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:16px">
|
||||
<span style="font-size:13px;color:#64748b">整体可用性:</span>
|
||||
<span style="font-size:22px;font-weight:700;color:#f59e0b">98.52%</span>
|
||||
</div>
|
||||
<table style="width:100%;font-size:13px;border-collapse:collapse">
|
||||
<thead>
|
||||
<tr style="border-bottom:2px solid #e2e8f0;text-align:left">
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">IP 地址</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">设备类型</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">故障时长</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">可用性</th>
|
||||
<th style="padding:8px 12px;color:#64748b;font-weight:500">状态</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.35</td>
|
||||
<td style="padding:8px 12px;color:#64748b">GPU</td>
|
||||
<td style="padding:8px 12px;color:#dc2626;font-weight:500">2,160 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#dc2626">95.12%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#fef2f2;color:#dc2626">进行中</span></td>
|
||||
</tr>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.42</td>
|
||||
<td style="padding:8px 12px;color:#64748b">GPU</td>
|
||||
<td style="padding:8px 12px;color:#0f172a">1,440 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#f59e0b">96.78%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#dcfce7;color:#15803d">已恢复</span></td>
|
||||
</tr>
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:8px 12px;font-weight:500;color:#0f172a">10.0.0.18</td>
|
||||
<td style="padding:8px 12px;color:#64748b">存储</td>
|
||||
<td style="padding:8px 12px;color:#0f172a">720 分钟</td>
|
||||
<td style="padding:8px 12px;font-weight:700;color:#f59e0b">98.41%</td>
|
||||
<td style="padding:8px 12px"><span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;background:#dcfce7;color:#15803d">已恢复</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="font-size:11px;color:#94a3b8;margin-top:8px">共 3 个 IP 可用性低于 100%,其余设备保持 100% 在线</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 不同状态下的按钮变化 -->
|
||||
<div class="section">
|
||||
<h3>右上角按钮 — 按状态切换</h3>
|
||||
</div>
|
||||
|
||||
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:12px">
|
||||
<div style="background:#fef3c7;border:1px solid #fde68a;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-size:11px;color:#a16207;margin-bottom:6px">数据已就绪</div>
|
||||
<span style="display:inline-block;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;background:#059669;color:#fff">生成报告文档</span>
|
||||
</div>
|
||||
<div style="background:#dbeafe;border:1px solid #bfdbfe;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-size:11px;color:#1e40af;margin-bottom:6px">文档生成中</div>
|
||||
<span style="display:inline-block;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;background:#94a3b8;color:#fff">生成中...</span>
|
||||
</div>
|
||||
<div style="background:#dcfce7;border:1px solid #bbf7d0;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-size:11px;color:#15803d;margin-bottom:6px">已完成</div>
|
||||
<span style="display:inline-block;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;background:#2563eb;color:#fff">⬇ 下载报告</span>
|
||||
</div>
|
||||
<div style="background:#fef2f2;border:1px solid #fecaca;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-size:11px;color:#b91c1c;margin-bottom:6px">生成失败</div>
|
||||
<span style="display:inline-block;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:600;background:#f59e0b;color:#fff">重新生成</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
<h2>报告管理列表</h2>
|
||||
<p class="subtitle">类型列用颜色区分月报/周报。批量操作按钮仅在选中后出现。</p>
|
||||
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">报告管理页面</div>
|
||||
<div class="mockup-body">
|
||||
|
||||
<!-- Header -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:16px 0;border-bottom:1px solid #e2e8f0;margin-bottom:16px">
|
||||
<div>
|
||||
<h2 style="font-size:20px;font-weight:700;color:#0f172a;margin:0">报告管理</h2>
|
||||
<span style="font-size:12px;color:#94a3b8">数据预览与文档生成</span>
|
||||
</div>
|
||||
<button class="mock-button">+ 新建报告</button>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<table style="width:100%;font-size:13px;border-collapse:collapse">
|
||||
<thead>
|
||||
<tr style="border-bottom:2px solid #e2e8f0;text-align:left">
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500;width:40px">
|
||||
<input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1">
|
||||
</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">报告名称</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">类型</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">时间段</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">状态</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">创建时间</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Row 1: preview -->
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:10px 12px"><input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1"></td>
|
||||
<td style="padding:10px 12px;max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">
|
||||
<a href="#" style="color:#2563eb;font-weight:500;text-decoration:none;cursor:pointer" onclick="event.preventDefault()">2026年4月图灵IT基础设施运营月报</a>
|
||||
</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-block;padding:3px 10px;border-radius:8px;font-size:11px;font-weight:600;background:#dbeafe;color:#1e40af">月报</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#64748b">2026-04-01 ~ 2026-04-30</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#fef3c7;color:#92400e">
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:#f59e0b"></span>
|
||||
数据已就绪
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#94a3b8;font-size:12px">2026-05-07 14:30</td>
|
||||
<td style="padding:10px 12px">
|
||||
<div style="display:flex;gap:4px">
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#f0fdf4;color:#059669">生成文档</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;color:#dc2626">🗑</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 2: generating -->
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:10px 12px"><input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1"></td>
|
||||
<td style="padding:10px 12px;max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">
|
||||
<a href="#" style="color:#2563eb;font-weight:500;text-decoration:none;cursor:pointer" onclick="event.preventDefault()">图灵IT基础设施运营周报(4月28日-5月4日)</a>
|
||||
</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-block;padding:3px 10px;border-radius:8px;font-size:11px;font-weight:600;background:#ede9fe;color:#6b21a8">周报</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#64748b">2026-04-28 ~ 2026-05-04</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#dbeafe;color:#1e40af">
|
||||
<span style="display:inline-block;width:10px;height:10px;border:2px solid #3b82f6;border-top-color:transparent;border-radius:50%"></span>
|
||||
文档生成中
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#94a3b8;font-size:12px">2026-05-07 14:35</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">预览</span>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 3: completed -->
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:10px 12px"><input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1"></td>
|
||||
<td style="padding:10px 12px;max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">
|
||||
<a href="#" style="color:#2563eb;font-weight:500;text-decoration:none;cursor:pointer" onclick="event.preventDefault()">2026年3月图灵IT基础设施运营月报</a>
|
||||
</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-block;padding:3px 10px;border-radius:8px;font-size:11px;font-weight:600;background:#dbeafe;color:#1e40af">月报</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#64748b">2026-03-01 ~ 2026-03-31</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#dcfce7;color:#15803d">
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:#22c55e"></span>
|
||||
已完成
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#94a3b8;font-size:12px">2026-05-06 10:15</td>
|
||||
<td style="padding:10px 12px">
|
||||
<div style="display:flex;gap:4px">
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#f0fdf4;color:#059669">⬇ 下载</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;color:#dc2626">🗑</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 4: failed -->
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:10px 12px"><input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1"></td>
|
||||
<td style="padding:10px 12px;max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">
|
||||
<a href="#" style="color:#2563eb;font-weight:500;text-decoration:none;cursor:pointer" onclick="event.preventDefault()">图灵IT基础设施运营周报(4月21日-4月27日)</a>
|
||||
</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-block;padding:3px 10px;border-radius:8px;font-size:11px;font-weight:600;background:#ede9fe;color:#6b21a8">周报</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#64748b">2026-04-21 ~ 2026-04-27</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#fef2f2;color:#b91c1c">
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:#ef4444"></span>
|
||||
生成失败
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#94a3b8;font-size:12px">2026-05-06 11:00</td>
|
||||
<td style="padding:10px 12px">
|
||||
<div style="display:flex;gap:4px">
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#fef3c7;color:#92400e">重试</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;color:#dc2626">🗑</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:16px">
|
||||
<div style="background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;padding:14px">
|
||||
<h4 style="margin:0 0 6px;font-size:14px;color:#15803d">✓ 类型颜色区分</h4>
|
||||
<div style="display:flex;gap:12px;align-items:center;font-size:13px">
|
||||
<span style="display:inline-block;padding:3px 10px;border-radius:8px;font-size:11px;font-weight:600;background:#dbeafe;color:#1e40af">月报</span>
|
||||
<span style="font-size:12px;color:#64748b">蓝色背景,与报告预览章节编号色呼应</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:12px;align-items:center;font-size:13px;margin-top:8px">
|
||||
<span style="display:inline-block;padding:3px 10px;border-radius:8px;font-size:11px;font-weight:600;background:#ede9fe;color:#6b21a8">周报</span>
|
||||
<span style="font-size:12px;color:#64748b">紫色背景,与月报明显区分</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;padding:14px">
|
||||
<h4 style="margin:0 0 6px;font-size:14px;color:#15803d">✓ 批量操作栏</h4>
|
||||
<ul style="margin:0;padding-left:18px;font-size:13px;color:#166534;line-height:1.8">
|
||||
<li>未选中任何行时不显示批量操作栏</li>
|
||||
<li>选中 ≥1 行后,在表格下方出现「📦 批量下载」「🗑 批量删除」</li>
|
||||
<li>与现有实现完全一致,无需改动</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
<h2>报告管理页 — 新流程重构</h2>
|
||||
<p class="subtitle">核心理念:预览数据先行(1-2s),确认后再生成 DOCX(10-30s)。</p>
|
||||
|
||||
<div class="section">
|
||||
<h3>流程对比</h3>
|
||||
</div>
|
||||
|
||||
<div class="split">
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">旧流程</div>
|
||||
<div class="mockup-body" style="padding:16px;font-size:13px;text-align:center;line-height:2.2">
|
||||
选择月份 → 点"生成报告" →<br/>
|
||||
<span style="color:#94a3b8">等待 10-30s(数据+图表+DOCX+OLE)</span> →<br/>
|
||||
报告完成 → 点"查看"预览 →<br/>
|
||||
发现数据有误 → 删除重来
|
||||
</div>
|
||||
</div>
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">新流程</div>
|
||||
<div class="mockup-body" style="padding:16px;font-size:13px;text-align:center;line-height:2.2">
|
||||
选择月份 → 点"预览报告" →<br/>
|
||||
<span style="color:#059669">等待 1-2s(仅数据采集)</span> →<br/>
|
||||
自动跳转预览页 → 确认数据无误 →<br/>
|
||||
点"生成报告文档" → 下载 DOCX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>报告列表页 — 新版布局</h3>
|
||||
</div>
|
||||
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">报告管理页面(列表)</div>
|
||||
<div class="mockup-body">
|
||||
|
||||
<!-- Header -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:16px 0;border-bottom:1px solid #e2e8f0;margin-bottom:16px">
|
||||
<div>
|
||||
<h2 style="font-size:20px;font-weight:700;color:#0f172a;margin:0">报告管理</h2>
|
||||
<span style="font-size:12px;color:#94a3b8">数据预览与文档生成</span>
|
||||
</div>
|
||||
<button class="mock-button" style="background:#3b82f6;color:#fff;border:none;padding:8px 16px;border-radius:10px;font-size:13px;font-weight:600">+ 新建报告</button>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<table style="width:100%;font-size:13px;border-collapse:collapse">
|
||||
<thead>
|
||||
<tr style="border-bottom:2px solid #e2e8f0;text-align:left">
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500;width:40px">
|
||||
<input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1">
|
||||
</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">报告名称</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">类型</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">时间段</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">状态</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">创建时间</th>
|
||||
<th style="padding:10px 12px;color:#64748b;font-weight:500">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Row 1: preview status -->
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:10px 12px"><input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1"></td>
|
||||
<td style="padding:10px 12px;font-weight:500;color:#0f172a;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="2026年4月图灵IT基础设施运营月报">2026年4月图灵IT基础设施运营月报</td>
|
||||
<td style="padding:10px 12px;font-weight:500;color:#0f172a">月报</td>
|
||||
<td style="padding:10px 12px;color:#64748b">2026-04-01 ~ 2026-04-30</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#fef3c7;color:#92400e">
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:#f59e0b"></span>
|
||||
数据已就绪
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#94a3b8;font-size:12px">2026-05-07 14:30</td>
|
||||
<td style="padding:10px 12px">
|
||||
<div style="display:flex;gap:4px">
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#f0fdf4;color:#059669">生成文档</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;color:#dc2626">🗑</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 2: generating status -->
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:10px 12px"><input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1"></td>
|
||||
<td style="padding:10px 12px;font-weight:500;color:#0f172a;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="图灵IT基础设施运营周报(4月28日-5月4日)">图灵IT基础设施运营周报(4月28日-5月4日)</td>
|
||||
<td style="padding:10px 12px;font-weight:500;color:#0f172a">周报</td>
|
||||
<td style="padding:10px 12px;color:#64748b">2026-04-28 ~ 2026-05-04</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#dbeafe;color:#1e40af">
|
||||
<span style="display:inline-block;width:10px;height:10px;border:2px solid #3b82f6;border-top-color:transparent;border-radius:50%;animation:spin 1s linear infinite"></span>
|
||||
文档生成中
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#94a3b8;font-size:12px">2026-05-07 14:35</td>
|
||||
<td style="padding:10px 12px">
|
||||
<div style="display:flex;gap:4px">
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">预览</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 3: completed status -->
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:10px 12px"><input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1"></td>
|
||||
<td style="padding:10px 12px;font-weight:500;color:#0f172a;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="2026年3月图灵IT基础设施运营月报">2026年3月图灵IT基础设施运营月报</td>
|
||||
<td style="padding:10px 12px;font-weight:500;color:#0f172a">月报</td>
|
||||
<td style="padding:10px 12px;color:#64748b">2026-03-01 ~ 2026-03-31</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#dcfce7;color:#15803d">
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:#22c55e"></span>
|
||||
已完成
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#94a3b8;font-size:12px">2026-05-06 10:15</td>
|
||||
<td style="padding:10px 12px">
|
||||
<div style="display:flex;gap:4px">
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#f0fdf4;color:#059669">⬇ 下载</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;color:#dc2626">🗑</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Row 4: failed -->
|
||||
<tr style="border-bottom:1px solid #f1f5f9">
|
||||
<td style="padding:10px 12px"><input type="checkbox" style="width:16px;height:16px;border-radius:4px;border:1px solid #cbd5e1"></td>
|
||||
<td style="padding:10px 12px;font-weight:500;color:#0f172a;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="图灵IT基础设施运营周报(4月21日-4月27日)">图灵IT基础设施运营周报(4月21日-4月27日)</td>
|
||||
<td style="padding:10px 12px;font-weight:500;color:#0f172a">周报</td>
|
||||
<td style="padding:10px 12px;color:#64748b">2026-04-21 ~ 2026-04-27</td>
|
||||
<td style="padding:10px 12px">
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;border-radius:10px;font-size:11px;font-weight:500;background:#fef2f2;color:#b91c1c">
|
||||
<span style="width:6px;height:6px;border-radius:50%;background:#ef4444"></span>
|
||||
生成失败
|
||||
</span>
|
||||
</td>
|
||||
<td style="padding:10px 12px;color:#94a3b8;font-size:12px">2026-05-06 11:00</td>
|
||||
<td style="padding:10px 12px">
|
||||
<div style="display:flex;gap:4px">
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;background:#fef3c7;color:#92400e">重试</span>
|
||||
<span style="cursor:pointer;padding:4px 10px;border-radius:6px;font-size:12px;font-weight:500;color:#dc2626">🗑</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Batch actions bar -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px 0;margin-top:12px;border-top:1px solid #e2e8f0">
|
||||
<span style="font-size:12px;color:#94a3b8">已选 2 项</span>
|
||||
<div style="display:flex;gap:8px">
|
||||
<span style="cursor:pointer;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:500;background:#eff6ff;color:#2563eb">📦 批量下载</span>
|
||||
<span style="cursor:pointer;padding:6px 14px;border-radius:8px;font-size:12px;font-weight:500;background:#fef2f2;color:#dc2626">🗑 批量删除</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>状态体系总览</h3>
|
||||
</div>
|
||||
|
||||
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:12px">
|
||||
<div style="background:#fef3c7;border:1px solid #fde68a;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-weight:700;color:#92400e;font-size:14px;margin-bottom:4px">数据已就绪</div>
|
||||
<div style="font-size:11px;color:#a16207">数据采集完成<br/>文档未生成</div>
|
||||
<div style="display:flex;gap:4px;justify-content:center;margin-top:8px">
|
||||
<span style="padding:3px 8px;border-radius:4px;font-size:10px;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="padding:3px 8px;border-radius:4px;font-size:10px;background:#f0fdf4;color:#059669">生成文档</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background:#dbeafe;border:1px solid #bfdbfe;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-weight:700;color:#1e40af;font-size:14px;margin-bottom:4px">文档生成中</div>
|
||||
<div style="font-size:11px;color:#3b82f6">DOCX 构建中<br/>图表+OLE嵌入</div>
|
||||
<div style="margin-top:8px">
|
||||
<span style="padding:3px 8px;border-radius:4px;font-size:10px;background:#eff6ff;color:#2563eb">预览</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background:#dcfce7;border:1px solid #bbf7d0;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-weight:700;color:#15803d;font-size:14px;margin-bottom:4px">已完成</div>
|
||||
<div style="font-size:11px;color:#16a34a">文档就绪<br/>可下载</div>
|
||||
<div style="display:flex;gap:4px;justify-content:center;margin-top:8px">
|
||||
<span style="padding:3px 8px;border-radius:4px;font-size:10px;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="padding:3px 8px;border-radius:4px;font-size:10px;background:#f0fdf4;color:#059669">下载</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background:#fef2f2;border:1px solid #fecaca;border-radius:8px;padding:12px;text-align:center">
|
||||
<div style="font-weight:700;color:#b91c1c;font-size:14px;margin-bottom:4px">生成失败</div>
|
||||
<div style="font-size:11px;color:#dc2626">文档构建出错<br/>可查看预览数据</div>
|
||||
<div style="display:flex;gap:4px;justify-content:center;margin-top:8px">
|
||||
<span style="padding:3px 8px;border-radius:4px;font-size:10px;background:#eff6ff;color:#2563eb">预览</span>
|
||||
<span style="padding:3px 8px;border-radius:4px;font-size:10px;background:#fef3c7;color:#92400e">重试</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" style="margin-top:20px">
|
||||
<h3>与预览页的衔接</h3>
|
||||
</div>
|
||||
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">用户操作流程</div>
|
||||
<div class="mockup-body" style="padding:20px;text-align:center">
|
||||
<div style="display:flex;align-items:center;justify-content:center;gap:16px;font-size:13px">
|
||||
<div style="background:#f1f5f9;padding:12px 20px;border-radius:8px;font-weight:600;color:#0f172a">
|
||||
列表页<br/>点"新建报告"
|
||||
</div>
|
||||
<span style="font-size:18px;color:#94a3b8">→</span>
|
||||
<div style="background:#f1f5f9;padding:12px 20px;border-radius:8px;font-weight:600;color:#0f172a">
|
||||
弹窗选择<br/>月份/日期
|
||||
</div>
|
||||
<span style="font-size:18px;color:#94a3b8">→</span>
|
||||
<div style="background:#fef3c7;padding:12px 20px;border-radius:8px;font-weight:600;color:#92400e">
|
||||
1-2s 数据采集<br/>自动跳转预览页
|
||||
</div>
|
||||
<span style="font-size:18px;color:#94a3b8">→</span>
|
||||
<div style="background:#eff6ff;padding:12px 20px;border-radius:8px;font-weight:600;color:#2563eb">
|
||||
预览页<br/>确认数据
|
||||
</div>
|
||||
<span style="font-size:18px;color:#94a3b8">→</span>
|
||||
<div style="background:#f0fdf4;padding:12px 20px;border-radius:8px;font-weight:600;color:#059669">
|
||||
点"生成文档"<br/>下载 DOCX
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"type":"server-started","port":60240,"host":"127.0.0.1","url_host":"localhost","url":"http://localhost:60240","screen_dir":"/Users/niuniu/programs/docker/issue-ai/.superpowers/brainstorm/9392-1778134394/content","state_dir":"/Users/niuniu/programs/docker/issue-ai/.superpowers/brainstorm/9392-1778134394/state"}
|
||||
10
CLAUDE.md
10
CLAUDE.md
|
|
@ -13,7 +13,7 @@ issue-ai 是基于 Next.js + SQLite 的工单跟踪管理系统,部署在腾
|
|||
| 站点域名 | `issue.tlyq.ai` |
|
||||
| 服务器 | txjp(IP: 43.133.38.210) |
|
||||
| 代码路径 | `/root/docker/issue-ai/` |
|
||||
| 本地端口 | 5176 |
|
||||
| 本地端口 | 6176 |
|
||||
| 容器名 | `issue-ai` |
|
||||
| 数据库 | SQLite:`data/issue.db` |
|
||||
| 报告存储 | `reports/` 目录(环境变量 `REPORTS_DIR` 可覆盖) |
|
||||
|
|
@ -139,9 +139,9 @@ npm run import # 导入工单
|
|||
|
||||
| 环境变量 | 本地开发 | 云服务器(txjp) | 说明 |
|
||||
|---------|---------|----------------|------|
|
||||
| `ASSETS_API_URL` | `http://localhost:5177/api` | `http://assets-ai:3000/api` | 调用 assets API 地址 |
|
||||
| `ASSETS_API_URL` | `http://localhost:6177/api` | `http://assets-ai:3000/api` | 调用 assets API 地址 |
|
||||
| `ASSETS_API_KEY` | 本地 assets-ai 生成 | 云上 assets-ai 生成 | **每个环境独立,不可跨环境使用** |
|
||||
| `NEXT_PUBLIC_ASSETS_URL` | `http://localhost:5177` | `https://assets.tlyq.ai` | 前端跳转链接(构建时内嵌) |
|
||||
| `NEXT_PUBLIC_ASSETS_URL` | `http://localhost:6177` | `https://assets.tlyq.ai` | 前端跳转链接(构建时内嵌) |
|
||||
| `ALLOWED_API_KEYS` | 本地 issue-ai 生成的 Key | 云上 issue-ai 生成的 Key | 允许外部系统调本系统的 Key,逗号分隔 |
|
||||
| `JWT_SECRET` | `dev-secret-key-local` | `${ISSUE_JWT_SECRET}` | 本地两系统需一致(同 localhost 域) |
|
||||
| `DATABASE_PATH` | `./data/issue.db` | `/app/data/issue.db` | Docker volume 挂载 |
|
||||
|
|
@ -154,10 +154,10 @@ DATABASE_PATH=./data/issue.db
|
|||
JWT_SECRET=dev-secret-key-local
|
||||
ADMIN_PASSWORD=admin123
|
||||
NODE_ENV=development
|
||||
ASSETS_API_URL=http://localhost:5177/api
|
||||
ASSETS_API_URL=http://localhost:6177/api
|
||||
ASSETS_API_KEY=ak_<32字节十六进制>
|
||||
ALLOWED_API_KEYS=ak_<32字节十六进制>
|
||||
NEXT_PUBLIC_ASSETS_URL=http://localhost:5177
|
||||
NEXT_PUBLIC_ASSETS_URL=http://localhost:6177
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ services:
|
|||
build: .
|
||||
container_name: issue-ai
|
||||
ports:
|
||||
- "5176:3000"
|
||||
- "6176:3000"
|
||||
volumes:
|
||||
- issue-data:/app/data
|
||||
- issue-uploads:/app/uploads
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "NODE_OPTIONS='--max-old-space-size=2048' next dev --port 5176",
|
||||
"dev": "NODE_OPTIONS='--max-old-space-size=2048' next dev --port 6176",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
|
|
@ -1,6 +1,10 @@
|
|||
import { NextResponse } from 'next/server'
|
||||
|
||||
export async function POST() {
|
||||
const r = NextResponse.json({ success: true })
|
||||
r.cookies.set('session_issue', '', { maxAge: 0, path: '/' })
|
||||
r.cookies.set('session', '', { maxAge: 0, path: '/' })
|
||||
// 清除 Authelia SSO cookie
|
||||
r.cookies.set('authelia_session', '', { maxAge: 0, path: '/', domain: '127.0.0.1' })
|
||||
return r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,49 @@
|
|||
import { NextResponse } from 'next/server'
|
||||
import { getCurrentUser } from '@/lib/auth'
|
||||
import { cookies, headers } from 'next/headers'
|
||||
import { getDb } from '@/lib/db'
|
||||
import { getCurrentUser, createToken } from '@/lib/auth'
|
||||
|
||||
export async function GET() {
|
||||
const user = await getCurrentUser()
|
||||
if (!user) return NextResponse.json({ error: '未登录' }, { status: 401 })
|
||||
return NextResponse.json({ user })
|
||||
try {
|
||||
const cookieStore = await cookies()
|
||||
|
||||
// 路径 1:SSO(来自 nginx auth_request 代理)
|
||||
let ssoUsername = ''
|
||||
try {
|
||||
const ssoSession = cookieStore.get('session')?.value
|
||||
if (ssoSession) ssoUsername = JSON.parse(ssoSession).username || ''
|
||||
} catch { }
|
||||
if (!ssoUsername) {
|
||||
const headersList = await headers()
|
||||
ssoUsername = headersList.get('x-remote-user') || ''
|
||||
}
|
||||
|
||||
if (ssoUsername) {
|
||||
const db = getDb()
|
||||
db.prepare(
|
||||
"INSERT OR IGNORE INTO users (username, password_hash, display_name, role, is_active) VALUES (?, '__SSO__', ?, ?, 1)"
|
||||
).run(ssoUsername, ssoUsername, 'viewer')
|
||||
const user = db.prepare(
|
||||
'SELECT id, username, display_name, role FROM users WHERE username = ? AND is_active = 1'
|
||||
).get(ssoUsername) as Record<string, unknown> | undefined
|
||||
if (user) {
|
||||
const jwt = await createToken({
|
||||
id: user.id as number,
|
||||
username: user.username as string,
|
||||
display_name: (user.display_name as string) || '',
|
||||
role: user.role as string,
|
||||
})
|
||||
const response = NextResponse.json({ user })
|
||||
response.cookies.set('session_issue', jwt, { httpOnly: true, sameSite: 'lax', path: '/', maxAge: 7 * 24 * 60 * 60 })
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
// 路径 2:JWT cookie(本地开发 / @fallback 紧急绕过)
|
||||
const user = await getCurrentUser()
|
||||
if (!user) return NextResponse.json({ error: '未登录' }, { status: 401 })
|
||||
return NextResponse.json({ user })
|
||||
} catch {
|
||||
return NextResponse.json({ error: '获取用户信息失败' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export default function Sidebar() {
|
|||
<List size={18} />全部工单
|
||||
</Link>
|
||||
)}
|
||||
{isAdmin && (
|
||||
<div className="pt-3 border-t border-slate-200 dark:border-slate-800 mt-3">
|
||||
<div className="flex items-center gap-3 px-3 py-2 text-xs font-semibold text-slate-400 dark:text-slate-500 uppercase tracking-wider">
|
||||
<Settings size={14} />系统设置
|
||||
|
|
@ -58,6 +59,7 @@ export default function Sidebar() {
|
|||
return (<Link key={item.href} href={item.href} className={`flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all duration-200 ${isActive ? 'bg-blue-50 text-blue-700 dark:bg-blue-500/10 dark:text-blue-400' : 'text-slate-600 hover:bg-slate-50 dark:text-slate-400 dark:hover:bg-slate-800'}`}><Icon size={18} />{item.label}</Link>)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
</aside>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ interface TopBarProps { user: { username: string; display_name: string; role: st
|
|||
export default function TopBar({ user }: TopBarProps) {
|
||||
const { theme, toggleTheme } = useTheme()
|
||||
const router = useRouter()
|
||||
const handleLogout = async () => { await fetch('/api/auth/logout', { method: 'POST' }); router.push('/login'); router.refresh() }
|
||||
const handleLogout = async () => {
|
||||
await fetch('/api/auth/logout', { method: 'POST' })
|
||||
router.push('/login'); router.refresh()
|
||||
}
|
||||
return (
|
||||
<header className="fixed top-0 left-60 right-0 h-14 bg-white dark:bg-slate-900 border-b border-slate-200 dark:border-slate-800 flex items-center justify-between px-6 z-30">
|
||||
<div />
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const ASSETS_API_URL = process.env.ASSETS_API_URL || 'http://localhost:5177/api'
|
||||
const ASSETS_API_URL = process.env.ASSETS_API_URL || 'http://localhost:6177/api'
|
||||
const ASSETS_API_KEY = process.env.ASSETS_API_KEY || ''
|
||||
|
||||
export interface Asset {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { NextRequest, NextResponse } from 'next/server'
|
|||
import { verifyToken } from '@/lib/jwt'
|
||||
|
||||
function verifyApiKey(key: string): boolean {
|
||||
// API Key 以环境变量形式存储,支持多个 Key(逗号分隔)
|
||||
const allowedKeys = process.env.ALLOWED_API_KEYS || ''
|
||||
if (!allowedKeys) return false
|
||||
const keys = allowedKeys.split(',').map(k => k.trim())
|
||||
|
|
@ -11,23 +10,50 @@ function verifyApiKey(key: string): boolean {
|
|||
|
||||
export async function middleware(request: NextRequest) {
|
||||
const { pathname } = request.nextUrl
|
||||
|
||||
// 清除外部注入的 trust proxy headers(防伪造)
|
||||
const requestHeaders = new Headers(request.headers)
|
||||
requestHeaders.delete('x-remote-user')
|
||||
requestHeaders.delete('x-remote-groups')
|
||||
|
||||
// SSO 代理认证路径:检测 X-Remote-User header + 代理密钥验证
|
||||
const remoteUser = request.headers.get('x-remote-user')
|
||||
const proxyKey = request.headers.get('x-auth-proxy-key')
|
||||
const isFromNginx = proxyKey === 'internal-auth-key-tlyq-2026'
|
||||
|
||||
if (remoteUser && isFromNginx) {
|
||||
// logout 路径不设置 SSO session(避免清除后又重新设置)
|
||||
if (pathname === '/api/auth/logout') return NextResponse.next()
|
||||
|
||||
const response = pathname === '/login' || pathname === '/'
|
||||
? NextResponse.redirect(new URL('/tickets', request.url))
|
||||
: NextResponse.next()
|
||||
|
||||
response.cookies.set('session', JSON.stringify({ username: remoteUser }), {
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
})
|
||||
if (pathname.startsWith('/api/')) {
|
||||
response.headers.set('x-original-pathname', pathname + (request.nextUrl.search || ''))
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
// 回退:现有 JWT 认证路径
|
||||
if (pathname.startsWith('/login') || pathname === '/') return NextResponse.next()
|
||||
if (pathname === '/api/auth/login') return NextResponse.next()
|
||||
|
||||
const authHeader = request.headers.get('authorization')
|
||||
|
||||
// API Key 认证:Bearer ak_xxx 格式
|
||||
if (authHeader?.startsWith('Bearer ak_')) {
|
||||
const key = authHeader.slice(7)
|
||||
if (verifyApiKey(key)) return NextResponse.next()
|
||||
// 环境变量中未匹配,API 路由仍放行(route handler 可查询数据库二次验证)
|
||||
if (pathname.startsWith('/api/')) return NextResponse.next()
|
||||
}
|
||||
|
||||
// Cookie 认证
|
||||
const token = request.cookies.get('session_issue')?.value
|
||||
|
||||
// 构建带 redirect 参数的登录 URL
|
||||
function buildLoginRedirect() {
|
||||
const loginUrl = new URL('/login', request.url)
|
||||
const dest = pathname + (request.nextUrl.search || '')
|
||||
|
|
|
|||
Loading…
Reference in New Issue