From 211305c10ca612e64ec47d47e60ee0cd987d5f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=90=A6?= Date: Mon, 3 Aug 2026 10:22:04 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E6=B5=B7=E6=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hunliji-api/posterconfig/poster.go | 12 +- .../src/composables/posterDefaults.js | 106 ++++++++++++++---- vite-tailwindcss/src/router/index.js | 6 + .../src/views/admin/AdminEditor.vue | 50 ++++++--- vite-tailwindcss/src/views/hb/index.vue | 4 +- 5 files changed, 137 insertions(+), 41 deletions(-) diff --git a/hunliji-api/posterconfig/poster.go b/hunliji-api/posterconfig/poster.go index 45747ed..d6df4b0 100644 --- a/hunliji-api/posterconfig/poster.go +++ b/hunliji-api/posterconfig/poster.go @@ -23,7 +23,7 @@ func Register(api *gin.RouterGroup, database *gorm.DB, adminGuard func(*gin.Cont api.POST("/poster/config", handleSavePosterConfig) } -// resolveSide 返回 "1"(男方)或 "2"(女方);无法识别返回空 +// resolveSide 返回 "1"(男方)、"2"(女方)或 "3"(回门宴);无法识别返回空 func resolveSide(raw string) string { v := strings.ToLower(strings.TrimSpace(raw)) switch v { @@ -31,6 +31,8 @@ func resolveSide(raw string) string { return "1" case "2", "female", "nv", "f", "bride": return "2" + case "3", "hm", "hmy", "return", "huimen": + return "3" default: return "" } @@ -40,7 +42,7 @@ func isLegacyFlat(m map[string]interface{}) bool { if m == nil { return false } - for _, k := range []string{"1", "2", "male", "female"} { + for _, k := range []string{"1", "2", "3", "male", "female", "hm"} { if _, ok := m[k]; ok { return false } @@ -73,7 +75,7 @@ func takeSide(raw map[string]interface{}, keys ...string) map[string]interface{} return emptyObj() } -// normalizeBundle 统一为 { "1", "2" };兼容旧 male/female 与扁平配置 +// normalizeBundle 统一为 { "1", "2", "3" };兼容旧 male/female 与扁平配置 func normalizeBundle(raw map[string]interface{}) map[string]interface{} { if raw == nil { raw = emptyObj() @@ -81,6 +83,7 @@ func normalizeBundle(raw map[string]interface{}) map[string]interface{} { out := map[string]interface{}{ "1": emptyObj(), "2": emptyObj(), + "3": emptyObj(), } if isLegacyFlat(raw) { out["1"] = raw @@ -92,6 +95,9 @@ func normalizeBundle(raw map[string]interface{}) map[string]interface{} { if f := takeSide(raw, "2", "female"); len(f) > 0 { out["2"] = f } + if h := takeSide(raw, "3", "hm", "hmy"); len(h) > 0 { + out["3"] = h + } return out } diff --git a/vite-tailwindcss/src/composables/posterDefaults.js b/vite-tailwindcss/src/composables/posterDefaults.js index 36d7ec6..afd2d9a 100644 --- a/vite-tailwindcss/src/composables/posterDefaults.js +++ b/vite-tailwindcss/src/composables/posterDefaults.js @@ -1,8 +1,9 @@ -/** 海报 side:1=男方(/hb-n),2=女方(/hb-nv) */ +/** 海报 side:1=男方(/hb-n),2=女方(/hb-nv),3=回门宴(/hb-hm) */ export const POSTER_SIDES = [ { key: 1, keyStr: '1', route: '/hb-n', label: '男方', short: 'n' }, { key: 2, keyStr: '2', route: '/hb-nv', label: '女方', short: 'nv' }, + { key: 3, keyStr: '3', route: '/hb-hm', label: '回门宴', short: 'hm' }, ] export const POSTER_TEMPLATES = [ @@ -17,11 +18,13 @@ export const MOBILE_LAYOUTS = [ { value: 'landscape', label: '横屏展示', desc: '手机端强制左右分栏' }, ] -/** 解析为 1 | 2,无法识别返回 0 */ +/** 解析为 1 | 2 | 3,无法识别返回 0 */ export function resolvePosterSide(input) { if (input === 1 || input === '1') return 1 if (input === 2 || input === '2') return 2 + if (input === 3 || input === '3') return 3 const v = String(input || '').trim().toLowerCase() + if (v === 'hm' || v === 'hmy' || v === 'return' || v === 'huimen') return 3 if (v === 'female' || v === 'nv' || v === 'f' || v === 'bride') return 2 if (v === 'male' || v === 'n' || v === 'm' || v === 'groom') return 1 return 0 @@ -32,6 +35,11 @@ export function sideKey(side) { return String(s) } +export function posterSideMeta(side) { + const s = resolvePosterSide(side) || 1 + return POSTER_SIDES.find((x) => x.key === s) || POSTER_SIDES[0] +} + function baseFields(side) { return { side: resolvePosterSide(side) || 1, @@ -42,6 +50,9 @@ function baseFields(side) { /** 二维码中心图;空则显示圆圈大囍 */ qrCenterImg: '', title: '婚礼邀请函', + /** 浏览器标签 / 分享用页面标题与描述(可与海报主标题不同) */ + pageTitle: '', + pageDescription: '', footer: '—诚挚邀请 ♥ 恭请光临—', loadingEffect: 'redSeal', enterEffect: 'fadeUp', @@ -68,22 +79,25 @@ export function defaultSide1PosterConfig() { ...baseFields(1), side: 1, sonLabel: '儿子:', - sonName: '张浩强', + sonName: '李琦', daughterInLawLabel: '儿媳:', - daughterInLawName: '刘佳怡', - groomName: '张浩强', - brideName: '刘佳怡', + daughterInLawName: '李逸烁', + groomName: '李琦', + brideName: '李逸烁', verticalSlogan: '吾家有喜', + dateText: '2026年9月4日 星期五', + lunarText: '农历七月廿三', + venueText: '山西省 阳泉市 芙蓉酒楼(阳泉店) 太行国际新城B区10号楼 二楼', lines: [ '各位亲朋好友', '吾家有喜 儿子结婚', '良辰已定 吉日待访', - '兹定于2026年10月3日 星期日', - '农历九月初八 中午11:08分', + '兹定于2026年9月4日 星期五', + '农历七月廿三 中午11:08分', '为儿子儿媳举办结婚典礼', '敬备喜宴 诚邀您携家人光临', - '地址:幸福大酒店二楼宴会厅', - '张国栋 & 陈晓玲 夫 妇 敬邀', + '地址:山西省 阳泉市 芙蓉酒楼(阳泉店) 二楼', + '李国贞 & 赵红燕 夫 妇 敬邀', ], } } @@ -93,27 +107,68 @@ export function defaultSide2PosterConfig() { return { ...baseFields(2), side: 2, + template: 'split', + mobileLayout: 'landscape', sonLabel: '女儿:', - sonName: '刘佳怡', + sonName: '李逸烁', daughterInLawLabel: '女婿:', - daughterInLawName: '张浩强', - groomName: '张浩强', - brideName: '刘佳怡', + daughterInLawName: '李琦', + groomName: '李琦', + brideName: '李逸烁', verticalSlogan: '小女出阁', + dateText: '2026年9月4日 星期五', + lunarText: '农历七月廿三', + venueText: '山西省 阳泉市 芙蓉酒楼(阳泉店) 太行国际新城B区10号楼 二楼', lines: [ '各位亲朋好友', '吾家有喜 女儿出嫁', '良辰已定 吉日待访', - '兹定于2026年10月3日 星期日', - '农历九月初八 中午11:08分', + '兹定于2026年9月4日 星期五', + '农历七月廿三 中午11:08分', '为女儿女婿举办结婚典礼', '敬备喜宴 诚邀您携家人光临', - '地址:幸福大酒店二楼宴会厅', + '地址:山西省 阳泉市 芙蓉酒楼(阳泉店) 太行国际新城B区10号楼 二楼', '刘建国 & 王秀兰 夫 妇 敬邀', ], } } +/** 回门宴(3) 默认:9月7日 */ +export function defaultSide3PosterConfig() { + return { + ...baseFields(3), + side: 3, + template: 'classic', + title: '回门宴邀请函', + footer: '—回门宴请 ♥ 恭请光临—', + sonLabel: '新郎:', + sonName: '李琦', + daughterInLawLabel: '新娘:', + daughterInLawName: '李逸烁', + groomName: '李琦', + brideName: '李逸烁', + verticalSlogan: '回门之喜', + subSlogan1: '琴瑟和鸣', + subSlogan2: '永结同心', + dateText: '2026年9月7日 星期一', + lunarText: '农历七月廿六', + venueText: '山西省 阳泉市 芙蓉酒楼(阳泉店) 太行国际新城B区10号楼 二楼', + enterEffect: 'curtain', + loadingEffect: 'redSeal', + lines: [ + '各位亲朋好友', + '新婚燕尔 回门宴请', + '良辰已定 吉日待访', + '兹定于2026年9月7日 星期一', + '农历七月廿六 中午11:08分', + '为新婚夫妇举办回门宴', + '敬备薄酒 诚邀您携家人光临', + '地址:山西省 阳泉市 芙蓉酒楼(阳泉店) 太行国际新城B区10号楼 二楼', + '李琦 & 李逸烁 敬邀', + ], + } +} + export function defaultMalePosterConfig() { return defaultSide1PosterConfig() } @@ -128,9 +183,17 @@ export function defaultPosterBundle() { return { '1': defaultSide1PosterConfig(), '2': defaultSide2PosterConfig(), + '3': defaultSide3PosterConfig(), } } +export function defaultPosterForSide(side) { + const s = resolvePosterSide(side) || 1 + if (s === 3) return defaultSide3PosterConfig() + if (s === 2) return defaultSide2PosterConfig() + return defaultSide1PosterConfig() +} + export const LOADING_EFFECTS = [ { value: 'fade', label: '淡入加载' }, { value: 'redSeal', label: '红印囍字' }, @@ -145,7 +208,7 @@ export const ENTER_EFFECTS = [ function isLegacyFlatPoster(raw) { if (!raw || typeof raw !== 'object') return false - if (raw['1'] || raw['2'] || raw[1] || raw[2] || raw.male || raw.female) return false + if (raw['1'] || raw['2'] || raw['3'] || raw[1] || raw[2] || raw[3] || raw.male || raw.female) return false return 'title' in raw || 'lines' in raw || 'heroImg' in raw || 'sonName' in raw || 'template' in raw } @@ -154,12 +217,13 @@ function pickSideSource(loaded, side) { if (loaded[k] && typeof loaded[k] === 'object') return loaded[k] if (side === 1 && loaded.male && typeof loaded.male === 'object') return loaded.male if (side === 2 && loaded.female && typeof loaded.female === 'object') return loaded.female + if (side === 3 && loaded.hm && typeof loaded.hm === 'object') return loaded.hm return null } export function normalizePosterConfig(raw, side = 1) { const s = resolvePosterSide(side) || 1 - const base = s === 2 ? defaultSide2PosterConfig() : defaultSide1PosterConfig() + const base = defaultPosterForSide(s) const loaded = raw && typeof raw === 'object' ? raw : {} const lines = Array.isArray(loaded.lines) ? loaded.lines.map((l) => String(l ?? '')) @@ -205,18 +269,20 @@ export function normalizePosterConfig(raw, side = 1) { } } -/** 归一化为 { 1, 2 };兼容旧 male/female 与扁平数据 */ +/** 归一化为 { 1, 2, 3 };兼容旧 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(), } } return { '1': normalizePosterConfig(pickSideSource(loaded, 1) || {}, 1), '2': normalizePosterConfig(pickSideSource(loaded, 2) || {}, 2), + '3': normalizePosterConfig(pickSideSource(loaded, 3) || {}, 3), } } diff --git a/vite-tailwindcss/src/router/index.js b/vite-tailwindcss/src/router/index.js index 5373b0e..20ac881 100644 --- a/vite-tailwindcss/src/router/index.js +++ b/vite-tailwindcss/src/router/index.js @@ -24,6 +24,12 @@ const routes = [ component: () => import('@/views/hb/index.vue'), meta: { posterSide: 2 }, }, + { + path: '/hb-hm', + name: 'PosterReturnBanquet', + component: () => import('@/views/hb/index.vue'), + meta: { posterSide: 3 }, + }, { path: '/login', name: 'Login', diff --git a/vite-tailwindcss/src/views/admin/AdminEditor.vue b/vite-tailwindcss/src/views/admin/AdminEditor.vue index c3869fc..f349d50 100644 --- a/vite-tailwindcss/src/views/admin/AdminEditor.vue +++ b/vite-tailwindcss/src/views/admin/AdminEditor.vue @@ -19,8 +19,9 @@ @@ -410,23 +411,22 @@ - + - - + - {{ posterSideTab === '2' ? '2 · 女方' : '1 · 男方' }} - 路由 {{ posterSideTab === '2' ? '/hb-nv' : '/hb-n' }} + {{ currentPosterSide.key }} · {{ currentPosterSide.label }} + 路由 {{ currentPosterSide.route }} @@ -475,13 +475,18 @@ - +
不配置时,二维码中心为圆圈大「囍」字
@@ -490,15 +495,15 @@