1. 修复海报图片
This commit is contained in:
@@ -6,6 +6,12 @@ export const POSTER_SIDES = [
|
||||
{ key: 3, keyStr: '3', route: '/hb-hm', label: '回门宴', short: 'hm' },
|
||||
]
|
||||
|
||||
/** 布局:1=竖版,2=横版(URL 后缀 /1 /2) */
|
||||
export const POSTER_LAYOUTS = [
|
||||
{ value: '1', label: '竖版', desc: '经典竖向 / portrait', mobileLayout: 'portrait', template: 'classic' },
|
||||
{ value: '2', label: '横版', desc: '左图右文 / landscape', mobileLayout: 'landscape', template: 'split' },
|
||||
]
|
||||
|
||||
export const POSTER_TEMPLATES = [
|
||||
{ value: 'classic', label: '经典竖版', desc: '顶图 + 正文逐行出现' },
|
||||
{ value: 'split', label: '左图右文', desc: '竖排书法 + 右侧宴席信息' },
|
||||
@@ -109,9 +115,34 @@ export function posterSideMeta(side) {
|
||||
return POSTER_SIDES.find((x) => x.key === s) || POSTER_SIDES[0]
|
||||
}
|
||||
|
||||
/** 解析布局 1|2,无法识别默认 1(竖版) */
|
||||
export function resolvePosterLayout(input) {
|
||||
if (input === 2 || input === '2') return 2
|
||||
if (input === 1 || input === '1') return 1
|
||||
const v = String(input || '').trim().toLowerCase()
|
||||
if (v === 'landscape' || v === 'h' || v === 'heng' || v === '横版') return 2
|
||||
if (v === 'portrait' || v === 'v' || v === 'shu' || v === '竖版') return 1
|
||||
return 1
|
||||
}
|
||||
|
||||
export function layoutKey(layout) {
|
||||
return String(resolvePosterLayout(layout))
|
||||
}
|
||||
|
||||
export function posterLayoutMeta(layout) {
|
||||
const k = layoutKey(layout)
|
||||
return POSTER_LAYOUTS.find((x) => x.value === k) || POSTER_LAYOUTS[0]
|
||||
}
|
||||
|
||||
export function posterRoute(side, layout = 1) {
|
||||
const meta = posterSideMeta(side)
|
||||
return `${meta.route}/${layoutKey(layout)}`
|
||||
}
|
||||
|
||||
function baseFields(side) {
|
||||
return {
|
||||
side: resolvePosterSide(side) || 1,
|
||||
layout: 1,
|
||||
template: 'classic',
|
||||
mobileLayout: 'auto',
|
||||
enabled: true,
|
||||
@@ -259,14 +290,6 @@ export function defaultPosterConfig() {
|
||||
return defaultSide1PosterConfig()
|
||||
}
|
||||
|
||||
export function defaultPosterBundle() {
|
||||
return {
|
||||
'1': defaultSide1PosterConfig(),
|
||||
'2': defaultSide2PosterConfig(),
|
||||
'3': defaultSide3PosterConfig(),
|
||||
}
|
||||
}
|
||||
|
||||
export function defaultPosterForSide(side) {
|
||||
const s = resolvePosterSide(side) || 1
|
||||
if (s === 3) return defaultSide3PosterConfig()
|
||||
@@ -274,6 +297,36 @@ export function defaultPosterForSide(side) {
|
||||
return defaultSide1PosterConfig()
|
||||
}
|
||||
|
||||
/** 按侧 + 布局生成默认配置(竖=classic/portrait,横=split/landscape) */
|
||||
export function defaultPosterForLayout(side, layout = 1) {
|
||||
const s = resolvePosterSide(side) || 1
|
||||
const l = resolvePosterLayout(layout)
|
||||
const base = defaultPosterForSide(s)
|
||||
const meta = posterLayoutMeta(l)
|
||||
return {
|
||||
...base,
|
||||
side: s,
|
||||
layout: l,
|
||||
template: meta.template,
|
||||
mobileLayout: meta.mobileLayout,
|
||||
}
|
||||
}
|
||||
|
||||
export function defaultSideLayouts(side) {
|
||||
return {
|
||||
'1': defaultPosterForLayout(side, 1),
|
||||
'2': defaultPosterForLayout(side, 2),
|
||||
}
|
||||
}
|
||||
|
||||
export function defaultPosterBundle() {
|
||||
return {
|
||||
'1': defaultSideLayouts(1),
|
||||
'2': defaultSideLayouts(2),
|
||||
'3': defaultSideLayouts(3),
|
||||
}
|
||||
}
|
||||
|
||||
export const LOADING_EFFECTS = [
|
||||
{ value: 'fade', label: '淡入加载' },
|
||||
{ value: 'redSeal', label: '红印囍字' },
|
||||
@@ -292,6 +345,19 @@ function isLegacyFlatPoster(raw) {
|
||||
return 'title' in raw || 'lines' in raw || 'heroImg' in raw || 'sonName' in raw || 'template' in raw
|
||||
}
|
||||
|
||||
/** 判断对象是否为「单份海报配置」(扁平字段),而非 {1,2} 布局包 */
|
||||
function isFlatPosterConfig(obj) {
|
||||
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return false
|
||||
if (obj['1'] || obj['2'] || obj[1] || obj[2]) {
|
||||
const hasNestedLayout = [obj['1'], obj['2'], obj[1], obj[2]].some(
|
||||
(v) => v && typeof v === 'object' && ('title' in v || 'template' in v || 'heroImg' in v || 'lines' in v),
|
||||
)
|
||||
if (hasNestedLayout) return false
|
||||
}
|
||||
return 'title' in obj || 'lines' in obj || 'heroImg' in obj || 'sonName' in obj || 'template' in obj
|
||||
|| 'groomName' in obj || 'mobileLayout' in obj || 'pageTitle' in obj
|
||||
}
|
||||
|
||||
function pickSideSource(loaded, side) {
|
||||
const k = sideKey(side)
|
||||
if (loaded[k] && typeof loaded[k] === 'object') return loaded[k]
|
||||
@@ -301,12 +367,33 @@ function pickSideSource(loaded, side) {
|
||||
return null
|
||||
}
|
||||
|
||||
export function normalizePosterConfig(raw, side = 1) {
|
||||
const SHARED_COPY_KEYS = [
|
||||
'sonLabel', 'sonName', 'daughterInLawLabel', 'daughterInLawName',
|
||||
'groomName', 'brideName', 'dateText', 'lunarText', 'venueText',
|
||||
'lines', 'heroImg', 'heroFocusX', 'heroFocusY', 'qrCenterImg',
|
||||
'musicUrl', 'invitePath', 'inviteButtonText', 'showInviteButton',
|
||||
'enabled', 'pageTitle', 'pageDescription', 'footer', 'title',
|
||||
'greeting', 'verticalSlogan', 'subSlogan1', 'subSlogan2', 'loveFooter',
|
||||
'loadingEffect', 'enterEffect',
|
||||
]
|
||||
|
||||
function copySharedFields(from, into) {
|
||||
if (!from || !into) return into
|
||||
for (const k of SHARED_COPY_KEYS) {
|
||||
if (from[k] !== undefined && from[k] !== null && from[k] !== '') {
|
||||
into[k] = Array.isArray(from[k]) ? from[k].slice() : from[k]
|
||||
}
|
||||
}
|
||||
return into
|
||||
}
|
||||
|
||||
export function normalizePosterConfig(raw, side = 1, layout = 1) {
|
||||
const s = resolvePosterSide(side) || 1
|
||||
const base = defaultPosterForSide(s)
|
||||
const l = resolvePosterLayout(layout)
|
||||
const base = defaultPosterForLayout(s, l)
|
||||
const loaded = raw && typeof raw === 'object' ? raw : {}
|
||||
const lines = Array.isArray(loaded.lines)
|
||||
? loaded.lines.map((l) => String(l ?? ''))
|
||||
? loaded.lines.map((x) => String(x ?? ''))
|
||||
: base.lines
|
||||
const template = POSTER_TEMPLATES.some((t) => t.value === loaded.template)
|
||||
? loaded.template
|
||||
@@ -322,6 +409,7 @@ export function normalizePosterConfig(raw, side = 1) {
|
||||
...base,
|
||||
...loaded,
|
||||
side: s,
|
||||
layout: l,
|
||||
template,
|
||||
mobileLayout,
|
||||
lines: lines.length ? lines : base.lines,
|
||||
@@ -353,25 +441,69 @@ export function normalizePosterConfig(raw, side = 1) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 归一化为 { 1, 2, 3 };兼容旧 male/female 与扁平数据 */
|
||||
/** 将单侧数据归一为 { "1": 竖版, "2": 横版 } */
|
||||
export function normalizeSideLayouts(raw, side = 1) {
|
||||
const s = resolvePosterSide(side) || 1
|
||||
const src = raw && typeof raw === 'object' ? raw : {}
|
||||
|
||||
if (!isFlatPosterConfig(src) && (src['1'] || src['2'] || src[1] || src[2])) {
|
||||
const l1raw = (src['1'] && typeof src['1'] === 'object' ? src['1'] : null)
|
||||
|| (src[1] && typeof src[1] === 'object' ? src[1] : null)
|
||||
|| {}
|
||||
const l2raw = (src['2'] && typeof src['2'] === 'object' ? src['2'] : null)
|
||||
|| (src[2] && typeof src[2] === 'object' ? src[2] : null)
|
||||
|| {}
|
||||
const l1 = normalizePosterConfig(l1raw, s, 1)
|
||||
l1.mobileLayout = 'portrait'
|
||||
l1.layout = 1
|
||||
let l2
|
||||
if (Object.keys(l2raw).length) {
|
||||
l2 = normalizePosterConfig(l2raw, s, 2)
|
||||
} else {
|
||||
l2 = defaultPosterForLayout(s, 2)
|
||||
copySharedFields(l1, l2)
|
||||
}
|
||||
l2.mobileLayout = 'landscape'
|
||||
l2.layout = 2
|
||||
return { '1': l1, '2': l2 }
|
||||
}
|
||||
|
||||
const flat = isFlatPosterConfig(src) ? src : {}
|
||||
const l1 = normalizePosterConfig(flat, s, 1)
|
||||
l1.mobileLayout = 'portrait'
|
||||
l1.layout = 1
|
||||
const l2 = defaultPosterForLayout(s, 2)
|
||||
copySharedFields(l1, l2)
|
||||
l2.mobileLayout = 'landscape'
|
||||
l2.layout = 2
|
||||
return { '1': l1, '2': l2 }
|
||||
}
|
||||
|
||||
/** 归一化为 { 1|2|3: { 1|2: cfg } };兼容旧 male/female、扁平与单侧扁平 */
|
||||
export function normalizePosterBundle(raw) {
|
||||
const loaded = raw && typeof raw === 'object' ? raw : {}
|
||||
if (isLegacyFlatPoster(loaded)) {
|
||||
return {
|
||||
'1': normalizePosterConfig(loaded, 1),
|
||||
'2': defaultSide2PosterConfig(),
|
||||
'3': defaultSide3PosterConfig(),
|
||||
'1': normalizeSideLayouts(loaded, 1),
|
||||
'2': defaultSideLayouts(2),
|
||||
'3': defaultSideLayouts(3),
|
||||
}
|
||||
}
|
||||
return {
|
||||
'1': normalizePosterConfig(pickSideSource(loaded, 1) || {}, 1),
|
||||
'2': normalizePosterConfig(pickSideSource(loaded, 2) || {}, 2),
|
||||
'3': normalizePosterConfig(pickSideSource(loaded, 3) || {}, 3),
|
||||
'1': normalizeSideLayouts(pickSideSource(loaded, 1) || {}, 1),
|
||||
'2': normalizeSideLayouts(pickSideSource(loaded, 2) || {}, 2),
|
||||
'3': normalizeSideLayouts(pickSideSource(loaded, 3) || {}, 3),
|
||||
}
|
||||
}
|
||||
|
||||
export function pickPosterSide(bundle, side) {
|
||||
export function pickPosterConfig(bundle, side, layout = 1) {
|
||||
const normalized = normalizePosterBundle(bundle)
|
||||
const s = sideKey(side)
|
||||
return normalized[s]
|
||||
const l = layoutKey(layout)
|
||||
return normalized[s]?.[l] || defaultPosterForLayout(s, l)
|
||||
}
|
||||
|
||||
/** @deprecated 兼容旧调用,默认取竖版 */
|
||||
export function pickPosterSide(bundle, side) {
|
||||
return pickPosterConfig(bundle, side, 1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user