🎨 邀请函编辑器

基于模板 "拼音模板H5版" 创建您的专属邀请函

内容设置 (拼音模板H5版)

该模板暂未定义可编辑字段,使用默认字段。

样式设置

预览设置

拼音模板H5版

拼音模板H5版

简单豪华

请在左侧填写邀请函内容,预览将实时更新

'; // 获取表单值并替换模板中的占位符 const title = document.getElementById('title')?.value || ''; const brideName = document.getElementById('bride_name')?.value || ''; const groomName = document.getElementById('groom_name')?.value || ''; const eventDate = document.getElementById('event_date')?.value || ''; const eventLocation = document.getElementById('event_location')?.value || ''; // 替换常见的占位符 fullHtml = fullHtml.replace(/ئالىمجان/g, groomName || '新郎姓名'); // 新郎名 fullHtml = fullHtml.replace(/ئادىلە/g, brideName || '新娘姓名'); // 新娘名 fullHtml = fullHtml.replace(/诚邀您参加我们的婚礼/g, title || '诚邀您参加我们的婚礼'); // 标题 fullHtml = fullHtml.replace(/2025-يىلى10-ئاينىڭ10-كۈنى سائەت بېيجىڭ ۋاقتى7:30 دا/g, eventDate ? new Date(eventDate).toLocaleDateString('zh-CN') : '待定日期'); fullHtml = fullHtml.replace(/ئۈرۈمچى غەربىي يۇلتۇز مەرىكە زالى/g, eventLocation || '举办地点'); fullHtml = fullHtml.replace(/ئۈرۈمچى شەھىرى ئازاتلىق يۇلى 100 نۇمۇر/g, eventLocation || '详细地址'); // 使用iframe显示模板内容 previewContainer.innerHTML = ``; // 设置iframe内容 - 简化设置 const iframe = document.getElementById('preview-iframe'); if (iframe) { console.log('设置iframe内容,fullHtml长度:', fullHtml.length); // 直接设置srcdoc,不使用try-catch iframe.srcdoc = fullHtml; console.log('iframe内容已设置'); } else { console.error('找不到iframe元素'); // 如果找不到iframe,直接显示HTML内容 previewContainer.innerHTML += '
预览内容:
' + fullHtml.substring(0, 1000) + '
'; } } else if (templateData.editable_fields && templateData.editable_fields.length > 0) { let html = generateTemplatePreviewHtml(); // 获取表单值 const title = document.getElementById('title')?.value || ''; const brideName = document.getElementById('bride_name')?.value || ''; const groomName = document.getElementById('groom_name')?.value || ''; const eventDate = document.getElementById('event_date')?.value || ''; const eventLocation = document.getElementById('event_location')?.value || ''; // 替换模板中的占位符文本 html = html.replace(/ئالىمجان/g, groomName || 'ئالىمجان'); // 新郎名 html = html.replace(/ئادىلە/g, brideName || 'ئادىلە'); // 新娘名 html = html.replace(/2025-يىلى10-ئاينىڭ10-كۈنى سائەت بېيجىڭ ۋاقتى7:30 دا/g, eventDate ? new Date(eventDate).toLocaleDateString('zh-CN') : '2025-يىلى10-ئاينىڭ10-كۈنى سائەت بېيجىڭ ۋاقتى7:30 دا'); html = html.replace(/ئۈرۈمچى غەربىي يۇلتۇز مەرىكە زالى/g, eventLocation || 'ئۈرۈمچى غەربىي يۇلتۇز مەرىكە زالى'); // 宴会厅 html = html.replace(/ئۈرۈمچى شەھىرى ئازاتلىق يۇلى 100 نۇمۇر/g, eventLocation || 'ئۈرۈمچى شەھىرى ئازاتلىق يۇلى 100 نۇمۇر'); // 宴会厅地址 previewContainer.innerHTML = html; } else { // fallback到原来的预览逻辑 const title = document.getElementById('title')?.value || ''; const brideName = document.getElementById('bride_name')?.value || ''; const groomName = document.getElementById('groom_name')?.value || ''; const eventDate = document.getElementById('event_date')?.value || ''; const eventLocation = document.getElementById('event_location')?.value || ''; const eventDescription = document.getElementById('event_description')?.value || ''; if (title || brideName || groomName || eventDate || eventLocation || eventDescription) { // 有内容时显示预览 previewContainer.innerHTML = `

${title || '邀请函标题'}

${brideName || groomName ? `
${brideName && groomName ? `${brideName} & ${groomName}` : brideName ? brideName : groomName}
喜结良缘
` : ''} ${eventDate ? `
举办时间
${new Date(eventDate).toLocaleString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' })}
` : ''} ${eventLocation ? `
举办地点
${eventLocation}
` : ''} ${eventDescription ? `
${eventDescription}
` : ''}
敬请光临 · 共赴良辰
`; } else { // 无内容时显示模板封面(而不是占位符) if (templateData.id) { previewContainer.innerHTML = `
拼音模板H5版

拼音模板H5版

简单豪华

请在左侧填写邀请函内容,预览将实时更新

`; } else { previewContainer.innerHTML = `

开始创建您的邀请函

请在左侧填写邀请函内容,预览将实时更新

