feat(admin): 备案号可编辑,页脚模板由服务端生成
备案号原来只能写死在 pageInfo.footer 的 HTML 里。现在 /admin/ 站点信息 拆出「ICP 备案号」「公安备案号」两个输入框,页脚 HTML 由服务端 beianFooter() 统一按模板生成(含 html.EscapeString 转义), 自定义页脚 HTML 降级为「高级」折叠项;旧 footer 会被解析回填到字段。 conf.example.yml 里重复的 .navi-search-bar 规则已由 web/navi.css 接管,删除。
This commit is contained in:
@ -88,10 +88,16 @@ details summary{cursor:pointer;font-size:13px;font-weight:600;color:var(--tx2)}
|
||||
<div class="fg"><label>标题</label><input id="p-title" placeholder="JianF 统一门户"></div>
|
||||
<div class="fg"><label>副标题</label><input id="p-desc" placeholder="内网服务导航"></div>
|
||||
</div>
|
||||
<div class="fg" style="margin-bottom:12px">
|
||||
<label>页脚(可含 HTML)</label>
|
||||
<textarea id="p-footer" placeholder="留空则不显示"></textarea>
|
||||
<div class="row">
|
||||
<div class="fg"><label>ICP 备案号</label><input id="p-icp" placeholder="京ICP备00000000号-1"></div>
|
||||
<div class="fg"><label>公安备案号(可选)</label><input id="p-gongan" placeholder="京公网安备00000000000000号"></div>
|
||||
</div>
|
||||
<details style="margin:12px 0">
|
||||
<summary style="cursor:pointer;font-size:13px;color:#475569">高级:自定义页脚 HTML</summary>
|
||||
<div class="fg" style="margin-top:8px">
|
||||
<textarea id="p-footer" placeholder="留空则按上面的备案号自动生成;填写后以这里为准"></textarea>
|
||||
</div>
|
||||
</details>
|
||||
<label>顶部导航链接</label>
|
||||
<div id="navlinks" style="margin:8px 0 10px"></div>
|
||||
<button class="ghost icon-btn" id="add-link">+ 添加链接</button>
|
||||
@ -237,6 +243,17 @@ function renderNavLinks() {
|
||||
});
|
||||
}
|
||||
|
||||
/* ── 备案号 ──
|
||||
备案号直接编辑,页脚 HTML 由服务端模板生成;高级模式下可整段覆盖。 */
|
||||
function parseIcp(html) {
|
||||
const m = /[\u4e00-\u9fa5]{2}ICP备\d+号(-\d+)?/.exec(html || '');
|
||||
return m ? m[0] : '';
|
||||
}
|
||||
function parseGongan(html) {
|
||||
const m = /[\u4e00-\u9fa5]{2}公网安备\d+号/.exec(html || '');
|
||||
return m ? m[0] : '';
|
||||
}
|
||||
|
||||
async function loadPageInfo() {
|
||||
try {
|
||||
const r = await fetch(A + '/pageinfo', { headers: authHeaders() });
|
||||
@ -248,7 +265,12 @@ async function loadPageInfo() {
|
||||
}
|
||||
document.getElementById('p-title').value = PAGE.title || '';
|
||||
document.getElementById('p-desc').value = PAGE.description || '';
|
||||
document.getElementById('p-footer').value = PAGE.footer || '';
|
||||
const icp = PAGE.icp || parseIcp(PAGE.footer);
|
||||
const gongan = PAGE.gongan || parseGongan(PAGE.footer);
|
||||
document.getElementById('p-icp').value = icp;
|
||||
document.getElementById('p-gongan').value = gongan;
|
||||
// 能从备案号字段还原时,高级 HTML 留空,保存时按模板重新生成
|
||||
document.getElementById('p-footer').value = (icp || gongan) ? '' : (PAGE.footer || '');
|
||||
if (!PAGE.navLinks && PAGE.navLinks !== null) PAGE.navLinks = [];
|
||||
renderNavLinks();
|
||||
}
|
||||
@ -263,6 +285,9 @@ document.getElementById('save-info').addEventListener('click', async () => {
|
||||
const body = {
|
||||
title: document.getElementById('p-title').value,
|
||||
description: document.getElementById('p-desc').value,
|
||||
icp: document.getElementById('p-icp').value,
|
||||
gongan: document.getElementById('p-gongan').value,
|
||||
// 留空 = 交给服务端按备案号生成模板;填写则整段覆盖
|
||||
footer: document.getElementById('p-footer').value,
|
||||
navLinks: (PAGE.navLinks || []).filter(l => l && (l.name || l.url)),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user