子菜单可视化编辑
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
yiqiu
2025-12-28 21:46:44 +08:00
parent d59c363f6c
commit e02c693bdc

View File

@@ -662,19 +662,23 @@
renderFeedbackTypes(types);
};
// ========== 顶部导航(简化) ==========
// ========== 顶部导航(完整版 - 支持子菜单) ==========
function renderHeaderNav(navs) {
const container = document.getElementById('headerNavList');
if (!container) return;
container.innerHTML = '';
navs.forEach((nav, index) => {
const hasChildren = Array.isArray(nav.children) && nav.children.length > 0;
const item = document.createElement('div');
item.className = 'config-item';
item.innerHTML = `
<div class="config-item__header">
<h4>导航 ${index + 1}</h4>
<h4>导航 ${index + 1}: ${nav.name || '(未命名)'}</h4>
<div style="display: flex; gap: 4px;">
<button class="btn-icon" onclick="toggleHeaderNavChildren(${index})" title="子菜单">☰${hasChildren ? ` (${nav.children.length})` : ''}</button>
<button class="btn-icon btn-icon-danger" onclick="removeHeaderNav(${index})">×</button>
</div>
</div>
<div class="config-item__body">
<div class="form-fields">
<div class="form-item">
@@ -683,12 +687,42 @@
</div>
<div class="form-item">
<label>链接</label>
<input type="text" class="form-control" data-hnav="${index}" data-field="file_address" value="${nav.file_address || ''}">
</div>
<div class="form-item">
<div style="font-size:13px;color:#666;">子菜单请使用JSON编辑器配置</div>
<input type="text" class="form-control" data-hnav="${index}" data-field="file_address" value="${nav.file_address || ''}" placeholder="/products.html">
</div>
</div>
<div id="header-nav-children-${index}" style="display:${hasChildren ? 'block' : 'none'}; margin-top:12px; padding-top:12px; border-top:1px solid #eee;">
<h5 style="margin:0 0 8px; font-size:13px;">子菜单</h5>
<div id="header-nav-children-list-${index}"></div>
<button class="btn btn-secondary btn-sm" onclick="addHeaderNavChild(${index})" style="margin-top:8px;">+ 添加子菜单</button>
</div>
</div>
`;
container.appendChild(item);
if (hasChildren) {
renderHeaderNavChildren(index, nav.children);
}
});
}
function renderHeaderNavChildren(navIndex, children) {
const container = document.getElementById(`header-nav-children-list-${navIndex}`);
if (!container) return;
container.innerHTML = '';
children.forEach((child, childIndex) => {
const item = document.createElement('div');
item.style.cssText = 'padding:8px; margin-bottom:8px; background:#f9f9f9; border-radius:4px;';
item.innerHTML = `
<div style="display:flex; justify-content:space-between; align-items:start;">
<div style="flex:1; display:grid; gap:8px;">
<input type="text" class="form-control" data-hnav-child="${navIndex}.${childIndex}" data-field="name" value="${child.name || ''}" placeholder="子菜单名称">
<input type="text" class="form-control" data-hnav-child="${navIndex}.${childIndex}" data-field="file_address" value="${child.file_address || ''}" placeholder="链接地址">
<input type="text" class="form-control" data-hnav-child="${navIndex}.${childIndex}" data-field="icon" value="${child.icon || ''}" placeholder="图标URL(可选)">
<input type="text" class="form-control" data-hnav-child="${navIndex}.${childIndex}" data-field="description" value="${child.description || ''}" placeholder="描述(可选)">
<label style="font-size:12px;"><input type="checkbox" data-hnav-child="${navIndex}.${childIndex}" data-field="blank" ${child.blank ? 'checked' : ''}> 新窗口打开</label>
</div>
<button class="btn-icon btn-icon-danger" onclick="removeHeaderNavChild(${navIndex}, ${childIndex})" style="margin-left:8px;">×</button>
</div>
`;
container.appendChild(item);
@@ -697,19 +731,32 @@
function collectHeaderNav() {
const navs = [];
// 收集主导航
document.querySelectorAll('[data-hnav]').forEach(input => {
const index = parseInt(input.dataset.hnav);
const field = input.dataset.field;
if (!navs[index]) navs[index] = { children: [] };
navs[index][field] = input.value;
});
// 保留原有的children
const orig = config.header_nav || [];
navs.forEach((nav, i) => {
if (orig[i] && orig[i].children) {
nav.children = orig[i].children;
// 收集子菜单
document.querySelectorAll('[data-hnav-child]').forEach(input => {
const [navIndex, childIndex] = input.dataset.hnavChild.split('.').map(Number);
const field = input.dataset.field;
if (!navs[navIndex]) navs[navIndex] = { children: [] };
if (!navs[navIndex].children[childIndex]) {
navs[navIndex].children[childIndex] = {};
}
if (input.type === 'checkbox') {
navs[navIndex].children[childIndex][field] = input.checked;
} else {
navs[navIndex].children[childIndex][field] = input.value;
}
});
return navs.filter(n => n);
}
@@ -725,6 +772,40 @@
renderHeaderNav(navs);
};
window.toggleHeaderNavChildren = function (index) {
const container = document.getElementById(`header-nav-children-${index}`);
if (container) {
const isHidden = container.style.display === 'none';
container.style.display = isHidden ? 'block' : 'none';
}
};
window.addHeaderNavChild = function (navIndex) {
const navs = collectHeaderNav();
if (!navs[navIndex]) navs[navIndex] = { children: [] };
if (!navs[navIndex].children) navs[navIndex].children = [];
navs[navIndex].children.push({
name: '',
file_address: '',
icon: '',
description: '',
blank: false
});
renderHeaderNav(navs);
// 确保展开
document.getElementById(`header-nav-children-${navIndex}`).style.display = 'block';
};
window.removeHeaderNavChild = function (navIndex, childIndex) {
const navs = collectHeaderNav();
if (navs[navIndex] && navs[navIndex].children) {
navs[navIndex].children.splice(childIndex, 1);
renderHeaderNav(navs);
}
};
// ========== 底部导航(简化) ==========
function renderFooterNav(navs) {
const container = document.getElementById('footerNavList');