From 03a112c734dab2334f447a37529b1b5f3fb51f6f Mon Sep 17 00:00:00 2001 From: Hera Zhao Date: Thu, 9 Apr 2026 10:40:16 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=B8=8A=E4=BC=A0=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E6=AF=94=E4=BE=8B=E3=80=81QR=E6=AD=A3?= =?UTF-8?q?=E6=96=B9=E5=BD=A2=E8=A3=81=E5=89=AA=E3=80=81Logo=E5=B7=A6?= =?UTF-8?q?=E4=B8=8B=E8=A7=92=E3=80=81=E6=97=A5=E6=9C=9F=E9=9D=A0=E5=8F=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上传图片: - object-fit: contain 保持原比例,不压扁不拉长 - QR上传检测是否正方形,非正方形提示并自动裁剪中心区域 配方卡片: - Logo位置改为左下角 (left:24px) - 制作日期靠右对齐 (text-align:right) 品牌预览: - Logo位置改为左下角 (left:16px) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/components/RecipeDetailOverlay.vue | 5 +- frontend/src/views/MyDiary.vue | 50 +++++++++++++++++-- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/RecipeDetailOverlay.vue b/frontend/src/components/RecipeDetailOverlay.vue index 63c1801..8a0b589 100644 --- a/frontend/src/components/RecipeDetailOverlay.vue +++ b/frontend/src/components/RecipeDetailOverlay.vue @@ -1170,8 +1170,7 @@ async function saveRecipe() { .card-logo { position: absolute; bottom: 60px; - left: 50%; - transform: translateX(-50%); + left: 24px; height: 60px; object-fit: contain; z-index: 1; @@ -1300,7 +1299,7 @@ async function saveRecipe() { .card-footer { margin-top: 16px; - text-align: center; + text-align: right; font-size: 11px; color: var(--text-light, #9a8570); letter-spacing: 1px; diff --git a/frontend/src/views/MyDiary.vue b/frontend/src/views/MyDiary.vue index cf82f0c..6805a5d 100644 --- a/frontend/src/views/MyDiary.vue +++ b/frontend/src/views/MyDiary.vue @@ -462,11 +462,56 @@ function compressImage(base64, maxSize = 500000) { }) } +// Crop image to square from center +function cropToSquare(base64) { + return new Promise((resolve) => { + const img = new Image() + img.onload = () => { + const size = Math.min(img.width, img.height) + const x = (img.width - size) / 2 + const y = (img.height - size) / 2 + const canvas = document.createElement('canvas') + canvas.width = size + canvas.height = size + canvas.getContext('2d').drawImage(img, x, y, size, size, 0, 0, size, size) + resolve(canvas.toDataURL('image/png')) + } + img.onerror = () => resolve(base64) + img.src = base64 + }) +} + +// Check if image is roughly square +function checkSquare(base64) { + return new Promise((resolve) => { + const img = new Image() + img.onload = () => { + const ratio = img.width / img.height + resolve(ratio > 0.85 && ratio < 1.15) // within 15% of square + } + img.onerror = () => resolve(true) + img.src = base64 + }) +} + async function handleUpload(type, event) { const file = event.target.files[0] if (!file) return try { let base64 = await readFileAsBase64(file) + + // QR: check if square, offer to crop + if (type === 'qr') { + const isSquare = await checkSquare(base64) + if (!isSquare) { + const { showConfirm: confirm } = await import('../composables/useDialog') + const ok = await confirm('二维码图片不是正方形,是否自动裁剪为正方形?\n(取中心区域)') + if (ok) { + base64 = await cropToSquare(base64) + } + } + } + const maxSize = type === 'bg' ? 1000000 : 500000 base64 = await compressImage(base64, maxSize) const fieldMap = { logo: 'brand_logo', bg: 'brand_bg', qr: 'qr_code' } @@ -958,7 +1003,7 @@ async function applyBusiness() { 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-img { width: 100%; height: 100%; object-fit: contain; } .upload-box-hint { font-size: 12px; color: var(--text-light, #9a8570); } .btn-clear { margin-top: 6px; @@ -1019,8 +1064,7 @@ async function applyBusiness() { .card-preview-logo { position: absolute; bottom: 40px; - left: 50%; - transform: translateX(-50%); + left: 16px; height: 20px; width: auto; object-fit: contain;