feat: 优化许可导入区划合并与来源展示
This commit is contained in:
parent
a5bc3c41b7
commit
5b86bd8799
File diff suppressed because it is too large
Load Diff
|
|
@ -761,6 +761,12 @@
|
||||||
animation: modalFadeIn 0.3s;
|
animation: modalFadeIn 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.import-modal-content {
|
||||||
|
width: 760px;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes modalFadeIn {
|
@keyframes modalFadeIn {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
@ -772,6 +778,167 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.import-section {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-section h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #333;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-upload-area {
|
||||||
|
border: 1px dashed #9fa8da;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f5f7ff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-upload-area input[type="file"] {
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #c5cae9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-meta {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #555;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-sheet-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-sheet-card {
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-sheet-card.selected {
|
||||||
|
border-color: #667eea;
|
||||||
|
background: #eef2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-sheet-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-sheet-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #3949ab;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-sheet-meta {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-duplicate-panel {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-duplicate-title {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #d84315;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-checkbox input[type="checkbox"] {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-messages {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-success {
|
||||||
|
color: #256029;
|
||||||
|
background: #e3f2e1;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-error {
|
||||||
|
color: #c62828;
|
||||||
|
background: #ffebee;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-form-grid textarea {
|
||||||
|
grid-column: span 2;
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 68px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-form-grid input,
|
||||||
|
.import-form-grid textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border: 1px solid #c5cae9;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 16px;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
|
@ -1120,6 +1287,9 @@
|
||||||
|
|
||||||
<!-- 检查点管理按钮 -->
|
<!-- 检查点管理按钮 -->
|
||||||
<div class="checkpoint-toolbar">
|
<div class="checkpoint-toolbar">
|
||||||
|
<button class="btn btn-primary" onclick="openImportModal()">
|
||||||
|
<span>📥</span> 许可导入
|
||||||
|
</button>
|
||||||
<button class="btn btn-warning" onclick="openCheckpointModal()">
|
<button class="btn btn-warning" onclick="openCheckpointModal()">
|
||||||
<span>🔒</span> 检查点管理
|
<span>🔒</span> 检查点管理
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -1184,6 +1354,19 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 许可导入模态窗口 -->
|
||||||
|
<div class="modal" id="importModal">
|
||||||
|
<div class="modal-content import-modal-content">
|
||||||
|
<div class="modal-header" style="display:flex; justify-content: space-between; align-items: center;">
|
||||||
|
<h3 style="color:#3949ab; margin:0; display:flex; align-items:center; gap:8px;">
|
||||||
|
<span>📥</span> 许可导入(Excel)
|
||||||
|
</h3>
|
||||||
|
<button class="btn btn-warning btn-sm" onclick="closeImportModal()">关闭</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="importModalBody"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// 导航状态管理
|
// 导航状态管理
|
||||||
let currentStep = 1; // 1=区域, 2=主题, 3=许可, 4=详情
|
let currentStep = 1; // 1=区域, 2=主题, 3=许可, 4=详情
|
||||||
|
|
@ -1217,6 +1400,21 @@
|
||||||
let checkpointListError = '';
|
let checkpointListError = '';
|
||||||
let expandedSnapshotGroups = new Set();
|
let expandedSnapshotGroups = new Set();
|
||||||
|
|
||||||
|
const permitImportState = {
|
||||||
|
uploading: false,
|
||||||
|
sessionId: '',
|
||||||
|
filename: '',
|
||||||
|
totalRows: 0,
|
||||||
|
sheetSummaries: [],
|
||||||
|
selectedSheets: new Set(),
|
||||||
|
overrides: new Map(),
|
||||||
|
error: '',
|
||||||
|
success: '',
|
||||||
|
commitLoading: false,
|
||||||
|
editedBy: '',
|
||||||
|
changeSummary: ''
|
||||||
|
};
|
||||||
|
|
||||||
// 步骤配置
|
// 步骤配置
|
||||||
const steps = {
|
const steps = {
|
||||||
1: { title: '选择区域', loadData: loadRegions },
|
1: { title: '选择区域', loadData: loadRegions },
|
||||||
|
|
@ -1572,6 +1770,7 @@
|
||||||
<h3>许可信息</h3>
|
<h3>许可信息</h3>
|
||||||
<div class="detail-content">
|
<div class="detail-content">
|
||||||
<p><strong>许可名称:</strong>${permit.name}</p>
|
<p><strong>许可名称:</strong>${permit.name}</p>
|
||||||
|
${permit.permit_source && permit.permit_source.source_name ? `<p style="margin-top: 10px;"><strong>数据来源:</strong>${escapeHtml(permit.permit_source.source_name)}</p>` : ''}
|
||||||
${permit.permit_status ? `<p style="margin-top: 10px;"><strong>许可状态:</strong><span class="permit-status ${permit.permit_status === 'active' ? 'status-active' : 'status-inactive'}">${permit.permit_status}</span></p>` : ''}
|
${permit.permit_status ? `<p style="margin-top: 10px;"><strong>许可状态:</strong><span class="permit-status ${permit.permit_status === 'active' ? 'status-active' : 'status-inactive'}">${permit.permit_status}</span></p>` : ''}
|
||||||
${permit.subitem_summary ? `<p style="margin-top: 10px;"><strong>子项说明:</strong>${permit.subitem_summary}</p>` : ''}
|
${permit.subitem_summary ? `<p style="margin-top: 10px;"><strong>子项说明:</strong>${permit.subitem_summary}</p>` : ''}
|
||||||
${permit.responsible_contact ? `<p style="margin-top: 10px;"><strong>负责部门:</strong>${permit.responsible_contact}</p>` : ''}
|
${permit.responsible_contact ? `<p style="margin-top: 10px;"><strong>负责部门:</strong>${permit.responsible_contact}</p>` : ''}
|
||||||
|
|
@ -1743,6 +1942,294 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================ 许可导入功能 ================
|
||||||
|
|
||||||
|
function openImportModal() {
|
||||||
|
const modal = document.getElementById('importModal');
|
||||||
|
if (!modal) return;
|
||||||
|
modal.classList.add('show');
|
||||||
|
if (!permitImportState.sessionId) {
|
||||||
|
permitImportState.selectedSheets = new Set();
|
||||||
|
permitImportState.overrides = new Map();
|
||||||
|
permitImportState.error = '';
|
||||||
|
permitImportState.success = '';
|
||||||
|
}
|
||||||
|
renderImportModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeImportModal() {
|
||||||
|
const modal = document.getElementById('importModal');
|
||||||
|
if (!modal) return;
|
||||||
|
modal.classList.remove('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSheetSelection(sheetName, forceChecked) {
|
||||||
|
if (!sheetName) return;
|
||||||
|
const shouldSelect = typeof forceChecked === 'boolean'
|
||||||
|
? forceChecked
|
||||||
|
: !permitImportState.selectedSheets.has(sheetName);
|
||||||
|
|
||||||
|
if (shouldSelect) {
|
||||||
|
permitImportState.selectedSheets.add(sheetName);
|
||||||
|
} else {
|
||||||
|
permitImportState.selectedSheets.delete(sheetName);
|
||||||
|
permitImportState.overrides.delete(sheetName);
|
||||||
|
}
|
||||||
|
renderImportModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSheetSelectionFromEvent(el) {
|
||||||
|
if (!el || !el.dataset) return;
|
||||||
|
toggleSheetSelection(el.dataset.sheet || '', el.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleOverridePermit(sheetName, permitName, forceChecked) {
|
||||||
|
if (!sheetName || !permitName) return;
|
||||||
|
if (!permitImportState.overrides.has(sheetName)) {
|
||||||
|
permitImportState.overrides.set(sheetName, new Set());
|
||||||
|
}
|
||||||
|
const set = permitImportState.overrides.get(sheetName);
|
||||||
|
const shouldCheck = typeof forceChecked === 'boolean'
|
||||||
|
? forceChecked
|
||||||
|
: !set.has(permitName);
|
||||||
|
if (shouldCheck) {
|
||||||
|
set.add(permitName);
|
||||||
|
} else {
|
||||||
|
set.delete(permitName);
|
||||||
|
}
|
||||||
|
if (set.size === 0) {
|
||||||
|
permitImportState.overrides.delete(sheetName);
|
||||||
|
}
|
||||||
|
renderImportModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleOverridePermitFromEvent(el) {
|
||||||
|
if (!el || !el.dataset) return;
|
||||||
|
toggleOverridePermit(el.dataset.sheet || '', el.dataset.permit || '', el.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateImportEditedBy(value) {
|
||||||
|
permitImportState.editedBy = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateImportChangeSummary(value) {
|
||||||
|
permitImportState.changeSummary = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleImportFile(input) {
|
||||||
|
if (!input || !input.files || !input.files.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const file = input.files[0];
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
permitImportState.uploading = true;
|
||||||
|
permitImportState.error = '';
|
||||||
|
permitImportState.success = '';
|
||||||
|
renderImportModal();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/permit-import/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
const data = await parseJsonResponse(response);
|
||||||
|
if (data.success) {
|
||||||
|
const payload = data.data || {};
|
||||||
|
permitImportState.sessionId = payload.session_id || payload.sessionId || '';
|
||||||
|
permitImportState.filename = payload.filename || (file && file.name) || '';
|
||||||
|
permitImportState.totalRows = payload.total_rows || payload.totalRows || 0;
|
||||||
|
permitImportState.sheetSummaries = payload.sheet_summaries || payload.sheetSummaries || [];
|
||||||
|
permitImportState.selectedSheets = new Set(
|
||||||
|
(permitImportState.sheetSummaries || []).map(item => item.sheet_name)
|
||||||
|
);
|
||||||
|
permitImportState.overrides = new Map();
|
||||||
|
permitImportState.success = `解析完成:${permitImportState.sheetSummaries.length} 个 Sheet,${permitImportState.totalRows} 条风险记录`;
|
||||||
|
} else {
|
||||||
|
permitImportState.error = data.message || '解析失败,请检查Excel格式';
|
||||||
|
permitImportState.sessionId = '';
|
||||||
|
permitImportState.sheetSummaries = [];
|
||||||
|
permitImportState.selectedSheets = new Set();
|
||||||
|
permitImportState.overrides = new Map();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
permitImportState.error = error.message || '文件上传失败';
|
||||||
|
permitImportState.sessionId = '';
|
||||||
|
permitImportState.sheetSummaries = [];
|
||||||
|
permitImportState.selectedSheets = new Set();
|
||||||
|
permitImportState.overrides = new Map();
|
||||||
|
} finally {
|
||||||
|
permitImportState.uploading = false;
|
||||||
|
renderImportModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitImport() {
|
||||||
|
if (!permitImportState.sessionId) {
|
||||||
|
permitImportState.error = '请先上传并解析Excel文件';
|
||||||
|
renderImportModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (permitImportState.selectedSheets.size === 0) {
|
||||||
|
permitImportState.error = '请选择至少一个Sheet进行导入';
|
||||||
|
renderImportModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
session_id: permitImportState.sessionId,
|
||||||
|
sheet_names: Array.from(permitImportState.selectedSheets),
|
||||||
|
overrides: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
permitImportState.overrides.forEach((set, sheet) => {
|
||||||
|
if (set.size) {
|
||||||
|
payload.overrides[sheet] = Array.from(set);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (permitImportState.editedBy && permitImportState.editedBy.trim()) {
|
||||||
|
payload.edited_by = permitImportState.editedBy.trim();
|
||||||
|
}
|
||||||
|
if (permitImportState.changeSummary && permitImportState.changeSummary.trim()) {
|
||||||
|
payload.change_summary = permitImportState.changeSummary.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
permitImportState.commitLoading = true;
|
||||||
|
permitImportState.error = '';
|
||||||
|
permitImportState.success = '';
|
||||||
|
renderImportModal();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/fs-ai-asistant/api/workflow/lawrisk/admin/permit-import/commit', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
const data = await parseJsonResponse(response);
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
const result = data.data || {};
|
||||||
|
const created = (result.created_permits || []).length;
|
||||||
|
const overwritten = (result.overwritten_permits || []).length;
|
||||||
|
permitImportState.success = `导入成功:新增 ${created} 个许可,覆盖 ${overwritten} 个许可。`;
|
||||||
|
permitImportState.sessionId = '';
|
||||||
|
permitImportState.sheetSummaries = [];
|
||||||
|
permitImportState.selectedSheets = new Set();
|
||||||
|
permitImportState.overrides = new Map();
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
refreshPermitRiskSnapshots(false),
|
||||||
|
refreshCheckpointList(false)
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 如果当前在首页,刷新地区列表,确保新地区可见
|
||||||
|
if (currentStep === 1) {
|
||||||
|
await loadRegions();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
permitImportState.error = data.message || '导入失败';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
permitImportState.error = error.message || '导入失败';
|
||||||
|
} finally {
|
||||||
|
permitImportState.commitLoading = false;
|
||||||
|
renderImportModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderImportModal() {
|
||||||
|
const container = document.getElementById('importModalBody');
|
||||||
|
if (!container) return;
|
||||||
|
const state = permitImportState;
|
||||||
|
|
||||||
|
let html = '<div class="import-section">';
|
||||||
|
html += '<h3><span>📄</span> 上传 Excel</h3>';
|
||||||
|
html += '<div class="import-upload-area">';
|
||||||
|
html += '<input type="file" accept=".xlsx,.xlsm" onchange="handleImportFile(this)">';
|
||||||
|
if (state.sessionId) {
|
||||||
|
const sheetCount = state.sheetSummaries ? state.sheetSummaries.length : 0;
|
||||||
|
html += `<div class="import-meta">当前会话:${escapeHtml(state.filename || '(未命名)')} | Sheet ${sheetCount} 个 | 风险 ${state.totalRows || 0} 条</div>`;
|
||||||
|
} else {
|
||||||
|
html += '<div class="import-meta">请选择包含许可数据的 Excel 文件,系统会自动解析所有 Sheet,并以区划为单位生成导入任务。</div>';
|
||||||
|
}
|
||||||
|
html += '</div></div>';
|
||||||
|
|
||||||
|
if (state.error) {
|
||||||
|
html += `<div class="import-error">${escapeHtml(state.error)}</div>`;
|
||||||
|
}
|
||||||
|
if (state.success) {
|
||||||
|
html += `<div class="import-success">${escapeHtml(state.success)}</div>`;
|
||||||
|
}
|
||||||
|
if (state.uploading) {
|
||||||
|
html += '<div class="loading" style="margin: 8px 0;">正在解析 Excel...</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.sessionId && state.sheetSummaries && state.sheetSummaries.length) {
|
||||||
|
html += '<div class="import-section">';
|
||||||
|
html += '<h3><span>🗂️</span> 选择导入的 Sheet</h3>';
|
||||||
|
html += '<div class="import-sheet-list">';
|
||||||
|
|
||||||
|
state.sheetSummaries.forEach(summary => {
|
||||||
|
const sheetName = summary.sheet_name || '';
|
||||||
|
const selected = state.selectedSheets.has(sheetName);
|
||||||
|
const duplicates = summary.duplicate_permits || summary.duplicatePermits || [];
|
||||||
|
const newPermits = summary.new_permits || summary.newPermits || [];
|
||||||
|
const overrideSet = state.overrides.get(sheetName) || new Set();
|
||||||
|
const missingRegion = summary.missing_region || summary.missingRegion;
|
||||||
|
const originalSheets = summary.original_sheet_names || summary.originalSheetNames || [];
|
||||||
|
const originalLabel = originalSheets.length
|
||||||
|
? originalSheets.map(name => escapeHtml(name)).join('、')
|
||||||
|
: escapeHtml(sheetName);
|
||||||
|
|
||||||
|
html += `<div class="import-sheet-card ${selected ? 'selected' : ''}">`;
|
||||||
|
html += '<div class="import-sheet-header">';
|
||||||
|
html += `<label class="import-checkbox"><input type="checkbox" data-sheet="${escapeHtml(sheetName)}" ${selected ? 'checked' : ''} onchange="toggleSheetSelectionFromEvent(this)"> <span class="import-sheet-title">${escapeHtml(sheetName)}${missingRegion ? '<span style="margin-left:6px;color:#c62828;font-size:12px;">(新地区)</span>' : ''}</span></label>`;
|
||||||
|
html += `<div class="import-sheet-meta">许可 ${summary.permit_count || 0} | 风险 ${summary.risk_count || summary.row_count || 0}</div>`;
|
||||||
|
html += '</div>';
|
||||||
|
html += `<div class="import-sheet-submeta">来源 Sheet:${originalLabel}</div>`;
|
||||||
|
|
||||||
|
if (newPermits.length) {
|
||||||
|
html += `<div class="import-meta" style="margin-bottom:8px; color:#2e7d32;">新增许可 ${newPermits.length} 项</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duplicates.length) {
|
||||||
|
html += '<div class="import-duplicate-panel">';
|
||||||
|
html += '<div class="import-duplicate-title">检测到已存在的许可,勾选代表同意覆盖:</div>';
|
||||||
|
duplicates.forEach(name => {
|
||||||
|
const checked = overrideSet.has(name);
|
||||||
|
const disabledAttr = selected ? '' : 'disabled';
|
||||||
|
html += `<label class="import-checkbox"><input type="checkbox" data-sheet="${escapeHtml(sheetName)}" data-permit="${escapeHtml(name)}" ${checked ? 'checked' : ''} ${disabledAttr} onchange="toggleOverridePermitFromEvent(this)"> <span>${escapeHtml(name)}</span></label>`;
|
||||||
|
});
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</div>';
|
||||||
|
});
|
||||||
|
|
||||||
|
html += '</div></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '<div class="import-section">';
|
||||||
|
html += '<h3><span>📝</span> 导入说明</h3>';
|
||||||
|
html += '<div class="import-form-grid">';
|
||||||
|
html += `<input type="text" placeholder="编辑人(可选)" value="${escapeHtml(state.editedBy)}" oninput="updateImportEditedBy(this.value)">`;
|
||||||
|
html += `<textarea placeholder="变更摘要 / 导入说明(可选)" oninput="updateImportChangeSummary(this.value)">${escapeHtml(state.changeSummary)}</textarea>`;
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
const commitDisabled = !state.sessionId || state.selectedSheets.size === 0 || state.commitLoading;
|
||||||
|
const commitLabel = state.commitLoading ? '导入中...' : '开始导入';
|
||||||
|
|
||||||
|
html += '<div class="import-actions">';
|
||||||
|
html += '<div class="import-hint">导入前会自动创建风险快照,可在“检查点管理”中查看恢复。</div>';
|
||||||
|
html += `<button class="btn btn-warning" onclick="submitImport()" ${commitDisabled ? 'disabled' : ''}>${commitLabel}</button>`;
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
container.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
// ================ 检查点管理功能 ================
|
// ================ 检查点管理功能 ================
|
||||||
|
|
||||||
// 打开检查点模态窗口
|
// 打开检查点模态窗口
|
||||||
|
|
@ -1794,6 +2281,12 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('importModal').addEventListener('click', function(e) {
|
||||||
|
if (e.target === this) {
|
||||||
|
closeImportModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 加载检查点列表(保持兼容性)
|
// 加载检查点列表(保持兼容性)
|
||||||
async function loadCheckpoints() {
|
async function loadCheckpoints() {
|
||||||
await openCheckpointModal();
|
await openCheckpointModal();
|
||||||
|
|
@ -1903,6 +2396,8 @@
|
||||||
const regionName = escapeHtml(group.region_name || primary.region_name || '-');
|
const regionName = escapeHtml(group.region_name || primary.region_name || '-');
|
||||||
const riskFull = primary.risk_content || '';
|
const riskFull = primary.risk_content || '';
|
||||||
const riskPreview = escapeHtml(truncateText(riskFull, 160));
|
const riskPreview = escapeHtml(truncateText(riskFull, 160));
|
||||||
|
const sourceNameRaw = primary.permit_source_name || group.permit_source_name || '';
|
||||||
|
const sourceTag = sourceNameRaw ? `<span>来源:${escapeHtml(sourceNameRaw)}</span>` : '';
|
||||||
const legalSegments = [];
|
const legalSegments = [];
|
||||||
if (primary.legal_basis) {
|
if (primary.legal_basis) {
|
||||||
legalSegments.push(`📕 ${escapeHtml(primary.legal_basis)}`);
|
legalSegments.push(`📕 ${escapeHtml(primary.legal_basis)}`);
|
||||||
|
|
@ -1938,6 +2433,9 @@
|
||||||
if (detail.edited_by) {
|
if (detail.edited_by) {
|
||||||
detailMetaParts.push(`编辑人:${escapeHtml(detail.edited_by)}`);
|
detailMetaParts.push(`编辑人:${escapeHtml(detail.edited_by)}`);
|
||||||
}
|
}
|
||||||
|
if (detail.permit_source_name) {
|
||||||
|
detailMetaParts.push(`来源:${escapeHtml(detail.permit_source_name)}`);
|
||||||
|
}
|
||||||
detailMetaParts.push(...detailLegal);
|
detailMetaParts.push(...detailLegal);
|
||||||
const detailMetaHtml = detailMetaParts.length
|
const detailMetaHtml = detailMetaParts.length
|
||||||
? `<div class="snapshot-detail-meta">${detailMetaParts.join('<span>|</span>')}</div>`
|
? `<div class="snapshot-detail-meta">${detailMetaParts.join('<span>|</span>')}</div>`
|
||||||
|
|
@ -1971,6 +2469,7 @@
|
||||||
${statusTag}
|
${statusTag}
|
||||||
<span>风险条目:${riskCount} 个</span>
|
<span>风险条目:${riskCount} 个</span>
|
||||||
<span>编辑人:${editorsText}</span>
|
<span>编辑人:${editorsText}</span>
|
||||||
|
${sourceTag}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue