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('已保存图片')
}