feat: 增强许可详情页面显示完整信息

在许可详情弹窗中添加了完整的许可信息展示区域,包括以下7个字段:
1. 许可情况 - 显示许可状态
2. 许可(备案)事项子项 - 显示子项详情
3. 行政区域 - 显示所属区域
4. 负责部门 - 显示负责部门和联系方式
5. 权限划分 - 显示权限范围
6. 经营范围 - 显示业务范围(跨列显示)

所有字段均使用清晰标签、两列网格布局,经营范围字段跨列显示适合长文本。
信息层次清晰:基本信息 → 许可信息 → 风险信息。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Codex Agent 2025-11-20 09:47:20 +08:00
parent ec44bec90a
commit 9aa6fabfb1
2 changed files with 416 additions and 90 deletions

View File

@ -1935,20 +1935,13 @@ def list_service_departments(region_id: Optional[str] = None) -> List[Dict[str,
cur = conn.cursor()
if region_id:
# Get departments associated with the specific region through permit_sources
# Get departments associated with the specific region through service_departments.region_id
# This includes both direct region match and hierarchical matching (child regions)
sql = _SERVICE_DEPARTMENT_SELECT + """
WHERE sd.id IN (
SELECT DISTINCT ps.uploader_department_id
FROM permit_sources ps
WHERE ps.region_id = %s AND ps.uploader_department_id IS NOT NULL
UNION
SELECT DISTINCT ps.bound_department_id
FROM permit_sources ps
WHERE ps.region_id = %s AND ps.bound_department_id IS NOT NULL
)
WHERE sd.region_id = %s
ORDER BY sd.created_at ASC
"""
cur.execute(sql, (region_id, region_id))
cur.execute(sql, (region_id,))
else:
# Get all departments
cur.execute(_SERVICE_DEPARTMENT_SELECT + " ORDER BY sd.created_at ASC")
@ -5563,15 +5556,18 @@ def filter_permits_advanced(
WHERE 1=1
"""
count_params = []
if region_id:
count_sql += " AND rtp.region_id = %s"
count_params.append(region_id)
if theme_id:
count_sql += " AND rtp.theme_id = %s"
count_params.append(theme_id)
if department_id:
count_sql += " AND (ps.uploader_department_id = %s OR ps.bound_department_id = %s)"
count_params.extend([department_id, department_id])
if regions:
placeholders = ', '.join(['%s'] * len(regions))
count_sql += f" AND rtp.region_id IN ({placeholders})"
count_params.extend(regions)
if themes:
placeholders = ', '.join(['%s'] * len(themes))
count_sql += f" AND rtp.theme_id IN ({placeholders})"
count_params.extend(themes)
if departments:
placeholders = ', '.join(['%s'] * len(departments))
count_sql += f" AND (ps.uploader_department_id IN ({placeholders}) OR ps.bound_department_id IN ({placeholders}))"
count_params.extend(departments * 2)
if search_text:
count_sql += " AND LOWER(p.name) LIKE LOWER(%s)"
count_params.append(f"%{search_text}%")

View File

@ -2256,14 +2256,19 @@
<p style="color: #666; margin-bottom: 20px;">使用筛选器快速定位许可事项,支持多维度筛选、分页浏览、风险统计等功能。</p>
<!-- 筛选器区域 -->
<div style="background: #f8f9fa; border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; margin-bottom: 20px;">
<div style="background: #f8f9fa; border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; margin-bottom: 20px; position: relative;">
<!-- 筛选器加载状态 -->
<div id="filterOptionsLoading" style="display: none; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.9); border-radius: 8px; z-index: 100; display: flex; flex-direction: column; align-items: center; justify-content: center;">
<div style="width: 50px; height: 50px; border: 4px solid #e0e0e0; border-top-color: #2c5282; border-radius: 50%; animation: spin 0.8s linear infinite; margin-bottom: 16px;"></div>
<div style="font-size: 14px; color: #666; font-weight: 600;">正在加载筛选选项...</div>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-bottom: 16px;">
<!-- 行政区域筛选 -->
<div style="display: flex; flex-direction: column; gap: 8px;">
<label style="font-size: 13px; font-weight: 600; color: #555;">行政区域 (可多选)</label>
<div style="position: relative;">
<div id="filterRegion" class="multi-select-dropdown" style="padding: 10px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; background: white; cursor: pointer;" onclick="toggleMultiSelect('regionOptions')">
<span id="regionSelectedText">请选择区域...</span>
<span id="regionSelectedText">全部区域</span>
<span style="float: right; color: #999;"></span>
</div>
<div id="regionOptions" class="multi-select-options" style="position: absolute; top: 100%; left: 0; right: 0; background: white; border: 1px solid #ddd; border-radius: 6px; margin-top: 4px; max-height: 200px; overflow-y: auto; z-index: 1000; display: none; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
@ -2283,7 +2288,7 @@
<label style="font-size: 13px; font-weight: 600; color: #555;">主题 (可多选)</label>
<div style="position: relative;">
<div id="filterTheme" class="multi-select-dropdown" style="padding: 10px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; background: white; cursor: pointer;" onclick="toggleMultiSelect('themeOptions')">
<span id="themeSelectedText">请选择主题...</span>
<span id="themeSelectedText">全部主题</span>
<span style="float: right; color: #999;"></span>
</div>
<div id="themeOptions" class="multi-select-options" style="position: absolute; top: 100%; left: 0; right: 0; background: white; border: 1px solid #ddd; border-radius: 6px; margin-top: 4px; max-height: 200px; overflow-y: auto; z-index: 1000; display: none; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
@ -2303,7 +2308,7 @@
<label style="font-size: 13px; font-weight: 600; color: #555;">关联部门 (可多选)</label>
<div style="position: relative;">
<div id="filterDepartment" class="multi-select-dropdown" style="padding: 10px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; background: white; cursor: pointer;" onclick="toggleMultiSelect('departmentOptions')">
<span id="departmentSelectedText">请选择部门...</span>
<span id="departmentSelectedText">全部部门</span>
<span style="float: right; color: #999;"></span>
</div>
<div id="departmentOptions" class="multi-select-options" style="position: absolute; top: 100%; left: 0; right: 0; background: white; border: 1px solid #ddd; border-radius: 6px; margin-top: 4px; max-height: 200px; overflow-y: auto; z-index: 1000; display: none; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
@ -5736,6 +5741,9 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
// ============== 许可事项筛选器相关函数 ==============
// 区域-部门映射关系缓存
let regionDepartmentMap = {};
let permitFilterOptions = {
regions: [],
themes: [],
@ -5748,6 +5756,12 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
// 加载筛选选项
async function loadPermitFilterOptions() {
// 显示加载状态
const loadingElement = document.getElementById('filterOptionsLoading');
if (loadingElement) {
loadingElement.style.display = 'flex';
}
try {
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/permits/filter-options');
const data = await response.json();
@ -5760,11 +5774,21 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
renderPermitFilterOptions();
} catch (error) {
console.error('加载筛选选项失败:', error);
// 可以在这里显示错误提示
alert('加载筛选选项失败: ' + error.message);
} finally {
// 隐藏加载状态
if (loadingElement) {
loadingElement.style.display = 'none';
}
}
}
// 渲染筛选选项
function renderPermitFilterOptions() {
// 构建区域-部门映射关系
buildRegionDepartmentMapping();
// 渲染区域选项
const regionOptionsList = document.getElementById('regionOptionsList');
if (regionOptionsList) {
@ -5799,21 +5823,83 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
});
}
// 渲染部门选项
const departmentOptionsList = document.getElementById('departmentOptionsList');
if (departmentOptionsList) {
departmentOptionsList.innerHTML = '';
permitFilterOptions.departments.forEach(dept => {
const div = document.createElement('div');
div.style.padding = '6px 12px';
div.innerHTML = `
<label style="display: flex; align-items: center; cursor: pointer;">
<input type="checkbox" name="departmentFilter" value="${dept.id}" onchange="updateSelectedText('department')" style="margin-right: 8px;">
<span>${dept.name} (${dept.code})</span>
</label>
`;
departmentOptionsList.appendChild(div);
// 渲染部门选项(显示所有部门)
renderDepartmentOptions(permitFilterOptions.departments);
// 自动加载权限范围内的许可事项
// 注意不要在渲染过程中直接调用需要延迟执行确保DOM更新完成
setTimeout(() => {
loadAllVisiblePermits();
}, 100);
}
// 构建区域-部门映射关系
function buildRegionDepartmentMapping() {
// 初始化映射对象
regionDepartmentMap = {};
// 获取所有部门数据
const allDepartments = permitFilterOptions.departments || [];
// 为每个区域建立部门映射
permitFilterOptions.regions.forEach(region => {
const regionId = region.id || region;
regionDepartmentMap[regionId] = [];
});
// 将部门分配到对应区域
allDepartments.forEach(dept => {
const regionId = dept.region_id;
if (regionId && regionDepartmentMap.hasOwnProperty(regionId)) {
regionDepartmentMap[regionId].push(dept);
}
});
console.log('区域-部门映射关系构建完成:', regionDepartmentMap);
}
// 自动加载所有可见的许可事项(按权限过滤)
async function loadAllVisiblePermits() {
// 重置分页到第一页
permitCurrentPage = 0;
// 显示加载状态
showPermitsLoading(true);
hidePermitsError();
try {
// 不传递任何筛选参数,直接获取权限范围内的所有许可事项
const filters = {
limit: permitPageSize,
offset: permitCurrentPage * permitPageSize
};
const params = new URLSearchParams();
Object.keys(filters).forEach(key => {
if (filters[key]) {
params.append(key, filters[key]);
}
});
console.log('自动加载许可事项,参数:', params.toString());
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 || '加载失败');
}
console.log('自动加载结果:', data.data);
renderPermitResults(data.data.permits || []);
updatePermitPagination(data.data.pagination || {});
} catch (error) {
console.error('自动加载失败:', error);
showPermitsError(error.message);
renderPermitResults([]);
updatePermitPagination({});
} finally {
showPermitsLoading(false);
}
}
@ -5897,7 +5983,7 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
if (selectedText) {
if (checkboxes.length === 0) {
selectedText.textContent = `请选择${type === 'region' ? '区域' : type === 'theme' ? '主题' : '部门'}...`;
selectedText.textContent = `全部${type === 'region' ? '区域' : type === 'theme' ? '主题' : '部门'}`;
} else if (checkboxes.length === 1) {
const label = checkboxes[0].closest('label');
selectedText.textContent = label ? label.querySelector('span').textContent : '已选择';
@ -5915,71 +6001,81 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
}
}
// 区域选择变化处理
async function onRegionSelectionChange() {
// 区域选择变化处理(基于前端缓存)
function onRegionSelectionChange() {
console.log('onRegionSelectionChange 被调用'); // 调试日志
// 更新区域显示文本
updateSelectedText('region');
// 获取当前选中的区域
const regionCheckboxes = document.querySelectorAll('input[name="regionFilter"]:checked');
const selectedRegions = Array.from(regionCheckboxes).map(cb => cb.value);
console.log('选中的区域:', selectedRegions); // 调试日志
// 如果只选择了一个区域,则重新加载部门列表
// 根据选中的区域,动态更新部门列表
if (selectedRegions.length === 1) {
await loadDepartmentsByRegion(selectedRegions[0]);
// 只选择一个区域时,显示该区域的部门
const regionId = selectedRegions[0];
console.log('显示区域关联部门:', regionId); // 调试日志
const departments = regionDepartmentMap[regionId] || [];
renderDepartmentOptions(departments);
} else if (selectedRegions.length === 0) {
// 如果没有选择任何区域,则重新加载所有部门
await loadDepartmentsByRegion(null);
}
// 如果选择了多个区域,暂时不做处理(可以选择是否显示所有关联部门)
}
// 没有选择区域时,清空已选部门并显示所有部门
console.log('显示所有部门,清空部门选择'); // 调试日志
// 清空部门选择状态
const departmentCheckboxes = document.querySelectorAll('input[name="departmentFilter"]:checked');
departmentCheckboxes.forEach(cb => cb.checked = false);
updateSelectedText('department');
// 重新加载所有部门
renderDepartmentOptions(permitFilterOptions.departments || []);
} else {
// 选择多个区域时,显示所有选中区域关联的部门(去重)
console.log('显示多个区域关联部门'); // 调试日志
const allDepartments = [];
const departmentIds = new Set();
// 根据区域加载部门列表
async function loadDepartmentsByRegion(regionId) {
try {
// 构建API URL
let url = '/fs-ai-asistant/api/workflow/lawrisk/admin/permits/filter-options';
if (regionId) {
url += `?region_id=${encodeURIComponent(regionId)}`;
}
selectedRegions.forEach(regionId => {
const depts = regionDepartmentMap[regionId] || [];
depts.forEach(dept => {
if (!departmentIds.has(dept.id)) {
departmentIds.add(dept.id);
allDepartments.push(dept);
}
});
});
// 获取筛选选项
const response = await fetch(url);
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '加载部门列表失败');
}
// 更新部门列表保留原有的themes和regions但更新departments
permitFilterOptions.themes = data.data.themes || [];
permitFilterOptions.regions = data.data.regions || [];
permitFilterOptions.departments = data.data.departments || [];
// 重新渲染部门选项
renderDepartmentOptions();
} catch (error) {
console.error('加载部门列表失败:', error);
renderDepartmentOptions(allDepartments);
}
}
// 渲染部门选项(仅渲染部门部分
function renderDepartmentOptions() {
// 渲染部门选项(基于传入的部门列表)
function renderDepartmentOptions(departments) {
const departmentOptionsList = document.getElementById('departmentOptionsList');
if (departmentOptionsList) {
departmentOptionsList.innerHTML = '';
permitFilterOptions.departments.forEach(dept => {
if (!departments || departments.length === 0) {
// 如果没有部门,显示提示信息
const div = document.createElement('div');
div.style.padding = '6px 12px';
div.innerHTML = `
<label style="display: flex; align-items: center; cursor: pointer;">
<input type="checkbox" name="departmentFilter" value="${dept.id}" onchange="updateSelectedText('department')" style="margin-right: 8px;">
<span>${dept.name} (${dept.code})</span>
</label>
`;
div.style.padding = '12px';
div.style.textAlign = 'center';
div.style.color = '#999';
div.style.fontSize = '13px';
div.innerHTML = '该区域暂无关联部门';
departmentOptionsList.appendChild(div);
});
} else {
departments.forEach(dept => {
const div = document.createElement('div');
div.style.padding = '6px 12px';
div.innerHTML = `
<label style="display: flex; align-items: center; cursor: pointer;">
<input type="checkbox" name="departmentFilter" value="${dept.id}" onchange="updateSelectedText('department')" style="margin-right: 8px;">
<span>${dept.name} (${dept.code})</span>
</label>
`;
departmentOptionsList.appendChild(div);
});
}
// 更新部门显示文本
updateSelectedText('department');
@ -6010,6 +6106,203 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
updateSelectedText('department');
}
// 查看许可详情
async function viewPermitDetail(permitId, regionId) {
if (!regionId) {
showAlert('error', '缺少区域信息,无法查看详情');
return;
}
// 显示加载动画
const loadingHtml = `
<div style="display: flex; justify-content: center; align-items: center; min-height: 200px; flex-direction: column;">
<div class="loading">
<span class="loading-icon"></span>
</div>
<p style="color: #666; margin-top: 16px; font-size: 14px;">正在加载许可详情...</p>
</div>
`;
showModal('许可事项详情', loadingHtml);
// 构建请求参数
const params = new URLSearchParams();
params.append('permit_id', permitId);
params.append('region_id', regionId);
try {
const response = await fetch(`/fs-ai-asistant/api/workflow/lawrisk/admin/permit-details?${params}`);
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '获取许可详情失败');
}
const permit = data.data.permit;
const themeDisplay = data.data.theme_display;
// 构建风险列表
const risksHtml = (permit.risks || [])
.map((risk, index) => `
<div style="border: 1px solid #e0e0e0; border-radius: 6px; padding: 20px; margin-bottom: 16px; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">
<div style="margin-bottom: 12px;">
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">风险提示内容</div>
<div style="color: #1a202c; font-size: 14px; line-height: 1.8; padding: 16px; background: #f0f9ff; border-left: 4px solid #2c5282; border-radius: 4px; font-weight: 500;">${escapeHtml(risk.risk_content || '')}</div>
</div>
${risk.summary ? `
<div style="margin-bottom: 12px;">
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">风险概述</div>
<div style="color: #444; font-size: 14px; line-height: 1.8; padding: 12px; background: #f9fafb; border-radius: 4px;">${escapeHtml(risk.summary || '')}</div>
</div>
` : ''}
${risk.legal_basis ? `
<div style="margin-bottom: 12px;">
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">法律依据</div>
<div style="color: #444; font-size: 14px; line-height: 1.8; padding: 12px; background: #f9fafb; border-radius: 4px; font-style: italic;">${escapeHtml(risk.legal_basis)}</div>
</div>
` : ''}
${risk.document_no ? `
<div style="margin-bottom: 12px;">
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">文件文号</div>
<div style="color: #444; font-size: 14px; line-height: 1.8; padding: 12px; background: #f9fafb; border-radius: 4px;">${escapeHtml(risk.document_no)}</div>
</div>
` : ''}
${risk.remarks ? `
<div style="margin-bottom: 0;">
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">备注</div>
<div style="color: #444; font-size: 14px; line-height: 1.8; padding: 12px; background: #f9fafb; border-radius: 4px;">${escapeHtml(risk.remarks)}</div>
</div>
` : ''}
</div>
`).join('');
// 构建主题列表
const themesList = (permit.themes || [])
.map(t => `<span style="display: inline-block; padding: 2px 8px; background: #eef2ff; color: #4c1d95; border-radius: 4px; font-size: 12px; margin-right: 4px; margin-bottom: 4px;">${escapeHtml(t.name)}</span>`)
.join('');
const detailHtml = `
<div style="max-height: 70vh; overflow-y: auto; padding: 24px;">
<div style="background: #f8f9fa; padding: 24px; border-radius: 8px; margin-bottom: 24px;">
<h3 style="margin: 0 0 12px 0; color: #2c5282; font-size: 20px;">${escapeHtml(permit.name || '未知许可')}</h3>
<div style="display: flex; gap: 20px; flex-wrap: wrap; font-size: 14px;">
<div><strong>行政区域:</strong>${escapeHtml(permit.region?.name || '-')}</div>
<div><strong>风险数量:</strong>${permit.risks?.length || 0}</div>
</div>
</div>
${themesList ? `<div style="margin-bottom: 24px;"><strong style="display: block; margin-bottom: 8px;">关联主题:</strong>${themesList}</div>` : ''}
<!-- 许可详细信息 -->
<div style="background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; margin-bottom: 24px;">
<h4 style="color: #333; margin-bottom: 16px; border-bottom: 2px solid #2c5282; padding-bottom: 8px;">许可信息</h4>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
${permit.permit_status ? `
<div>
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">许可情况</div>
<div style="color: #444; font-size: 14px; padding: 10px; background: #f9fafb; border-radius: 4px;">${escapeHtml(permit.permit_status)}</div>
</div>
` : ''}
${permit.subitem_summary ? `
<div>
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">许可(备案)事项子项</div>
<div style="color: #444; font-size: 14px; padding: 10px; background: #f9fafb; border-radius: 4px;">${escapeHtml(permit.subitem_summary)}</div>
</div>
` : ''}
${permit.region?.name ? `
<div>
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">行政区域</div>
<div style="color: #444; font-size: 14px; padding: 10px; background: #f9fafb; border-radius: 4px;">${escapeHtml(permit.region.name)}</div>
</div>
` : ''}
${permit.responsible_contact ? `
<div>
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">负责部门</div>
<div style="color: #444; font-size: 14px; padding: 10px; background: #f9fafb; border-radius: 4px;">${escapeHtml(permit.responsible_contact)}</div>
</div>
` : ''}
${permit.jurisdiction_scope ? `
<div>
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">权限划分</div>
<div style="color: #444; font-size: 14px; padding: 10px; background: #f9fafb; border-radius: 4px;">${escapeHtml(permit.jurisdiction_scope)}</div>
</div>
` : ''}
${permit.business_scope ? `
<div style="grid-column: 1 / -1;">
<div style="font-size: 13px; color: #666; font-weight: 600; margin-bottom: 6px;">经营范围</div>
<div style="color: #444; font-size: 14px; padding: 10px; background: #f9fafb; border-radius: 4px; line-height: 1.8;">${escapeHtml(permit.business_scope)}</div>
</div>
` : ''}
</div>
</div>
<div>
<h4 style="color: #333; margin-bottom: 12px; border-bottom: 2px solid #2c5282; padding-bottom: 8px;">风险信息</h4>
${risksHtml || '<div style="color: #999; text-align: center; padding: 20px;">暂无风险信息</div>'}
</div>
</div>
`;
showModal('许可事项详情', detailHtml);
} catch (error) {
console.error('获取许可详情失败:', error);
const errorHtml = `
<div style="display: flex; justify-content: center; align-items: center; min-height: 200px; flex-direction: column;">
<div style="color: #dc2626; font-size: 16px; margin-bottom: 16px;">❌ 获取许可详情失败</div>
<div style="color: #666; font-size: 14px; text-align: center; max-width: 400px;">${escapeHtml(error.message || '未知错误')}</div>
<button class="btn btn-warning btn-sm" style="margin-top: 20px;" onclick="closePermitDetailModal()">关闭</button>
</div>
`;
showModal('许可事项详情', errorHtml);
}
}
// 删除许可事项
async function deletePermit(permitId, regionId) {
if (!confirm('确定要删除该许可事项吗?此操作不可恢复,并且会创建风险快照。')) {
return;
}
try {
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/permits', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
permit_id: permitId,
region_id: regionId,
edited_by: currentUser?.display_name || currentUser?.username || '未知用户',
change_summary: '通过管理界面删除许可事项'
})
});
const data = await response.json();
if (!data.success) {
throw new Error(data.message || '删除失败');
}
showAlert('success', '许可事项删除成功');
// 重新加载当前页面的数据
loadAllVisiblePermits();
} catch (error) {
console.error('删除许可失败:', error);
showAlert('error', '删除许可失败:' + error.message);
}
}
// 渲染筛选结果
function renderPermitResults(permits) {
const permitsList = document.getElementById('permitsList');
@ -6038,7 +6331,7 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
<th style="padding: 14px 16px; text-align: left; font-weight: 600; color: #555; font-size: 14px; width: 180px;">行政区域</th>
<th style="padding: 14px 16px; text-align: left; font-weight: 600; color: #555; font-size: 14px; width: 120px;">主题</th>
<th style="padding: 14px 16px; text-align: left; font-weight: 600; color: #555; font-size: 14px; width: 100px;">风险数</th>
<th style="padding: 14px 16px; text-align: left; font-weight: 600; color: #555; font-size: 14px; width: 100px;">操作</th>
<th style="padding: 14px 16px; text-align: left; font-weight: 600; color: #555; font-size: 14px; width: 180px;">操作</th>
</tr>
</thead>
<tbody>
@ -6049,6 +6342,8 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
.map(t => `<span style="display: inline-block; padding: 2px 8px; background: #eef2ff; color: #4c1d95; border-radius: 4px; font-size: 12px; margin-right: 4px;">${escapeHtml(t.name)}</span>`)
.join('');
const regionId = permit.region?.id || '';
html += `
<tr style="border-bottom: 1px solid #f0f0f0;">
<td style="padding: 16px;">
@ -6059,9 +6354,12 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
<td style="padding: 16px; color: #666;">${permit.theme_count || 0} 个</td>
<td style="padding: 16px; color: #666;">${permit.risk_count || 0}</td>
<td style="padding: 16px;">
<button onclick="viewPermitDetail('${permit.id}')" style="padding: 6px 12px; background: #2c5282; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 13px;">
<button onclick="viewPermitDetail('${permit.id}', '${regionId}')" style="padding: 6px 12px; background: #2c5282; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 13px; margin-right: 8px;">
查看
</button>
<button onclick="deletePermit('${permit.id}', '${regionId}')" style="padding: 6px 12px; background: #dc2626; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 13px;">
删除
</button>
</td>
</tr>
`;
@ -6185,9 +6483,41 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
return div.innerHTML;
}
// 查看许可详情
function viewPermitDetail(permitId) {
alert('查看许可详情功能待实现许可ID: ' + permitId);
// 显示通用模态框
function showModal(title, contentHtml) {
// 移除已存在的详情模态框
const existingModal = document.getElementById('permitDetailModal');
if (existingModal) {
existingModal.remove();
}
// 创建新的模态框
const modalDiv = document.createElement('div');
modalDiv.className = 'modal';
modalDiv.id = 'permitDetailModal';
modalDiv.innerHTML = `
<div class="modal-content" style="max-width: 900px; width: 90%;">
<div class="modal-header" style="display: flex; justify-content: space-between; align-items: center; padding: 20px; border-bottom: 1px solid #e5e7eb;">
<h3 style="margin: 0; color: #2c5282; font-size: 18px;">${escapeHtml(title)}</h3>
<button class="btn btn-warning btn-sm" onclick="closePermitDetailModal()">关闭</button>
</div>
<div class="modal-body" style="padding: 20px;">
${contentHtml}
</div>
</div>
`;
document.body.appendChild(modalDiv);
modalDiv.classList.add('show');
}
// 关闭许可详情模态框
function closePermitDetailModal() {
const modal = document.getElementById('permitDetailModal');
if (modal) {
modal.classList.remove('show');
setTimeout(() => modal.remove(), 300);
}
}
// 加载文件管理