feat: 收口知识库治理入口与配置口径

This commit is contained in:
2026-06-04 00:54:51 +08:00
parent 77d9420d43
commit cac9a4aaeb
4 changed files with 292 additions and 119 deletions

View File

@@ -109,6 +109,88 @@ def get_platform_demo_context():
{"label": "业务资料切片", "value": "342"},
{"label": "最近人工校订", "value": "2 次"},
]
governance_sections = [
{"title": "法规规则包", "desc": "维护章节规则、要求项与模板字段映射。"},
{"title": "RAG 文档源", "desc": "统一管理法规资料、业务资料和模板来源。"},
{"title": "RAG 切片", "desc": "查看切片摘要、召回状态和证据命中历史。"},
{"title": "字段 Schema", "desc": "维护强一致字段、回填字段和来源优先级。"},
{"title": "责任人映射", "desc": "按章节和风险类型维护飞书责任人实体。"},
{"title": "飞书通知配置", "desc": "固定支持 task_completed / task_failed 两类通知。"},
]
rag_chunks = [
{
"chunk_id": "chunk-001",
"document_name": "资料要求说明",
"chapter": "CH1",
"summary": "CH1.11.5 沟通记录需保留可追溯留痕。",
"status": "已启用",
},
{
"chunk_id": "chunk-002",
"document_name": "批准证明文件格式要求",
"chapter": "CH1",
"summary": "注册证输出模板需满足固定版式字段映射。",
"status": "待重建",
},
]
field_schemas = [
{
"field_code": "product_name",
"field_name": "产品名称",
"field_type": "string",
"fillable": "",
"strict_consistency": "",
"status": "启用",
},
{
"field_code": "storage_condition",
"field_name": "储存条件",
"field_type": "string",
"fillable": "",
"strict_consistency": "",
"status": "待校订",
},
]
owner_mappings = [
{
"owner_role": "注册资料负责人",
"owner_name": "张三",
"department": "注册事务部",
"chapter_scope": "CH1",
"risk_scope": "字段冲突 / 缺失项",
"feishu_user_id": "ou_demo_1",
"feishu_open_id": "on_demo_1",
"feishu_name": "张三",
"notify_enabled": "",
},
{
"owner_role": "注册申报负责人",
"owner_name": "李四",
"department": "临床注册组",
"chapter_scope": "CH2-CH6",
"risk_scope": "完整性风险 / 导出阻断",
"feishu_user_id": "ou_demo_2",
"feishu_open_id": "on_demo_2",
"feishu_name": "李四",
"notify_enabled": "",
},
]
feishu_configs = [
{
"config_name": "注册审核完成通知",
"notify_reason": "task_completed",
"channel": "群机器人",
"message_template": "审核完成摘要 + @处理人",
"status": "启用",
},
{
"config_name": "注册审核异常通知",
"notify_reason": "task_failed",
"channel": "群机器人",
"message_template": "异常摘要 + @处理人",
"status": "启用",
},
]
mcp_connectors = [
{"name": "飞书任务通知", "kind": "协同办公", "auth": "App Token", "status": "已连接", "sync": "5 分钟前"},
{"name": "法规规则源导入", "kind": "法规服务", "auth": "文件轮询", "status": "待验证", "sync": "今天 08:50"},
@@ -333,6 +415,11 @@ def get_platform_demo_context():
"knowledge_sources": knowledge_sources,
"rule_tree": rule_tree,
"knowledge_stats": knowledge_stats,
"governance_sections": governance_sections,
"rag_chunks": rag_chunks,
"field_schemas": field_schemas,
"owner_mappings": owner_mappings,
"feishu_configs": feishu_configs,
"knowledge_filters": knowledge_filters,
"knowledge_form": knowledge_form,
"rule_form": rule_form,

View File

@@ -1,12 +1,12 @@
{% extends "base.html" %}
{% block title %}知识库配置{% endblock %}
{% 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>
<span class="eyebrow">Knowledge Governance</span>
<h1 class="page-title">知识库</h1>
<p class="page-lead">统一承载法规资料、业务资料、RAG 治理、字段标准、责任人映射和飞书通知配置</p>
</section>
<section class="metric-grid">
@@ -18,49 +18,54 @@
{% endfor %}
</section>
<section class="grid-3">
{% for section in governance_sections %}
<article class="panel">
<h2 class="section-title">{{ section.title }}</h2>
<p class="section-copy">{{ section.desc }}</p>
</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>
<h2 class="section-title">法规规则包</h2>
<p class="section-copy">按章-条-要求项-模板字段维护规则包,并向审核节点输出结构化依据</p>
</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>
<div class="table-wrap">
<table class="data-table">
<thead>
<tr>
<th>编码</th>
<th>章节</th>
<th>规则名称</th>
<th>模板字段</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for item in rule_tree %}
<tr>
<td>{{ item.code }}</td>
<td>{{ item.chapter }}</td>
<td>{{ item.item }}</td>
<td>{{ item.field }}</td>
<td>{{ item.status }}</td>
</tr>
{% endfor %}
</select>
</div>
<div>
<label for="knowledge-status">状态</label>
<select id="knowledge-status">
<option selected>全部状态</option>
<option>已生效</option>
<option>待人工校订</option>
<option>已入库</option>
</select>
</div>
</tbody>
</table>
</div>
</section>
<section class="workspace-grid-wide">
<section class="grid-2">
<article class="panel">
<div class="section-heading">
<div>
<h2 class="section-title">知识源管理</h2>
<p class="section-copy">传统 CRUD 列表,直接在表格里做查看、编辑、删除</p>
<h2 class="section-title">RAG 文档源</h2>
<p class="section-copy">支持法规、模板与业务资料分层管理</p>
</div>
</div>
<div class="table-wrap">
@@ -72,32 +77,16 @@
<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>
<td>{{ source.code }}</td>
<td>{{ source.name }}</td>
<td>{{ source.type }}</td>
<td>{{ source.scope }}</td>
<td>{{ source.status }}</td>
</tr>
{% endfor %}
</tbody>
@@ -105,73 +94,69 @@
</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>
<h2 class="section-title">RAG 切片</h2>
<p class="section-copy">展示切片摘要、章节与召回状态</p>
</div>
</div>
<div class="table-wrap">
<table class="data-table">
<thead>
<tr>
<th>编码</th>
<th>切片 ID</th>
<th>文档</th>
<th>章节</th>
<th>规则名称</th>
<th>模板字段</th>
<th>摘要</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for item in rule_tree %}
{% for chunk in rag_chunks %}
<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>
<td>{{ chunk.chunk_id }}</td>
<td>{{ chunk.document_name }}</td>
<td>{{ chunk.chapter }}</td>
<td>{{ chunk.summary }}</td>
<td>{{ chunk.status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</article>
</section>
<section class="grid-2">
<article class="panel">
<div class="section-heading">
<div>
<h2 class="section-title">字段 Schema</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 field in field_schemas %}
<tr>
<td>{{ field.field_code }}</td>
<td>{{ field.field_name }}</td>
<td>{{ field.field_type }}</td>
<td>{{ field.fillable }}</td>
<td>{{ field.strict_consistency }}</td>
<td>{{ field.status }}</td>
</tr>
{% endfor %}
</tbody>
@@ -180,19 +165,77 @@
</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 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>owner_role</th>
<th>owner_name</th>
<th>department</th>
<th>chapter_scope</th>
<th>risk_scope</th>
<th>feishu_user_id</th>
<th>feishu_open_id</th>
<th>feishu_name</th>
<th>notify_enabled</th>
</tr>
</thead>
<tbody>
{% for item in owner_mappings %}
<tr>
<td>{{ item.owner_role }}</td>
<td>{{ item.owner_name }}</td>
<td>{{ item.department }}</td>
<td>{{ item.chapter_scope }}</td>
<td>{{ item.risk_scope }}</td>
<td>{{ item.feishu_user_id }}</td>
<td>{{ item.feishu_open_id }}</td>
<td>{{ item.feishu_name }}</td>
<td>{{ item.notify_enabled }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</article>
</section>
<section class="panel">
<div class="section-heading">
<div>
<h2 class="section-title">飞书通知配置</h2>
<p class="section-copy">V1 Demo 固定支持 `task_completed` 与 `task_failed` 两类通知。</p>
</div>
</div>
<div class="table-wrap">
<table class="data-table">
<thead>
<tr>
<th>配置名称</th>
<th>notify_reason</th>
<th>渠道</th>
<th>消息模板</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for item in feishu_configs %}
<tr>
<td>{{ item.config_name }}</td>
<td>{{ item.notify_reason }}</td>
<td>{{ item.channel }}</td>
<td>{{ item.message_template }}</td>
<td>{{ item.status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
{% endblock %}

32
tests/test_platform_ui.py Normal file
View File

@@ -0,0 +1,32 @@
from django.urls import reverse
def test_knowledge_base_page_shows_governance_sections(client):
response = client.get(reverse("platform_ui:knowledge-base"))
content = response.content.decode("utf-8")
assert response.status_code == 200
assert "法规规则包" in content
assert "RAG 文档源" in content
assert "RAG 切片" in content
assert "字段 Schema" in content
assert "责任人映射" in content
assert "飞书通知配置" in content
def test_knowledge_base_page_shows_owner_mapping_fields_and_notify_reasons(client):
response = client.get(reverse("platform_ui:knowledge-base"))
content = response.content.decode("utf-8")
assert response.status_code == 200
assert "owner_role" in content
assert "owner_name" in content
assert "department" in content
assert "chapter_scope" in content
assert "risk_scope" in content
assert "feishu_user_id" in content
assert "feishu_open_id" in content
assert "feishu_name" in content
assert "notify_enabled" in content
assert "task_completed" in content
assert "task_failed" in content

View File

@@ -127,3 +127,14 @@ audit:
assert "有效场景" in content
assert "配置异常" in content
assert "invalid.yaml" in content
def test_home_page_uses_four_top_level_product_entries(client):
response = client.get("/")
content = response.content.decode("utf-8")
assert response.status_code == 200
assert "审核智能体" in content
assert "资料包" in content
assert "知识库" in content
assert "处理历史" in content