feat: load ticket home from scenic api

This commit is contained in:
2026-08-11 11:14:16 +08:00
parent 0059b76de4
commit e2dc7d98bb
2 changed files with 77 additions and 12 deletions

View File

@@ -1,31 +1,77 @@
<template> <template>
<view class="h-screen min-w-0 overflow-hidden bg-[#f5f7fa] text-[#172033]"> <view class="h-screen min-w-0 overflow-hidden bg-[#f5f7fa] text-[#172033]">
<TicketHome <TicketHome
:scenic-spot="SCENIC_SPOT" v-if="homeData"
:groups="visibleGroups" :home-data="homeData"
:products="ticketStore.products"
@back="goBack" @back="goBack"
@open-travelers="openTravelers" @open-travelers="openTravelers"
@open-orders="openOrders" @open-orders="openOrders"
@open-detail="openProductDetail" @open-detail="openProductDetail"
@buy="startBooking" @buy="startBooking"
/> />
<view v-else class="flex h-full flex-col">
<TopNavBar title="" @back="goBack" />
<view
v-if="loading"
class="flex min-h-0 flex-1 items-center justify-center"
>
<text class="text-[14px] text-[#808997]">正在加载景区商品...</text>
</view>
<view
v-else-if="errorMessage"
class="flex min-h-0 flex-1 flex-col items-center justify-center px-[32px] text-center"
>
<text class="text-[14px] leading-[21px] text-[#808997]">
{{ errorMessage }}
</text>
<view
class="mt-[18px] flex h-[38px] items-center justify-center rounded-full bg-[#149474] px-[22px]"
@click="loadTicketHome"
>
<text class="text-[13px] font-medium text-white">重新加载</text>
</view>
</view>
</view>
</view> </view>
</template> </template>
<script setup> <script setup>
import { computed } from "vue"; import { onMounted, ref } from "vue";
import TopNavBar from "@/components/TopNavBar/index.vue";
import TicketHome from "./components/TicketHome.vue"; import TicketHome from "./components/TicketHome.vue";
import { GROUPS, SCENIC_SPOT } from "./data.js"; import { scenicProductHome } from "./api/scenic.js";
import { useTicketStore } from "./store.js";
const ticketStore = useTicketStore(); const homeData = ref(null);
const loading = ref(false);
const errorMessage = ref("");
const loadTicketHome = async () => {
loading.value = true;
errorMessage.value = "";
try {
const response = await scenicProductHome({ scenicId: 20260811 });
const validData =
response?.data &&
typeof response.data === "object" &&
!Array.isArray(response.data);
if (response?.code !== 0 || !validData) {
throw new Error(response?.msg || "景区商品加载失败,请稍后重试");
}
homeData.value = response.data;
} catch (error) {
homeData.value = null;
errorMessage.value = error?.message || "景区商品加载失败,请稍后重试";
} finally {
loading.value = false;
}
};
onMounted(loadTicketHome);
const visibleGroups = computed(() =>
[...GROUPS]
.filter((group) => group.enabled)
.sort((left, right) => left.sortOrder - right.sortOrder)
);
const goBack = () => uni.navigateBack(); const goBack = () => uni.navigateBack();
const openTravelers = () => const openTravelers = () =>
uni.navigateTo({ url: "/pages-service/tickets/travelers" }); uni.navigateTo({ url: "/pages-service/tickets/travelers" });

View File

@@ -63,6 +63,25 @@ test("storefront synchronizes the left category from right-column scrolling", as
assert.match(source, /TopNavBar/); assert.match(source, /TopNavBar/);
}); });
test("ticket storefront loads API home data without a static adapter", async () => {
const source = await readTicketFile("index.vue");
assert.match(
source,
/import \{ scenicProductHome \} from "\.\/api\/scenic\.js"/
);
assert.match(source, /scenicProductHome\(\{ scenicId: 20260811 \}\)/);
assert.match(source, /const homeData = ref\(null\)/);
assert.match(source, /:home-data="homeData"/);
assert.match(source, /v-if="loading"/);
assert.match(source, /v-else-if="errorMessage"/);
assert.match(source, /@click="loadTicketHome"/);
assert.doesNotMatch(
source,
/SCENIC_SPOT|GROUPS|ticketStore\.products|visibleGroups/
);
});
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");