fs-lawrisk/static/permit_browser.html

638 lines
20 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>许可事项浏览 - LawRisk</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: "Microsoft YaHei", "PingFang SC", -apple-system, BlinkMacSystemFont, sans-serif;
background: linear-gradient(135deg, #f7fafc 0%, #e2e8f0 100%);
min-height: 100vh;
color: #1f2937;
}
.page {
max-width: 1600px;
margin: 0 auto;
padding: 32px 20px 60px;
}
.header {
background: #fff;
border-radius: 18px;
padding: 28px;
box-shadow: 0 20px 60px rgba(79, 70, 229, 0.12);
margin-bottom: 24px;
position: relative;
}
.title {
text-align: center;
}
.title h1 {
font-size: 30px;
margin: 0;
color: #111827;
}
.title p {
margin: 6px 0 0;
color: #4b5563;
font-size: 15px;
}
.filter-section {
background: #fff;
border-radius: 18px;
padding: 28px;
box-shadow: 0 20px 60px rgba(79, 70, 229, 0.12);
margin-bottom: 24px;
}
.filter-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
margin-bottom: 24px;
}
.filter-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.filter-label {
font-size: 14px;
font-weight: 600;
color: #374151;
}
.filter-select, .filter-input {
width: 100%;
padding: 12px 16px;
border: 1px solid #d1d5db;
border-radius: 10px;
font-size: 14px;
background: #fff;
transition: all 0.2s;
}
.filter-select:focus, .filter-input:focus {
outline: none;
border-color: #6366f1;
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
}
.filter-select:disabled {
background: #f3f4f6;
color: #9ca3af;
cursor: not-allowed;
}
.filter-actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 10px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-primary {
background: #6366f1;
color: #fff;
}
.btn-primary:hover {
background: #4f46e5;
transform: translateY(-1px);
box-shadow: 0 10px 20px rgba(99, 102, 241, 0.3);
}
.btn-secondary {
background: #e5e7eb;
color: #374151;
}
.btn-secondary:hover {
background: #d1d5db;
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none !important;
}
.results-section {
background: #fff;
border-radius: 18px;
padding: 28px;
box-shadow: 0 20px 60px rgba(79, 70, 229, 0.12);
}
.results-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 2px solid #f3f4f6;
}
.results-count {
font-size: 16px;
color: #4b5563;
}
.results-count strong {
color: #6366f1;
font-size: 18px;
}
.pagination {
display: flex;
gap: 8px;
align-items: center;
}
.pagination-btn {
padding: 8px 16px;
border: 1px solid #d1d5db;
background: #fff;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
.pagination-btn:hover:not(:disabled) {
border-color: #6366f1;
color: #6366f1;
}
.pagination-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pagination-btn.active {
background: #6366f1;
color: #fff;
border-color: #6366f1;
}
.loading {
text-align: center;
padding: 60px 20px;
color: #6b7280;
}
.loading-spinner {
display: inline-block;
width: 40px;
height: 40px;
border: 4px solid #f3f4f6;
border-top-color: #6366f1;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin-bottom: 12px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.error-message {
background: #fee2e2;
border: 1px solid #fecaca;
color: #991b1b;
padding: 16px;
border-radius: 10px;
margin-bottom: 20px;
}
.permits-table {
width: 100%;
border-collapse: collapse;
}
.permits-table th {
background: #f9fafb;
padding: 14px 16px;
text-align: left;
font-weight: 600;
color: #374151;
border-bottom: 2px solid #e5e7eb;
font-size: 14px;
}
.permits-table td {
padding: 14px 16px;
border-bottom: 1px solid #f3f4f6;
font-size: 14px;
color: #4b5563;
}
.permits-table tr:hover {
background: #f9fafb;
}
.permit-name {
font-weight: 600;
color: #111827;
margin-bottom: 4px;
}
.permit-themes {
display: flex;
gap: 6px;
flex-wrap: wrap;
margin-top: 6px;
}
.theme-tag {
display: inline-block;
padding: 2px 8px;
background: #eef2ff;
color: #4c1d95;
border-radius: 4px;
font-size: 12px;
}
.empty-state {
text-align: center;
padding: 80px 20px;
color: #9ca3af;
}
.empty-icon {
font-size: 48px;
margin-bottom: 16px;
}
.action-buttons {
display: flex;
gap: 8px;
}
.btn-small {
padding: 6px 12px;
font-size: 13px;
}
.btn-outline {
background: #fff;
border: 1px solid #6366f1;
color: #6366f1;
}
.btn-outline:hover {
background: #6366f1;
color: #fff;
}
</style>
</head>
<body>
<div class="page">
<!-- 页面头部 -->
<div class="header">
<div class="title">
<h1>许可事项浏览</h1>
<p>使用筛选器快速定位所需许可事项</p>
</div>
</div>
<!-- 筛选器区域 -->
<div class="filter-section">
<div class="filter-grid">
<!-- 行政区域筛选 -->
<div class="filter-group">
<label class="filter-label">行政区域</label>
<select id="regionFilter" class="filter-select">
<option value="">全部区域</option>
</select>
</div>
<!-- 主题筛选 -->
<div class="filter-group">
<label class="filter-label">主题</label>
<select id="themeFilter" class="filter-select">
<option value="">全部主题</option>
</select>
</div>
<!-- 关联部门筛选 -->
<div class="filter-group">
<label class="filter-label">关联部门</label>
<select id="departmentFilter" class="filter-select">
<option value="">全部部门</option>
</select>
</div>
<!-- 搜索关键词 -->
<div class="filter-group">
<label class="filter-label">搜索关键词</label>
<input
type="text"
id="searchText"
class="filter-input"
placeholder="输入许可名称关键词..."
/>
</div>
</div>
<!-- 操作按钮 -->
<div class="filter-actions">
<button id="applyBtn" class="btn btn-primary">应用筛选</button>
<button id="resetBtn" class="btn btn-secondary">重置筛选</button>
</div>
</div>
<!-- 结果展示区域 -->
<div class="results-section">
<div class="results-header">
<div class="results-count">
共找到 <strong id="resultCount">0</strong> 个许可事项
</div>
<div class="pagination" id="pagination" style="display: none;">
<button id="prevPage" class="pagination-btn">上一页</button>
<span id="pageInfo">第 1 页 / 共 1 页</span>
<button id="nextPage" class="pagination-btn">下一页</button>
</div>
</div>
<div id="loading" class="loading" style="display: none;">
<div class="loading-spinner"></div>
<div>正在加载许可数据...</div>
</div>
<div id="errorMessage" class="error-message" style="display: none;"></div>
<div id="resultsTable">
<div class="empty-state">
<div class="empty-icon">📋</div>
<div>请选择筛选条件并点击"应用筛选"</div>
</div>
</div>
</div>
</div>
<script>
// 全局变量
let currentPage = 0;
let pageSize = 50;
let totalPages = 0;
let filterOptions = {
regions: [],
themes: [],
departments: []
};
// DOM元素
const regionSelect = document.getElementById('regionFilter');
const themeSelect = document.getElementById('themeFilter');
const departmentSelect = document.getElementById('departmentFilter');
const searchInput = document.getElementById('searchText');
const applyBtn = document.getElementById('applyBtn');
const resetBtn = document.getElementById('resetBtn');
const resultsTable = document.getElementById('resultsTable');
const resultCount = document.getElementById('resultCount');
const pagination = document.getElementById('pagination');
const pageInfo = document.getElementById('pageInfo');
const prevPageBtn = document.getElementById('prevPage');
const nextPageBtn = document.getElementById('nextPage');
const loading = document.getElementById('loading');
const errorMessage = document.getElementById('errorMessage');
// 页面初始化
document.addEventListener('DOMContentLoaded', function() {
loadFilterOptions();
bindEvents();
});
// 绑定事件
function bindEvents() {
// 应用筛选
applyBtn.addEventListener('click', function() {
currentPage = 0;
applyFilter();
});
// 重置筛选
resetBtn.addEventListener('click', resetFilter);
// 搜索框回车筛选
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
currentPage = 0;
applyFilter();
}
});
// 分页按钮
prevPageBtn.addEventListener('click', function() {
if (currentPage > 0) {
currentPage--;
applyFilter();
}
});
nextPageBtn.addEventListener('click', function() {
if (currentPage < totalPages - 1) {
currentPage++;
applyFilter();
}
});
}
// 加载筛选选项
async function loadFilterOptions() {
try {
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/permits/filter-options');
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '加载筛选选项失败');
}
filterOptions = data.data || {};
renderFilterOptions();
} catch (error) {
console.error('加载筛选选项失败:', error);
showError('加载筛选选项失败: ' + error.message);
}
}
// 渲染筛选选项
function renderFilterOptions() {
// 渲染区域选项
regionSelect.innerHTML = '<option value="">全部区域</option>';
filterOptions.regions.forEach(region => {
const option = document.createElement('option');
option.value = region.id || region;
option.textContent = region.name || region;
regionSelect.appendChild(option);
});
// 渲染主题选项
themeSelect.innerHTML = '<option value="">全部主题</option>';
filterOptions.themes.forEach(theme => {
const option = document.createElement('option');
option.value = theme.id;
option.textContent = theme.name;
themeSelect.appendChild(option);
});
// 渲染部门选项
departmentSelect.innerHTML = '<option value="">全部部门</option>';
filterOptions.departments.forEach(dept => {
const option = document.createElement('option');
option.value = dept.id;
option.textContent = `${dept.name} (${dept.code})`;
departmentSelect.appendChild(option);
});
}
// 应用筛选
async function applyFilter() {
const filters = {
region: regionSelect.value || null,
theme: themeSelect.value || null,
department: departmentSelect.value || null,
search_text: searchInput.value.trim() || null,
limit: pageSize,
offset: currentPage * pageSize
};
// 显示加载状态
showLoading(true);
hideError();
try {
const params = new URLSearchParams();
Object.keys(filters).forEach(key => {
if (filters[key]) {
params.append(key, filters[key]);
}
});
const response = await fetch(`/fs-ai-asistant/api/workflow/lawrisk/admin/permits/advanced-filter?${params}`);
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '筛选失败');
}
renderResults(data.data.permits || []);
updatePagination(data.data.pagination || {});
} catch (error) {
console.error('筛选失败:', error);
showError('筛选失败: ' + error.message);
renderResults([]);
updatePagination({});
} finally {
showLoading(false);
}
}
// 渲染筛选结果
function renderResults(permits) {
if (!permits || permits.length === 0) {
resultsTable.innerHTML = `
<div class="empty-state">
<div class="empty-icon">📂</div>
<div>未找到符合条件的许可事项</div>
</div>
`;
return;
}
let html = `
<table class="permits-table">
<thead>
<tr>
<th style="width: 40%;">许可事项</th>
<th style="width: 20%;">行政区域</th>
<th style="width: 20%;">主题</th>
<th style="width: 10%;">风险数</th>
<th style="width: 10%;">操作</th>
</tr>
</thead>
<tbody>
`;
permits.forEach(permit => {
const themesHtml = (permit.themes || [])
.map(t => `<span class="theme-tag">${escapeHtml(t.name)}</span>`)
.join('');
html += `
<tr>
<td>
<div class="permit-name">${escapeHtml(permit.name || '未知许可')}</div>
<div class="permit-themes">${themesHtml}</div>
</td>
<td>${escapeHtml(permit.region?.name || '-')}</td>
<td>${permit.theme_count || 0} 个主题</td>
<td>${permit.risk_count || 0}</td>
<td>
<div class="action-buttons">
<button class="btn btn-small btn-outline" onclick="viewPermit('${permit.id}')">
查看
</button>
</div>
</td>
</tr>
`;
});
html += `
</tbody>
</table>
`;
resultsTable.innerHTML = html;
}
// 更新分页信息
function updatePagination(pagination) {
if (!pagination || pagination.total === 0) {
pagination.style.display = 'none';
resultCount.textContent = '0';
return;
}
const total = pagination.total || 0;
totalPages = Math.ceil(total / pageSize);
resultCount.textContent = total;
pageInfo.textContent = `${currentPage + 1} 页 / 共 ${totalPages}`;
// 更新按钮状态
prevPageBtn.disabled = currentPage === 0;
nextPageBtn.disabled = currentPage >= totalPages - 1;
// 显示分页
pagination.style.display = 'flex';
}
// 重置筛选
function resetFilter() {
regionSelect.value = '';
themeSelect.value = '';
departmentSelect.value = '';
searchInput.value = '';
currentPage = 0;
renderResults([]);
updatePagination({});
resultCount.textContent = '0';
}
// 显示/隐藏加载状态
function showLoading(show) {
loading.style.display = show ? 'block' : 'none';
applyBtn.disabled = show;
}
// 显示错误信息
function showError(message) {
errorMessage.textContent = message;
errorMessage.style.display = 'block';
setTimeout(() => hideError(), 5000);
}
// 隐藏错误信息
function hideError() {
errorMessage.style.display = 'none';
}
// HTML转义
function escapeHtml(text) {
if (!text) return '';
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 查看许可详情
function viewPermit(permitId) {
// TODO: 实现许可详情查看功能
alert('查看许可详情功能待实现许可ID: ' + permitId);
}
</script>
</body>
</html>