[CMS-VISUAL] F1: 站点设置 Tab 化(7 Tab 独立表单/dirty/保存,增量合并互不连带)+ 新建渐进式向导(两步后全开放,无灰态)+ 自定义样式独立 Tab + 页脚/基础展示字段视觉位置说明(165 测试绿)
This commit is contained in:
@@ -30,6 +30,7 @@ export const SITE_CONFIG_FIELD_DEFS: SiteConfigFieldDef[] = [
|
||||
{
|
||||
key: "favicon", label: "浏览器图标 favicon", group: "display", kind: "asset", maxLength: 500,
|
||||
placeholder: "如 /yschcms/upload/…/favicon.png(留空用主题内置图标)",
|
||||
tip: "浏览器标签页与收藏夹的小图标,不显示在页面正文中。",
|
||||
},
|
||||
{
|
||||
key: "slogan", label: "首页标语", group: "display", kind: "text", maxLength: 200,
|
||||
@@ -43,6 +44,7 @@ export const SITE_CONFIG_FIELD_DEFS: SiteConfigFieldDef[] = [
|
||||
{
|
||||
key: "contact", label: "联系方式", group: "footer", kind: "text", maxLength: 200, multiline: true,
|
||||
placeholder: "如:电话 0571-88888888 · 地址杭州市 XX 路 100 号",
|
||||
tip: "显示在页脚品牌区(页脚第一行位置)。",
|
||||
},
|
||||
{
|
||||
key: "footer_addresses", label: "多校区地址", group: "footer", kind: "text", maxLength: 500, multiline: true,
|
||||
@@ -57,30 +59,37 @@ export const SITE_CONFIG_FIELD_DEFS: SiteConfigFieldDef[] = [
|
||||
{
|
||||
key: "qr_weibo", label: "微博二维码", group: "footer", kind: "asset", maxLength: 500,
|
||||
placeholder: "如 /yschcms/upload/…/qr-weibo.png(留空不展示)",
|
||||
tip: "显示在页脚右侧二维码区,与微信二维码并排,悬停放大预览。",
|
||||
},
|
||||
{
|
||||
key: "social_wechat", label: "微信公众号", group: "footer", kind: "url", maxLength: 500,
|
||||
placeholder: "微信公众号主页链接,如 https://mp.weixin.qq.com/…(留空不展示图标)",
|
||||
tip: "页脚社媒图标行(点击跳转链接地址)。",
|
||||
},
|
||||
{
|
||||
key: "social_weibo", label: "微博", group: "footer", kind: "url", maxLength: 500,
|
||||
placeholder: "微博主页链接 https://weibo.com/…(留空不展示图标)",
|
||||
tip: "页脚社媒图标行(点击跳转链接地址)。",
|
||||
},
|
||||
{
|
||||
key: "social_douyin", label: "抖音", group: "footer", kind: "url", maxLength: 500,
|
||||
placeholder: "抖音主页链接 https://www.douyin.com/…(留空不展示图标)",
|
||||
tip: "页脚社媒图标行(点击跳转链接地址)。",
|
||||
},
|
||||
{
|
||||
key: "social_bilibili", label: "哔哩哔哩", group: "footer", kind: "url", maxLength: 500,
|
||||
placeholder: "B 站主页链接 https://space.bilibili.com/…(留空不展示图标)",
|
||||
tip: "页脚社媒图标行(点击跳转链接地址)。",
|
||||
},
|
||||
{
|
||||
key: "copyright", label: "版权文字", group: "footer", kind: "text", maxLength: 200,
|
||||
placeholder: "如:XX学校 · 版权所有 © 2026",
|
||||
tip: "页脚最底行的版权声明文字。",
|
||||
},
|
||||
{
|
||||
key: "beian", label: "备案号", group: "footer", kind: "text", maxLength: 100,
|
||||
placeholder: "如:浙ICP备XXXXXXXX号-1",
|
||||
tip: "页脚最底行版权文字旁的 ICP 备案号(可点击性质由模板决定,通常为纯文字)。",
|
||||
},
|
||||
{
|
||||
key: "seo_description", label: "SEO 描述", group: "seo", kind: "text", maxLength: 500, multiline: true,
|
||||
@@ -180,6 +189,29 @@ export function serializeSiteConfig(model: SiteConfigFormModel): string {
|
||||
return JSON.stringify(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* F1(docs/20)Tab 独立保存:服务端事实源 base + 本 Tab 增量 patch 合并——
|
||||
* patch 值为空串/null/undefined = 删除该键;其余键原样保留。
|
||||
* 各 Tab 只提交自己的键空间,其他 Tab 未保存的内存修改不会被连带提交。
|
||||
*/
|
||||
export function mergeConfigPatch(base: string | undefined | null, patch: Record<string, unknown>): string {
|
||||
let obj: Record<string, unknown>;
|
||||
try {
|
||||
const parsed = base && base.trim() ? JSON.parse(base) : {};
|
||||
obj = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? { ...parsed } : {};
|
||||
} catch {
|
||||
obj = {};
|
||||
}
|
||||
Object.entries(patch).forEach(([k, v]) => {
|
||||
if (v === undefined || v === null || (typeof v === "string" && !v.trim())) {
|
||||
delete obj[k];
|
||||
} else {
|
||||
obj[k] = v;
|
||||
}
|
||||
});
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
|
||||
/** 已知字段值校验:返回错误消息,空串=通过(与后端 validateConfigJson 同语义) */
|
||||
export function validateFieldValue(def: SiteConfigFieldDef, value: string): string {
|
||||
const v = (value || "").trim();
|
||||
|
||||
Reference in New Issue
Block a user