-
-
-
![]()
-
📲 点击上传二维码图片
+
+
+
+
+
+
-
-
上传后将显示在配方卡片右下角
-
@@ -241,6 +269,7 @@ const brandQrUrl = ref('')
const brandQrImage = ref('')
const brandLogo = ref('')
const brandBg = ref('')
+const brandAlign = ref('center')
const logoInput = ref(null)
const bgInput = ref(null)
const qrInput = ref(null)
@@ -362,6 +391,7 @@ async function loadBrandSettings() {
brandQrImage.value = data.qr_code || ''
brandLogo.value = data.brand_logo || ''
brandBg.value = data.brand_bg || ''
+ brandAlign.value = data.brand_align || 'center'
}
} catch {
// no brand settings yet
@@ -374,7 +404,7 @@ async function saveBrandSettings() {
method: 'PUT',
body: JSON.stringify({
brand_name: brandName.value,
- qr_url: brandQrUrl.value,
+ brand_align: brandAlign.value,
}),
})
} catch {
@@ -397,11 +427,43 @@ function readFileAsBase64(file) {
})
}
+// Compress image if too large
+function compressImage(base64, maxSize = 500000) {
+ return new Promise((resolve) => {
+ if (base64.length <= maxSize) { resolve(base64); return }
+ const img = new Image()
+ img.onload = () => {
+ const canvas = document.createElement('canvas')
+ let w = img.width, h = img.height
+ // Scale down if very large
+ const maxDim = 800
+ if (w > maxDim || h > maxDim) {
+ const ratio = Math.min(maxDim / w, maxDim / h)
+ w = Math.round(w * ratio)
+ h = Math.round(h * ratio)
+ }
+ canvas.width = w
+ canvas.height = h
+ canvas.getContext('2d').drawImage(img, 0, 0, w, h)
+ let quality = 0.8
+ let result = canvas.toDataURL('image/jpeg', quality)
+ while (result.length > maxSize && quality > 0.2) {
+ quality -= 0.1
+ result = canvas.toDataURL('image/jpeg', quality)
+ }
+ resolve(result)
+ }
+ img.src = base64
+ })
+}
+
async function handleUpload(type, event) {
const file = event.target.files[0]
if (!file) return
try {
- const base64 = await readFileAsBase64(file)
+ let base64 = await readFileAsBase64(file)
+ const maxSize = type === 'bg' ? 1000000 : 500000
+ base64 = await compressImage(base64, maxSize)
const fieldMap = { logo: 'brand_logo', bg: 'brand_bg', qr: 'qr_code' }
const field = fieldMap[type]
if (!field) return
@@ -414,9 +476,31 @@ async function handleUpload(type, event) {
else if (type === 'bg') brandBg.value = base64
else if (type === 'qr') brandQrImage.value = base64
ui.showToast('上传成功')
+ } else {
+ const err = await res.json().catch(() => ({}))
+ ui.showToast(err.detail || '上传失败')
}
+ } catch (e) {
+ ui.showToast('上传失败: ' + (e.message || ''))
+ }
+ // Reset input so same file can be re-selected
+ event.target.value = ''
+}
+
+async function clearBrandImage(type) {
+ const fieldMap = { logo: 'brand_logo', bg: 'brand_bg', qr: 'qr_code' }
+ const field = fieldMap[type]
+ try {
+ await api('/api/brand', {
+ method: 'PUT',
+ body: JSON.stringify({ [field]: null }),
+ })
+ if (type === 'logo') brandLogo.value = ''
+ else if (type === 'bg') brandBg.value = ''
+ else if (type === 'qr') brandQrImage.value = ''
+ ui.showToast('已清除')
} catch {
- ui.showToast('上传失败')
+ ui.showToast('清除失败')
}
}
@@ -853,6 +937,115 @@ async function applyBusiness() {
color: #b0aab5;
}
+/* Upload box (matching initial commit style) */
+.upload-box {
+ width: 100px;
+ height: 100px;
+ border: 2px dashed var(--border, #e0d4c0);
+ border-radius: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ overflow: hidden;
+ background: white;
+ transition: border-color 0.15s;
+}
+.upload-box:hover { border-color: var(--sage, #7a9e7e); }
+.upload-box-img { width: 100%; height: 100%; object-fit: cover; }
+.upload-box-hint { font-size: 12px; color: var(--text-light, #9a8570); }
+.btn-clear {
+ margin-top: 6px;
+ font-size: 11px;
+ background: none;
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ padding: 2px 8px;
+ cursor: pointer;
+ color: var(--text-light);
+}
+.btn-clear:hover { border-color: #c0392b; color: #c0392b; }
+.btn-align {
+ font-size: 11px;
+ padding: 3px 10px;
+ border: 1.5px solid var(--border);
+ border-radius: 6px;
+ background: white;
+ cursor: pointer;
+ color: var(--text-mid);
+}
+.btn-align.active {
+ background: var(--sage-mist);
+ border-color: var(--sage);
+ color: var(--sage-dark);
+}
+
+/* Card preview mini */
+.card-preview-mini {
+ position: relative;
+ width: 280px;
+ height: 180px;
+ background: linear-gradient(145deg, #faf7f0, #f5ede0);
+ border-radius: 14px;
+ border: 1px solid #e0ccaa;
+ overflow: hidden;
+ font-family: 'Noto Serif SC', serif;
+ padding: 16px;
+}
+.card-preview-bg {
+ position: absolute;
+ inset: 0;
+ background-size: cover;
+ background-position: center;
+ opacity: 0.15;
+}
+.card-preview-content { position: relative; z-index: 1; }
+.card-preview-qr {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ width: 40px;
+ height: 40px;
+ object-fit: cover;
+ border-radius: 4px;
+ z-index: 1;
+}
+.card-preview-logo {
+ position: absolute;
+ bottom: 40px;
+ left: 50%;
+ transform: translateX(-50%);
+ height: 20px;
+ width: auto;
+ object-fit: contain;
+ z-index: 1;
+}
+.card-preview-cost {
+ position: absolute;
+ bottom: 12px;
+ left: 16px;
+ right: 16px;
+ height: 24px;
+ background: linear-gradient(135deg, var(--sage), #5a7d5e);
+ border-radius: 6px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: white;
+ font-size: 10px;
+ z-index: 1;
+}
+.card-preview-brand {
+ position: absolute;
+ bottom: 40px;
+ left: 16px;
+ right: 16px;
+ font-size: 9px;
+ color: var(--text-light);
+ z-index: 1;
+ white-space: pre-line;
+}
+
.hint-text {
font-size: 13px;
color: #6b6375;