feat: Header重排、共享配方到公共库、待审核配方、权限优化 #17
@@ -51,29 +51,25 @@
|
||||
<div v-show="!cardImageUrl" ref="cardRef" class="export-card">
|
||||
<!-- 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">
|
||||
<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:3">
|
||||
<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>
|
||||
<!-- Card content (z-index above overlays) -->
|
||||
<!-- Card content -->
|
||||
<div style="position:relative;z-index:2">
|
||||
<div style="font-size:11px;letter-spacing:3px;color:var(--sage);margin-bottom:8px">
|
||||
<div class="ec-subtitle">
|
||||
{{ cardLang === 'en' ? 'doTERRA · Gifts of the Earth' : 'doTERRA · 来自大地的礼物' }}
|
||||
</div>
|
||||
<div style="font-size:26px;font-weight:700;color:var(--text-dark);margin-bottom:6px;line-height:1.3">
|
||||
{{ getCardRecipeName() }}
|
||||
</div>
|
||||
<div class="ec-title">{{ getCardRecipeName() }}</div>
|
||||
<div style="width:80px;height:2px;background:linear-gradient(90deg,var(--sage),var(--gold));border-radius:2px;margin:14px 0"></div>
|
||||
|
||||
<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 v-for="(ing, i) in cardIngredients" :key="i" class="ec-ing">
|
||||
<span class="ec-oil-name">{{ getCardOilName(ing.oil) }}</span>
|
||||
<span class="ec-drops">{{ ing.drops }} {{ cardLang === 'en' ? 'drops' : '滴' }}</span>
|
||||
<span class="ec-cost">{{ oilsStore.fmtPrice(oilsStore.pricePerDrop(ing.oil) * ing.drops) }}</span>
|
||||
<span v-if="hasRetailForOil(ing.oil) && retailPerDrop(ing.oil) > oilsStore.pricePerDrop(ing.oil)" class="ec-retail">{{ oilsStore.fmtPrice(retailPerDrop(ing.oil) * ing.drops) }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -81,13 +77,16 @@
|
||||
|
||||
<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">
|
||||
<div class="ec-total-bar">
|
||||
<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>
|
||||
|
||||
<div style="margin-top:16px;text-align:center;font-size:11px;color:var(--text-light);letter-spacing:1px">
|
||||
{{ cardLang === 'en' ? 'Date: ' : '制作日期:' }}{{ todayStr }}
|
||||
<!-- Logo left + Date right -->
|
||||
<div class="ec-bottom">
|
||||
<img v-if="brand.brand_logo" :src="brand.brand_logo" crossorigin="anonymous" class="ec-logo" />
|
||||
<span v-else></span>
|
||||
<span class="ec-date">{{ cardLang === 'en' ? 'Date: ' : '制作日期:' }}{{ todayStr }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1088,10 +1087,105 @@ async function saveRecipe() {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding-right: 80px; /* leave room for QR (54px) + gap */
|
||||
/* ===== Export Card Content (responsive) ===== */
|
||||
.ec-subtitle {
|
||||
font-size: 11px;
|
||||
letter-spacing: 3px;
|
||||
color: var(--sage);
|
||||
margin-bottom: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ec-title {
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
color: var(--text-dark);
|
||||
margin-bottom: 6px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc(100% - 80px); /* leave room for QR */
|
||||
}
|
||||
.ec-ing {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 9px 0;
|
||||
border-bottom: 1px solid rgba(180,150,100,0.15);
|
||||
font-size: 14px;
|
||||
}
|
||||
.ec-oil-name {
|
||||
flex: 1;
|
||||
color: var(--text-dark);
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
min-width: 0;
|
||||
}
|
||||
.ec-drops {
|
||||
width: 50px;
|
||||
text-align: right;
|
||||
color: var(--sage-dark);
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ec-cost {
|
||||
width: 60px;
|
||||
text-align: right;
|
||||
color: var(--text-light);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ec-retail {
|
||||
width: 55px;
|
||||
text-align: right;
|
||||
color: var(--text-light);
|
||||
font-size: 10px;
|
||||
text-decoration: line-through;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ec-total-bar {
|
||||
background: linear-gradient(135deg, var(--sage), #5a7d5e);
|
||||
border-radius: 12px;
|
||||
padding: 14px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.ec-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.ec-logo {
|
||||
height: 36px;
|
||||
object-fit: contain;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.ec-date {
|
||||
font-size: 11px;
|
||||
color: var(--text-light);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* Mobile: smaller card text */
|
||||
@media (max-width: 420px) {
|
||||
.export-card { padding: 24px; }
|
||||
.ec-subtitle { font-size: 9px; letter-spacing: 2px; }
|
||||
.ec-title { font-size: 20px; max-width: calc(100% - 65px); }
|
||||
.ec-ing { font-size: 12px; padding: 7px 0; }
|
||||
.ec-drops { width: 42px; font-size: 11px; }
|
||||
.ec-cost { width: 50px; font-size: 10px; }
|
||||
.ec-retail { width: 45px; font-size: 9px; }
|
||||
.ec-total-bar { padding: 10px 14px; }
|
||||
.ec-total-bar span:first-child { font-size: 11px; }
|
||||
.ec-total-bar span:last-child { font-size: 16px; }
|
||||
.ec-date { font-size: 9px; }
|
||||
.ec-logo { height: 28px; }
|
||||
}
|
||||
|
||||
/* Brand overlays */
|
||||
|
||||
@@ -171,8 +171,7 @@
|
||||
<div class="card-preview-mini">
|
||||
<!-- 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" />
|
||||
<!-- Logo: shown in bottom row, not as watermark -->
|
||||
<!-- 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)" />
|
||||
@@ -189,9 +188,11 @@
|
||||
<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') }}
|
||||
<!-- Logo left + Date right -->
|
||||
<div style="display:flex;justify-content:space-between;align-items:flex-end;margin-top:8px">
|
||||
<img v-if="brandLogo" :src="brandLogo" style="height:18px;object-fit:contain;opacity:0.5" />
|
||||
<span v-else></span>
|
||||
<span style="font-size:7px;color:var(--text-light);letter-spacing:0.5px">制作日期:{{ new Date().toLocaleDateString('zh-CN') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user