448 lines
15 KiB
HTML
448 lines
15 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"],
|
||
select {
|
||
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;
|
||
}
|
||
.risk-item-line + .risk-item-line {
|
||
margin-top: 0.35rem;
|
||
}
|
||
.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>
|
||
<label for="region-select" class="visually-hidden">地区</label>
|
||
<select id="region-select" multiple size="4" aria-label="限定地区,可多选(可留空)">
|
||
<option value="" selected>全部地区(默认)</option>
|
||
</select>
|
||
<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 regionSelectEl = document.getElementById("region-select");
|
||
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 params = new URLSearchParams();
|
||
params.set("query", query);
|
||
const selectedRegions = Array.from(regionSelectEl.selectedOptions)
|
||
.map((option) => option.value)
|
||
.filter((value) => value && value.trim());
|
||
if (selectedRegions.length) {
|
||
selectedRegions.forEach((value) => params.append("region", value));
|
||
}
|
||
|
||
const response = await fetch(`/fs-ai-asistant/api/workflow/lawrisk/v2?${params.toString()}`, {
|
||
method: "GET",
|
||
});
|
||
|
||
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 = "";
|
||
Array.from(regionSelectEl.options).forEach((option, idx) => {
|
||
option.selected = idx === 0;
|
||
});
|
||
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;
|
||
}
|
||
}
|
||
|
||
async function initRegionOptions() {
|
||
try {
|
||
const response = await fetch("/fs-ai-asistant/api/workflow/lawrisk/v2/regions");
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}`);
|
||
}
|
||
const payload = await response.json();
|
||
const regions = (payload && payload.data && Array.isArray(payload.data.regions))
|
||
? payload.data.regions
|
||
: [];
|
||
if (!regions.length) {
|
||
return;
|
||
}
|
||
const existing = new Set(Array.from(regionSelectEl.options).map((opt) => opt.value));
|
||
regions.forEach((region) => {
|
||
if (!region || !region.id) return;
|
||
if (existing.has(region.id)) return;
|
||
const option = document.createElement("option");
|
||
option.value = region.id;
|
||
option.textContent = region.name || region.id;
|
||
regionSelectEl.appendChild(option);
|
||
});
|
||
} catch (error) {
|
||
console.warn("加载地区列表失败:", error);
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
window.addEventListener("DOMContentLoaded", () => {
|
||
initRegionOptions();
|
||
});
|
||
|
||
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 addLine = (text) => {
|
||
if (!text) return;
|
||
const div = document.createElement("div");
|
||
div.className = "risk-item-line";
|
||
div.textContent = text;
|
||
li.appendChild(div);
|
||
};
|
||
addLine(risk.risk_content ? `${idx + 1}. ${risk.risk_content}` : "");
|
||
addLine(risk.legal_basis ? `法律依据:${risk.legal_basis}` : "");
|
||
addLine(risk.document_no ? `文号:${risk.document_no}` : "");
|
||
addLine(risk.summary ? `摘要:${risk.summary}` : "");
|
||
if (li.childNodes.length) {
|
||
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>
|