feat(ui): 重构注册审核平台原型界面
This commit is contained in:
@@ -3,59 +3,71 @@
|
||||
{% block title %}审计日志详情{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<header class="page-header">
|
||||
<span class="eyebrow">日志详情</span>
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Audit Snapshot</span>
|
||||
<h1 class="page-title">审计日志 #{{ log.id }}</h1>
|
||||
<p class="page-lead">这里集中展示当前请求的输入、模型输出、知识库引用和工具调用记录。</p>
|
||||
<p style="margin-top: 14px;"><a class="button" href="{% url 'audit:list' %}">返回审计列表</a></p>
|
||||
</header>
|
||||
<p class="page-lead">详情页集中展示当前请求的输入、结构化输出、引用来源、工具调用和原始输出,用来解释这一轮 Agent 执行到底做了什么。</p>
|
||||
<div class="button-row">
|
||||
<a class="button" href="{% url 'audit:list' %}">返回审计列表</a>
|
||||
<a class="button" href="{% url 'platform_ui:command-center' %}">返回工作台大屏</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="stack">
|
||||
<article class="panel">
|
||||
<h2 class="section-title">基础信息</h2>
|
||||
<ul class="meta-list">
|
||||
<li class="meta-badge">场景:{{ log.scenario_name }}</li>
|
||||
<li class="meta-badge">状态:{{ log.get_status_display_text }}</li>
|
||||
<li class="meta-badge">模型:{{ log.model_name }}</li>
|
||||
<li class="meta-badge">耗时:{{ log.latency_ms }} ms</li>
|
||||
</ul>
|
||||
<section class="hero-metrics">
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">场景</div>
|
||||
<div class="metric-value">{{ log.scenario_name }}</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">用户输入</h2>
|
||||
<div class="detail-item">{{ log.user_input|linebreaksbr }}</div>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">状态</div>
|
||||
<div class="metric-value">{{ log.get_status_display_text }}</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">最终回答</h2>
|
||||
<div class="detail-item">{{ log.final_answer|linebreaksbr }}</div>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">耗时</div>
|
||||
<div class="metric-value">{{ log.latency_ms }} ms</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">结构化输出</h2>
|
||||
<pre class="code-block">{{ log.structured_output }}</pre>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">引用来源</h2>
|
||||
<pre class="code-block">{{ log.retrieved_chunks }}</pre>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">工具调用</h2>
|
||||
<pre class="code-block">{{ log.tool_calls }}</pre>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">原始输出</h2>
|
||||
<pre class="code-block">{{ log.raw_output }}</pre>
|
||||
</article>
|
||||
|
||||
{% if log.error_message %}
|
||||
<section class="layout-two-columns">
|
||||
<div class="stack">
|
||||
<article class="panel">
|
||||
<h2 class="section-title">错误信息</h2>
|
||||
<pre class="code-block">{{ log.error_message }}</pre>
|
||||
<h2 class="section-title">用户输入</h2>
|
||||
<div class="detail-item">{{ log.user_input|linebreaksbr }}</div>
|
||||
</article>
|
||||
{% endif %}
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">最终回答</h2>
|
||||
<div class="detail-item">{{ log.final_answer|linebreaksbr }}</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">结构化输出</h2>
|
||||
<pre class="code-block">{{ log.structured_output }}</pre>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="stack">
|
||||
<article class="panel">
|
||||
<h2 class="section-title">引用来源</h2>
|
||||
<pre class="code-block">{{ log.retrieved_chunks }}</pre>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">工具调用</h2>
|
||||
<pre class="code-block">{{ log.tool_calls }}</pre>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">原始输出</h2>
|
||||
<pre class="code-block">{{ log.raw_output }}</pre>
|
||||
</article>
|
||||
|
||||
{% if log.error_message %}
|
||||
<article class="panel">
|
||||
<h2 class="section-title">错误信息</h2>
|
||||
<pre class="code-block">{{ log.error_message }}</pre>
|
||||
</article>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -3,48 +3,76 @@
|
||||
{% block title %}审计日志{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<header class="page-header">
|
||||
<span class="eyebrow">执行留痕</span>
|
||||
<h1 class="page-title">审计日志</h1>
|
||||
<p class="page-lead">每次 Agent 执行都会记录模型、检索片段、工具调用和最终结果,方便演示链路可解释性。</p>
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Audit Trail</span>
|
||||
<h1 class="page-title">审计日志与执行留痕中心</h1>
|
||||
<p class="page-lead">每次 Agent 执行都会保留输入、结构化结果、引用片段、工具调用和最终输出。这个页面用于说明系统为何可追溯、可复核、可解释。</p>
|
||||
{% if selected_scenario_id %}
|
||||
<p style="margin-top: 14px;">
|
||||
<span class="meta-badge">当前筛选场景:{{ selected_scenario_id }}</span>
|
||||
<div class="badge-row">
|
||||
<span class="pill pill-accent">当前筛选场景:{{ selected_scenario_id }}</span>
|
||||
<a class="button" href="{% url 'audit:list' %}">清空筛选</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</header>
|
||||
</section>
|
||||
|
||||
<article class="panel">
|
||||
<table class="kv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>场景</th>
|
||||
<th>输入摘要</th>
|
||||
<th>状态</th>
|
||||
<th>模型</th>
|
||||
<th>耗时</th>
|
||||
<th>创建时间</th>
|
||||
<th>详情</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in logs %}
|
||||
<section class="hero-metrics">
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">日志总数</div>
|
||||
<div class="metric-value">{{ logs|length }}</div>
|
||||
<div class="metric-note">当前页面加载的执行快照数量。</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">最近状态</div>
|
||||
<div class="metric-value">{% if logs %}{{ logs.0.get_status_display_text }}{% else %}暂无{% endif %}</div>
|
||||
<div class="metric-note">默认按时间倒序展示最近一次 Agent 执行。</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">最近场景</div>
|
||||
<div class="metric-value">{% if logs %}{{ logs.0.scenario_name }}{% else %}暂无{% endif %}</div>
|
||||
<div class="metric-note">便于快速定位当前复试演示对应的执行记录。</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">执行快照列表</h2>
|
||||
<p class="section-copy">保留真实审计数据列表,同时把展示形式升级为与首页、大屏一致的分析板风格。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ log.id }}</td>
|
||||
<td>{{ log.scenario_name }}</td>
|
||||
<td>{{ log.get_user_input_summary }}</td>
|
||||
<td>{{ log.get_status_display_text }}</td>
|
||||
<td>{{ log.model_name }}</td>
|
||||
<td>{{ log.latency_ms }} ms</td>
|
||||
<td>{{ log.created_at|date:"Y-m-d H:i" }}</td>
|
||||
<td><a class="button" href="{% url 'audit:detail' log.id %}">查看详情</a></td>
|
||||
<th>ID</th>
|
||||
<th>场景</th>
|
||||
<th>输入摘要</th>
|
||||
<th>状态</th>
|
||||
<th>模型</th>
|
||||
<th>耗时</th>
|
||||
<th>创建时间</th>
|
||||
<th>详情</th>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="8">暂无审计日志,先去执行一次对话吧。</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</article>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in logs %}
|
||||
<tr>
|
||||
<td>{{ log.id }}</td>
|
||||
<td>{{ log.scenario_name }}</td>
|
||||
<td>{{ log.get_user_input_summary }}</td>
|
||||
<td>
|
||||
<span class="pill {% if log.status == 'success' %}pill-success{% else %}pill-danger{% endif %}">{{ log.get_status_display_text }}</span>
|
||||
</td>
|
||||
<td>{{ log.model_name }}</td>
|
||||
<td>{{ log.latency_ms }} ms</td>
|
||||
<td>{{ log.created_at|date:"Y-m-d H:i" }}</td>
|
||||
<td><a class="button" href="{% url 'audit:detail' log.id %}">查看详情</a></td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="8">暂无审计日志,先去执行一次审核工作台任务。</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -3,349 +3,387 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}Universal Agent Demo Framework{% endblock %}</title>
|
||||
<title>{% block title %}注册审核智能体平台{% endblock %}</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f4f1ea;
|
||||
--surface: #fffdf8;
|
||||
--surface-strong: #fff7ea;
|
||||
--border: #d7c9b0;
|
||||
--text: #2f261d;
|
||||
--muted: #73614f;
|
||||
--accent: #a54c2b;
|
||||
--accent-soft: #f1d2b8;
|
||||
--success: #2b6a4d;
|
||||
--warning: #9a5a00;
|
||||
--danger: #8d2f2f;
|
||||
--shadow: 0 18px 40px rgba(91, 63, 36, 0.10);
|
||||
--bg: #f5f7fa;
|
||||
--surface: #ffffff;
|
||||
--surface-soft: #f8fafc;
|
||||
--border: #d8e0e8;
|
||||
--text: #1f2d3d;
|
||||
--muted: #6a7a8b;
|
||||
--primary: #2f6fec;
|
||||
--primary-soft: #eef4ff;
|
||||
--success: #1f8f5f;
|
||||
--success-soft: #ecfaf3;
|
||||
--warning: #c97a16;
|
||||
--warning-soft: #fff5e8;
|
||||
--danger: #cc4b3e;
|
||||
--danger-soft: #fff1ef;
|
||||
--shadow: 0 8px 24px rgba(31, 45, 61, 0.06);
|
||||
--radius: 14px;
|
||||
--radius-lg: 18px;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
|
||||
font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
color: var(--text);
|
||||
background:
|
||||
radial-gradient(circle at top left, #f7e2c8 0, transparent 30%),
|
||||
linear-gradient(180deg, #f6efe2 0%, #f4f1ea 45%, #efe7da 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
.shell {
|
||||
width: min(1180px, calc(100vw - 32px));
|
||||
margin: 0 auto;
|
||||
padding: 24px 0 40px;
|
||||
background: var(--bg);
|
||||
}
|
||||
a { color: inherit; text-decoration: none; }
|
||||
button, input, select, textarea { font: inherit; }
|
||||
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-bottom: 1px solid var(--border);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.topbar-inner {
|
||||
width: min(1680px, calc(100vw - 40px));
|
||||
margin: 0 auto;
|
||||
min-height: 64px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 18px 20px;
|
||||
border: 1px solid rgba(215, 201, 176, 0.7);
|
||||
background: rgba(255, 253, 248, 0.88);
|
||||
backdrop-filter: blur(12px);
|
||||
border-radius: 22px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.brand-title {
|
||||
margin: 0;
|
||||
font-size: 1.35rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.brand-note {
|
||||
margin: 6px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
.brand {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-width: 0;
|
||||
}
|
||||
.brand-mark {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 10px;
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 700;
|
||||
flex: none;
|
||||
}
|
||||
.brand h1 {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.brand p {
|
||||
margin: 2px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
.topnav {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.topnav a {
|
||||
padding: 9px 12px;
|
||||
border-radius: 10px;
|
||||
color: var(--muted);
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
.topnav a:hover {
|
||||
background: var(--surface-soft);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.nav-link,
|
||||
.button,
|
||||
button {
|
||||
.page {
|
||||
width: min(1680px, calc(100vw - 40px));
|
||||
margin: 24px auto 40px;
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 22px 24px;
|
||||
box-shadow: var(--shadow);
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
.eyebrow {
|
||||
display: inline-flex;
|
||||
width: fit-content;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 1.9rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.page-lead {
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 18px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.section-heading {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.section-title {
|
||||
margin: 0;
|
||||
font-size: 1.08rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.section-copy, .muted, .help-text {
|
||||
color: var(--muted);
|
||||
line-height: 1.6;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
.workspace-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 360px minmax(0, 1fr);
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
}
|
||||
.workspace-grid-wide {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.45fr) minmax(420px, 0.85fr);
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
}
|
||||
.stack { display: grid; gap: 14px; }
|
||||
|
||||
.metric-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
.metric-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 16px;
|
||||
}
|
||||
.metric-label {
|
||||
color: var(--muted);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.metric-value {
|
||||
margin-top: 8px;
|
||||
font-size: 1.55rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.metric-note {
|
||||
margin-top: 6px;
|
||||
color: var(--muted);
|
||||
font-size: 0.86rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.button-row, .badge-row, .meta-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
.button, button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
border-radius: 999px;
|
||||
min-height: 38px;
|
||||
padding: 0 14px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--text);
|
||||
padding: 10px 16px;
|
||||
font-size: 0.95rem;
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
|
||||
}
|
||||
|
||||
.button-primary,
|
||||
button {
|
||||
border-color: var(--accent);
|
||||
background: linear-gradient(135deg, #b9562f, #94452a);
|
||||
color: #fffaf4;
|
||||
box-shadow: 0 10px 22px rgba(165, 76, 43, 0.20);
|
||||
.button-primary, button {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.nav-link:hover,
|
||||
.button:hover,
|
||||
button:hover {
|
||||
text-decoration: none;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 12px 24px rgba(91, 63, 36, 0.12);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(241, 210, 184, 0.8);
|
||||
color: var(--accent);
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0 0 10px;
|
||||
font-size: clamp(2rem, 3vw, 3rem);
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.page-lead {
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
font-size: 1rem;
|
||||
max-width: 720px;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.panel,
|
||||
.card {
|
||||
background: rgba(255, 253, 248, 0.94);
|
||||
border: 1px solid rgba(215, 201, 176, 0.85);
|
||||
border-radius: 24px;
|
||||
padding: 20px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.card h2,
|
||||
.panel h2,
|
||||
.panel h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.meta-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin: 12px 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
color: var(--muted);
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.meta-badge {
|
||||
.pill, .meta-badge, .status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-strong);
|
||||
border: 1px solid rgba(215, 201, 176, 0.75);
|
||||
}
|
||||
|
||||
.layout-two-columns {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(320px, 420px) minmax(0, 1fr);
|
||||
gap: 20px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.stack {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
textarea,
|
||||
select,
|
||||
input[type="text"],
|
||||
input[type="file"] {
|
||||
width: 100%;
|
||||
border-radius: 16px;
|
||||
border: 1px solid var(--border);
|
||||
background: #fff;
|
||||
padding: 12px 14px;
|
||||
font: inherit;
|
||||
color: var(--text);
|
||||
background: var(--surface-soft);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
.pill-accent { color: var(--primary); background: var(--primary-soft); border-color: #d8e5ff; }
|
||||
.pill-success, .status-success { color: var(--success); background: var(--success-soft); border-color: #ccebdc; }
|
||||
.pill-signal { color: var(--warning); background: var(--warning-soft); border-color: #f3dcc0; }
|
||||
.pill-danger, .status-failed { color: var(--danger); background: var(--danger-soft); border-color: #f2d3cf; }
|
||||
|
||||
textarea { min-height: 150px; resize: vertical; }
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.help-text,
|
||||
.muted {
|
||||
color: var(--muted);
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.checkbox-list {
|
||||
.simple-list, .detail-list, .risk-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
padding: 10px 12px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid rgba(215, 201, 176, 0.85);
|
||||
}
|
||||
.detail-item, .risk-item {
|
||||
padding: 12px 14px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: var(--surface-soft);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.detail-item strong, .risk-item strong { display: block; margin-bottom: 4px; }
|
||||
|
||||
textarea, select, input[type="text"], input[type="file"] {
|
||||
width: 100%;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
background: var(--surface-strong);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.status-success { color: var(--success); }
|
||||
.status-failed { color: var(--danger); }
|
||||
|
||||
.notice {
|
||||
padding: 14px 16px;
|
||||
border-radius: 18px;
|
||||
border: 1px solid rgba(215, 201, 176, 0.85);
|
||||
background: rgba(255, 247, 234, 0.92);
|
||||
padding: 11px 12px;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.notice-error {
|
||||
border-color: rgba(141, 47, 47, 0.25);
|
||||
background: rgba(255, 238, 238, 0.95);
|
||||
color: var(--danger);
|
||||
textarea { min-height: 140px; resize: vertical; line-height: 1.6; }
|
||||
label { display: block; margin-bottom: 8px; font-weight: 600; }
|
||||
.checkbox-list { display: grid; gap: 8px; }
|
||||
.checkbox-item {
|
||||
display: grid;
|
||||
grid-template-columns: 20px minmax(0, 1fr);
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
background: var(--surface-soft);
|
||||
}
|
||||
|
||||
.kv-table {
|
||||
.table-wrap { overflow-x: auto; }
|
||||
.data-table, .kv-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.kv-table th,
|
||||
.kv-table td {
|
||||
.data-table th, .data-table td, .kv-table th, .kv-table td {
|
||||
padding: 12px 10px;
|
||||
border-bottom: 1px solid rgba(215, 201, 176, 0.6);
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #e9eef3;
|
||||
vertical-align: top;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.kv-table th {
|
||||
width: 150px;
|
||||
.data-table th, .kv-table th {
|
||||
color: var(--muted);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
background: var(--surface-soft);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.nowrap { white-space: nowrap; }
|
||||
.cell-min-220 { min-width: 220px; }
|
||||
.cell-min-280 { min-width: 280px; }
|
||||
|
||||
.detail-list {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
.notice {
|
||||
padding: 12px 14px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #d8e5ff;
|
||||
background: var(--primary-soft);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
padding: 14px 16px;
|
||||
border-radius: 18px;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(215, 201, 176, 0.75);
|
||||
.notice-error {
|
||||
border-color: #f2d3cf;
|
||||
background: var(--danger-soft);
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.detail-item strong {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
margin: 0;
|
||||
padding: 14px;
|
||||
border-radius: 18px;
|
||||
background: #2f261d;
|
||||
color: #fdf8f1;
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
border-radius: 10px;
|
||||
background: #1f2937;
|
||||
color: #f9fafb;
|
||||
overflow-x: auto;
|
||||
font-size: 0.84rem;
|
||||
line-height: 1.55;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
font-size: 0.92rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0 0 12px;
|
||||
font-size: 1.1rem;
|
||||
.link-card {
|
||||
display: block;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: var(--surface);
|
||||
}
|
||||
.link-card h3 { margin: 0 0 6px; font-size: 1rem; }
|
||||
.link-card p { margin: 0; color: var(--muted); font-size: 0.9rem; line-height: 1.55; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.layout-two-columns { grid-template-columns: 1fr; }
|
||||
.topbar { flex-direction: column; align-items: flex-start; }
|
||||
.nav-links { justify-content: flex-start; }
|
||||
@media (max-width: 1024px) {
|
||||
.metric-grid, .grid-2, .grid-3, .workspace-grid, .workspace-grid-wide { grid-template-columns: 1fr; }
|
||||
.topbar-inner { flex-direction: column; align-items: flex-start; padding: 12px 0; }
|
||||
.topnav { justify-content: flex-start; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<p class="brand-title">Universal Agent Demo Framework</p>
|
||||
<p class="brand-note">面向复试演示的可配置 AI Agent 单体系统</p>
|
||||
<header class="topbar">
|
||||
<div class="topbar-inner">
|
||||
<div class="brand">
|
||||
<div class="brand-mark">RA</div>
|
||||
<div>
|
||||
<h1>注册审核智能体平台</h1>
|
||||
<p>极简后台原型</p>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="nav-links">
|
||||
<a class="nav-link" href="{% url 'scenarios:index' %}">场景首页</a>
|
||||
<a class="nav-link" href="{% url 'documents:list' %}">文档中心</a>
|
||||
<a class="nav-link" href="{% url 'audit:list' %}">审计日志</a>
|
||||
<nav class="topnav">
|
||||
<a href="{% url 'scenarios:index' %}">总览</a>
|
||||
<a href="{% url 'documents:list' %}">文件中心</a>
|
||||
<a href="{% url 'chat:index' 'document_review' %}">审核工作台</a>
|
||||
<a href="{% url 'platform_ui:knowledge-base' %}">知识库</a>
|
||||
<a href="{% url 'platform_ui:mcp-center' %}">MCP</a>
|
||||
<a href="{% url 'platform_ui:skills' %}">Skills</a>
|
||||
<a href="{% url 'platform_ui:command-center' %}">工作台</a>
|
||||
<a href="{% url 'audit:list' %}">审计</a>
|
||||
</nav>
|
||||
</header>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="page">
|
||||
{% if messages %}
|
||||
<section class="stack" style="margin-bottom: 18px;">
|
||||
<div class="stack">
|
||||
{% for message in messages %}
|
||||
<div class="notice{% if message.tags == 'error' %} notice-error{% endif %}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ scenario.name|default:"Agent 对话" }}{% endblock %}
|
||||
{% block title %}{{ scenario.name|default:"Agent 审核工作台" }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if error %}
|
||||
@@ -8,23 +8,25 @@
|
||||
{% endif %}
|
||||
|
||||
{% if scenario %}
|
||||
<header class="page-header">
|
||||
<span class="eyebrow">Agent 对话</span>
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Workspace</span>
|
||||
<h1 class="page-title">{{ scenario.name }}</h1>
|
||||
<p class="page-lead">{{ scenario.description }}</p>
|
||||
<ul class="meta-list">
|
||||
<li class="meta-badge">角色:{{ scenario.agent.role }}</li>
|
||||
<li class="meta-badge">目标:{{ scenario.agent.goal }}</li>
|
||||
<li class="meta-badge">已入库文档:{{ document_count }}</li>
|
||||
<li class="meta-badge">输出类型:{{ scenario.output.type }}</li>
|
||||
</ul>
|
||||
</header>
|
||||
<p class="page-lead">左侧输入问题和选择文档,右侧查看执行结果。</p>
|
||||
<div class="badge-row">
|
||||
<span class="pill pill-accent">已入库文档:{{ document_count }}</span>
|
||||
<span class="pill">输出:{{ scenario.output.type }}</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="layout-two-columns">
|
||||
<section class="workspace-grid">
|
||||
<div class="stack">
|
||||
<article class="panel">
|
||||
<h2 class="section-title">提问面板</h2>
|
||||
<p class="muted">可以直接提问,也可以勾选部分已入库文档作为当前上下文范围。</p>
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">任务输入与资料范围</h2>
|
||||
<p class="section-copy">左侧突出受控输入:先描述审核目标,再限定本轮使用的文档范围。</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" class="stack">
|
||||
{% csrf_token %}
|
||||
<div>
|
||||
@@ -36,7 +38,7 @@
|
||||
</div>
|
||||
<div>
|
||||
{{ form.document_ids.label_tag }}
|
||||
<p class="help-text">不勾选时默认检索当前场景全部已入库文档。</p>
|
||||
<p class="help-text">不勾选时默认使用全部已入库文档。</p>
|
||||
<div class="checkbox-list">
|
||||
{% for checkbox in form.document_ids %}
|
||||
<label class="checkbox-item">
|
||||
@@ -51,34 +53,25 @@
|
||||
<p class="notice notice-error">{{ form.document_ids.errors|join:" " }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
<div class="button-row">
|
||||
<button type="submit">提交问题并执行 Agent</button>
|
||||
</div>
|
||||
</form>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">执行说明</h2>
|
||||
<h2 class="section-title">快捷示例</h2>
|
||||
<ul class="detail-list">
|
||||
<li class="detail-item">
|
||||
<strong>1. 场景配置</strong>
|
||||
系统会先读取当前 YAML 场景配置,确定角色、目标、工具和输出结构。
|
||||
</li>
|
||||
<li class="detail-item">
|
||||
<strong>2. RAG 与工具</strong>
|
||||
如果场景启用了知识库检索,系统会根据你的问题召回相关片段,并执行声明式工具。
|
||||
</li>
|
||||
<li class="detail-item">
|
||||
<strong>3. 结构化结果</strong>
|
||||
Agent Core 会优先解析 JSON 输出,解析失败时回退为稳定的展示结构。
|
||||
</li>
|
||||
<li class="detail-item">检查当前资料是否存在缺失项</li>
|
||||
<li class="detail-item">抽取说明书中的关键字段</li>
|
||||
<li class="detail-item">比较两份文档中的产品名称是否一致</li>
|
||||
</ul>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="stack">
|
||||
<article class="panel">
|
||||
<h2 class="section-title">回答总览</h2>
|
||||
<h2 class="section-title">结果</h2>
|
||||
{% if result %}
|
||||
<ul class="meta-list">
|
||||
<li class="meta-badge">模型:{{ result.model_name }}</li>
|
||||
@@ -89,41 +82,18 @@
|
||||
<strong>主回答</strong>
|
||||
<div>{{ result.answer|linebreaksbr }}</div>
|
||||
</div>
|
||||
{% if audit_log %}
|
||||
<p style="margin-top: 14px;">
|
||||
<a class="button" href="{% url 'audit:detail' audit_log.id %}">查看本次审计日志</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="notice">提交问题后,这里会展示 Agent 的主回答、模型信息和执行状态。</div>
|
||||
<div class="notice">提交任务后,这里会展示 Agent 的执行状态、主回答和过程摘要。</div>
|
||||
{% endif %}
|
||||
</article>
|
||||
|
||||
{% if result %}
|
||||
<article class="panel">
|
||||
<h2 class="section-title">结构化结果</h2>
|
||||
<table class="kv-table">
|
||||
<tbody>
|
||||
{% for key, value in result.structured_output.items %}
|
||||
<tr>
|
||||
<th>{{ key }}</th>
|
||||
<td>
|
||||
{% if key == "answer" or key == "summary" or key == "reply" %}
|
||||
{{ value|linebreaksbr }}
|
||||
{% else %}
|
||||
<pre class="code-block">{{ value }}</pre>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">引用片段</h2>
|
||||
<h2 class="section-title">证据引用与工具调用</h2>
|
||||
<p class="muted" style="margin-bottom: 14px;">引用片段与工具调用用于支撑结果可解释性。</p>
|
||||
{% if result.references %}
|
||||
<ul class="detail-list">
|
||||
<h3 style="margin-top: 0;">引用片段</h3>
|
||||
<ul class="detail-list" style="margin-bottom: 16px;">
|
||||
{% for reference in result.references %}
|
||||
<li class="detail-item">
|
||||
<strong>{{ reference.source }}</strong>
|
||||
@@ -132,13 +102,11 @@
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<div class="notice">当前回答没有引用知识库片段。</div>
|
||||
<div class="notice" style="margin-bottom: 16px;">当前回答没有引用知识库片段。</div>
|
||||
{% endif %}
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">工具调用</h2>
|
||||
{% if result.tool_calls %}
|
||||
<h3>工具调用</h3>
|
||||
<ul class="detail-list">
|
||||
{% for tool_call in result.tool_calls %}
|
||||
<li class="detail-item">
|
||||
@@ -164,6 +132,50 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="stack">
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">结构化审核结果</h2>
|
||||
<p class="section-copy">右侧结果舱用于展示缺失项、冲突项、字段池结果或风险清单。</p>
|
||||
</div>
|
||||
</div>
|
||||
{% if result %}
|
||||
<table class="kv-table">
|
||||
<caption style="text-align:left; padding-bottom:12px; color:var(--ink-soft);">结构化结果</caption>
|
||||
<tbody>
|
||||
{% for key, value in result.structured_output.items %}
|
||||
<tr>
|
||||
<th>{{ key }}</th>
|
||||
<td>
|
||||
{% if key == "answer" or key == "summary" or key == "reply" %}
|
||||
{{ value|linebreaksbr }}
|
||||
{% else %}
|
||||
<pre class="code-block">{{ value }}</pre>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="notice">执行任务后,这里会展示结构化审核结果和回填准备信息。</div>
|
||||
{% endif %}
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">引用与审计</h2>
|
||||
<ul class="detail-list">
|
||||
<li class="detail-item">可查看引用片段、工具调用和本次审计日志。</li>
|
||||
</ul>
|
||||
{% if audit_log %}
|
||||
<div class="button-row" style="margin-top: 16px;">
|
||||
<a class="button" href="{% url 'audit:detail' audit_log.id %}">查看本次审计日志</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,54 +1,108 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}文档中心{% endblock %}
|
||||
{% block title %}文件中心{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<header class="page-header">
|
||||
<span class="eyebrow">知识库资料</span>
|
||||
<h1 class="page-title">文档中心</h1>
|
||||
<p class="page-lead">上传题目材料后,可以在这里管理文件状态,并手动触发入库。</p>
|
||||
<p style="margin-top: 14px;"><a class="button button-primary" href="{% url 'documents:upload' %}">上传新文件</a></p>
|
||||
</header>
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Documents</span>
|
||||
<h1 class="page-title">文件中心</h1>
|
||||
<p class="page-lead">上传资料、查看状态、执行入库。页面只保留最常用操作。</p>
|
||||
<div class="button-row">
|
||||
<a class="button button-primary" href="{% url 'documents:upload' %}">上传文件</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<article class="panel">
|
||||
<table class="kv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>文件名</th>
|
||||
<th>场景</th>
|
||||
<th>类型</th>
|
||||
<th>大小</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for document in documents %}
|
||||
<section class="metric-grid">
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">文件总数</div>
|
||||
<div class="metric-value">{{ status_counts.total }}</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">已完成入库</div>
|
||||
<div class="metric-value">{{ status_counts.indexed }}</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">待入库</div>
|
||||
<div class="metric-value">{{ status_counts.uploaded }}</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">失败</div>
|
||||
<div class="metric-value">{{ status_counts.failed }}</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">异常提示</h2>
|
||||
<p class="section-copy">只保留需要处理的异常。</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="risk-list">
|
||||
{% for item in exception_items %}
|
||||
<li class="risk-item">
|
||||
<strong>{{ item.title }}</strong>
|
||||
<div class="muted">{{ item.detail }}</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">资料目录总览</h2>
|
||||
<p class="section-copy">页面下方保留真实文件记录与手动入库动作,保证演示原型仍基于当前系统能力运行。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ document.original_name }}</td>
|
||||
<td>{{ document.scenario_id }}</td>
|
||||
<td>{{ document.file_type }}</td>
|
||||
<td>{{ document.size }}</td>
|
||||
<td>{{ document.get_status_display_text }}</td>
|
||||
<td>
|
||||
{% if document.status != "indexed" %}
|
||||
<form action="{% url 'documents:index' document.id %}" method="post">
|
||||
{% csrf_token %}
|
||||
<button type="submit">执行入库</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<span class="status status-success">已可用于检索</span>
|
||||
{% endif %}
|
||||
{% if document.error_message %}
|
||||
<pre class="code-block" style="margin-top: 10px;">{{ document.error_message }}</pre>
|
||||
{% endif %}
|
||||
<p class="muted" style="margin-top: 10px;">上传时间:{{ document.created_at|date:"Y-m-d H:i" }}</p>
|
||||
</td>
|
||||
<th>文件名</th>
|
||||
<th>场景</th>
|
||||
<th>类型</th>
|
||||
<th>大小</th>
|
||||
<th>状态</th>
|
||||
<th>操作与备注</th>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="6">暂无文件,请先上传题目材料。</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</article>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for document in documents %}
|
||||
<tr>
|
||||
<td>{{ document.original_name }}</td>
|
||||
<td>{{ document.scenario_id }}</td>
|
||||
<td>{{ document.file_type }}</td>
|
||||
<td>{{ document.size }}</td>
|
||||
<td>
|
||||
<span class="pill {% if document.status == 'indexed' %}pill-success{% elif document.status == 'failed' %}pill-danger{% else %}pill-signal{% endif %}">
|
||||
{{ document.get_status_display_text }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="stack">
|
||||
{% if document.status != "indexed" %}
|
||||
<form action="{% url 'documents:index' document.id %}" method="post">
|
||||
{% csrf_token %}
|
||||
<button type="submit">执行入库</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<span class="status status-success">已可参与检索与审核</span>
|
||||
{% endif %}
|
||||
{% if document.error_message %}
|
||||
<pre class="code-block">{{ document.error_message }}</pre>
|
||||
{% endif %}
|
||||
<span class="muted">上传时间:{{ document.created_at|date:"Y-m-d H:i" }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="6">暂无文件,请先导入申报资料或法规原文。</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,38 +1,63 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}上传文件{% endblock %}
|
||||
{% block title %}导入资料{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<header class="page-header">
|
||||
<span class="eyebrow">文件上传</span>
|
||||
<h1 class="page-title">上传题目材料或知识库文档</h1>
|
||||
<p class="page-lead">支持 `.txt`、`.md`、`.pdf` 和 `.docx`。上传后可以在文档中心手动执行入库。</p>
|
||||
</header>
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Batch Intake</span>
|
||||
<h1 class="page-title">导入申报资料与法规依据文件</h1>
|
||||
<p class="page-lead">上传页采用“引导式导入”思路,强调业务资料与法规依据资料的边界、目录类文件的优先级,以及上传后进入解析和切片流程的下一步动作。</p>
|
||||
</section>
|
||||
|
||||
<article class="panel" style="max-width: 760px;">
|
||||
<form method="post" enctype="multipart/form-data" class="stack">
|
||||
{% csrf_token %}
|
||||
<div>
|
||||
{{ form.scenario_id.label_tag }}
|
||||
{{ form.scenario_id }}
|
||||
{% if form.scenario_id.errors %}
|
||||
<p class="notice notice-error">{{ form.scenario_id.errors|join:" " }}</p>
|
||||
<section class="layout-two-columns">
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">资料导入向导</h2>
|
||||
<p class="section-copy">当前支持 `.txt`、`.md`、`.pdf` 和 `.docx`。上传成功后即可回到文件中心执行解析与入库。</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" class="stack">
|
||||
{% csrf_token %}
|
||||
<div>
|
||||
{{ form.scenario_id.label_tag }}
|
||||
{{ form.scenario_id }}
|
||||
{% if form.scenario_id.errors %}
|
||||
<p class="notice notice-error">{{ form.scenario_id.errors|join:" " }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
{{ form.file.label_tag }}
|
||||
{{ form.file }}
|
||||
{% if form.file.errors %}
|
||||
<p class="notice notice-error">{{ form.file.errors|join:" " }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if form.errors %}
|
||||
<div class="notice notice-error">{{ form.errors }}</div>
|
||||
{% endif %}
|
||||
<div class="button-row">
|
||||
<button type="submit">确认导入</button>
|
||||
<a class="button" href="{% url 'documents:list' %}">返回文件中心</a>
|
||||
</div>
|
||||
</form>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">上传前检查清单</h2>
|
||||
<p class="section-copy">用业务语言告诉演示对象,平台并不是“随便上传,随便搜”。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ form.file.label_tag }}
|
||||
{{ form.file }}
|
||||
{% if form.file.errors %}
|
||||
<p class="notice notice-error">{{ form.file.errors|join:" " }}</p>
|
||||
{% endif %}
|
||||
<ul class="detail-list">
|
||||
{% for item in upload_checks %}
|
||||
<li class="detail-item">{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div class="notice" style="margin-top: 16px;">
|
||||
建议先导入监管信息目录、申请表、说明书、产品列表和公告附件包,再进入完整性检查场景。
|
||||
</div>
|
||||
{% if form.errors %}
|
||||
<div class="notice notice-error">{{ form.errors }}</div>
|
||||
{% endif %}
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<button type="submit">上传文件</button>
|
||||
<a class="button" href="{% url 'documents:list' %}">返回文件列表</a>
|
||||
</div>
|
||||
</form>
|
||||
</article>
|
||||
</article>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
58
templates/platform_ui/command_center.html
Normal file
58
templates/platform_ui/command_center.html
Normal file
@@ -0,0 +1,58 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}工作台大屏{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Workbench</span>
|
||||
<h1 class="page-title">工作台</h1>
|
||||
<p class="page-lead">用简洁视图展示当前批次状态、主要问题和下一步动作。</p>
|
||||
</section>
|
||||
|
||||
<section class="metric-grid">
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">当前阶段</div>
|
||||
<div class="metric-value">{{ batch.stage }}</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">整体完成度</div>
|
||||
<div class="metric-value">{{ batch.completion }}</div>
|
||||
</article>
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">高优先级问题</div>
|
||||
<div class="metric-value">03</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="grid-3">
|
||||
<article class="panel">
|
||||
<h2 class="section-title">流程</h2>
|
||||
<div class="stack" style="margin-top: 14px;">
|
||||
{% for step in workflow_overview %}
|
||||
<div class="detail-item"><strong>{{ step.title }}</strong><div class="muted">{{ step.detail }}</div></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">执行记录</h2>
|
||||
<div class="stack" style="margin-top: 14px;">
|
||||
{% for step in workflow_steps %}
|
||||
<div class="detail-item"><strong>{{ step.time }} {{ step.title }}</strong><div class="muted">{{ step.detail }}</div></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">待处理问题</h2>
|
||||
<ul class="risk-list">
|
||||
{% for risk in risk_board %}
|
||||
<li class="risk-item">
|
||||
<strong>{{ risk.title }}</strong>
|
||||
<div class="muted">{{ risk.action|default:risk.detail }}</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
{% endblock %}
|
||||
198
templates/platform_ui/knowledge_base.html
Normal file
198
templates/platform_ui/knowledge_base.html
Normal file
@@ -0,0 +1,198 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}知识库配置{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Knowledge Base</span>
|
||||
<h1 class="page-title">知识库配置</h1>
|
||||
<p class="page-lead">支持传统增删改查:新增知识源、编辑规则项、删除无效配置、筛选和搜索当前知识内容。</p>
|
||||
</section>
|
||||
|
||||
<section class="metric-grid">
|
||||
{% for item in knowledge_stats %}
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">{{ item.label }}</div>
|
||||
<div class="metric-value">{{ item.value }}</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">操作栏</h2>
|
||||
<p class="section-copy">把知识库做成传统后台,而不是只读展示页。</p>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<a class="button button-primary" href="#">新增知识源</a>
|
||||
<a class="button" href="#">新增规则项</a>
|
||||
<a class="button" href="#">批量删除</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-3">
|
||||
<div>
|
||||
<label for="knowledge-search">搜索</label>
|
||||
<input id="knowledge-search" type="text" value="体外诊断试剂" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="knowledge-type">知识类型</label>
|
||||
<select id="knowledge-type">
|
||||
{% for filter in knowledge_filters %}
|
||||
<option{% if filter.active %} selected{% endif %}>{{ filter.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="knowledge-status">状态</label>
|
||||
<select id="knowledge-status">
|
||||
<option selected>全部状态</option>
|
||||
<option>已生效</option>
|
||||
<option>待人工校订</option>
|
||||
<option>已入库</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="workspace-grid-wide">
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">知识源管理</h2>
|
||||
<p class="section-copy">传统 CRUD 列表,直接在表格里做查看、编辑、删除。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>编码</th>
|
||||
<th>名称</th>
|
||||
<th>类型</th>
|
||||
<th>范围</th>
|
||||
<th>状态</th>
|
||||
<th>负责人</th>
|
||||
<th>更新时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for source in knowledge_sources %}
|
||||
<tr>
|
||||
<td class="nowrap">{{ source.code }}</td>
|
||||
<td><div class="cell-min-280">{{ source.name }}</div></td>
|
||||
<td class="nowrap">{{ source.type }}</td>
|
||||
<td class="nowrap">{{ source.scope }}</td>
|
||||
<td>
|
||||
<span class="pill {% if source.status == '已生效' or source.status == '已入库' %}pill-success{% else %}pill-signal{% endif %}">
|
||||
{{ source.status }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="nowrap">{{ source.owner }}</td>
|
||||
<td class="nowrap">{{ source.updated_at }}</td>
|
||||
<td>
|
||||
<div class="button-row">
|
||||
<a class="button" href="#">查看</a>
|
||||
<a class="button" href="#">编辑</a>
|
||||
<a class="button" href="#">删除</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div class="stack">
|
||||
<article class="panel">
|
||||
<h2 class="section-title">{{ knowledge_form.title }}</h2>
|
||||
<div class="stack" style="margin-top: 14px;">
|
||||
{% for field in knowledge_form.fields %}
|
||||
<div>
|
||||
<label>{{ field.label }}</label>
|
||||
<input type="text" value="{{ field.value }}" />
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="button-row">
|
||||
<a class="button button-primary" href="#">保存知识源</a>
|
||||
<a class="button" href="#">重置</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">批量操作</h2>
|
||||
<ul class="detail-list">
|
||||
<li class="detail-item">支持批量启用 / 停用知识源</li>
|
||||
<li class="detail-item">支持批量重建切片</li>
|
||||
<li class="detail-item">支持批量删除过期规则</li>
|
||||
</ul>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid-2">
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">规则项管理</h2>
|
||||
<p class="section-copy">规则项也用传统表格管理,支持新增、编辑、删除。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>编码</th>
|
||||
<th>章节</th>
|
||||
<th>规则名称</th>
|
||||
<th>模板字段</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in rule_tree %}
|
||||
<tr>
|
||||
<td class="nowrap">{{ item.code }}</td>
|
||||
<td class="nowrap">{{ item.chapter }}</td>
|
||||
<td><div class="cell-min-220">{{ item.item }}</div></td>
|
||||
<td><div class="cell-min-220">{{ item.field }}</div></td>
|
||||
<td>
|
||||
<span class="pill {% if item.status == '启用' %}pill-success{% else %}pill-signal{% endif %}">
|
||||
{{ item.status }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="button-row">
|
||||
<a class="button" href="#">查看</a>
|
||||
<a class="button" href="#">编辑</a>
|
||||
<a class="button" href="#">删除</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">{{ rule_form.title }}</h2>
|
||||
<div class="stack" style="margin-top: 14px;">
|
||||
{% for field in rule_form.fields %}
|
||||
<div>
|
||||
<label>{{ field.label }}</label>
|
||||
<input type="text" value="{{ field.value }}" />
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="button-row">
|
||||
<a class="button button-primary" href="#">保存规则项</a>
|
||||
<a class="button" href="#">删除规则项</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
{% endblock %}
|
||||
67
templates/platform_ui/mcp_center.html
Normal file
67
templates/platform_ui/mcp_center.html
Normal file
@@ -0,0 +1,67 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}MCP 中心{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">MCP Connectors</span>
|
||||
<h1 class="page-title">外部 MCP 能力导入与协同接入中心</h1>
|
||||
<p class="page-lead">MCP 页面说明平台不是封闭工作台,它可以导入法规源、飞书通知、模板服务和企业数据源,但仍服务于注册审核这一条主线。</p>
|
||||
</section>
|
||||
|
||||
<section class="card-grid">
|
||||
{% for connector in mcp_connectors %}
|
||||
<article class="panel" style="padding: 20px;">
|
||||
<div class="badge-row">
|
||||
<span class="pill">{{ connector.kind }}</span>
|
||||
<span class="pill {% if connector.status == '已连接' %}pill-success{% elif connector.status == '待验证' %}pill-signal{% else %}pill-danger{% endif %}">{{ connector.status }}</span>
|
||||
</div>
|
||||
<h3 style="margin-top: 16px;">{{ connector.name }}</h3>
|
||||
<p class="muted">鉴权方式:{{ connector.auth }}</p>
|
||||
<p>最近同步:{{ connector.sync }}</p>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<section class="layout-two-columns">
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">导入向导</h2>
|
||||
<p class="section-copy">原型用一个简洁流程展示外部能力如何进入平台。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-strip">
|
||||
<article class="flow-node">
|
||||
<div class="flow-index">01</div>
|
||||
<h3>选择能力类型</h3>
|
||||
<p>法规源、协同工具、模板服务或企业主数据。</p>
|
||||
</article>
|
||||
<article class="flow-node">
|
||||
<div class="flow-index">02</div>
|
||||
<h3>完成鉴权</h3>
|
||||
<p>支持 API Key、App Token、文件轮询和 MCP Bridge。</p>
|
||||
</article>
|
||||
<article class="flow-node">
|
||||
<div class="flow-index">03</div>
|
||||
<h3>定义输入输出契约</h3>
|
||||
<p>明确它向 Agent 暴露什么能力、返回什么结构。</p>
|
||||
</article>
|
||||
<article class="flow-node">
|
||||
<div class="flow-index">04</div>
|
||||
<h3>纳入审核编排</h3>
|
||||
<p>由 Skill 或 Agent 任务按需调用,不在页面层散落实现。</p>
|
||||
</article>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<h2 class="section-title">本题重点接入建议</h2>
|
||||
<ul class="detail-list">
|
||||
<li class="detail-item"><strong>飞书任务通知</strong> 把高风险项和责任人通知闭环到群聊机器人或会话入口。</li>
|
||||
<li class="detail-item"><strong>Word 模板服务</strong> 用于报送版式输出与模板回填能力。</li>
|
||||
<li class="detail-item"><strong>法规规则源</strong> 为后续规则包更新和版本治理提供自动化入口。</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
{% endblock %}
|
||||
69
templates/platform_ui/skill_studio.html
Normal file
69
templates/platform_ui/skill_studio.html
Normal file
@@ -0,0 +1,69 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Skill Studio{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Skill Studio</span>
|
||||
<h1 class="page-title">Skill 编辑、编排与运行预览</h1>
|
||||
<p class="page-lead">Skill 页面用于解释 Agent 行为为何可控、可维护、可复用。通过角色说明、工具绑定、输入输出约束和测试运行预览,展示平台的治理能力。</p>
|
||||
</section>
|
||||
|
||||
<section class="workspace-grid">
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">Skill 列表</h2>
|
||||
<p class="section-copy">围绕注册审核主流程沉淀能力单元。</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="detail-list">
|
||||
{% for skill in skills %}
|
||||
<li class="detail-item">
|
||||
<span class="pill {% if skill.status == '已发布' %}pill-success{% elif skill.status == '发布中' %}pill-accent{% else %}pill-signal{% endif %}">{{ skill.status }}</span>
|
||||
<strong>{{ skill.name }}</strong>
|
||||
<div class="muted">触发场景:{{ skill.trigger }}</div>
|
||||
<div class="muted">工具链:{{ skill.tools }}</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">Skill 编辑区</h2>
|
||||
<p class="section-copy">展示角色、约束、工具和输出契约如何被治理。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stack">
|
||||
<div class="detail-item">
|
||||
<strong>角色说明</strong>
|
||||
当前 Skill 负责对照 NMPA 注册申报资料要求执行完整性检查,优先输出命中项、缺失项、风险等级和建议动作。
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<strong>工具绑定</strong>
|
||||
规则树匹配、RAG 引用、字段池比对、风险映射、审计写入。
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<strong>输入输出约束</strong>
|
||||
输入限定资料范围、任务类型与批次;输出必须包含结构化结果、证据引用和人工复核提示。
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">运行预览</h2>
|
||||
<p class="section-copy">通过最近一次测试运行说明 Skill 的稳定性。</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="detail-list">
|
||||
<li class="detail-item"><strong>最近测试结果</strong> 命中 3 个规则项,识别 1 个缺失项,生成 2 条建议动作。</li>
|
||||
<li class="detail-item"><strong>命中工具</strong> completeness_rule_match、rag_lookup、risk_mapper</li>
|
||||
<li class="detail-item"><strong>失败原因样例</strong> 当法规模板未配置时,页面会提示“法规规则未配置,无法执行完整性检查”。</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@@ -1,53 +1,82 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}场景首页{% endblock %}
|
||||
{% block title %}任务总览{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<header class="page-header">
|
||||
<span class="eyebrow">场景总览</span>
|
||||
<h1 class="page-title">用同一套底座快速切换不同业务 Agent</h1>
|
||||
<p class="page-lead">当前首页直接读取 YAML 场景配置。你可以从这里进入对话、上传资料,再用审计日志验证整条执行链路。</p>
|
||||
</header>
|
||||
<section class="page-header">
|
||||
<span class="eyebrow">Overview</span>
|
||||
<h1 class="page-title">批次总览</h1>
|
||||
<p class="page-lead">从这里直接进入知识库、文件中心、审核工作台和审计页。保留必要信息,不堆大段说明。</p>
|
||||
</section>
|
||||
|
||||
{% if scenario_issues %}
|
||||
<section class="panel" style="margin-bottom: 20px;">
|
||||
<h2 class="section-title">配置异常</h2>
|
||||
<p class="muted">以下 YAML 场景文件存在问题,系统已自动跳过,不会影响其它合法场景展示。</p>
|
||||
<ul class="detail-list">
|
||||
{% for issue in scenario_issues %}
|
||||
<li class="detail-item">
|
||||
<strong>{{ issue.file_name }}</strong>
|
||||
<div>{{ issue.message }}</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<section class="card-grid">
|
||||
{% for scenario in scenarios %}
|
||||
<article class="card">
|
||||
<h2>{{ scenario.name }}</h2>
|
||||
<p>{{ scenario.description }}</p>
|
||||
<ul class="meta-list">
|
||||
<li class="meta-badge">场景 ID:{{ scenario.id }}</li>
|
||||
<li class="meta-badge">输出:{{ scenario.output.type }}</li>
|
||||
<li class="meta-badge">RAG:{% if scenario.rag.enabled %}已启用{% else %}未启用{% endif %}</li>
|
||||
<li class="meta-badge">工具数:{{ scenario.tool_count }}</li>
|
||||
</ul>
|
||||
<p class="muted" style="margin-top: 14px;">适用题型:
|
||||
{% if scenario.applicable_questions %}
|
||||
{{ scenario.applicable_questions|join:"、" }}
|
||||
{% else %}
|
||||
暂未配置
|
||||
{% endif %}
|
||||
</p>
|
||||
<p style="margin-top: 16px;">
|
||||
<a class="button button-primary" href="{% url 'chat:index' scenario.id %}">进入对话</a>
|
||||
</p>
|
||||
<section class="metric-grid">
|
||||
{% for metric in hero_metrics %}
|
||||
<article class="metric-card">
|
||||
<div class="metric-label">{{ metric.label }}</div>
|
||||
<div class="metric-value">{{ metric.value }}</div>
|
||||
</article>
|
||||
{% empty %}
|
||||
<div class="notice">暂无可用场景,请检查 `configs/` 目录和 YAML 配置内容。</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<section class="grid-2">
|
||||
<a class="link-card" href="{% url 'platform_ui:knowledge-base' %}">
|
||||
<h3>知识库配置</h3>
|
||||
<p>查看规则树、知识源和切片策略。</p>
|
||||
</a>
|
||||
<a class="link-card" href="{% url 'documents:list' %}">
|
||||
<h3>文件中心</h3>
|
||||
<p>上传资料、执行入库、查看状态。</p>
|
||||
</a>
|
||||
<a class="link-card" href="{% url 'chat:index' 'document_review' %}">
|
||||
<h3>审核工作台</h3>
|
||||
<p>输入问题、选择文档、查看结果。</p>
|
||||
</a>
|
||||
<a class="link-card" href="{% url 'audit:list' %}">
|
||||
<h3>审计日志</h3>
|
||||
<p>查看每次执行的输入、输出和引用。</p>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2 class="section-title">已配置审核场景</h2>
|
||||
<p class="section-copy">保留现有场景列表,直接进入使用。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if scenario_issues %}
|
||||
<div class="stack" style="margin-bottom: 18px;">
|
||||
<div class="muted">配置异常</div>
|
||||
{% for issue in scenario_issues %}
|
||||
<article class="notice notice-error"><strong>{{ issue.file_name }}</strong>:{{ issue.message }}</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="grid-2">
|
||||
{% for scenario in scenarios %}
|
||||
<article class="panel">
|
||||
<div class="badge-row">
|
||||
<span class="pill">{{ scenario.id }}</span>
|
||||
<span class="pill {% if scenario.rag.enabled %}pill-success{% else %}pill-signal{% endif %}">RAG {% if scenario.rag.enabled %}开启{% else %}关闭{% endif %}</span>
|
||||
</div>
|
||||
<h3 style="margin: 14px 0 8px;">{{ scenario.name }}</h3>
|
||||
<p>{{ scenario.description }}</p>
|
||||
<p class="muted" style="margin-top: 10px;">适用题型:
|
||||
{% if scenario.applicable_questions %}
|
||||
{{ scenario.applicable_questions|join:"、" }}
|
||||
{% else %}
|
||||
暂未配置
|
||||
{% endif %}
|
||||
</p>
|
||||
<div class="button-row" style="margin-top: 16px;">
|
||||
<a class="button button-primary" href="{% url 'chat:index' scenario.id %}">进入审核工作台</a>
|
||||
</div>
|
||||
</article>
|
||||
{% empty %}
|
||||
<div class="notice">暂无可用场景,请检查 `configs/` 目录和 YAML 配置内容。</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user