底部导航子菜单可视化配置
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
yiqiu
2025-12-28 22:07:48 +08:00
parent 2846561d8c
commit de313ebf13

View File

@@ -671,11 +671,12 @@
const hasChildren = Array.isArray(nav.children) && nav.children.length > 0; const hasChildren = Array.isArray(nav.children) && nav.children.length > 0;
const item = document.createElement('div'); const item = document.createElement('div');
item.className = 'config-item'; item.className = 'config-item';
item.style.borderLeft = '3px solid #52c41a'; // 绿色标识
item.innerHTML = ` item.innerHTML = `
<div class="config-item__header"> <div class="config-item__header" style="background:#f6ffed;">
<h4>导航 ${index + 1}: ${nav.name || '(未命名)'}</h4> <h4 style="color:#52c41a;">导航 ${index + 1}: ${nav.name || '(未命名)'}</h4>
<div style="display: flex; gap: 4px;"> <div style="display: flex; gap: 4px;">
<button class="btn btn-secondary btn-sm" id="toggle-nav-${index}" onclick="toggleHeaderNavChildren(${index})" style="font-size:12px;">${hasChildren && nav.children.length > 0 ? '收起子菜单' : '展开子菜单'}</button> <button class="btn btn-success btn-sm" id="toggle-nav-${index}" onclick="toggleHeaderNavChildren(${index})" style="font-size:12px;">${hasChildren && nav.children.length > 0 ? '收起子菜单' : '展开子菜单'}</button>
<button class="btn-icon btn-icon-danger" onclick="removeHeaderNav(${index})">×</button> <button class="btn-icon btn-icon-danger" onclick="removeHeaderNav(${index})">×</button>
</div> </div>
</div> </div>
@@ -809,47 +810,93 @@
} }
}; };
// ========== 底部导航(简化) ========== // ========== 底部导航(完整版 - 支持子菜单) ==========
function renderFooterNav(navs) { function renderFooterNav(navs) {
const container = document.getElementById('footerNavList'); const container = document.getElementById('footerNavList');
if (!container) return; if (!container) return;
container.innerHTML = ''; container.innerHTML = '';
navs.forEach((col, index) => { navs.forEach((col, index) => {
const hasChildren = Array.isArray(col.children) && col.children.length > 0;
const item = document.createElement('div'); const item = document.createElement('div');
item.className = 'config-item'; item.className = 'config-item';
item.style.borderLeft = '3px solid #1890ff'; // 蓝色标识
item.innerHTML = ` item.innerHTML = `
<div class="config-item__header"> <div class="config-item__header" style="background:#e6f7ff;">
<h4>栏目 ${index + 1}</h4> <h4 style="color:#1890ff;">栏目 ${index + 1}: ${col.name || '(未命名)'}</h4>
<button class="btn-icon btn-icon-danger" onclick="removeFooterNav(${index})">×</button> <div style="display: flex; gap: 4px;">
<button class="btn btn-primary btn-sm" id="toggle-footer-${index}" onclick="toggleFooterNavChildren(${index})" style="font-size:12px;">${hasChildren && col.children.length > 0 ? '收起链接列表' : '展开链接列表'}</button>
<button class="btn-icon btn-icon-danger" onclick="removeFooterNav(${index})">×</button>
</div>
</div> </div>
<div class="config-item__body"> <div class="config-item__body">
<div class="form-item"> <div class="form-item">
<label>栏目名称</label> <label>栏目名称</label>
<input type="text" class="form-control" data-fnav="${index}" data-field="name" value="${col.name || ''}" placeholder="热门云产品"> <input type="text" class="form-control" data-fnav="${index}" data-field="name" value="${col.name || ''}" placeholder="热门云产品">
</div> </div>
<div class="form-item"> <div id="footer-nav-children-${index}" style="display:${hasChildren ? 'block' : 'none'}; margin-top:12px; padding-top:12px; border-top:1px solid #d9d9d9;">
<div style="font-size:13px;color:#666;">链接列表请使用JSON编辑器配置</div> <h5 style="margin:0 0 8px; font-size:13px; color:#1890ff;">链接列表</h5>
<div id="footer-nav-children-list-${index}"></div>
<button class="btn btn-primary btn-sm" onclick="addFooterNavChild(${index})" style="margin-top:8px;">+ 添加链接</button>
</div> </div>
</div> </div>
`; `;
container.appendChild(item); container.appendChild(item);
if (hasChildren) {
renderFooterNavChildren(index, col.children);
}
});
}
function renderFooterNavChildren(navIndex, children) {
const container = document.getElementById(`footer-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:#f0f8ff; border-radius:4px; border-left:2px solid #1890ff;';
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-fnav-child="${navIndex}.${childIndex}" data-field="name" value="${child.name || ''}" placeholder="链接名称">
<input type="text" class="form-control" data-fnav-child="${navIndex}.${childIndex}" data-field="url" value="${child.url || ''}" placeholder="链接地址">
<label style="font-size:12px;"><input type="checkbox" data-fnav-child="${navIndex}.${childIndex}" data-field="blank" ${child.blank ? 'checked' : ''}> 新窗口打开</label>
</div>
<button class="btn-icon btn-icon-danger" onclick="removeFooterNavChild(${navIndex}, ${childIndex})" style="margin-left:8px;">×</button>
</div>
`;
container.appendChild(item);
}); });
} }
function collectFooterNav() { function collectFooterNav() {
const navs = []; const navs = [];
// 收集栏目名称
document.querySelectorAll('[data-fnav]').forEach(input => { document.querySelectorAll('[data-fnav]').forEach(input => {
const index = parseInt(input.dataset.fnav); const index = parseInt(input.dataset.fnav);
if (!navs[index]) navs[index] = { children: [] }; if (!navs[index]) navs[index] = { children: [] };
navs[index][input.dataset.field] = input.value; navs[index][input.dataset.field] = input.value;
}); });
// 保留原有的children
const orig = config.footer_nav || []; // 收集链接列表
navs.forEach((nav, i) => { document.querySelectorAll('[data-fnav-child]').forEach(input => {
if (orig[i] && orig[i].children) { const [navIndex, childIndex] = input.dataset.fnavChild.split('.').map(Number);
nav.children = orig[i].children; 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); return navs.filter(n => n);
} }
@@ -865,6 +912,41 @@
renderFooterNav(navs); renderFooterNav(navs);
}; };
window.toggleFooterNavChildren = function (index) {
const container = document.getElementById(`footer-nav-children-${index}`);
const toggleBtn = document.getElementById(`toggle-footer-${index}`);
if (container && toggleBtn) {
const isHidden = container.style.display === 'none';
container.style.display = isHidden ? 'block' : 'none';
toggleBtn.textContent = isHidden ? '收起链接列表' : '展开链接列表';
}
};
window.addFooterNavChild = function (navIndex) {
const navs = collectFooterNav();
if (!navs[navIndex]) navs[navIndex] = { children: [] };
if (!navs[navIndex].children) navs[navIndex].children = [];
navs[navIndex].children.push({
name: '',
url: '',
blank: false
});
renderFooterNav(navs);
// 确保展开
document.getElementById(`footer-nav-children-${navIndex}`).style.display = 'block';
};
window.removeFooterNavChild = function (navIndex, childIndex) {
const navs = collectFooterNav();
if (navs[navIndex] && navs[navIndex].children) {
navs[navIndex].children.splice(childIndex, 1);
renderFooterNav(navs);
}
};
// 文件上传 // 文件上传
document.addEventListener('click', (e) => { document.addEventListener('click', (e) => {