feat: support ticket home video cover
This commit is contained in:
@@ -1,7 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="h-screen overflow-hidden bg-[#06111f] flex flex-col">
|
<view class="h-screen overflow-hidden bg-[#06111f] flex flex-col">
|
||||||
<view class="relative z-0 h-[43vh] shrink-0 overflow-hidden bg-[#173a34]">
|
<view class="relative z-0 h-[43vh] shrink-0 overflow-hidden bg-[#173a34]">
|
||||||
<image class="absolute inset-0 h-full w-full" :src="homeData.coverImage" mode="aspectFill" />
|
<video
|
||||||
|
v-if="homeData.coverImage && isMp4Video(homeData.coverImage)"
|
||||||
|
class="absolute inset-0 h-full w-full"
|
||||||
|
:src="homeData.coverImage"
|
||||||
|
autoplay
|
||||||
|
loop
|
||||||
|
muted
|
||||||
|
:controls="false"
|
||||||
|
:show-center-play-btn="false"
|
||||||
|
:show-play-btn="false"
|
||||||
|
:show-fullscreen-btn="false"
|
||||||
|
:show-mute-btn="false"
|
||||||
|
:enable-progress-gesture="false"
|
||||||
|
object-fit="cover"
|
||||||
|
/>
|
||||||
|
<image
|
||||||
|
v-else-if="homeData.coverImage"
|
||||||
|
class="absolute inset-0 h-full w-full"
|
||||||
|
:src="homeData.coverImage"
|
||||||
|
mode="aspectFill"
|
||||||
|
/>
|
||||||
<view class="absolute inset-0 bg-[linear-gradient(180deg,rgba(6,17,31,0.15)_18%,rgba(6,17,31,0.1)_45%,rgba(6,17,31,0.92)_100%)]" />
|
<view class="absolute inset-0 bg-[linear-gradient(180deg,rgba(6,17,31,0.15)_18%,rgba(6,17,31,0.1)_45%,rgba(6,17,31,0.92)_100%)]" />
|
||||||
|
|
||||||
<view class="absolute inset-x-0 top-0 z-20">
|
<view class="absolute inset-x-0 top-0 z-20">
|
||||||
@@ -151,6 +171,11 @@ const instance = getCurrentInstance()
|
|||||||
const scenicMetaText = computed(() =>
|
const scenicMetaText = computed(() =>
|
||||||
[props.homeData.levelText, props.homeData.subtitle].filter(Boolean).join('|')
|
[props.homeData.levelText, props.homeData.subtitle].filter(Boolean).join('|')
|
||||||
)
|
)
|
||||||
|
const isMp4Video = (url) => {
|
||||||
|
if (typeof url !== 'string') return false
|
||||||
|
const resourcePath = url.trim().split(/[?#]/)[0]
|
||||||
|
return resourcePath.toLowerCase().endsWith('.mp4')
|
||||||
|
}
|
||||||
const isActiveGroup = (groupId) =>
|
const isActiveGroup = (groupId) =>
|
||||||
String(groupId) === String(activeGroupId.value)
|
String(groupId) === String(activeGroupId.value)
|
||||||
const productsForGroup = (group) =>
|
const productsForGroup = (group) =>
|
||||||
|
|||||||
@@ -117,6 +117,27 @@ test("TicketHome consumes scenic home response fields directly", async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("TicketHome renders MP4 cover images as background videos", async () => {
|
||||||
|
const source = await readTicketFile("components/TicketHome.vue");
|
||||||
|
|
||||||
|
assert.match(
|
||||||
|
source,
|
||||||
|
/<video\s+v-if="homeData\.coverImage && isMp4Video\(homeData\.coverImage\)"/
|
||||||
|
);
|
||||||
|
assert.match(source, /autoplay\s+loop\s+muted/);
|
||||||
|
assert.match(source, /:controls="false"/);
|
||||||
|
assert.match(source, /:show-center-play-btn="false"/);
|
||||||
|
assert.match(source, /:show-play-btn="false"/);
|
||||||
|
assert.match(source, /:show-fullscreen-btn="false"/);
|
||||||
|
assert.match(source, /:show-mute-btn="false"/);
|
||||||
|
assert.match(source, /:enable-progress-gesture="false"/);
|
||||||
|
assert.match(source, /object-fit="cover"/);
|
||||||
|
assert.match(source, /<image\s+v-else-if="homeData\.coverImage"/);
|
||||||
|
assert.match(source, /const isMp4Video = \(url\) =>/);
|
||||||
|
assert.match(source, /url\.trim\(\)\.split\(\/\[\?\#\]\/\)\[0\]/);
|
||||||
|
assert.match(source, /toLowerCase\(\)\.endsWith\('\.mp4'\)/);
|
||||||
|
});
|
||||||
|
|
||||||
test("product detail is an independent prototype-aligned page", async () => {
|
test("product detail is an independent prototype-aligned page", async () => {
|
||||||
const indexPage = await readTicketFile("index.vue");
|
const indexPage = await readTicketFile("index.vue");
|
||||||
const detailPage = await readTicketFile("product-detail.vue");
|
const detailPage = await readTicketFile("product-detail.vue");
|
||||||
|
|||||||
Reference in New Issue
Block a user