1. 修复海报图片
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user