rewrite: 配方卡片和预览图完全重写,匹配initial commit样式
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 4s
Test / build-check (push) Successful in 3s
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 14s
Test / e2e-test (push) Failing after 1m43s
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 4s
Test / build-check (push) Successful in 3s
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 14s
Test / e2e-test (push) Failing after 1m43s
完全删除之前的CSS class方案,改用inline style匹配原版HTML: 配方卡片 (RecipeDetailOverlay): - 背景图: absolute全覆盖, opacity:0.12 - Logo: absolute底部居中水印, bottom:60px, opacity:0.2 - QR: absolute右上角 top:36px right:24px, 品牌名在下方 - 内容区: position:relative z-index:2 (在overlay之上) - 制作日期: text-align:center (居中,匹配原版) - 所有样式用inline style,跟原版_buildBrandHtml()一致 预览图 (MyDiary): - 等比缩小版配方卡片,同样布局 - QR右上,Logo底部居中,日期居中 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,76 +49,45 @@
|
||||
|
||||
<!-- Card image (rendered by html2canvas) -->
|
||||
<div v-show="!cardImageUrl" ref="cardRef" class="export-card">
|
||||
<!-- Brand overlay layers -->
|
||||
<div
|
||||
v-if="brand.brand_bg"
|
||||
class="card-brand-bg"
|
||||
:style="{ backgroundImage: `url('${brand.brand_bg}')` }"
|
||||
/>
|
||||
<!-- QR: absolute positioned in export-card, top-right corner of content area -->
|
||||
<div v-if="brand.qr_code" class="card-qr-wrapper">
|
||||
<img :src="brand.qr_code" class="card-qr" crossorigin="anonymous" />
|
||||
<div v-if="brand.brand_name" class="card-qr-name">{{ brand.brand_name }}</div>
|
||||
<!-- Background image overlay -->
|
||||
<div v-if="brand.brand_bg" style="position:absolute;inset:0;width:100%;height:100%;background-size:cover;background-position:center;opacity:0.12;pointer-events:none;z-index:0" :style="{ backgroundImage: `url('${brand.brand_bg}')` }"></div>
|
||||
<!-- Logo watermark: bottom center -->
|
||||
<img v-if="brand.brand_logo" :src="brand.brand_logo" crossorigin="anonymous" style="position:absolute;bottom:60px;left:50%;transform:translateX(-50%);height:60px;opacity:0.2;pointer-events:none;z-index:1" />
|
||||
<!-- QR: top-right -->
|
||||
<div v-if="brand.qr_code" style="position:absolute;top:36px;right:24px;display:flex;flex-direction:column;align-items:center;gap:3px;z-index:2">
|
||||
<img :src="brand.qr_code" crossorigin="anonymous" style="width:54px;height:54px;object-fit:cover;border-radius:6px;box-shadow:0 2px 6px rgba(0,0,0,0.1)" />
|
||||
<div v-if="brand.brand_name" :style="{ textAlign: brand.brand_align || 'center' }" style="font-size:7px;color:var(--text-light);line-height:1.3;max-width:68px;white-space:pre-line">{{ brand.brand_name }}</div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-brand-text">
|
||||
<!-- Card content (z-index above overlays) -->
|
||||
<div style="position:relative;z-index:2">
|
||||
<div style="font-size:11px;letter-spacing:3px;color:var(--sage);margin-bottom:8px">
|
||||
{{ cardLang === 'en' ? 'doTERRA · Gifts of the Earth' : 'doTERRA · 来自大地的礼物' }}
|
||||
</div>
|
||||
<div class="card-title">
|
||||
<div style="font-size:26px;font-weight:700;color:var(--text-dark);margin-bottom:6px;line-height:1.3">
|
||||
{{ getCardRecipeName() }}
|
||||
</div>
|
||||
<div class="card-divider"></div>
|
||||
<div style="width:80px;height:2px;background:linear-gradient(90deg,var(--sage),var(--gold));border-radius:2px;margin:14px 0"></div>
|
||||
|
||||
<!-- Ingredients (excluding coconut oil) -->
|
||||
<ul class="card-ingredients">
|
||||
<li v-for="(ing, i) in cardIngredients" :key="i">
|
||||
<span class="card-oil-name">
|
||||
{{ getCardOilName(ing.oil) }}
|
||||
</span>
|
||||
<span class="card-oil-drops">
|
||||
{{ ing.drops }} {{ cardLang === 'en' ? 'drops' : '滴' }}
|
||||
</span>
|
||||
<span class="card-oil-cost">
|
||||
{{ oilsStore.fmtPrice(oilsStore.pricePerDrop(ing.oil) * ing.drops) }}
|
||||
</span>
|
||||
<span
|
||||
v-if="hasRetailForOil(ing.oil) && retailPerDrop(ing.oil) > oilsStore.pricePerDrop(ing.oil)"
|
||||
class="card-retail-strike"
|
||||
>{{ oilsStore.fmtPrice(retailPerDrop(ing.oil) * ing.drops) }}</span>
|
||||
<ul style="list-style:none;margin-bottom:20px;padding:0">
|
||||
<li v-for="(ing, i) in cardIngredients" :key="i" style="display:flex;align-items:center;padding:9px 0;border-bottom:1px solid rgba(180,150,100,0.15);font-size:14px">
|
||||
<span style="flex:1;color:var(--text-dark);font-weight:500">{{ getCardOilName(ing.oil) }}</span>
|
||||
<span style="width:50px;text-align:right;color:var(--sage-dark);font-size:13px">{{ ing.drops }} {{ cardLang === 'en' ? 'drops' : '滴' }}</span>
|
||||
<span style="width:60px;text-align:right;color:var(--text-light);font-size:12px">{{ oilsStore.fmtPrice(oilsStore.pricePerDrop(ing.oil) * ing.drops) }}</span>
|
||||
<span v-if="hasRetailForOil(ing.oil) && retailPerDrop(ing.oil) > oilsStore.pricePerDrop(ing.oil)" style="width:55px;text-align:right;color:var(--text-light);font-size:10px;text-decoration:line-through">{{ oilsStore.fmtPrice(retailPerDrop(ing.oil) * ing.drops) }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Dilution description -->
|
||||
<div v-if="dilutionDesc" class="card-dilution">{{ dilutionDesc }}</div>
|
||||
<div v-if="dilutionDesc" style="padding:10px 14px;background:rgba(180,150,100,0.08);border-radius:10px;font-size:12px;color:var(--text-mid);margin-bottom:12px">{{ dilutionDesc }}</div>
|
||||
|
||||
<!-- Note -->
|
||||
<div v-if="displayRecipe.note" class="card-note">
|
||||
{{ '📝 ' + displayRecipe.note }}
|
||||
<div v-if="displayRecipe.note" style="font-size:12px;color:var(--brown-light);margin-bottom:12px;font-style:italic">📝 {{ displayRecipe.note }}</div>
|
||||
|
||||
<div style="background:linear-gradient(135deg,var(--sage),#5a7d5e);border-radius:12px;padding:14px 20px;display:flex;justify-content:space-between;align-items:center">
|
||||
<span style="color:rgba(255,255,255,0.85);font-size:13px;letter-spacing:1px">{{ cardLang === 'en' ? 'Total Cost' : '配方总成本' }}</span>
|
||||
<span style="color:white;font-size:20px;font-weight:700">{{ priceInfo.cost }}<span v-if="priceInfo.hasRetail" style="text-decoration:line-through;opacity:0.6;font-size:13px;margin-left:6px">{{ priceInfo.retail }}</span></span>
|
||||
</div>
|
||||
|
||||
<!-- Total cost bar -->
|
||||
<div class="card-total">
|
||||
<div class="card-total-label">
|
||||
{{ cardLang === 'en' ? 'Total Cost' : '配方总成本' }}
|
||||
</div>
|
||||
<div class="card-total-price">
|
||||
{{ priceInfo.cost }}
|
||||
<span v-if="priceInfo.hasRetail" class="card-total-retail">{{ priceInfo.retail }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logo + Date row -->
|
||||
<div class="card-bottom-row">
|
||||
<img
|
||||
v-if="brand.brand_logo"
|
||||
:src="brand.brand_logo"
|
||||
class="card-logo"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<div v-else class="card-logo-placeholder"></div>
|
||||
<div class="card-footer">
|
||||
{{ cardLang === 'en' ? 'Date: ' : '制作日期:' }}{{ todayStr }}
|
||||
</div>
|
||||
<div style="margin-top:16px;text-align:center;font-size:11px;color:var(--text-light);letter-spacing:1px">
|
||||
{{ cardLang === 'en' ? 'Date: ' : '制作日期:' }}{{ todayStr }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -169,28 +169,30 @@
|
||||
<div style="margin-bottom:16px">
|
||||
<label class="form-label">📋 配方卡片预览</label>
|
||||
<div class="card-preview-mini">
|
||||
<div v-if="brandBg" class="card-preview-bg" :style="{ backgroundImage: 'url(' + brandBg + ')' }"></div>
|
||||
<!-- QR + brand name: top-right -->
|
||||
<div v-if="brandQrImage" class="card-preview-qr-area">
|
||||
<img :src="brandQrImage" class="card-preview-qr" />
|
||||
<div v-if="brandName" class="card-preview-qr-text" :style="{ textAlign: brandAlign }">{{ brandName }}</div>
|
||||
<!-- Background overlay -->
|
||||
<div v-if="brandBg" style="position:absolute;inset:0;background-size:cover;background-position:center;opacity:0.12;pointer-events:none" :style="{ backgroundImage: 'url(' + brandBg + ')' }"></div>
|
||||
<!-- Logo watermark: bottom center -->
|
||||
<img v-if="brandLogo" :src="brandLogo" style="position:absolute;bottom:34px;left:50%;transform:translateX(-50%);height:30px;opacity:0.2;pointer-events:none;z-index:1" />
|
||||
<!-- QR: top-right -->
|
||||
<div v-if="brandQrImage" style="position:absolute;top:16px;right:12px;display:flex;flex-direction:column;align-items:center;gap:2px;z-index:2">
|
||||
<img :src="brandQrImage" style="width:36px;height:36px;object-fit:cover;border-radius:4px;box-shadow:0 1px 4px rgba(0,0,0,0.1)" />
|
||||
<div v-if="brandName" :style="{ textAlign: brandAlign }" style="font-size:5px;color:var(--text-light);line-height:1.2;max-width:42px;white-space:pre-line">{{ brandName }}</div>
|
||||
</div>
|
||||
<!-- Content: left side -->
|
||||
<div class="card-preview-content">
|
||||
<div style="font-size:8px;letter-spacing:2px;color:var(--sage);margin-bottom:4px">doTERRA · 来自大地的礼物</div>
|
||||
<div style="font-size:14px;font-weight:700;color:var(--text-dark)">配方名称</div>
|
||||
<div style="font-size:10px;color:var(--text-light);margin-top:2px">薰衣草 · 乳香 · 茶树</div>
|
||||
</div>
|
||||
<!-- Total cost bar -->
|
||||
<div class="card-preview-cost">
|
||||
<span>配方总成本</span>
|
||||
<span>¥12.50</span>
|
||||
</div>
|
||||
<!-- Logo left + date right -->
|
||||
<div class="card-preview-bottom">
|
||||
<img v-if="brandLogo" :src="brandLogo" class="card-preview-logo" />
|
||||
<span v-else></span>
|
||||
<span class="card-preview-date">制作日期:{{ new Date().toLocaleDateString('zh-CN') }}</span>
|
||||
<!-- Content -->
|
||||
<div style="position:relative;z-index:1">
|
||||
<div style="font-size:7px;letter-spacing:1.5px;color:var(--sage);margin-bottom:3px">doTERRA · 来自大地的礼物</div>
|
||||
<div style="font-size:13px;font-weight:700;color:var(--text-dark);margin-bottom:3px;line-height:1.3">配方名称</div>
|
||||
<div style="width:30px;height:1px;background:linear-gradient(90deg,var(--sage),var(--gold));margin:6px 0"></div>
|
||||
<div style="font-size:9px;color:var(--text-light);margin-bottom:6px">薰衣草 · 乳香 · 茶树</div>
|
||||
<!-- Total cost bar -->
|
||||
<div style="background:linear-gradient(135deg,var(--sage),#5a7d5e);border-radius:6px;padding:6px 10px;display:flex;justify-content:space-between;align-items:center">
|
||||
<span style="color:rgba(255,255,255,0.85);font-size:8px;letter-spacing:0.5px">配方总成本</span>
|
||||
<span style="color:white;font-size:12px;font-weight:700">¥12.50</span>
|
||||
</div>
|
||||
<!-- Date: centered -->
|
||||
<div style="margin-top:8px;text-align:center;font-size:7px;color:var(--text-light);letter-spacing:0.5px">
|
||||
制作日期:{{ new Date().toLocaleDateString('zh-CN') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1047,7 +1049,7 @@ async function applyBusiness() {
|
||||
color: var(--sage-dark);
|
||||
}
|
||||
|
||||
/* Card preview mini — matches actual card layout */
|
||||
/* Card preview mini */
|
||||
.card-preview-mini {
|
||||
position: relative;
|
||||
width: 280px;
|
||||
@@ -1056,79 +1058,8 @@ async function applyBusiness() {
|
||||
border: 1px solid #e0ccaa;
|
||||
overflow: hidden;
|
||||
font-family: 'Noto Serif SC', serif;
|
||||
padding: 16px;
|
||||
padding: 18px;
|
||||
}
|
||||
.card-preview-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
opacity: 0.15;
|
||||
}
|
||||
.card-preview-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding-right: 60px; /* leave room for QR area */
|
||||
}
|
||||
.card-preview-qr-area {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
z-index: 2;
|
||||
max-width: 50px;
|
||||
}
|
||||
.card-preview-qr {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.card-preview-qr-text {
|
||||
font-size: 6px;
|
||||
color: var(--text-light);
|
||||
line-height: 1.2;
|
||||
white-space: pre-line;
|
||||
max-width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
.card-preview-cost {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-top: 12px;
|
||||
height: 22px;
|
||||
background: linear-gradient(135deg, var(--sage), #5a7d5e);
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
color: white;
|
||||
font-size: 9px;
|
||||
}
|
||||
.card-preview-bottom {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.card-preview-logo {
|
||||
height: 16px;
|
||||
width: auto;
|
||||
object-fit: contain;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.card-preview-date {
|
||||
font-size: 8px;
|
||||
color: var(--text-light);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
/* brand name now inside .card-preview-qr-text */
|
||||
|
||||
.hint-text {
|
||||
font-size: 13px;
|
||||
|
||||
Reference in New Issue
Block a user