fs-lawrisk/static/permit_filter.html

587 lines
19 KiB
HTML
Raw 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;
}
.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;
}
.empty-state {
text-align: center;
padding: 80px 20px;
color: #9ca3af;
}
.empty-icon {
font-size: 48px;
margin-bottom: 16px;
}
</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="municipalDept" class="filter-select">
<option value="">请选择市级单位</option>
</select>
</div>
<!-- 区级单位筛选 -->
<div class="filter-group">
<label class="filter-label">区级单位</label>
<select id="districtDept" class="filter-select" disabled>
<option value="">请先选择市级单位</option>
</select>
</div>
<!-- 行政区域筛选 -->
<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>
<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>
<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 municipalTree = [];
let regions = [];
// DOM元素
const municipalSelect = document.getElementById('municipalDept');
const districtSelect = document.getElementById('districtDept');
const regionSelect = document.getElementById('regionFilter');
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 loading = document.getElementById('loading');
const errorMessage = document.getElementById('errorMessage');
// 页面初始化
document.addEventListener('DOMContentLoaded', function() {
loadInitialData();
bindEvents();
});
// 绑定事件
function bindEvents() {
// 市级单位选择变更 - 联动加载区级单位
municipalSelect.addEventListener('change', handleMunicipalChange);
// 应用筛选
applyBtn.addEventListener('click', applyFilter);
// 重置筛选
resetBtn.addEventListener('click', resetFilter);
// 搜索框回车筛选
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
applyFilter();
}
});
}
// 加载初始数据
async function loadInitialData() {
try {
await Promise.all([
loadMunicipalDepartments(),
loadRegions()
]);
} catch (error) {
showError('加载初始数据失败: ' + error.message);
}
}
// 加载市级单位树
async function loadMunicipalDepartments() {
try {
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/service-departments/tree');
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '加载市级单位失败');
}
municipalTree = data.data.tree || [];
renderMunicipalOptions(municipalTree);
} catch (error) {
console.error('加载市级单位失败:', error);
throw error;
}
}
// 渲染市级单位选项
function renderMunicipalOptions(tree) {
municipalSelect.innerHTML = '<option value="">请选择市级单位</option>';
tree.forEach(dept => {
const option = document.createElement('option');
option.value = dept.id;
option.textContent = `${dept.name} (${dept.code})`;
municipalSelect.appendChild(option);
});
}
// 加载行政区域
async function loadRegions() {
try {
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/v2/regions');
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '加载区域失败');
}
regions = data.data.regions || [];
renderRegionOptions(regions);
} catch (error) {
console.error('加载区域失败:', error);
throw error;
}
}
// 渲染区域选项
function renderRegionOptions(regionList) {
regionSelect.innerHTML = '<option value="">全部区域</option>';
regionList.forEach(region => {
const option = document.createElement('option');
option.value = region.id || region;
option.textContent = region.name || region;
regionSelect.appendChild(option);
});
}
// 处理市级单位选择变更
async function handleMunicipalChange() {
const municipalId = municipalSelect.value;
// 重置区级单位
districtSelect.innerHTML = '<option value="">请选择区级单位</option>';
districtSelect.disabled = !municipalId;
if (!municipalId) {
return;
}
// 加载区级单位
try {
const response = await fetch(
`/fs-ai-asistant/api/workflow/lawrisk/admin/departments/children?parent_id=${municipalId}`
);
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '加载区级单位失败');
}
const children = data.data.units || [];
districtSelect.innerHTML = '<option value="">全部区级单位</option>';
children.forEach(dept => {
const option = document.createElement('option');
option.value = dept.id;
option.textContent = `${dept.name} (${dept.code})`;
districtSelect.appendChild(option);
});
} catch (error) {
console.error('加载区级单位失败:', error);
showError('加载区级单位失败: ' + error.message);
}
}
// 应用筛选
async function applyFilter() {
const filters = {
municipal_dept_id: municipalSelect.value || null,
district_dept_id: districtSelect.value || null,
region: regionSelect.value || null,
search_text: searchInput.value.trim() || null
};
// 显示加载状态
showLoading(true);
hideError();
try {
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/permits/filter', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(filters)
});
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '筛选失败');
}
renderResults(data.data.permits || []);
resultCount.textContent = data.data.pagination?.total || 0;
} catch (error) {
console.error('筛选失败:', error);
showError('筛选失败: ' + error.message);
renderResults([]);
resultCount.textContent = 0;
} 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>许可名称</th>
<th>所属单位</th>
<th>行政区域</th>
<th>上传时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
`;
permits.forEach(permit => {
html += `
<tr>
<td>${escapeHtml(permit.name || '未知许可')}</td>
<td>${escapeHtml(permit.department_name || '未知单位')}</td>
<td>${escapeHtml(permit.region_name || '未知区域')}</td>
<td>${formatDate(permit.created_at)}</td>
<td>
<button class="btn btn-primary" style="padding: 6px 12px; font-size: 13px;"
onclick="viewPermit('${permit.id}')">
查看详情
</button>
</td>
</tr>
`;
});
html += `
</tbody>
</table>
`;
resultsTable.innerHTML = html;
}
// 重置筛选
function resetFilter() {
municipalSelect.value = '';
districtSelect.value = '';
districtSelect.disabled = true;
districtSelect.innerHTML = '<option value="">请先选择市级单位</option>';
regionSelect.value = '';
searchInput.value = '';
renderResults([]);
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 formatDate(dateString) {
if (!dateString) return '-';
const date = new Date(dateString);
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
}
// 查看许可详情
function viewPermit(permitId) {
// TODO: 实现许可详情查看功能
alert('查看许可详情功能待实现许可ID: ' + permitId);
}
</script>
</body>
</html>