393 lines
13 KiB
HTML
393 lines
13 KiB
HTML
|
|
<!doctype html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="utf-8">
|
|||
|
|
<title>LawRisk V2 接口测试</title>
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|||
|
|
<style>
|
|||
|
|
:root {
|
|||
|
|
color-scheme: light dark;
|
|||
|
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|||
|
|
}
|
|||
|
|
body {
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0 1.5rem 2rem;
|
|||
|
|
background: #f7f7f7;
|
|||
|
|
}
|
|||
|
|
h1, h2 {
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
form {
|
|||
|
|
margin-top: 1.5rem;
|
|||
|
|
display: flex;
|
|||
|
|
gap: 0.75rem;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
input[type="text"] {
|
|||
|
|
flex: 1 1 320px;
|
|||
|
|
padding: 0.6rem 0.75rem;
|
|||
|
|
font-size: 1rem;
|
|||
|
|
border: 1px solid #bbb;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
}
|
|||
|
|
button {
|
|||
|
|
padding: 0.6rem 1.1rem;
|
|||
|
|
font-size: 1rem;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
border: none;
|
|||
|
|
cursor: pointer;
|
|||
|
|
background: #2563eb;
|
|||
|
|
color: #fff;
|
|||
|
|
}
|
|||
|
|
button[type="button"] {
|
|||
|
|
background: #6b7280;
|
|||
|
|
}
|
|||
|
|
#status {
|
|||
|
|
margin-top: 1rem;
|
|||
|
|
min-height: 1.5rem;
|
|||
|
|
color: #2563eb;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
.results {
|
|||
|
|
margin-top: 1.5rem;
|
|||
|
|
}
|
|||
|
|
.subject-block {
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 12px;
|
|||
|
|
padding: 1.25rem;
|
|||
|
|
margin-bottom: 1.25rem;
|
|||
|
|
box-shadow: 0 8px 18px rgba(12, 45, 90, 0.05);
|
|||
|
|
}
|
|||
|
|
.subject-meta {
|
|||
|
|
margin: 0.4rem 0 1rem;
|
|||
|
|
color: #4b5563;
|
|||
|
|
}
|
|||
|
|
table {
|
|||
|
|
width: 100%;
|
|||
|
|
border-collapse: collapse;
|
|||
|
|
margin-top: 0.75rem;
|
|||
|
|
}
|
|||
|
|
th, td {
|
|||
|
|
border: 1px solid #d1d5db;
|
|||
|
|
padding: 0.6rem 0.75rem;
|
|||
|
|
text-align: left;
|
|||
|
|
vertical-align: top;
|
|||
|
|
}
|
|||
|
|
th {
|
|||
|
|
background: #eff6ff;
|
|||
|
|
color: #1d4ed8;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
td ul {
|
|||
|
|
margin: 0;
|
|||
|
|
padding-left: 1.4rem;
|
|||
|
|
}
|
|||
|
|
td ul li {
|
|||
|
|
margin-bottom: 0.4rem;
|
|||
|
|
}
|
|||
|
|
.empty-hint {
|
|||
|
|
margin: 1rem 0 0;
|
|||
|
|
padding: 0.75rem;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
background: #fef3c7;
|
|||
|
|
color: #7c2d12;
|
|||
|
|
}
|
|||
|
|
.supplementary {
|
|||
|
|
margin-top: 1.5rem;
|
|||
|
|
}
|
|||
|
|
.supplementary h3 {
|
|||
|
|
margin-bottom: 0.5rem;
|
|||
|
|
}
|
|||
|
|
.supplementary ul {
|
|||
|
|
margin: 0;
|
|||
|
|
padding-left: 1.5rem;
|
|||
|
|
}
|
|||
|
|
.raw-json {
|
|||
|
|
margin-top: 1.25rem;
|
|||
|
|
background: #111827;
|
|||
|
|
color: #f3f4f6;
|
|||
|
|
padding: 1rem;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
overflow-x: auto;
|
|||
|
|
font-family: ui-monospace, SFMono-Regular, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|||
|
|
font-size: 0.9rem;
|
|||
|
|
display: none;
|
|||
|
|
}
|
|||
|
|
.toggle-raw {
|
|||
|
|
margin-top: 0.75rem;
|
|||
|
|
background: #10b981;
|
|||
|
|
}
|
|||
|
|
@media (max-width: 720px) {
|
|||
|
|
body {
|
|||
|
|
padding: 0 0.75rem 1.5rem;
|
|||
|
|
}
|
|||
|
|
table, th, td {
|
|||
|
|
font-size: 0.92rem;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<main>
|
|||
|
|
<h1>LawRisk V2 接口测试台</h1>
|
|||
|
|
<p>输入问题后调用 <code>/fs-ai-asistant/api/workflow/lawrisk/v2</code>,将返回的主题及许可详情以表格展示。</p>
|
|||
|
|
|
|||
|
|
<form id="query-form">
|
|||
|
|
<label for="query-input" class="visually-hidden">问题</label>
|
|||
|
|
<input id="query-input" type="text" placeholder="例如:开办电影院需要哪些许可事项" autocomplete="off" required>
|
|||
|
|
<button type="submit">查询</button>
|
|||
|
|
<button type="button" id="reset-btn">清空</button>
|
|||
|
|
</form>
|
|||
|
|
|
|||
|
|
<div id="status"></div>
|
|||
|
|
|
|||
|
|
<section class="results" id="results"></section>
|
|||
|
|
|
|||
|
|
<section class="supplementary" id="supplementary"></section>
|
|||
|
|
|
|||
|
|
<button type="button" class="toggle-raw" id="toggle-raw-btn" style="display:none;">显示原始 JSON</button>
|
|||
|
|
<pre class="raw-json" id="raw-json"></pre>
|
|||
|
|
</main>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
const formEl = document.getElementById("query-form");
|
|||
|
|
const queryInputEl = document.getElementById("query-input");
|
|||
|
|
const resetBtnEl = document.getElementById("reset-btn");
|
|||
|
|
const statusEl = document.getElementById("status");
|
|||
|
|
const resultsEl = document.getElementById("results");
|
|||
|
|
const supplementaryEl = document.getElementById("supplementary");
|
|||
|
|
const rawBtnEl = document.getElementById("toggle-raw-btn");
|
|||
|
|
const rawJsonEl = document.getElementById("raw-json");
|
|||
|
|
|
|||
|
|
let lastPayload = null;
|
|||
|
|
|
|||
|
|
formEl.addEventListener("submit", async (event) => {
|
|||
|
|
event.preventDefault();
|
|||
|
|
const query = queryInputEl.value.trim();
|
|||
|
|
if (!query) {
|
|||
|
|
statusEl.textContent = "请输入问题后再查询。";
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setLoading(true);
|
|||
|
|
clearResults();
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const response = await fetch("/fs-ai-asistant/api/workflow/lawrisk/v2", {
|
|||
|
|
method: "POST",
|
|||
|
|
headers: {
|
|||
|
|
"Content-Type": "application/json",
|
|||
|
|
},
|
|||
|
|
body: JSON.stringify({ query }),
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!response.ok) {
|
|||
|
|
throw new Error(`HTTP ${response.status}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const payload = await response.json();
|
|||
|
|
lastPayload = payload;
|
|||
|
|
renderPayload(payload);
|
|||
|
|
} catch (error) {
|
|||
|
|
statusEl.textContent = `请求失败:${error.message}`;
|
|||
|
|
statusEl.style.color = "#dc2626";
|
|||
|
|
} finally {
|
|||
|
|
setLoading(false);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
resetBtnEl.addEventListener("click", () => {
|
|||
|
|
queryInputEl.value = "";
|
|||
|
|
queryInputEl.focus();
|
|||
|
|
statusEl.textContent = "";
|
|||
|
|
statusEl.style.color = "#2563eb";
|
|||
|
|
clearResults();
|
|||
|
|
lastPayload = null;
|
|||
|
|
rawBtnEl.style.display = "none";
|
|||
|
|
rawJsonEl.style.display = "none";
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
rawBtnEl.addEventListener("click", () => {
|
|||
|
|
if (!lastPayload) return;
|
|||
|
|
const isHidden = rawJsonEl.style.display === "none";
|
|||
|
|
rawJsonEl.style.display = isHidden ? "block" : "none";
|
|||
|
|
rawBtnEl.textContent = isHidden ? "隐藏原始 JSON" : "显示原始 JSON";
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
function setLoading(isLoading) {
|
|||
|
|
if (isLoading) {
|
|||
|
|
statusEl.textContent = "查询中,请稍候…";
|
|||
|
|
statusEl.style.color = "#2563eb";
|
|||
|
|
formEl.querySelector("button[type='submit']").disabled = true;
|
|||
|
|
} else {
|
|||
|
|
formEl.querySelector("button[type='submit']").disabled = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function clearResults() {
|
|||
|
|
resultsEl.innerHTML = "";
|
|||
|
|
supplementaryEl.innerHTML = "";
|
|||
|
|
rawJsonEl.textContent = "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function renderPayload(payload) {
|
|||
|
|
if (!payload || typeof payload !== "object") {
|
|||
|
|
statusEl.textContent = "响应格式不正确。";
|
|||
|
|
statusEl.style.color = "#dc2626";
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!payload.success) {
|
|||
|
|
statusEl.textContent = payload.message ? `接口返回错误:${payload.message}` : "接口执行失败。";
|
|||
|
|
statusEl.style.color = "#dc2626";
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const data = payload.data || {};
|
|||
|
|
const subjects = Array.isArray(data.risk_subject) ? data.risk_subject : [];
|
|||
|
|
|
|||
|
|
statusEl.textContent = subjects.length
|
|||
|
|
? `已匹配 ${subjects.length} 个主题事项,共含 ${countPermits(subjects)} 条许可信息。`
|
|||
|
|
: "未检索到相关主题或许可事项。";
|
|||
|
|
statusEl.style.color = subjects.length ? "#065f46" : "#dc2626";
|
|||
|
|
|
|||
|
|
if (subjects.length) {
|
|||
|
|
subjects.forEach((subject, idx) => {
|
|||
|
|
resultsEl.appendChild(renderSubjectBlock(subject, idx));
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
renderSupplementary(data);
|
|||
|
|
rawBtnEl.style.display = "inline-block";
|
|||
|
|
rawBtnEl.textContent = "显示原始 JSON";
|
|||
|
|
rawJsonEl.style.display = "none";
|
|||
|
|
rawJsonEl.textContent = JSON.stringify(payload, null, 2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function renderSubjectBlock(subject, index) {
|
|||
|
|
const block = document.createElement("section");
|
|||
|
|
block.className = "subject-block";
|
|||
|
|
|
|||
|
|
const title = document.createElement("h2");
|
|||
|
|
title.textContent = subject.display_name || `主题 ${index + 1}`;
|
|||
|
|
block.appendChild(title);
|
|||
|
|
|
|||
|
|
const meta = document.createElement("p");
|
|||
|
|
meta.className = "subject-meta";
|
|||
|
|
const regionName = (subject.region && subject.region.name) || "未知地区";
|
|||
|
|
const themeName = (subject.theme && subject.theme.name) || "未知主题事项";
|
|||
|
|
meta.textContent = `地区:${regionName} | 主题事项:${themeName}`;
|
|||
|
|
block.appendChild(meta);
|
|||
|
|
|
|||
|
|
const permits = Array.isArray(subject.permits) ? subject.permits : [];
|
|||
|
|
if (!permits.length) {
|
|||
|
|
const emptyHint = document.createElement("div");
|
|||
|
|
emptyHint.className = "empty-hint";
|
|||
|
|
emptyHint.textContent = "该主题未关联具体许可事项。";
|
|||
|
|
block.appendChild(emptyHint);
|
|||
|
|
return block;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const table = document.createElement("table");
|
|||
|
|
const thead = document.createElement("thead");
|
|||
|
|
const headerRow = document.createElement("tr");
|
|||
|
|
[
|
|||
|
|
"许可事项",
|
|||
|
|
"事项属性",
|
|||
|
|
"子项概述",
|
|||
|
|
"经营范围",
|
|||
|
|
"风险提示",
|
|||
|
|
"责任联系方式",
|
|||
|
|
"管辖范围",
|
|||
|
|
].forEach((label) => {
|
|||
|
|
const th = document.createElement("th");
|
|||
|
|
th.textContent = label;
|
|||
|
|
headerRow.appendChild(th);
|
|||
|
|
});
|
|||
|
|
thead.appendChild(headerRow);
|
|||
|
|
table.appendChild(thead);
|
|||
|
|
|
|||
|
|
const tbody = document.createElement("tbody");
|
|||
|
|
|
|||
|
|
permits.forEach((permit) => {
|
|||
|
|
const tr = document.createElement("tr");
|
|||
|
|
|
|||
|
|
tr.appendChild(createTextCell(permit.name || "(未命名许可)"));
|
|||
|
|
tr.appendChild(createTextCell(permit.permit_status || "—"));
|
|||
|
|
tr.appendChild(createTextCell(permit.subitem_summary || "—"));
|
|||
|
|
|
|||
|
|
const scopes = Array.isArray(permit.business_scopes)
|
|||
|
|
? permit.business_scopes
|
|||
|
|
.map((scope) => typeof scope.description === "string" ? scope.description : "")
|
|||
|
|
.filter(Boolean)
|
|||
|
|
.join("、")
|
|||
|
|
: "";
|
|||
|
|
tr.appendChild(createTextCell(scopes || "—"));
|
|||
|
|
|
|||
|
|
tr.appendChild(createRiskCell(Array.isArray(permit.risks) ? permit.risks : []));
|
|||
|
|
tr.appendChild(createTextCell(permit.responsible_contact || "—"));
|
|||
|
|
tr.appendChild(createTextCell(permit.jurisdiction_scope || "—"));
|
|||
|
|
|
|||
|
|
tbody.appendChild(tr);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
table.appendChild(tbody);
|
|||
|
|
block.appendChild(table);
|
|||
|
|
return block;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function createTextCell(text) {
|
|||
|
|
const td = document.createElement("td");
|
|||
|
|
td.textContent = text || "—";
|
|||
|
|
return td;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function createRiskCell(risks) {
|
|||
|
|
const td = document.createElement("td");
|
|||
|
|
if (!risks.length) {
|
|||
|
|
td.textContent = "—";
|
|||
|
|
return td;
|
|||
|
|
}
|
|||
|
|
const list = document.createElement("ul");
|
|||
|
|
risks.forEach((risk, idx) => {
|
|||
|
|
const li = document.createElement("li");
|
|||
|
|
const parts = [];
|
|||
|
|
if (risk.risk_content) parts.push(`${idx + 1}. ${risk.risk_content}`);
|
|||
|
|
if (risk.legal_basis) parts.push(`法律依据:${risk.legal_basis}`);
|
|||
|
|
if (risk.document_no) parts.push(`文号:${risk.document_no}`);
|
|||
|
|
if (risk.summary) parts.push(`摘要:${risk.summary}`);
|
|||
|
|
li.textContent = parts.join(" | ");
|
|||
|
|
list.appendChild(li);
|
|||
|
|
});
|
|||
|
|
td.appendChild(list);
|
|||
|
|
return td;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function renderSupplementary(data) {
|
|||
|
|
const recQuestions = Array.isArray(data.questionExtend) ? data.questionExtend : [];
|
|||
|
|
if (!recQuestions.length) return;
|
|||
|
|
|
|||
|
|
const title = document.createElement("h3");
|
|||
|
|
title.textContent = "推荐追问";
|
|||
|
|
supplementaryEl.appendChild(title);
|
|||
|
|
|
|||
|
|
const list = document.createElement("ul");
|
|||
|
|
recQuestions.forEach((question) => {
|
|||
|
|
const li = document.createElement("li");
|
|||
|
|
li.textContent = question;
|
|||
|
|
list.appendChild(li);
|
|||
|
|
});
|
|||
|
|
supplementaryEl.appendChild(list);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function countPermits(subjects) {
|
|||
|
|
return subjects.reduce((sum, subject) => {
|
|||
|
|
const permits = Array.isArray(subject.permits) ? subject.permits.length : 0;
|
|||
|
|
return sum + permits;
|
|||
|
|
}, 0);
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|