192 lines
6.5 KiB
Vue
192 lines
6.5 KiB
Vue
<template>
|
||
<view class="flex h-screen min-w-0 flex-col overflow-hidden bg-[#f4f6f8]">
|
||
<TopNavBar
|
||
:title="item?.name || ''"
|
||
:subtitle="sectionTitle"
|
||
title-align="left"
|
||
background="#ffffff"
|
||
/>
|
||
|
||
<scroll-view v-if="item" class="min-h-0 flex-1" scroll-y>
|
||
<view class="h-[240px] overflow-hidden bg-[#dfe8e5]">
|
||
<DuohuaMediaSwiper :media-list="imageList" />
|
||
</view>
|
||
|
||
<view class="bg-white px-[16px] pb-[18px] pt-[16px]">
|
||
<view class="flex items-center gap-[8px]">
|
||
<text class="min-w-0 text-[22px] font-bold leading-[30px] text-[#172033]">
|
||
{{ item.name }}
|
||
</text>
|
||
<text
|
||
v-if="item.grade"
|
||
class="shrink-0 rounded-[5px] bg-[#e9f7f1] px-[7px] py-[3px] text-[11px] font-semibold text-[#149474]"
|
||
>
|
||
{{ item.grade }}
|
||
</text>
|
||
</view>
|
||
<text
|
||
v-if="item.name_en"
|
||
class="mt-[3px] block text-[12px] leading-[18px] text-[#808997]"
|
||
>
|
||
{{ item.name_en }}
|
||
</text>
|
||
<view v-if="displayAddress" class="mt-[10px] flex items-center">
|
||
<uni-icons class="shrink-0" type="location" size="15" color="#808997" />
|
||
<text class="ml-[4px] min-w-0 flex-1 text-[12px] leading-[19px] text-[#6f7884]">
|
||
{{ displayAddress }}
|
||
</text>
|
||
</view>
|
||
|
||
<view v-if="contactText || canOpenLocation" class="mt-[14px] flex items-center gap-[10px]">
|
||
<view v-if="contactText" class="flex min-w-0 items-center gap-[8px]">
|
||
<text class="min-w-0 text-[13px] font-medium text-[#4f5966]">
|
||
{{ contactText }}
|
||
</text>
|
||
<view
|
||
class="flex h-[36px] shrink-0 items-center rounded-full bg-[#ecf8f2] px-[14px]"
|
||
@click="makePhoneCall"
|
||
>
|
||
<uni-icons type="phone" size="15" color="#149474" />
|
||
<text class="ml-[5px] text-[12px] font-medium text-[#149474]">拨打电话</text>
|
||
</view>
|
||
</view>
|
||
<view
|
||
v-if="canOpenLocation"
|
||
class="flex h-[36px] items-center rounded-full bg-[#ecf8f2] px-[14px]"
|
||
@click="openLocation"
|
||
>
|
||
<uni-icons type="navigate" size="15" color="#149474" />
|
||
<text class="ml-[5px] text-[12px] font-medium text-[#149474]">地图导航</text>
|
||
</view>
|
||
</view>
|
||
<view v-if="item.tags?.length" class="mt-[14px] flex flex-wrap gap-[6px]">
|
||
<text
|
||
v-for="tag in item.tags"
|
||
:key="tag"
|
||
class="rounded-[4px] bg-[#e8f2ff] px-[6px] py-[3px] text-[10px] text-[#3474c7]"
|
||
>
|
||
{{ tag }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="item.description" class="mx-[12px] mt-[12px] rounded-[16px] bg-white p-[16px]">
|
||
<text class="block text-[16px] font-semibold text-[#202733]">介绍</text>
|
||
<text class="mt-[10px] block text-[14px] leading-[23px] text-[#5f6875]">
|
||
{{ item.description }}
|
||
</text>
|
||
</view>
|
||
|
||
<view
|
||
v-for="section in arraySections"
|
||
:key="section.title"
|
||
class="mx-[12px] mt-[12px] rounded-[16px] bg-white p-[16px]"
|
||
>
|
||
<text class="block text-[16px] font-semibold text-[#202733]">
|
||
{{ section.title }}
|
||
</text>
|
||
<view class="mt-[9px] flex flex-wrap gap-[7px]">
|
||
<text
|
||
v-for="(value, index) in section.values"
|
||
:key="`${section.title}-${index}`"
|
||
class="rounded-[6px] bg-[#f2f6f5] px-[9px] py-[6px] text-[12px] leading-[18px] text-[#52605c]"
|
||
>
|
||
{{ formatValue(value) }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="h-[24px]" />
|
||
</scroll-view>
|
||
|
||
<view v-else class="flex min-h-0 flex-1 items-center justify-center">
|
||
<text class="text-[14px] text-[#808997]">未找到对应内容</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, ref } from "vue";
|
||
import { onLoad } from "@dcloudio/uni-app";
|
||
import TopNavBar from "@/components/TopNavBar/index.vue";
|
||
import DuohuaMediaSwiper from "./components/DuohuaMediaSwiper.vue";
|
||
import {
|
||
getItem,
|
||
getSectionForCollection,
|
||
normalizeImageList,
|
||
} from "./data";
|
||
|
||
const item = ref(null);
|
||
const collection = ref("");
|
||
const sectionTitle = computed(
|
||
() => getSectionForCollection(collection.value)?.title || ""
|
||
);
|
||
const imageList = computed(() => normalizeImageList(item.value));
|
||
const contactText = computed(
|
||
() => item.value?.contact?.normalized || item.value?.contact?.raw || ""
|
||
);
|
||
const displayAddress = computed(() => {
|
||
const address = item.value?.address;
|
||
if (!address) return "";
|
||
return address.normalized || "";
|
||
});
|
||
const canOpenLocation = computed(() => {
|
||
const latitudeValue = item.value?.address?.latitude;
|
||
const longitudeValue = item.value?.address?.longitude;
|
||
if (
|
||
latitudeValue === null ||
|
||
latitudeValue === undefined ||
|
||
latitudeValue === "" ||
|
||
longitudeValue === null ||
|
||
longitudeValue === undefined ||
|
||
longitudeValue === ""
|
||
) {
|
||
return false;
|
||
}
|
||
const latitude = Number(latitudeValue);
|
||
const longitude = Number(longitudeValue);
|
||
return Number.isFinite(latitude) && Number.isFinite(longitude);
|
||
});
|
||
|
||
const arraySections = computed(() => {
|
||
if (!item.value) return [];
|
||
return [
|
||
{ title: "房型", values: item.value.room_types },
|
||
{ title: "设施服务", values: item.value.facilities },
|
||
{ title: "主要食材", values: item.value.ingredients },
|
||
{ title: "烹饪方式", values: item.value.cooking_methods },
|
||
{ title: "营养信息", values: item.value.nutrition_facts },
|
||
].filter((section) => Array.isArray(section.values) && section.values.length);
|
||
});
|
||
|
||
const formatValue = (value) => {
|
||
if (value && typeof value === "object") {
|
||
return Object.entries(value)
|
||
.filter(([, itemValue]) => itemValue !== "" && itemValue !== null)
|
||
.map(([key, itemValue]) => `${key}:${itemValue}`)
|
||
.join(";");
|
||
}
|
||
return String(value ?? "");
|
||
};
|
||
|
||
const makePhoneCall = () => {
|
||
if (!contactText.value) return;
|
||
uni.makePhoneCall({ phoneNumber: contactText.value });
|
||
};
|
||
|
||
const openLocation = () => {
|
||
if (!canOpenLocation.value) return;
|
||
uni.openLocation({
|
||
latitude: Number(item.value.address.latitude),
|
||
longitude: Number(item.value.address.longitude),
|
||
name: item.value.name,
|
||
address: item.value.address.raw || item.value.address.normalized || "",
|
||
});
|
||
};
|
||
|
||
onLoad((options) => {
|
||
collection.value = options?.collection || "";
|
||
item.value = getItem(collection.value, options?.id || "");
|
||
});
|
||
</script>
|