1. 修复海报图片

This commit is contained in:
李琦
2026-08-03 16:54:14 +08:00
parent 18d7296f01
commit adc40c1834
5 changed files with 135 additions and 38 deletions

View File

@@ -762,22 +762,26 @@
/>
</a-form-item>
<a-form-item label="照片展示焦点">
<a-radio-group v-model:value="heroFocusDevice" size="small" class="mb-2" button-style="solid">
<a-radio-button value="pc">PC </a-radio-button>
<a-radio-button value="mobile">手机端</a-radio-button>
</a-radio-group>
<div
v-if="posterCfg.heroImg"
ref="heroFocusPreviewEl"
class="hero-focus-preview hero-focus-preview--drag"
:class="{ dragging: heroFocusDragging }"
:class="{ dragging: heroFocusDragging, 'is-mobile': heroFocusDevice === 'mobile' }"
@pointerdown="onHeroFocusPointerDown"
>
<img
:src="posterCfg.heroImg"
alt=""
draggable="false"
:style="{ objectPosition: heroFocusCss(posterCfg) }"
:style="{ objectPosition: heroFocusPreviewCss }"
/>
<span
class="hero-focus-crosshair"
:style="{ left: posterCfg.heroFocusX + '%', top: posterCfg.heroFocusY + '%' }"
:style="{ left: heroFocusActiveX + '%', top: heroFocusActiveY + '%' }"
/>
</div>
<div v-else class="hero-focus-preview hero-focus-preview--empty">
@@ -797,7 +801,8 @@
</button>
</div>
<div class="text-[11px] text-[#8A8680] mt-1">
在预览上拖拽十字准星或点下方 9×9 网格当前 {{ Math.round(posterCfg.heroFocusX) }}% · {{ Math.round(posterCfg.heroFocusY) }}%
{{ heroFocusDevice === 'mobile' ? '手机端' : 'PC 端' }}焦点拖拽十字准星或点网格当前
{{ Math.round(heroFocusActiveX) }}% · {{ Math.round(heroFocusActiveY) }}%
</div>
</a-form-item>
<a-form-item label="二维码中心图">
@@ -1635,19 +1640,45 @@ function ensurePosterSlot(side = posterSideTab.value, layout = posterLayoutTab.v
const heroFocusGrid = heroFocusGridPoints(HERO_FOCUS_GRID)
const heroFocusPreviewEl = ref(null)
const heroFocusDragging = ref(false)
const heroFocusDevice = ref('pc') // pc | mobile
const heroFocusActiveX = computed(() => {
const cfg = posterCfg.value
if (!cfg) return 50
if (heroFocusDevice.value === 'mobile') {
return Number.isFinite(Number(cfg.heroFocusMobileX)) ? cfg.heroFocusMobileX : (cfg.heroFocusX ?? 50)
}
return cfg.heroFocusX ?? 50
})
const heroFocusActiveY = computed(() => {
const cfg = posterCfg.value
if (!cfg) return 50
if (heroFocusDevice.value === 'mobile') {
return Number.isFinite(Number(cfg.heroFocusMobileY)) ? cfg.heroFocusMobileY : (cfg.heroFocusY ?? 50)
}
return cfg.heroFocusY ?? 50
})
const heroFocusPreviewCss = computed(() => {
const cfg = posterCfg.value
if (!cfg) return '50% 50%'
return heroFocusCss(cfg, heroFocusDevice.value === 'mobile' ? 'mobile' : undefined)
})
function setHeroFocus(x, y) {
const cfg = posterCfg.value
if (!cfg) return
cfg.heroFocusX = clampHeroFocus(x)
cfg.heroFocusY = clampHeroFocus(y)
if (heroFocusDevice.value === 'mobile') {
cfg.heroFocusMobileX = clampHeroFocus(x)
cfg.heroFocusMobileY = clampHeroFocus(y)
} else {
cfg.heroFocusX = clampHeroFocus(x)
cfg.heroFocusY = clampHeroFocus(y)
}
}
function isHeroFocusGridActive(pt) {
const cfg = posterCfg.value
if (!cfg) return false
return Math.abs(cfg.heroFocusX - pt.x) < 0.6
&& Math.abs(cfg.heroFocusY - pt.y) < 0.6
return Math.abs(heroFocusActiveX.value - pt.x) < 0.6
&& Math.abs(heroFocusActiveY.value - pt.y) < 0.6
}
function heroFocusFromClient(clientX, clientY) {
@@ -1733,7 +1764,6 @@ watch([posterSideTab, posterLayoutTab], () => {
const slot = ensurePosterSlot()
const l = layoutKey(posterLayoutTab.value)
slot.layout = Number(l)
slot.mobileLayout = l === '2' ? 'landscape' : 'portrait'
})
const currentPhotoIndex = computed(() => Math.min(Number(activePhotoTab.value) || 0, Math.max(cfg.photoPages.length - 1, 0)))
@@ -2244,11 +2274,9 @@ async function loadPosterConfig() {
async function onSavePosterConfig() {
posterSaving.value = true
try {
// 保存前强制各布局语义
// 仅同步 layout 编号与 Tab 一致,不覆盖用户所选 template / mobileLayout
for (const s of ['1', '2', '3']) {
ensurePosterSlot(s, '1').mobileLayout = 'portrait'
ensurePosterSlot(s, '1').layout = 1
ensurePosterSlot(s, '2').mobileLayout = 'landscape'
ensurePosterSlot(s, '2').layout = 2
}
const payload = normalizePosterBundle(posterBundle)
@@ -3452,6 +3480,10 @@ onUnmounted(() => {
user-select: none;
touch-action: none;
}
.hero-focus-preview.is-mobile {
width: min(100%, 200px);
aspect-ratio: 3 / 4;
}
.hero-focus-preview--drag { cursor: crosshair; }
.hero-focus-preview--drag.dragging { cursor: grabbing; }
.hero-focus-preview--empty {