[id].vue
5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
<script lang="ts" setup>
import { getAppDetail } from "~/api/app";
import type { appDetail, Types } from "~/api/types/app";
import type { webSiteType } from "~/api/types/webSite";
const route = useRoute();
const config = useRuntimeConfig();
const DetailData = ref<appDetail>({
id: 0,
title: "",
content: "",
image: "",
description: "",
link: "",
types: [],
});
const webSite = useState<webSiteType>("webSite");
function mergeDuplicates(data: Types[]) {
const map = new Map();
data.forEach((item) => {
if (!map.has(item.id)) {
// 如果是第一次遇到这个id,创建新对象
map.set(item.id, {
id: item.id,
label: item.label,
children: [...(item.children || [])],
});
} else {
// 如果已经存在,合并children
const existing = map.get(item.id);
// 避免重复的子项(基于子项id)
const existingChildIds = new Set(
existing.children.map((child: any) => child.id)
);
item.children.forEach((child) => {
if (!existingChildIds.has(child.id)) {
existing.children.push(child);
}
});
}
});
return Array.from(map.values());
}
// 获取详情数据
const detailRes = await getAppDetail(Number(route.params.id));
DetailData.value = detailRes.data;
DetailData.value.types = mergeDuplicates(detailRes.data.types);
useHead({
title: DetailData.value.popupContent
? `${DetailData.value.title} - ${DetailData.value.popupContent}`
: DetailData.value.title,
meta: [
{ name: "description", content: DetailData.value.description },
{
name: "og:title",
content: `${DetailData.value.title}-${DetailData.value.popupContent}`,
},
{ name: "og:description", content: DetailData.value.description },
{
name: "og:image",
content: config.public.baseUrl + DetailData.value.image,
},
{ name: "og:url", content: route.fullPath },
{ name: "og:site_name", content: webSite.value.webname },
],
});
</script>
<template>
<div class="flex flex-col min-h-screen bg-white">
<main class="flex-grow md:p-6 bg-white p-1">
<!-- Top Application Info Bar -->
<header
v-show="DetailData.types.length > 0"
class="bg-white shadow-sm md:py-4 md:px-8 py-2 px-4 flex md:items-center md:justify-between flex-col md:flex-row"
>
<div class="flex items-center space-x-4">
<img
:src="config.public.baseUrl + DetailData.image"
:alt="DetailData.title"
class="w-16 h-16 object-contain"
/>
<div>
<h1 class="text-2xl font-bold text-[#5961f9]">
{{ DetailData.title }}
</h1>
<p class="text-sm text-gray-600 mt-1">
{{ DetailData.description }}
</p>
<div class="mt-2 flex items-center space-x-2">
<div
v-for="tag in DetailData.types"
class="flex items-center space-x-2"
>
<template v-if="tag.children.length > 0">
<NuxtLink
v-for="child in tag.children"
:to="'/category/' + child.alias"
class="px-2 py-1 bg-blue-100 text-[#5961f9] rounded-full text-xs"
>
{{ child.label }}
</NuxtLink>
</template>
<template v-else>
<NuxtLink
:to="'/category/' + tag.alias"
class="px-2 py-1 bg-blue-100 text-[#5961f9] rounded-full text-xs"
>
{{ tag.label }}
</NuxtLink>
</template>
</div>
</div>
</div>
</div>
<div class="flex md:space-x-3 md:mt-0 mt-4">
<a
:href="DetailData.link"
target="_blank"
class="!rounded-button whitespace-nowrap px-4 py-2 bg-[#5961f9] max-[768px]:text-xs text-white hover:bg-blue-600 transition-colors"
>
<i class="iconfont icon-guide"></i>访问官网
</a>
</div>
</header>
<main class="relative w-full">
<!-- 悬浮广告弹窗 -->
<!-- <div
class="md:absolute top-0 right-0 md:m-4 z-50 relative max-[768px]:m-auto"
v-show="showAd"
:style="{
width: `${detailAd.width}px`,
height: `${detailAd.height}px`,
}"
>
<div
class="w-full h-full relative"
v-for="item in detailAd.frontAdVos"
>
<img
class="w-full h-full object-contain"
:src="config.public.baseUrl + item.image"
:alt="item.title"
/>
<div
class="absolute top-1 right-1 cursor-pointer bg-white w-4 h-4 text-center rounded-[50%] text-xs"
@click="showAd = false"
>
X
</div>
</div>
</div> -->
<div class="md:max-w-5xl mx-auto md:p-8 p-2 w-full">
<div v-html="DetailData.content"></div>
</div>
</main>
</main>
</div>
</template>