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:
parent
ec44bec90a
commit
9aa6fabfb1
|
|
@ -1935,20 +1935,13 @@ def list_service_departments(region_id: Optional[str] = None) -> List[Dict[str,
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
|
|
||||||
if region_id:
|
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 + """
|
sql = _SERVICE_DEPARTMENT_SELECT + """
|
||||||
WHERE sd.id IN (
|
WHERE sd.region_id = %s
|
||||||
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
|
|
||||||
)
|
|
||||||
ORDER BY sd.created_at ASC
|
ORDER BY sd.created_at ASC
|
||||||
"""
|
"""
|
||||||
cur.execute(sql, (region_id, region_id))
|
cur.execute(sql, (region_id,))
|
||||||
else:
|
else:
|
||||||
# Get all departments
|
# Get all departments
|
||||||
cur.execute(_SERVICE_DEPARTMENT_SELECT + " ORDER BY sd.created_at ASC")
|
cur.execute(_SERVICE_DEPARTMENT_SELECT + " ORDER BY sd.created_at ASC")
|
||||||
|
|
@ -5563,15 +5556,18 @@ def filter_permits_advanced(
|
||||||
WHERE 1=1
|
WHERE 1=1
|
||||||
"""
|
"""
|
||||||
count_params = []
|
count_params = []
|
||||||
if region_id:
|
if regions:
|
||||||
count_sql += " AND rtp.region_id = %s"
|
placeholders = ', '.join(['%s'] * len(regions))
|
||||||
count_params.append(region_id)
|
count_sql += f" AND rtp.region_id IN ({placeholders})"
|
||||||
if theme_id:
|
count_params.extend(regions)
|
||||||
count_sql += " AND rtp.theme_id = %s"
|
if themes:
|
||||||
count_params.append(theme_id)
|
placeholders = ', '.join(['%s'] * len(themes))
|
||||||
if department_id:
|
count_sql += f" AND rtp.theme_id IN ({placeholders})"
|
||||||
count_sql += " AND (ps.uploader_department_id = %s OR ps.bound_department_id = %s)"
|
count_params.extend(themes)
|
||||||
count_params.extend([department_id, department_id])
|
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:
|
if search_text:
|
||||||
count_sql += " AND LOWER(p.name) LIKE LOWER(%s)"
|
count_sql += " AND LOWER(p.name) LIKE LOWER(%s)"
|
||||||
count_params.append(f"%{search_text}%")
|
count_params.append(f"%{search_text}%")
|
||||||
|
|
|
||||||
|
|
@ -2256,14 +2256,19 @@
|
||||||
<p style="color: #666; margin-bottom: 20px;">使用筛选器快速定位许可事项,支持多维度筛选、分页浏览、风险统计等功能。</p>
|
<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: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-bottom: 16px;">
|
||||||
<!-- 行政区域筛选 -->
|
<!-- 行政区域筛选 -->
|
||||||
<div style="display: flex; flex-direction: column; gap: 8px;">
|
<div style="display: flex; flex-direction: column; gap: 8px;">
|
||||||
<label style="font-size: 13px; font-weight: 600; color: #555;">行政区域 (可多选)</label>
|
<label style="font-size: 13px; font-weight: 600; color: #555;">行政区域 (可多选)</label>
|
||||||
<div style="position: relative;">
|
<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')">
|
<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>
|
<span style="float: right; color: #999;">▼</span>
|
||||||
</div>
|
</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);">
|
<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>
|
<label style="font-size: 13px; font-weight: 600; color: #555;">主题 (可多选)</label>
|
||||||
<div style="position: relative;">
|
<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')">
|
<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>
|
<span style="float: right; color: #999;">▼</span>
|
||||||
</div>
|
</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);">
|
<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>
|
<label style="font-size: 13px; font-weight: 600; color: #555;">关联部门 (可多选)</label>
|
||||||
<div style="position: relative;">
|
<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')">
|
<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>
|
<span style="float: right; color: #999;">▼</span>
|
||||||
</div>
|
</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);">
|
<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 = {
|
let permitFilterOptions = {
|
||||||
regions: [],
|
regions: [],
|
||||||
themes: [],
|
themes: [],
|
||||||
|
|
@ -5748,6 +5756,12 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
|
||||||
|
|
||||||
// 加载筛选选项
|
// 加载筛选选项
|
||||||
async function loadPermitFilterOptions() {
|
async function loadPermitFilterOptions() {
|
||||||
|
// 显示加载状态
|
||||||
|
const loadingElement = document.getElementById('filterOptionsLoading');
|
||||||
|
if (loadingElement) {
|
||||||
|
loadingElement.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/permits/filter-options');
|
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/permits/filter-options');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
@ -5760,11 +5774,21 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
|
||||||
renderPermitFilterOptions();
|
renderPermitFilterOptions();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载筛选选项失败:', error);
|
console.error('加载筛选选项失败:', error);
|
||||||
|
// 可以在这里显示错误提示
|
||||||
|
alert('加载筛选选项失败: ' + error.message);
|
||||||
|
} finally {
|
||||||
|
// 隐藏加载状态
|
||||||
|
if (loadingElement) {
|
||||||
|
loadingElement.style.display = 'none';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染筛选选项
|
// 渲染筛选选项
|
||||||
function renderPermitFilterOptions() {
|
function renderPermitFilterOptions() {
|
||||||
|
// 构建区域-部门映射关系
|
||||||
|
buildRegionDepartmentMapping();
|
||||||
|
|
||||||
// 渲染区域选项
|
// 渲染区域选项
|
||||||
const regionOptionsList = document.getElementById('regionOptionsList');
|
const regionOptionsList = document.getElementById('regionOptionsList');
|
||||||
if (regionOptionsList) {
|
if (regionOptionsList) {
|
||||||
|
|
@ -5799,21 +5823,83 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染部门选项
|
// 渲染部门选项(显示所有部门)
|
||||||
const departmentOptionsList = document.getElementById('departmentOptionsList');
|
renderDepartmentOptions(permitFilterOptions.departments);
|
||||||
if (departmentOptionsList) {
|
|
||||||
departmentOptionsList.innerHTML = '';
|
// 自动加载权限范围内的许可事项
|
||||||
permitFilterOptions.departments.forEach(dept => {
|
// 注意:不要在渲染过程中直接调用,需要延迟执行确保DOM更新完成
|
||||||
const div = document.createElement('div');
|
setTimeout(() => {
|
||||||
div.style.padding = '6px 12px';
|
loadAllVisiblePermits();
|
||||||
div.innerHTML = `
|
}, 100);
|
||||||
<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>
|
function buildRegionDepartmentMapping() {
|
||||||
`;
|
// 初始化映射对象
|
||||||
departmentOptionsList.appendChild(div);
|
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 (selectedText) {
|
||||||
if (checkboxes.length === 0) {
|
if (checkboxes.length === 0) {
|
||||||
selectedText.textContent = `请选择${type === 'region' ? '区域' : type === 'theme' ? '主题' : '部门'}...`;
|
selectedText.textContent = `全部${type === 'region' ? '区域' : type === 'theme' ? '主题' : '部门'}`;
|
||||||
} else if (checkboxes.length === 1) {
|
} else if (checkboxes.length === 1) {
|
||||||
const label = checkboxes[0].closest('label');
|
const label = checkboxes[0].closest('label');
|
||||||
selectedText.textContent = label ? label.querySelector('span').textContent : '已选择';
|
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');
|
updateSelectedText('region');
|
||||||
|
|
||||||
// 获取当前选中的区域
|
// 获取当前选中的区域
|
||||||
const regionCheckboxes = document.querySelectorAll('input[name="regionFilter"]:checked');
|
const regionCheckboxes = document.querySelectorAll('input[name="regionFilter"]:checked');
|
||||||
const selectedRegions = Array.from(regionCheckboxes).map(cb => cb.value);
|
const selectedRegions = Array.from(regionCheckboxes).map(cb => cb.value);
|
||||||
|
console.log('选中的区域:', selectedRegions); // 调试日志
|
||||||
|
|
||||||
// 如果只选择了一个区域,则重新加载部门列表
|
// 根据选中的区域,动态更新部门列表
|
||||||
if (selectedRegions.length === 1) {
|
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) {
|
} 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();
|
||||||
|
|
||||||
// 根据区域加载部门列表
|
selectedRegions.forEach(regionId => {
|
||||||
async function loadDepartmentsByRegion(regionId) {
|
const depts = regionDepartmentMap[regionId] || [];
|
||||||
try {
|
depts.forEach(dept => {
|
||||||
// 构建API URL
|
if (!departmentIds.has(dept.id)) {
|
||||||
let url = '/fs-ai-asistant/api/workflow/lawrisk/admin/permits/filter-options';
|
departmentIds.add(dept.id);
|
||||||
if (regionId) {
|
allDepartments.push(dept);
|
||||||
url += `?region_id=${encodeURIComponent(regionId)}`;
|
}
|
||||||
}
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 获取筛选选项
|
renderDepartmentOptions(allDepartments);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染部门选项(仅渲染部门部分)
|
// 渲染部门选项(基于传入的部门列表)
|
||||||
function renderDepartmentOptions() {
|
function renderDepartmentOptions(departments) {
|
||||||
const departmentOptionsList = document.getElementById('departmentOptionsList');
|
const departmentOptionsList = document.getElementById('departmentOptionsList');
|
||||||
if (departmentOptionsList) {
|
if (departmentOptionsList) {
|
||||||
departmentOptionsList.innerHTML = '';
|
departmentOptionsList.innerHTML = '';
|
||||||
permitFilterOptions.departments.forEach(dept => {
|
|
||||||
|
if (!departments || departments.length === 0) {
|
||||||
|
// 如果没有部门,显示提示信息
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.style.padding = '6px 12px';
|
div.style.padding = '12px';
|
||||||
div.innerHTML = `
|
div.style.textAlign = 'center';
|
||||||
<label style="display: flex; align-items: center; cursor: pointer;">
|
div.style.color = '#999';
|
||||||
<input type="checkbox" name="departmentFilter" value="${dept.id}" onchange="updateSelectedText('department')" style="margin-right: 8px;">
|
div.style.fontSize = '13px';
|
||||||
<span>${dept.name} (${dept.code})</span>
|
div.innerHTML = '该区域暂无关联部门';
|
||||||
</label>
|
|
||||||
`;
|
|
||||||
departmentOptionsList.appendChild(div);
|
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');
|
updateSelectedText('department');
|
||||||
|
|
@ -6010,6 +6106,203 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
|
||||||
updateSelectedText('department');
|
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) {
|
function renderPermitResults(permits) {
|
||||||
const permitsList = document.getElementById('permitsList');
|
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: 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: 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: 100px;">操作</th>
|
<th style="padding: 14px 16px; text-align: left; font-weight: 600; color: #555; font-size: 14px; width: 180px;">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<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>`)
|
.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('');
|
.join('');
|
||||||
|
|
||||||
|
const regionId = permit.region?.id || '';
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
<tr style="border-bottom: 1px solid #f0f0f0;">
|
<tr style="border-bottom: 1px solid #f0f0f0;">
|
||||||
<td style="padding: 16px;">
|
<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.theme_count || 0} 个</td>
|
||||||
<td style="padding: 16px; color: #666;">${permit.risk_count || 0}</td>
|
<td style="padding: 16px; color: #666;">${permit.risk_count || 0}</td>
|
||||||
<td style="padding: 16px;">
|
<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>
|
||||||
|
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
|
|
@ -6185,9 +6483,41 @@ document.getElementById('checkpointModal').addEventListener('click', function(e)
|
||||||
return div.innerHTML;
|
return div.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查看许可详情
|
// 显示通用模态框
|
||||||
function viewPermitDetail(permitId) {
|
function showModal(title, contentHtml) {
|
||||||
alert('查看许可详情功能待实现,许可ID: ' + permitId);
|
// 移除已存在的详情模态框
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载文件管理
|
// 加载文件管理
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue