From 5b5b73bba8fb84c3d7f44b10ed5f326a6f675ca1 Mon Sep 17 00:00:00 2001 From: Hera Zhao Date: Thu, 9 Apr 2026 09:52:33 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=9D=E5=AD=98=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E4=B8=80=E6=AC=A1=E7=82=B9=E5=87=BB=E5=8D=B3=E5=BC=B9=E5=88=86?= =?UTF-8?q?=E4=BA=AB=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: navigator.share 需要在用户手势同步上下文中调用。 之前点保存→html2canvas截图(异步)→share(手势已过期),失败。 修复: 打开 modal 时预生成图片(watch showDilution/showContra, openOilDetail里预生成),点保存按钮时 dataUrl 已缓存, navigator.share 在用户手势上下文内直接调用,一次即弹分享面板。 保存按钮放回卡片内部。 Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/views/OilReference.vue | 80 +++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/frontend/src/views/OilReference.vue b/frontend/src/views/OilReference.vue index fb60fe2..aec177d 100644 --- a/frontend/src/views/OilReference.vue +++ b/frontend/src/views/OilReference.vue @@ -36,9 +36,11 @@
💡 稀释比例 = 1滴精油 : N滴椰子油
比例越大越温和,新手建议从高稀释比例开始
+
+ +
- @@ -75,9 +77,11 @@ 💧
少量多次,多喝水
使用精油后多补充水分,帮助身体代谢
+
+ +
- @@ -203,9 +207,11 @@

⚠️ 注意事项

{{ activeCard.caution }}

+
+ +
- @@ -546,12 +552,18 @@ function parseMethodBadges(methodStr) { } // Actions -function openOilDetail(name) { +async function openOilDetail(name) { const card = getOilCard(name) if (card) { activeCardName.value = name activeCard.value = card selectedOilName.value = null + // Pre-generate card image for instant save + oilCardImageUrl.value = null + await nextTick() + await new Promise(r => setTimeout(r, 300)) + const el = document.querySelector('.oil-card-modal') + if (el) await generateImageFromRef({ value: el }, oilCardImageUrl) } else { activeCard.value = null activeCardName.value = null @@ -748,33 +760,59 @@ async function generateImageFromRef(elRef, imageUrlRef) { } } -async function saveGeneratedImage(imageUrlRef, elRef, name) { - // Generate if not already done - if (!imageUrlRef.value) { - await generateImageFromRef(elRef, imageUrlRef) +// When modal opens, pre-generate the image (so save button has instant dataUrl) +watch(showDilution, async (v) => { + if (v) { + dilutionImageUrl.value = null + await nextTick() + await new Promise(r => setTimeout(r, 300)) + await generateImageFromRef(dilutionCardRef, dilutionImageUrl) } - if (!imageUrlRef.value) { - ui.showToast('图片生成失败') +}) +watch(showContra, async (v) => { + if (v) { + contraImageUrl.value = null + await nextTick() + await new Promise(r => setTimeout(r, 300)) + await generateImageFromRef(contraCardRef, contraImageUrl) + } +}) + +// Save: dataUrl is already cached, navigator.share runs in fresh user gesture +async function saveDilutionImage() { + if (!dilutionImageUrl.value) { + ui.showToast('图片生成中,请稍后再试') return } - // Same as RecipeDetailOverlay.saveImage const { saveImageFromUrl } = await import('../composables/useSaveImage') - await saveImageFromUrl(imageUrlRef.value, name) + await saveImageFromUrl(dilutionImageUrl.value, '精油稀释比例指南') ui.showToast('已保存图片') } -function saveDilutionImage() { - saveGeneratedImage(dilutionImageUrl, dilutionCardRef, '精油稀释比例指南') +async function saveContraImage() { + if (!contraImageUrl.value) { + ui.showToast('图片生成中,请稍后再试') + return + } + const { saveImageFromUrl } = await import('../composables/useSaveImage') + await saveImageFromUrl(contraImageUrl.value, '精油使用禁忌') + ui.showToast('已保存图片') } -function saveContraImage() { - saveGeneratedImage(contraImageUrl, contraCardRef, '精油使用禁忌') -} -function saveCardImage(name) { + +async function saveCardImage(name) { + // Oil card: generate on demand since we don't know which card opens const el = document.querySelector('.oil-card-modal') if (!el) { ui.showToast('找不到卡片'); return } - // Use a temporary ref-like object - const tmpRef = { value: el } - saveGeneratedImage(oilCardImageUrl, tmpRef, name + '_精油知识卡') + if (!oilCardImageUrl.value) { + await generateImageFromRef({ value: el }, oilCardImageUrl) + } + if (!oilCardImageUrl.value) { + ui.showToast('图片生成失败') + return + } + const { saveImageFromUrl } = await import('../composables/useSaveImage') + await saveImageFromUrl(oilCardImageUrl.value, name + '_精油知识卡') + ui.showToast('已保存图片') }