@@ -731,12 +821,17 @@ import { CanvasRenderer } from 'echarts/renderers'
import {
getConfigSection, saveConfigSection, uploadImage, getRsvpList, getUploadConfig, saveUploadConfig,
getDanmakuList, updateDanmakuStatus, getVisitStats, getVisitList,
+ getPosterConfig, savePosterConfig,
} from '@/api/wedding'
import { useAdminStore } from '@/stores/admin'
import ImageField from '@/components/ImageField.vue'
import { BORDER_STYLES, borderClass } from '@/composables/borderStyles'
import { resolveDanmakuSwatch } from '@/utils/danmakuColors'
import { getSlotResizeSpecs, resizeSlotToFile, probeResizedMeta, metaHasFileSize } from '@/composables/resizeImage'
+import {
+ defaultPosterBundle, normalizePosterBundle, normalizePosterConfig,
+ LOADING_EFFECTS, ENTER_EFFECTS, POSTER_SIDES,
+} from '@/composables/posterDefaults'
echarts.use([PieChart, TooltipComponent, LegendComponent, CanvasRenderer])
@@ -745,7 +840,7 @@ const adminStore = useAdminStore()
const TAB_KEY = 'wedding_admin_active_tab'
const CONFIG_SECTIONS = ['basic', 'copy', 'visual', 'music', 'photos', 'schedule']
-const VALID_TABS = ['overview', ...CONFIG_SECTIONS, 'upload', 'rsvp', 'danmaku']
+const VALID_TABS = ['overview', ...CONFIG_SECTIONS, 'upload', 'poster', 'rsvp', 'danmaku']
const SECTION_KEYS = {
basic: ['groom', 'bride', 'date', 'lunar', 'calendarDate', 'hotel', 'address', 'heroImg', 'endImg'],
@@ -774,6 +869,8 @@ const uploading = ref(false)
const resizingPage = ref(false)
const resizeProgress = ref('')
const uploadConfigSaving = ref(false)
+const posterSaving = ref(false)
+const posterLoading = ref(false)
const tabLoading = ref(false)
const rsvpLoading = ref(false)
const rsvpList = ref([])
@@ -791,6 +888,22 @@ let regionChart = null
const cfg = reactive(defaultConfig())
const uploadCfg = reactive(defaultUploadConfig())
+const posterSideTab = ref('male')
+const posterBundle = reactive(defaultPosterBundle())
+const posterCfg = computed(() => posterBundle[posterSideTab.value] || posterBundle.male)
+const posterLinesText = computed({
+ get: () => {
+ const lines = posterCfg.value?.lines
+ return Array.isArray(lines) ? lines.join('\n') : ''
+ },
+ set: (v) => {
+ const side = posterSideTab.value
+ if (!posterBundle[side]) posterBundle[side] = normalizePosterConfig(null, side)
+ posterBundle[side].lines = String(v || '')
+ .split('\n')
+ .map((s) => s.trimEnd())
+ },
+})
const currentPhotoIndex = computed(() => Math.min(Number(activePhotoTab.value) || 0, Math.max(cfg.photoPages.length - 1, 0)))
const isConfigTab = computed(() => CONFIG_SECTIONS.includes(activeTab.value))
const visitPagination = computed(() => ({
@@ -1206,6 +1319,36 @@ async function onSaveUploadConfig() {
}
}
+async function loadPosterConfig() {
+ posterLoading.value = true
+ try {
+ const res = await getPosterConfig()
+ const bundle = normalizePosterBundle(res.data || {})
+ posterBundle.male = bundle.male
+ posterBundle.female = bundle.female
+ } catch (e) {
+ message.error(e?.message || '海报配置加载失败')
+ } finally {
+ posterLoading.value = false
+ }
+}
+
+async function onSavePosterConfig() {
+ posterSaving.value = true
+ try {
+ const payload = normalizePosterBundle(posterBundle)
+ const res = await savePosterConfig(payload)
+ const bundle = normalizePosterBundle(res.data || payload)
+ posterBundle.male = bundle.male
+ posterBundle.female = bundle.female
+ message.success('海报配置已保存')
+ } catch (e) {
+ message.error(e?.message || '海报配置保存失败')
+ } finally {
+ posterSaving.value = false
+ }
+}
+
function pickSectionData(section) {
const keys = SECTION_KEYS[section] || []
const data = {}
@@ -1390,6 +1533,10 @@ async function onTabActivate(tab) {
await loadUploadConfig()
return
}
+ if (tab === 'poster') {
+ await loadPosterConfig()
+ return
+ }
if (tab === 'rsvp') {
await loadRsvp()
return
@@ -1400,6 +1547,10 @@ async function onTabActivate(tab) {
}
function openPreview() { window.open('/', '_blank') }
+function openPosterPreview(side = 'male') {
+ const meta = POSTER_SIDES.find((s) => s.key === side) || POSTER_SIDES[0]
+ window.open(meta.route, '_blank')
+}
function onLogout() {
adminStore.logout()
diff --git a/vite-tailwindcss/src/views/hb/index.vue b/vite-tailwindcss/src/views/hb/index.vue
new file mode 100644
index 0000000..3ece147
--- /dev/null
+++ b/vite-tailwindcss/src/views/hb/index.vue
@@ -0,0 +1,862 @@
+
+
+
+
+ 囍
+ 囍
+ 囍
+ 囍
+ 囍
+ 囍
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
囍
+
+
+
+
+
+
+
囍
+
囍
+
+
+
+
+
+
+
+
+
+
+
![]()
+
婚礼照片
+
囍
+
囍
+
+
+
+
+
+ 囍
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vite-tailwindcss/vite.config.js b/vite-tailwindcss/vite.config.js
index b54e842..c342a39 100644
--- a/vite-tailwindcss/vite.config.js
+++ b/vite-tailwindcss/vite.config.js
@@ -17,10 +17,10 @@ export default defineConfig({
server: {
port: 8888,
proxy: {
- // 婚礼纪 Go 后端运行在 :8080,接口统一以 /api 开头,无需重写
+ // 婚礼纪 Go 后端运行在 :15201,接口统一以 /api 开头,无需重写
'/api': {
- // target: 'http://127.0.0.1:15201',
- target: 'https://hl.yqh.nailaoyun.cn',
+ target: 'http://127.0.0.1:15201',
+ // target: 'https://hl.yqh.nailaoyun.cn',
changeOrigin: true
}
}