`; } } } } // 保存草稿 function saveDraft() { const formData = new FormData(document.getElementById('invitation-form')); // 显示保存中状态 const saveBtn = event.target; const originalText = saveBtn.innerHTML; saveBtn.innerHTML = '
保存中...'; saveBtn.disabled = true; axios.post('/api/invitations/create/', formData, { headers: { 'X-CSRFToken': getCsrfToken() } }) .then(response => { if (response.data.success) { showNotification('草稿保存成功', 'success'); } else { showNotification(response.data.message || '保存失败', 'error'); } }) .catch(error => { console.error('保存失败:', error); showNotification('保存失败,请重试', 'error'); }) .finally(() => { saveBtn.innerHTML = originalText; saveBtn.disabled = false; }); } // 生成邀请函 function generateInvitation() { const form = document.getElementById('invitation-form'); if (!form.checkValidity()) { form.reportValidity(); return; } const formData = new FormData(form); // 显示生成中状态 const generateBtn = event.target; const originalText = generateBtn.innerHTML; generateBtn.innerHTML = '
生成中...'; generateBtn.disabled = true; axios.post('/api/invitations/create/', formData, { headers: { 'X-CSRFToken': getCsrfToken() } }) .then(response => { if (response.data.success) { showNotification('邀请函生成成功!', 'success'); // 跳转到邀请函详情页面 setTimeout(() => { window.location.href = `/invitations/${response.data.invitation_id}/`; }, 1500); } else { showNotification(response.data.message || '生成失败', 'error'); } }) .catch(error => { console.error('生成失败:', error); showNotification('生成失败,请重试', 'error'); }) .finally(() => { generateBtn.innerHTML = originalText; generateBtn.disabled = false; }); } // 刷新预览 function refreshPreview() { updatePreview(); showNotification('预览已刷新', 'info'); } // 完整预览 function previewFull() { const formData = new FormData(document.getElementById('invitation-form')); const params = new URLSearchParams(); for (let [key, value] of formData.entries()) { if (value) params.append(key, value); } // 打开新窗口进行完整预览 const previewUrl = `/invitations/preview/live/?${params}`; window.open(previewUrl, '_blank', 'width=400,height=600'); } // 模板数据 const templateData = { id: 39, name: "拼音模板H5版", html_content: "\u003C!DOCTYPE html\u003E\u000A\u003Chtml lang\u003D\u0022zh\u002DCN\u0022\u003E\u000A\u003Chead\u003E\u000A \u003Cmeta charset\u003D\u0022UTF\u002D8\u0022 /\u003E\u000A \u003Cmeta name\u003D\u0022viewport\u0022 content\u003D\u0022width\u003Ddevice\u002Dwidth, initial\u002Dscale\u003D1.0\u0022 /\u003E\u000A \u003Ctitle\u003E拼音模板H5版\u003C/title\u003E\u000A \u003C!\u002D\u002D Template styles will be injected here \u002D\u002D\u003E\u000A\u003C/head\u003E\u000A\u003Cbody\u003E\u003Cdiv class\u003D\u0022ds\u002Dstage\u002Dhost\u0022\u003E\u000A\u003Cdiv class\u003D\u0022ds\u002Dstage\u0022 data\u002Dstage\u002Dwidth\u003D\u0022390\u0022 data\u002Dstage\u002Dheight\u003D\u00224500\u0022 style\u003D\u0022position: relative\u003B width: 390px\u003B height: 4500px\u003B margin: 0 auto\u003B background: #ffffff\u003B overflow: visible\u003B\u0022\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 0px\u003B\u000A top: 1px\u003B\u000A width: 387.5px\u003B\u000A height: 564.4088282535279px\u003B\u000A background: #f5f5f5\u003B\u000A border\u002Dradius: 12px\u003B\u000A overflow: hidden\u003B\u000A opacity: 1\u003B\u000A box\u002Dshadow: 0 8px 24px rgba(15,23,42,0.12)\u003B\u000A \u0022\u003E\u000A \u003Cimg src\u003D\u0022/media/invitation_preview_images/1f/ee/1fee78596cc35fa3.jpg\u0022 alt\u003D\u0022轮播图\u0022 style\u003D\u0022\u000A width: 100%\u003B\u000A height: 100%\u003B\u000A object\u002Dfit: cover\u003B\u000A \u0022 /\u003E\u000A \u000A \u000A \u003C/div\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/d2/02/d2023fd21d8728f3.jpg\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 7.712752546381516px\u003B\u000A top: 3297.63824704047px\u003B\u000A width: 230.56171000814396px\u003B\u000A height: 339.14320204878254px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: cover\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/ae/8e/ae8e0c5405dec9ca.gif\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 107.90664378372527px\u003B\u000A top: 4237.698006552993px\u003B\u000A width: 190.90032005195047px\u003B\u000A height: 136.66614097747268px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: cover\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/ed/a1/eda13cc415226bdb.jpg\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 0px\u003B\u000A top: 1037.3382034411402px\u003B\u000A width: 387.5px\u003B\u000A height: 508.34848175998206px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: cover\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/62/f0/62f09b70c1656320.png\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 24.295885708984656px\u003B\u000A top: 4263.189792345168px\u003B\u000A width: 341.4082285820307px\u003B\u000A height: 231.45244138672962px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: cover\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 32.65743618287797px\u003B\u000A top: 4273.306512064358px\u003B\u000A width: 324.68512763424405px\u003B\u000A height: 82.1598095149744px\u003B\u000A background\u002Dcolor: rgba(0, 0, 0, 0)\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 50px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: center\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003EWEDDING\u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 17.5px\u003B\u000A top: 621.2601324044192px\u003B\u000A width: 355px\u003B\u000A height: 83.082544038734px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 60px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: center\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003ETaklip Name\u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 29.478489498964713px\u003B\u000A top: 716.3266492091641px\u003B\u000A width: 124.46006950254917px\u003B\u000A height: 59.9120898736013px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 20px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: left\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003EHormatlik:\u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 158.5714969410003px\u003B\u000A top: 723.7826941459648px\u003B\u000A width: 196.14125560538122px\u003B\u000A height: 44.99999999999999px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 20px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: left\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003EDoslar\u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 9.999999999999972px\u003B\u000A top: 9.90368480298332px\u003B\u000A width: 365.00000000000006px\u003B\u000A height: 50.30572419774502px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 41px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: center\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003EFaruk \u0026 Subinur\u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 24.491950868502954px\u003B\u000A top: 790.9859106885474px\u003B\u000A width: 341.0160982629941px\u003B\u000A height: 210.37051318693125px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 6px\u003B\u000A opacity: 1\u003B\u000A overflow: auto\u003B\u000A padding: 6px\u003B\u000A box\u002Dsizing: border\u002Dbox\u003B\u000A \u0022\u003E\u003Cp style\u003D\u0022text\u002Dalign: justify\u003B\u0022\u003E\u003Cspan style\u003D\u0022letter\u002Dspacing: 0px\u003B\u0022\u003E\u003Cb style\u003D\u0022\u0022\u003E\u0026nbsp\u003B \u0026nbsp\u003BHayatimizning ag guzal dakikilirida bizga bahit tiligan barlih doslirimiz bialn jam boluxni arzo kilip toy marikimizga taklip kilimiz!!!\u003C/b\u003E\u003C/span\u003E\u003C/p\u003E\u003C/div\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/53/9e/539eff158ab4b790.jpg\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 2px\u003B\u000A top: 2960.146047948339px\u003B\u000A width: 383.59059317023105px\u003B\u000A height: 173.56167020138375px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: cover\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 12.135574595312221px\u003B\u000A top: 3148.170165611531px\u003B\u000A width: 365.72885080937556px\u003B\u000A height: 69.50114710351704px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 19px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: center\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003E「BUGUN MAGGU BIZGA MANSUP」\u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 34.2765152782891px\u003B\u000A top: 3215.3097312425557px\u003B\u000A width: 316.8832067115142px\u003B\u000A height: 77.20178026539797px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 21px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: left\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003EBahit ozini, ozidinmu bakarak yahxi koridigan adam bilan birga yaxaxtur \u003C/div\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/e1/b4/e1b40b4c426acfa6.jpg\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 170.93987043307513px\u003B\u000A top: 3834.466456712425px\u003B\u000A width: 180.60918100715867px\u003B\u000A height: 258.32988516517855px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: cover\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/fb/dc/fbdc78833f04c4a2.gif\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 24.06395455770692px\u003B\u000A top: 3882.2356465522507px\u003B\u000A width: 133.87209088458616px\u003B\u000A height: 185.19619877096812px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: contain\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/bf/e0/bfe00042fc6f01c1.gif\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 247.568238786003px\u003B\u000A top: 3312.143303508628px\u003B\u000A width: 120.08880015996797px\u003B\u000A height: 275.0061828876652px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: cover\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 20.436708567187708px\u003B\u000A top: 3729.400938018095px\u003B\u000A width: 349.1265828656246px\u003B\u000A height: 100.84825456342199px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 20px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: left\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003EHakiki bahit yahxi turmuxka erixkandin amas, balki yahxi bir kixi taripidin suyulganliktin kilidu!\u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 19.150316186588753px\u003B\u000A top: 3650.0737036472406px\u003B\u000A width: 351.6993676268225px\u003B\u000A height: 95.24720630145974px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A font\u002Dsize: 20px\u003B\u000A color: #333333\u003B\u000A text\u002Dalign: center\u003B\u000A font\u002Dweight: normal\u003B\u000A display: flex\u003B\u000A align\u002Ditems: center\u003B\u000A padding: 5px\u003B\u000A \u0022\u003E「Billa Yaxap Billa Kerip Billa Kitayli」\u003C/div\u003E\u003Cimg src\u003D\u0022/media/invitation_preview_images/ce/c4/cec4626b1d16bb66.gif\u0022 alt\u003D\u0022图片\u0022 style\u003D\u0022\u000A position: absolute\u003B\u000A left: 31.37104380227902px\u003B\u000A top: 4113.858045716124px\u003B\u000A width: 327.25791239544196px\u003B\u000A height: 59.952533358071655px\u003B\u000A background\u002Dcolor: transparent\u003B\u000A border: none\u003B\u000A border\u002Dradius: 0px\u003B\u000A opacity: 1\u003B\u000A object\u002Dfit: contain\u003B\u000A object\u002Dposition: center\u003B\u000A \u0022 /\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 20.77919832212146px\u003B\u000A top: 1599.7122724851345px\u003B\u000A width: 348.4416033557571px\u003B\u000A height: 285.1147405647222px\u003B\u000A background: linear\u002Dgradient(180deg, #f8fafc 0%, #eef2ff 100%)\u003B\u000A border: 1px solid rgba(99,102,241,0.18)\u003B\u000A border\u002Dradius: 8px\u003B\u000A opacity: 1\u003B\u000A overflow: hidden\u003B\u000A box\u002Dshadow: 0 8px 24px rgba(15,23,42,0.08)\u003B\u000A \u0022\u003E\u000A \u003Cdiv style\u003D\u0022padding: 14px 16px 10px\u003B border\u002Dbottom: 1px solid rgba(99,102,241,0.14)\u003B background: rgba(255,255,255,0.75)\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize: 13px\u003B color: #64748b\u003B margin\u002Dbottom: 6px\u003B\u0022\u003E📍 婚礼地址\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize: 16px\u003B color: #0f172a\u003B font\u002Dweight: 600\u003B line\u002Dheight: 1.35\u003B\u0022\u003E请输入地址\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022padding: 12px 16px\u003B font\u002Dsize: 13px\u003B color: #475569\u003B line\u002Dheight: 1.6\u003B\u0022\u003E\u000A \u003Cdiv\u003E地标:附近标志性建筑\u003C/div\u003E\u000A \u003Cdiv\u003E电话:联系电话\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022position:absolute\u003Bleft:0\u003Bright:0\u003Bbottom:0\u003Bheight:42px\u003Bbackground:#4f46e5\u003Bcolor:#fff\u003Bdisplay:flex\u003Balign\u002Ditems:center\u003Bjustify\u002Dcontent:center\u003Bfont\u002Dsize:14px\u003Bfont\u002Dweight:600\u003B\u0022\u003E\u000A 打开地图导航\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 0px\u003B\u000A top: 1948.9524857899078px\u003B\u000A width: 390px\u003B\u000A height: 352.06439305197637px\u003B\u000A background: linear\u002Dgradient(135deg, #5f67ea 0%, #8557be 45%, #4f8df6 100%)\u003B\u000A border\u002Dradius: 8px\u003B\u000A padding: 22px 24px\u003B\u000A box\u002Dsizing: border\u002Dbox\u003B\u000A color: white\u003B\u000A text\u002Dalign: center\u003B\u000A opacity: 1\u003B\u000A overflow: hidden\u003B\u000A \u0022 data\u002Dcountdown\u002Dtarget\u003D\u00222024\u002D12\u002D31T18:00:00\u0022\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize: 28px\u003B margin\u002Dbottom: 14px\u003B\u0022\u003E⏰\u003C/div\u003E\u000A \u003Ch3 style\u003D\u0022margin: 0 0 18px 0\u003B font\u002Dsize: 34px\u003B line\u002Dheight:1.1\u003B font\u002Dweight: 600\u003B\u0022\u003E距离婚礼还有\u003C/h3\u003E\u000A \u003Cdiv style\u003D\u0022display:flex\u003Bjustify\u002Dcontent:center\u003Balign\u002Ditems:center\u003Bgap:14px\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022width:90px\u003Bheight:108px\u003Bborder\u002Dradius:20px\u003Bbackground:#f8fafc\u003Bcolor:#ef4444\u003Bdisplay:flex\u003Bflex\u002Ddirection:column\u003Balign\u002Ditems:center\u003Bjustify\u002Dcontent:center\u003Bbox\u002Dshadow:0 8px 16px rgba(15,23,42,0.2)\u003B\u0022\u003E\u000A \u003Cspan style\u003D\u0022font\u002Dsize:18px\u003Bfont\u002Dweight:800\u003Bline\u002Dheight:1\u003B\u0022 data\u002Dcountdown\u002Dunit\u003D\u0022days\u0022\u003E00\u003C/span\u003E\u000A \u003Cspan style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#334155\u003Bmargin\u002Dtop:8px\u003B\u0022\u003E天\u003C/span\u003E\u000A \u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:34px\u003Bopacity:0.9\u003B\u0022\u003E:\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022width:90px\u003Bheight:108px\u003Bborder\u002Dradius:20px\u003Bbackground:#f8fafc\u003Bcolor:#ef4444\u003Bdisplay:flex\u003Bflex\u002Ddirection:column\u003Balign\u002Ditems:center\u003Bjustify\u002Dcontent:center\u003Bbox\u002Dshadow:0 8px 16px rgba(15,23,42,0.2)\u003B\u0022\u003E\u000A \u003Cspan style\u003D\u0022font\u002Dsize:18px\u003Bfont\u002Dweight:800\u003Bline\u002Dheight:1\u003B\u0022 data\u002Dcountdown\u002Dunit\u003D\u0022hours\u0022\u003E00\u003C/span\u003E\u000A \u003Cspan style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#334155\u003Bmargin\u002Dtop:8px\u003B\u0022\u003E时\u003C/span\u003E\u000A \u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:34px\u003Bopacity:0.9\u003B\u0022\u003E:\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022width:90px\u003Bheight:108px\u003Bborder\u002Dradius:20px\u003Bbackground:#f8fafc\u003Bcolor:#ef4444\u003Bdisplay:flex\u003Bflex\u002Ddirection:column\u003Balign\u002Ditems:center\u003Bjustify\u002Dcontent:center\u003Bbox\u002Dshadow:0 8px 16px rgba(15,23,42,0.2)\u003B\u0022\u003E\u000A \u003Cspan style\u003D\u0022font\u002Dsize:18px\u003Bfont\u002Dweight:800\u003Bline\u002Dheight:1\u003B\u0022 data\u002Dcountdown\u002Dunit\u003D\u0022minutes\u0022\u003E00\u003C/span\u003E\u000A \u003Cspan style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#334155\u003Bmargin\u002Dtop:8px\u003B\u0022\u003E分\u003C/span\u003E\u000A \u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:34px\u003Bopacity:0.9\u003B\u0022\u003E:\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022width:90px\u003Bheight:108px\u003Bborder\u002Dradius:20px\u003Bbackground:#f8fafc\u003Bcolor:#ef4444\u003Bdisplay:flex\u003Bflex\u002Ddirection:column\u003Balign\u002Ditems:center\u003Bjustify\u002Dcontent:center\u003Bbox\u002Dshadow:0 8px 16px rgba(15,23,42,0.2)\u003B\u0022\u003E\u000A \u003Cspan style\u003D\u0022font\u002Dsize:18px\u003Bfont\u002Dweight:800\u003Bline\u002Dheight:1\u003B\u0022\u003E00\u003C/span\u003E\u000A \u003Cspan style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#334155\u003Bmargin\u002Dtop:8px\u003B\u0022\u003E秒\u003C/span\u003E\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022margin\u002Dtop:16px\u003Bfont\u002Dsize:12px\u003Bfont\u002Dweight:500\u003Bcolor:rgba(0, 0, 0, 0.88)\u003B\u0022\u003E2024\u002D12\u002D31 18:00:00\u003C/div\u003E\u000A \u003C/div\u003E\u003Cdiv style\u003D\u0022\u000A position: absolute\u003B\u000A left: 0px\u003B\u000A top: 2346.09375px\u003B\u000A width: 390px\u003B\u000A height: 593px\u003B\u000A background: #f8fafc\u003B\u000A border: 1px solid #e2e8f0\u003B\u000A border\u002Dradius: 8px\u003B\u000A padding: 14px 14px 10px\u003B\u000A opacity: 1\u003B\u000A overflow: hidden\u003B\u000A box\u002Dsizing: border\u002Dbox\u003B\u000A \u0022\u003E\u000A \u000A \u003Cdiv style\u003D\u0022display:flex\u003Bgap:10px\u003Bmargin\u002Dbottom:10px\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022width:8px\u003Bheight:8px\u003Bborder\u002Dradius:50%\u003Bbackground:#3b82f6\u003Bmargin\u002Dtop:6px\u003Bbox\u002Dshadow:0 0 0 4px rgba(59,130,246,0.12)\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#64748b\u003B\u0022\u003E10:00\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#1e293b\u003Bfont\u002Dweight:600\u003B\u0022\u003E迎宾签到\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#475569\u003B\u0022\u003E宾客签到入场\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u000A \u000A \u003Cdiv style\u003D\u0022display:flex\u003Bgap:10px\u003Bmargin\u002Dbottom:10px\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022width:8px\u003Bheight:8px\u003Bborder\u002Dradius:50%\u003Bbackground:#3b82f6\u003Bmargin\u002Dtop:6px\u003Bbox\u002Dshadow:0 0 0 4px rgba(59,130,246,0.12)\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#64748b\u003B\u0022\u003E11:30\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#1e293b\u003Bfont\u002Dweight:600\u003B\u0022\u003E婚礼仪式\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#475569\u003B\u0022\u003E交换誓言与戒指\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u000A \u000A \u003Cdiv style\u003D\u0022display:flex\u003Bgap:10px\u003Bmargin\u002Dbottom:10px\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022width:8px\u003Bheight:8px\u003Bborder\u002Dradius:50%\u003Bbackground:#3b82f6\u003Bmargin\u002Dtop:6px\u003Bbox\u002Dshadow:0 0 0 4px rgba(59,130,246,0.12)\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#64748b\u003B\u0022\u003E12:30\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#1e293b\u003Bfont\u002Dweight:600\u003B\u0022\u003E婚宴开始\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#475569\u003B\u0022\u003E宴席与敬酒环节\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u000A \u000A \u003Cdiv style\u003D\u0022display:flex\u003Bgap:10px\u003Bmargin\u002Dbottom:10px\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022width:8px\u003Bheight:8px\u003Bborder\u002Dradius:50%\u003Bbackground:#3b82f6\u003Bmargin\u002Dtop:6px\u003Bbox\u002Dshadow:0 0 0 4px rgba(59,130,246,0.12)\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#64748b\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#1e293b\u003Bfont\u002Dweight:600\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#475569\u003B\u0022\u003E\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u000A \u000A \u003Cdiv style\u003D\u0022display:flex\u003Bgap:10px\u003Bmargin\u002Dbottom:10px\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022width:8px\u003Bheight:8px\u003Bborder\u002Dradius:50%\u003Bbackground:#3b82f6\u003Bmargin\u002Dtop:6px\u003Bbox\u002Dshadow:0 0 0 4px rgba(59,130,246,0.12)\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#64748b\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#1e293b\u003Bfont\u002Dweight:600\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#475569\u003B\u0022\u003E\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u000A \u000A \u003Cdiv style\u003D\u0022display:flex\u003Bgap:10px\u003Bmargin\u002Dbottom:10px\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022width:8px\u003Bheight:8px\u003Bborder\u002Dradius:50%\u003Bbackground:#3b82f6\u003Bmargin\u002Dtop:6px\u003Bbox\u002Dshadow:0 0 0 4px rgba(59,130,246,0.12)\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#64748b\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#1e293b\u003Bfont\u002Dweight:600\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#475569\u003B\u0022\u003E\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u000A \u000A \u003Cdiv style\u003D\u0022display:flex\u003Bgap:10px\u003Bmargin\u002Dbottom:10px\u003B\u0022\u003E\u000A \u003Cdiv style\u003D\u0022width:8px\u003Bheight:8px\u003Bborder\u002Dradius:50%\u003Bbackground:#3b82f6\u003Bmargin\u002Dtop:6px\u003Bbox\u002Dshadow:0 0 0 4px rgba(59,130,246,0.12)\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#64748b\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:14px\u003Bcolor:#1e293b\u003Bfont\u002Dweight:600\u003B\u0022\u003E\u003C/div\u003E\u000A \u003Cdiv style\u003D\u0022font\u002Dsize:12px\u003Bcolor:#475569\u003B\u0022\u003E\u003C/div\u003E\u000A \u003C/div\u003E\u000A \u003C/div\u003E\u000A \u000A \u003C/div\u003E\u003C/div\u003E\u000A \u003C/div\u003E\u003C!\u002D\u002D Template scripts will be injected here \u002D\u002D\u003E\u000A\u003C/body\u003E\u000A\u003C/html\u003E", css_styles: "html, body {\u000A margin: 0\u003B\u000A padding: 0\u003B\u000A background: #f5f5f5\u003B\u000A width: 100%\u003B\u000A min\u002Dheight: 100%\u003B\u000A}\u000Abody {\u000A overflow\u002Dx: hidden\u003B\u000A}\u000A.ds\u002Dstage\u002Dhost {\u000A width: 100%\u003B\u000A padding: 0\u003B\u000A margin: 0\u003B\u000A}\u000A.ds\u002Dstage {\u000A transform\u002Dorigin: top left\u003B\u000A}\u000A* {\u000A box\u002Dsizing: border\u002Dbox\u003B\u000A}\u000A[data\u002Dwebview\u002Daction] {\u000A touch\u002Daction: manipulation\u003B\u000A}", js_scripts: "(function () {\u000A function safeParseAction(payload) {\u000A try {\u000A return JSON.parse(decodeURIComponent(payload || \u0027\u0027))\u003B\u000A } catch (e) {\u000A return null\u003B\u000A }\u000A }\u000A\u000A function isMiniProgramWebview() {\u000A try {\u000A if (window.__wxjs_environment \u003D\u003D\u003D \u0027miniprogram\u0027) return true\u003B\u000A } catch (_e) {}\u000A try {\u000A return !!(window.wx \u0026\u0026 window.wx.miniProgram \u0026\u0026 typeof window.wx.miniProgram.postMessage \u003D\u003D\u003D \u0027function\u0027)\u003B\u000A } catch (_e2) {\u000A return false\u003B\u000A }\u000A }\u000A\u000A function postHost(action, extra) {\u000A try {\u000A var wx \u003D window.wx\u003B\u000A if (!wx || !wx.miniProgram || typeof wx.miniProgram.postMessage !\u003D\u003D \u0027function\u0027) return false\u003B\u000A var payload \u003D { type: \u0027runtime_action\u0027, action: String(action || \u0027\u0027), at: Date.now() }\u003B\u000A if (extra \u0026\u0026 typeof extra \u003D\u003D\u003D \u0027object\u0027) {\u000A for (var k in extra) {\u000A if (Object.prototype.hasOwnProperty.call(extra, k)) payload[k] \u003D extra[k]\u003B\u000A }\u000A }\u000A wx.miniProgram.postMessage({ data: payload })\u003B\u000A return true\u003B\u000A } catch (e) {\u000A return false\u003B\u000A }\u000A }\u000A\u000A function tryMpNavigateImmediate(action, extra) {\u000A try {\u000A var mp \u003D window.wx \u0026\u0026 window.wx.miniProgram\u003B\u000A if (!isMiniProgramWebview() || !mp || typeof mp.navigateTo !\u003D\u003D \u0027function\u0027) return false\u003B\u000A var ext \u003D extra \u0026\u0026 typeof extra \u003D\u003D\u003D \u0027object\u0027 ? extra : {}\u003B\u000A var a \u003D String(action || \u0027\u0027).replace(/\u002D/g, \u0027_\u0027).toLowerCase()\u003B\u000A function fallbackPost() {\u000A postHost(action, ext)\u003B\u000A }\u000A if (a \u003D\u003D\u003D \u0027open_merchant\u0027) {\u000A var mid \u003D Number(ext.merchant_id !\u003D null ? ext.merchant_id : ext.id)\u003B\u000A if (!(mid \u003E 0 \u0026\u0026 isFinite(mid))) return false\u003B\u000A mp.navigateTo({ url: \u0027/pages/merchants/detail?id\u003D\u0027 + mid, fail: fallbackPost })\u003B\u000A return true\u003B\u000A }\u000A if (a \u003D\u003D\u003D \u0027open_map\u0027) {\u000A var lat \u003D Number(ext.latitude !\u003D null ? ext.latitude : ext.lat)\u003B\u000A var lng \u003D Number(ext.longitude !\u003D null ? ext.longitude : ext.lng)\u003B\u000A if (!(isFinite(lat) \u0026\u0026 isFinite(lng))) return false\u003B\u000A var nm \u003D String(ext.name !\u003D null ? ext.name : \u0027\u0027).slice(0, 100)\u003B\u000A var addr \u003D String(ext.address !\u003D null ? ext.address : \u0027\u0027).slice(0, 200)\u003B\u000A var u \u003D \u0027/pages/webview\u002Daction\u002Dbridge/webview\u002Daction\u002Dbridge?kind\u003Dopen_map\u0026lat\u003D\u0027 + encodeURIComponent(String(lat)) + \u0027\u0026lng\u003D\u0027 + encodeURIComponent(String(lng)) + \u0027\u0026n\u003D\u0027 + encodeURIComponent(nm) + \u0027\u0026a\u003D\u0027 + encodeURIComponent(addr)\u003B\u000A if (u.length \u003E 1900) {\u000A u \u003D \u0027/pages/webview\u002Daction\u002Dbridge/webview\u002Daction\u002Dbridge?kind\u003Dopen_map\u0026lat\u003D\u0027 + encodeURIComponent(String(lat)) + \u0027\u0026lng\u003D\u0027 + encodeURIComponent(String(lng)) + \u0027\u0026n\u003D\u0027 + encodeURIComponent(nm.slice(0, 40)) + \u0027\u0026a\u003D\u0027 + encodeURIComponent(addr.slice(0, 80))\u003B\u000A }\u000A mp.navigateTo({ url: u, fail: fallbackPost })\u003B\u000A return true\u003B\u000A }\u000A return false\u003B\u000A } catch (_e) {\u000A return false\u003B\u000A }\u000A }\u000A\u000A function postHostReliable(action, extra) {\u000A if (tryMpNavigateImmediate(action, extra)) return\u003B\u000A if (!postHost(action, extra)) return\u003B\u000A var a \u003D String(action || \u0027\u0027)\u003B\u000A if (!a) return\u003B\u000A setTimeout(function () { postHost(a, extra)\u003B }, 90)\u003B\u000A setTimeout(function () { postHost(a, extra)\u003B }, 220)\u003B\u000A }\u000A\u000A function bindActions() {\u000A var nodes \u003D document.querySelectorAll(\u0027[data\u002Dwebview\u002Daction]\u0027)\u003B\u000A nodes.forEach(function (node) {\u000A node.addEventListener(\u0027click\u0027, function () {\u000A var action \u003D safeParseAction(node.getAttribute(\u0027data\u002Dwebview\u002Daction\u0027))\u003B\u000A if (!action || !action.type) return\u003B\u000A if (isMiniProgramWebview()) {\u000A if (action.type \u003D\u003D\u003D \u0027open_map\u0027 \u0026\u0026 action.latitude !\u003D null \u0026\u0026 action.longitude !\u003D null) {\u000A postHostReliable(\u0027open_map\u0027, {\u000A latitude: Number(action.latitude),\u000A longitude: Number(action.longitude),\u000A name: String(action.name || \u0027\u0027),\u000A address: String(action.address || \u0027\u0027)\u000A })\u003B\u000A return\u003B\u000A }\u000A if (action.type \u003D\u003D\u003D \u0027call_phone\u0027 \u0026\u0026 action.text) {\u000A postHostReliable(\u0027call_phone\u0027, { text: String(action.text) })\u003B\u000A return\u003B\u000A }\u000A if (action.type \u003D\u003D\u003D \u0027copy_text\u0027 \u0026\u0026 action.text) {\u000A postHostReliable(\u0027copy_text\u0027, { text: String(action.text) })\u003B\u000A return\u003B\u000A }\u000A if (action.type \u003D\u003D\u003D \u0027open_url\u0027 \u0026\u0026 action.url) {\u000A postHostReliable(\u0027open_url\u0027, { url: String(action.url) })\u003B\u000A return\u003B\u000A }\u000A }\u000A if (action.type \u003D\u003D\u003D \u0027open_url\u0027 \u0026\u0026 action.url) {\u000A window.location.href \u003D action.url\u003B\u000A return\u003B\u000A }\u000A if (action.type \u003D\u003D\u003D \u0027copy_text\u0027 \u0026\u0026 action.text \u0026\u0026 navigator.clipboard) {\u000A navigator.clipboard.writeText(String(action.text)).catch(function () {})\u003B\u000A return\u003B\u000A }\u000A if (action.type \u003D\u003D\u003D \u0027call_phone\u0027 \u0026\u0026 action.text) {\u000A window.location.href \u003D \u0027tel:\u0027 + String(action.text)\u003B\u000A return\u003B\u000A }\u000A if (action.type \u003D\u003D\u003D \u0027open_map\u0027 \u0026\u0026 action.latitude \u0026\u0026 action.longitude) {\u000A var lat \u003D encodeURIComponent(String(action.latitude))\u003B\u000A var lng \u003D encodeURIComponent(String(action.longitude))\u003B\u000A var name \u003D encodeURIComponent(String(action.name || \u0027位置\u0027))\u003B\u000A var addr \u003D encodeURIComponent(String(action.address || \u0027\u0027))\u003B\u000A window.location.href \u003D \u0027https://uri.amap.com/marker?position\u003D\u0027 + lng + \u0027,\u0027 + lat + \u0027\u0026name\u003D\u0027 + name + \u0027\u0026src\u003Dinvitation\u0026coordinate\u003Dgaode\u0026callnative\u003D1\u0026address\u003D\u0027 + addr\u003B\u000A }\u000A })\u003B\u000A })\u003B\u000A }\u000A\u000A function bindCountdown() {\u000A var cards \u003D document.querySelectorAll(\u0027[data\u002Dcountdown\u002Dtarget]\u0027)\u003B\u000A if (!cards.length) return\u003B\u000A\u000A function tick() {\u000A var now \u003D Date.now()\u003B\u000A cards.forEach(function (card) {\u000A var targetRaw \u003D card.getAttribute(\u0027data\u002Dcountdown\u002Dtarget\u0027) || \u0027\u0027\u003B\u000A var target \u003D new Date(targetRaw).getTime()\u003B\u000A if (!target || Number.isNaN(target)) return\u003B\u000A var diff \u003D Math.max(0, target \u002D now)\u003B\u000A var days \u003D Math.floor(diff / 86400000)\u003B\u000A var hours \u003D Math.floor((diff % 86400000) / 3600000)\u003B\u000A var minutes \u003D Math.floor((diff % 3600000) / 60000)\u003B\u000A var dayEl \u003D card.querySelector(\u0027[data\u002Dcountdown\u002Dunit\u003D\u0022days\u0022]\u0027)\u003B\u000A var hourEl \u003D card.querySelector(\u0027[data\u002Dcountdown\u002Dunit\u003D\u0022hours\u0022]\u0027)\u003B\u000A var minuteEl \u003D card.querySelector(\u0027[data\u002Dcountdown\u002Dunit\u003D\u0022minutes\u0022]\u0027)\u003B\u000A if (dayEl) dayEl.textContent \u003D String(days)\u003B\u000A if (hourEl) hourEl.textContent \u003D String(hours)\u003B\u000A if (minuteEl) minuteEl.textContent \u003D String(minutes)\u003B\u000A })\u003B\u000A }\u000A\u000A tick()\u003B\u000A setInterval(tick, 30000)\u003B\u000A }\u000A\u000A function applyStageScale() {\u000A var stage \u003D document.querySelector(\u0027.ds\u002Dstage\u0027)\u003B\u000A if (!stage) return\u003B\u000A var stageWidth \u003D Number(stage.getAttribute(\u0027data\u002Dstage\u002Dwidth\u0027) || 750)\u003B\u000A var viewportWidth \u003D window.innerWidth || document.documentElement.clientWidth || stageWidth\u003B\u000A var scale \u003D viewportWidth / stageWidth\u003B\u000A if (!Number.isFinite(scale) || scale \u003C\u003D 0) scale \u003D 1\u003B\u000A scale \u003D Math.min(1, scale)\u003B\u000A stage.style.transform \u003D \u0027scale(\u0027 + scale + \u0027)\u0027\u003B\u000A stage.style.marginLeft \u003D \u00270\u0027\u003B\u000A stage.style.marginRight \u003D \u00270\u0027\u003B\u000A document.body.style.minHeight \u003D Math.ceil((Number(stage.getAttribute(\u0027data\u002Dstage\u002Dheight\u0027) || 1334)) * scale) + \u0027px\u0027\u003B\u000A }\u000A\u000A document.addEventListener(\u0027DOMContentLoaded\u0027, function () {\u000A bindActions()\u003B\u000A bindCountdown()\u003B\u000A applyStageScale()\u003B\u000A })\u003B\u000A\u000A window.addEventListener(\u0027resize\u0027, applyStageScale)\u003B\u000A})()\u003B", editable_fields: [] }; console.log('模板数据:', templateData); console.log('editable_elements_json:', []); // 如果editable_fields为空,添加测试数据 if (!templateData.editable_fields || templateData.editable_fields.length === 0) { console.log('⚠️ editable_fields为空,使用测试数据'); templateData.editable_fields = [ { 'id': 'invitation_title', 'type': 'TextComponent', 'name': '请柬标题', 'element_key': 'invitation_title', 'label': '请柬标题', 'placeholder': '例如:诚邀您参加我们的婚礼', 'default_value': '诚邀您参加我们的婚礼', 'is_required': true, 'validation': {}, 'style': {'left': 0, 'top': 0, 'width': 200, 'height': 40, 'fontSize': 16, 'color': '#333'}, 'config': {'text': '诚邀您参加我们的婚礼'} }, { 'id': 'groom_name', 'type': 'TextComponent', 'name': '新郎姓名', 'element_key': 'groom_name', 'label': '新郎姓名', 'placeholder': '请输入新郎姓名', 'default_value': '', 'is_required': true, 'validation': {}, 'style': {'left': 0, 'top': 0, 'width': 200, 'height': 40, 'fontSize': 16, 'color': '#333'}, 'config': {'text': '新郎姓名'} }, { 'id': 'bride_name', 'type': 'TextComponent', 'name': '新娘姓名', 'element_key': 'bride_name', 'label': '新娘姓名', 'placeholder': '请输入新娘姓名', 'default_value': '', 'is_required': true, 'validation': {}, 'style': {'left': 0, 'top': 0, 'width': 200, 'height': 40, 'fontSize': 16, 'color': '#333'}, 'config': {'text': '新娘姓名'} }, { 'id': 'wedding_date', 'type': 'DateComponent', 'name': '婚礼日期', 'element_key': 'wedding_date', 'label': '婚礼日期', 'placeholder': '请选择婚礼日期', 'default_value': '', 'is_required': true, 'validation': {}, 'style': {'left': 0, 'top': 0, 'width': 200, 'height': 40, 'fontSize': 16, 'color': '#333'}, 'config': {'text': '婚礼日期'} }, { 'id': 'wedding_venue', 'type': 'TextComponent', 'name': '婚礼地点', 'element_key': 'wedding_venue', 'label': '婚礼地点', 'placeholder': '例如:某某大酒店宴会厅', 'default_value': '', 'is_required': true, 'validation': {}, 'style': {'left': 0, 'top': 0, 'width': 200, 'height': 40, 'fontSize': 16, 'color': '#333'}, 'config': {'text': '婚礼地点'} } }; } console.log('模板数据加载:', templateData); console.log('HTML内容长度:', templateData.html_content.length); console.log('CSS内容长度:', templateData.css_styles.length); console.log('JS内容长度:', templateData.js_scripts.length); console.log('editable_fields:', templateData.editable_fields); // 生成模板预览HTML function generateTemplatePreviewHtml() { const components = templateData.editable_fields; // 如果是对象,转换为数组 const componentsArray = Array.isArray(components) ? components : Object.values(components || {}); if (!componentsArray || componentsArray.length === 0) { return '
暂无可编辑内容
'; } // 检查是否有样式信息 const hasStyleInfo = componentsArray.some(element => element.style && Object.keys(element.style).length > 0); if (hasStyleInfo) { // 如果有样式信息,使用绝对定位布局(原始模板布局) let html = ''; componentsArray.forEach(element => { const style = element.style || {}; const config = element.config || {}; let elementHtml = ''; if (element.type === 'TextComponent') { const text = config.text || element.name || '文本内容'; elementHtml = `
${text}
`; } html += elementHtml; }); return `
${html}
`; } else { // 如果没有样式信息,使用友好的垂直布局 let html = ''; componentsArray.forEach((element, index) => { const config = element.config || {}; const isRequired = element.is_required || false; let elementHtml = ''; if (element.type === 'TextComponent') { const text = config.text || element.default_value || element.name || '请填写内容'; const fontSize = element.element_key === 'invitation_title' ? '24px' : '18px'; const fontWeight = element.element_key === 'invitation_title' ? 'bold' : 'normal'; const textAlign = element.element_key === 'invitation_title' ? 'center' : 'left'; const marginBottom = index < componentsArray.length - 1 ? '20px' : '0'; elementHtml = `
${isRequired ? '*' : ''} ${element.name}:
${text}
`; } html += elementHtml; }); return `

💒 婚礼邀请函

${html}
诚邀您参加我们的婚礼 · 共赴良辰
`; } } // 初始化 document.addEventListener('DOMContentLoaded', function() { console.log('🎨 初始化邀请编辑器...'); // 选项卡切换事件 document.querySelectorAll('.tab-button').forEach(button => { button.addEventListener('click', () => switchTab(button.dataset.tab)); }); // 表单输入事件 - 实时更新预览 const formInputs = document.querySelectorAll('#invitation-form input, #invitation-form textarea'); formInputs.forEach(input => { input.addEventListener('input', updatePreview); }); // 初始化预览 updatePreview(); showNotification('🎨 欢迎使用邀请函编辑器!', 'success'); console.log('✅ 邀请编辑器初始化完成'); });