正在显示
21 个修改的文件
包含
318 行增加
和
58 行删除
.output.zip
0 → 100644
不能预览此文件类型
api/ad.ts
0 → 100644
api/types/ad.ts
0 → 100644
| 1 | +export interface adListType { | ||
| 2 | + id: number | ||
| 3 | + code: string | ||
| 4 | + name: string | ||
| 5 | + width: number | ||
| 6 | + height: number | ||
| 7 | + frontAdVos: frontAdVosType[] | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +export interface frontAdVosType { | ||
| 11 | + id: number | ||
| 12 | + positions: number | ||
| 13 | + link: string | ||
| 14 | + image: string | ||
| 15 | + title: string | ||
| 16 | + sort: number | ||
| 17 | +} |
| @@ -25,6 +25,7 @@ export interface appDetail { | @@ -25,6 +25,7 @@ export interface appDetail { | ||
| 25 | link: string | 25 | link: string |
| 26 | isRecommend?: string | 26 | isRecommend?: string |
| 27 | types: Types[] | 27 | types: Types[] |
| 28 | + updateTime? :string | ||
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | export interface Types{ | 31 | export interface Types{ |
| @@ -14,13 +14,6 @@ const sortList = useState<classifyType[]>("sortTree"); | @@ -14,13 +14,6 @@ const sortList = useState<classifyType[]>("sortTree"); | ||
| 14 | 14 | ||
| 15 | webSite.value = await getWebSite(); | 15 | webSite.value = await getWebSite(); |
| 16 | sortList.value = await getClassifyList(); | 16 | sortList.value = await getClassifyList(); |
| 17 | -useHead({ | ||
| 18 | - title: webSite.value.webname, | ||
| 19 | - meta: [ | ||
| 20 | - { name: "description", content: webSite.value.webdescription }, | ||
| 21 | - { name: "keywords", content: webSite.value.webkeywords }, | ||
| 22 | - ], | ||
| 23 | -}); | ||
| 24 | </script> | 17 | </script> |
| 25 | 18 | ||
| 26 | <style> | 19 | <style> |
assets/Annie-logo.jpg
0 → 100644
100.7 KB
components/AD/SwiperCarousel.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <!-- 轮播容器,固定1920x300尺寸 --> | ||
| 3 | + <div | ||
| 4 | + v-if="adSwiperList && adSwiperList.frontAdVos.length > 0 && isShowAD" | ||
| 5 | + class="banner-container" | ||
| 6 | + > | ||
| 7 | + <el-carousel | ||
| 8 | + :height="`${height}px`" | ||
| 9 | + indicator-position="none" | ||
| 10 | + autoplay | ||
| 11 | + :interval="5000" | ||
| 12 | + arrow="never" | ||
| 13 | + > | ||
| 14 | + <!-- 遍历轮播数据 --> | ||
| 15 | + <el-carousel-item v-for="item in adSwiperList.frontAdVos" :key="item.id"> | ||
| 16 | + <a :href="item.link" target="_blank" class="banner-link"> | ||
| 17 | + <img | ||
| 18 | + :src="config.public.apiUrl + item.image" | ||
| 19 | + :alt="item.title" | ||
| 20 | + class="banner-image aspect-[4/1] max-[768px]:aspect-[2/1]" | ||
| 21 | + loading="lazy" | ||
| 22 | + /> | ||
| 23 | + </a> | ||
| 24 | + </el-carousel-item> | ||
| 25 | + </el-carousel> | ||
| 26 | + | ||
| 27 | + <!-- 关闭广告按钮 --> | ||
| 28 | + <div class="close-button" @click="isShowAD = false"> | ||
| 29 | + <span class="close-icon">x</span> | ||
| 30 | + <span class="close-text">关闭</span> | ||
| 31 | + </div> | ||
| 32 | + </div> | ||
| 33 | +</template> | ||
| 34 | + | ||
| 35 | +<script setup lang="ts"> | ||
| 36 | +import type { adListType } from "~/api/types/ad"; | ||
| 37 | +defineProps<{ | ||
| 38 | + adSwiperList: adListType | null; | ||
| 39 | +}>(); | ||
| 40 | +// 定义轮播数据类型 | ||
| 41 | +interface BannerItem { | ||
| 42 | + title: string; | ||
| 43 | + link: string; | ||
| 44 | + image: string; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +const isShowAD = ref(true); | ||
| 48 | +const config = useRuntimeConfig(); | ||
| 49 | + | ||
| 50 | +// 响应式宽度 | ||
| 51 | +const windowWidth = ref(0); | ||
| 52 | + | ||
| 53 | +// 监听窗口大小变化 | ||
| 54 | + | ||
| 55 | +onMounted(() => { | ||
| 56 | + windowWidth.value = window.innerWidth; | ||
| 57 | + window.addEventListener("resize", () => { | ||
| 58 | + windowWidth.value = window.innerWidth; | ||
| 59 | + }); | ||
| 60 | +}); | ||
| 61 | + | ||
| 62 | +onUnmounted(() => { | ||
| 63 | + window.removeEventListener("resize", () => { | ||
| 64 | + windowWidth.value = window.innerWidth; | ||
| 65 | + }); | ||
| 66 | +}); | ||
| 67 | + | ||
| 68 | +// 计算属性:高度 = 浏览器宽度 * 1/4 | ||
| 69 | +const height = computed(() => { | ||
| 70 | + if (windowWidth.value < 768) { | ||
| 71 | + return Math.floor((windowWidth.value * 1) / 2); | ||
| 72 | + } else { | ||
| 73 | + return Math.floor((windowWidth.value * 1) / 4); | ||
| 74 | + } | ||
| 75 | +}); | ||
| 76 | +</script> | ||
| 77 | + | ||
| 78 | +<style scoped lang="less"> | ||
| 79 | +/* 容器样式:适配1920宽度,居中显示 */ | ||
| 80 | +.banner-container { | ||
| 81 | + width: 100%; | ||
| 82 | + max-width: 1920px; | ||
| 83 | + margin: 0 auto; | ||
| 84 | + overflow: hidden; | ||
| 85 | + margin-bottom: 30px; | ||
| 86 | + position: relative; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +/* 广告链接样式 */ | ||
| 90 | +.banner-link { | ||
| 91 | + display: block; | ||
| 92 | + width: 100%; | ||
| 93 | + height: 100%; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +/* 图片样式:适配轮播容器,保持1920x300比例 */ | ||
| 97 | +.banner-image { | ||
| 98 | + width: 100%; | ||
| 99 | + height: 100%; | ||
| 100 | + object-fit: cover; /* 保证图片不变形 */ | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +.close-button { | ||
| 104 | + position: absolute; | ||
| 105 | + top: 4px; | ||
| 106 | + right: 4px; | ||
| 107 | + display: flex; | ||
| 108 | + align-items: center; | ||
| 109 | + font-size: 14px; | ||
| 110 | + padding: 2px 12px; | ||
| 111 | + background-color: rgba(255, 255, 255, 0.35); | ||
| 112 | + border-radius: 10px; | ||
| 113 | + vertical-align: middle; | ||
| 114 | + .close-icon { | ||
| 115 | + font-size: 20px; | ||
| 116 | + margin-right: 2px; | ||
| 117 | + color: red; | ||
| 118 | + margin-top: -2px; | ||
| 119 | + } | ||
| 120 | +} | ||
| 121 | + | ||
| 122 | +@media screen and (max-width: 768px) { | ||
| 123 | + .banner-image { | ||
| 124 | + object-fit: contain; | ||
| 125 | + } | ||
| 126 | +} | ||
| 127 | +</style> |
| @@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
| 4 | <div class="max-w-6xl mx-auto grid grid-cols-1 md:grid-cols-4 gap-8"> | 4 | <div class="max-w-6xl mx-auto grid grid-cols-1 md:grid-cols-4 gap-8"> |
| 5 | <div> | 5 | <div> |
| 6 | <h3 class="text-xl font-bold mb-4"> | 6 | <h3 class="text-xl font-bold mb-4"> |
| 7 | - {{ webSite.webname }} | 7 | + {{ webSite.webname.slice(0, 7) }} |
| 8 | </h3> | 8 | </h3> |
| 9 | <p class="text-gray-400"> | 9 | <p class="text-gray-400"> |
| 10 | 提供安全、快速的网址跳转服务,保护您的隐私安全。 | 10 | 提供安全、快速的网址跳转服务,保护您的隐私安全。 |
| @@ -5,10 +5,18 @@ | @@ -5,10 +5,18 @@ | ||
| 5 | > | 5 | > |
| 6 | <div class="mx-auto md:px-6 px-3 py-3 flex items-center justify-between"> | 6 | <div class="mx-auto md:px-6 px-3 py-3 flex items-center justify-between"> |
| 7 | <NuxtLink to="/" class="flex items-center space-x-2"> | 7 | <NuxtLink to="/" class="flex items-center space-x-2"> |
| 8 | - <el-icon :size="24"><Promotion /></el-icon> | ||
| 9 | - <h1 class="md:text-xl text-base font-bold"> | 8 | + <img |
| 9 | + width="30" | ||
| 10 | + height="30" | ||
| 11 | + src="../../assets/Annie-logo.jpg" | ||
| 12 | + alt="Annie-logo" | ||
| 13 | + /> | ||
| 14 | + <h1 style="font-size: 0px"> | ||
| 10 | {{ webSite.webname }} | 15 | {{ webSite.webname }} |
| 11 | </h1> | 16 | </h1> |
| 17 | + <h2 class="md:text-xl text-base font-bold"> | ||
| 18 | + {{ webSite.webname.slice(0, 7) }} | ||
| 19 | + </h2> | ||
| 12 | </NuxtLink> | 20 | </NuxtLink> |
| 13 | 21 | ||
| 14 | <div class="flex items-center gap-2"> | 22 | <div class="flex items-center gap-2"> |
| 1 | <template> | 1 | <template> |
| 2 | <nav | 2 | <nav |
| 3 | - class="max-[768px]:flex-[0] scroll-container w-56 bg-white shadow-lg h-[calc(100vh-4rem)] sticky top-16 overflow-y-auto" | 3 | + class="max-[768px]:flex-[0] flex-shrink-0 scroll-container w-56 bg-white shadow-lg h-[calc(100vh-4rem)] sticky top-16 overflow-y-auto" |
| 4 | > | 4 | > |
| 5 | <div class="md:p-4 p-2"> | 5 | <div class="md:p-4 p-2"> |
| 6 | <h2 class="text-lg font-semibold mb-4 text-gray-700">工具分类</h2> | 6 | <h2 class="text-lg font-semibold mb-4 text-gray-700">工具分类</h2> |
| 7 | - <ul class="space-y-1"> | ||
| 8 | - <li v-for="(category, index) in sortList" :key="index"> | 7 | + <ul id="menu" class="space-y-1"> |
| 8 | + <li | ||
| 9 | + :id="`menu-${category.id}`" | ||
| 10 | + v-for="(category, index) in sortList" | ||
| 11 | + :key="index" | ||
| 12 | + class="menu-item" | ||
| 13 | + > | ||
| 9 | <a | 14 | <a |
| 10 | :href="`#term-${category.id}`" | 15 | :href="`#term-${category.id}`" |
| 11 | @click.stop="toggleCategory($event, category.id, index)" | 16 | @click.stop="toggleCategory($event, category.id, index)" |
| @@ -41,6 +46,7 @@ | @@ -41,6 +46,7 @@ | ||
| 41 | <li | 46 | <li |
| 42 | v-for="(subItem, subIndex) in category.children" | 47 | v-for="(subItem, subIndex) in category.children" |
| 43 | :key="subItem.id" | 48 | :key="subItem.id" |
| 49 | + :id="`menu-${category.id}-${subItem.id}`" | ||
| 44 | > | 50 | > |
| 45 | <a | 51 | <a |
| 46 | :href="`#term-${category.id}-${subItem.id}`" | 52 | :href="`#term-${category.id}-${subItem.id}`" |
| @@ -40,12 +40,12 @@ | @@ -40,12 +40,12 @@ | ||
| 40 | <div class="flex-auto"></div> | 40 | <div class="flex-auto"></div> |
| 41 | <a | 41 | <a |
| 42 | class="hidden md:block text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]" | 42 | class="hidden md:block text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]" |
| 43 | - :href="`/category/${childAlias}`" | 43 | + :href="`${config.public.baseUrl}/category/${childAlias}`" |
| 44 | >查看更多 >></a | 44 | >查看更多 >></a |
| 45 | > | 45 | > |
| 46 | <a | 46 | <a |
| 47 | class="md:hidden text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]" | 47 | class="md:hidden text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]" |
| 48 | - :href="`/category/${childAlias}`" | 48 | + :href="`${config.public.baseUrl}/category/${childAlias}`" |
| 49 | >>></a | 49 | >>></a |
| 50 | > | 50 | > |
| 51 | </div> | 51 | </div> |
| @@ -76,14 +76,15 @@ | @@ -76,14 +76,15 @@ | ||
| 76 | > | 76 | > |
| 77 | <template #reference> | 77 | <template #reference> |
| 78 | <a | 78 | <a |
| 79 | - :href="'/details/' + appItem.id" | 79 | + :href="config.public.baseUrl + '/site-details/' + appItem.id" |
| 80 | target="_blank" | 80 | target="_blank" |
| 81 | @click.stop="onNuxtLink" | 81 | @click.stop="onNuxtLink" |
| 82 | > | 82 | > |
| 83 | <div class="group p-3"> | 83 | <div class="group p-3"> |
| 84 | <div class="flex items-start space-x-4"> | 84 | <div class="flex items-start space-x-4"> |
| 85 | <img | 85 | <img |
| 86 | - :src="config.public.baseUrl + appItem.image" | 86 | + loading="lazy" |
| 87 | + :src="config.public.apiUrl + appItem.image" | ||
| 87 | :alt="appItem.title" | 88 | :alt="appItem.title" |
| 88 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" | 89 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" |
| 89 | /> | 90 | /> |
| @@ -104,11 +105,16 @@ | @@ -104,11 +105,16 @@ | ||
| 104 | </a> | 105 | </a> |
| 105 | </template> | 106 | </template> |
| 106 | </el-popconfirm> | 107 | </el-popconfirm> |
| 107 | - <a v-else :href="'/details/' + appItem.id" target="_blank"> | 108 | + <a |
| 109 | + v-else | ||
| 110 | + :href="config.public.baseUrl + '/site-details/' + appItem.id" | ||
| 111 | + target="_blank" | ||
| 112 | + > | ||
| 108 | <div class="group p-3"> | 113 | <div class="group p-3"> |
| 109 | <div class="flex items-start space-x-4"> | 114 | <div class="flex items-start space-x-4"> |
| 110 | <img | 115 | <img |
| 111 | - :src="config.public.baseUrl + appItem.image" | 116 | + loading="lazy" |
| 117 | + :src="config.public.apiUrl + appItem.image" | ||
| 112 | :alt="appItem.title" | 118 | :alt="appItem.title" |
| 113 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" | 119 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" |
| 114 | /> | 120 | /> |
| @@ -146,7 +152,7 @@ function onNuxtLink(event: any) { | @@ -146,7 +152,7 @@ function onNuxtLink(event: any) { | ||
| 146 | } | 152 | } |
| 147 | // 点击确认跳转 | 153 | // 点击确认跳转 |
| 148 | function onConfirm(id: number) { | 154 | function onConfirm(id: number) { |
| 149 | - window.open(`/details/${id}`); | 155 | + window.open(`/site-details/${id}`); |
| 150 | } | 156 | } |
| 151 | // 导航样式内容 | 157 | // 导航样式内容 |
| 152 | const currentFilter = ref(0); | 158 | const currentFilter = ref(0); |
| @@ -13,12 +13,12 @@ | @@ -13,12 +13,12 @@ | ||
| 13 | <div class="flex-auto"></div> | 13 | <div class="flex-auto"></div> |
| 14 | <a | 14 | <a |
| 15 | class="hidden md:block text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]" | 15 | class="hidden md:block text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]" |
| 16 | - :href="`/category/${childData.alias}`" | 16 | + :href="`${config.public.baseUrl}/category/${childData.alias}`" |
| 17 | >查看更多 >></a | 17 | >查看更多 >></a |
| 18 | > | 18 | > |
| 19 | <a | 19 | <a |
| 20 | class="md:hidden text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]" | 20 | class="md:hidden text-xs ml-2 text-[#282a2d] hover:text-[#5961f9]" |
| 21 | - :href="`/category/${childData.alias}`" | 21 | + :href="`${config.public.baseUrl}/category/${childData.alias}`" |
| 22 | >>></a | 22 | >>></a |
| 23 | > | 23 | > |
| 24 | </div> | 24 | </div> |
| @@ -46,14 +46,15 @@ | @@ -46,14 +46,15 @@ | ||
| 46 | > | 46 | > |
| 47 | <template #reference> | 47 | <template #reference> |
| 48 | <a | 48 | <a |
| 49 | - :href="'/details/' + item.id" | 49 | + :href="'/site-details/' + item.id" |
| 50 | target="_blank" | 50 | target="_blank" |
| 51 | @click.stop="onNuxtLink" | 51 | @click.stop="onNuxtLink" |
| 52 | > | 52 | > |
| 53 | <div class="group p-3"> | 53 | <div class="group p-3"> |
| 54 | <div class="flex items-start space-x-4"> | 54 | <div class="flex items-start space-x-4"> |
| 55 | <img | 55 | <img |
| 56 | - :src="config.public.baseUrl + item.image" | 56 | + loading="lazy" |
| 57 | + :src="config.public.apiUrl + item.image" | ||
| 57 | :alt="item.title" | 58 | :alt="item.title" |
| 58 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" | 59 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" |
| 59 | /> | 60 | /> |
| @@ -74,11 +75,12 @@ | @@ -74,11 +75,12 @@ | ||
| 74 | </a> | 75 | </a> |
| 75 | </template> | 76 | </template> |
| 76 | </el-popconfirm> | 77 | </el-popconfirm> |
| 77 | - <a v-else :href="'/details/' + item.id" target="_blank"> | 78 | + <a v-else :href="'/site-details/' + item.id" target="_blank"> |
| 78 | <div class="group p-3"> | 79 | <div class="group p-3"> |
| 79 | <div class="flex items-start space-x-4"> | 80 | <div class="flex items-start space-x-4"> |
| 80 | <img | 81 | <img |
| 81 | - :src="config.public.baseUrl + item.image" | 82 | + loading="lazy" |
| 83 | + :src="config.public.apiUrl + item.image" | ||
| 82 | :alt="item.title" | 84 | :alt="item.title" |
| 83 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" | 85 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" |
| 84 | /> | 86 | /> |
| @@ -113,6 +115,6 @@ function onNuxtLink(event: any) { | @@ -113,6 +115,6 @@ function onNuxtLink(event: any) { | ||
| 113 | } | 115 | } |
| 114 | // 点击确认跳转 | 116 | // 点击确认跳转 |
| 115 | function onConfirm(id: number) { | 117 | function onConfirm(id: number) { |
| 116 | - window.open(`/details/${id}`); | 118 | + window.open(`/site-details/${id}`); |
| 117 | } | 119 | } |
| 118 | </script> | 120 | </script> |
| @@ -52,14 +52,15 @@ | @@ -52,14 +52,15 @@ | ||
| 52 | > | 52 | > |
| 53 | <template #reference> | 53 | <template #reference> |
| 54 | <a | 54 | <a |
| 55 | - :href="'/details/' + item.id" | 55 | + :href="config.public.baseUrl + '/site-details/' + item.id" |
| 56 | target="_blank" | 56 | target="_blank" |
| 57 | @click.stop="onNuxtLink" | 57 | @click.stop="onNuxtLink" |
| 58 | > | 58 | > |
| 59 | <div class="group p-3"> | 59 | <div class="group p-3"> |
| 60 | <div class="flex items-start space-x-4"> | 60 | <div class="flex items-start space-x-4"> |
| 61 | <img | 61 | <img |
| 62 | - :src="config.public.baseUrl + item.image" | 62 | + loading="lazy" |
| 63 | + :src="config.public.apiUrl + item.image" | ||
| 63 | :alt="item.title" | 64 | :alt="item.title" |
| 64 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" | 65 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" |
| 65 | /> | 66 | /> |
| @@ -80,11 +81,16 @@ | @@ -80,11 +81,16 @@ | ||
| 80 | </a> | 81 | </a> |
| 81 | </template> | 82 | </template> |
| 82 | </el-popconfirm> | 83 | </el-popconfirm> |
| 83 | - <a v-else :href="'/details/' + item.id" target="_blank"> | 84 | + <a |
| 85 | + v-else | ||
| 86 | + :href="config.public.baseUrl + '/site-details/' + item.id" | ||
| 87 | + target="_blank" | ||
| 88 | + > | ||
| 84 | <div class="group p-3"> | 89 | <div class="group p-3"> |
| 85 | <div class="flex items-start space-x-4"> | 90 | <div class="flex items-start space-x-4"> |
| 86 | <img | 91 | <img |
| 87 | - :src="config.public.baseUrl + item.image" | 92 | + loading="lazy" |
| 93 | + :src="config.public.apiUrl + item.image" | ||
| 88 | :alt="item.title" | 94 | :alt="item.title" |
| 89 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" | 95 | class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg" |
| 90 | /> | 96 | /> |
| @@ -122,6 +128,6 @@ function onNuxtLink(event: any) { | @@ -122,6 +128,6 @@ function onNuxtLink(event: any) { | ||
| 122 | } | 128 | } |
| 123 | // 点击确认跳转 | 129 | // 点击确认跳转 |
| 124 | function onConfirm(id: number) { | 130 | function onConfirm(id: number) { |
| 125 | - window.open(`/details/${id}`); | 131 | + window.open(`/site-details/${id}`); |
| 126 | } | 132 | } |
| 127 | </script> | 133 | </script> |
| @@ -3,22 +3,29 @@ export default defineNuxtConfig({ | @@ -3,22 +3,29 @@ export default defineNuxtConfig({ | ||
| 3 | ssr: true, | 3 | ssr: true, |
| 4 | runtimeConfig: { | 4 | runtimeConfig: { |
| 5 | public: { | 5 | public: { |
| 6 | - baseUrl: process.env.NUXT_API_URL, | 6 | + baseUrl: process.env.NUXT_BASE_URL, |
| 7 | + apiUrl: process.env.NUXT_API_URL, | ||
| 7 | } | 8 | } |
| 8 | }, | 9 | }, |
| 9 | - devtools: { enabled: true }, | 10 | + devtools: { enabled: false }, |
| 10 | modules: [ | 11 | modules: [ |
| 11 | '@nuxtjs/tailwindcss', | 12 | '@nuxtjs/tailwindcss', |
| 12 | '@element-plus/nuxt' | 13 | '@element-plus/nuxt' |
| 13 | ], | 14 | ], |
| 15 | + features: { | ||
| 16 | + inlineStyles: false, | ||
| 17 | + devLogs: false, | ||
| 18 | + }, | ||
| 14 | devServer: { | 19 | devServer: { |
| 15 | host: 'localhost', | 20 | host: 'localhost', |
| 16 | port: 3666 | 21 | port: 3666 |
| 17 | }, | 22 | }, |
| 18 | nitro: { | 23 | nitro: { |
| 24 | + compressPublicAssets: false, | ||
| 19 | devProxy: { | 25 | devProxy: { |
| 20 | '/dev-api': { | 26 | '/dev-api': { |
| 21 | - target: 'http://192.168.2.15:35273/', | 27 | + // target: 'http://192.168.2.15:35273/', |
| 28 | + target: 'http://htai.aiboxgo.com/', | ||
| 22 | changeOrigin: true, | 29 | changeOrigin: true, |
| 23 | 30 | ||
| 24 | } | 31 | } |
| @@ -26,14 +33,15 @@ export default defineNuxtConfig({ | @@ -26,14 +33,15 @@ export default defineNuxtConfig({ | ||
| 26 | // 该配置用于服务端请求转发 | 33 | // 该配置用于服务端请求转发 |
| 27 | routeRules: { | 34 | routeRules: { |
| 28 | '/dev-api/**': { | 35 | '/dev-api/**': { |
| 29 | - proxy: 'http://192.168.2.15:35273/**' | 36 | + // proxy: 'http://192.168.2.15:35273/**' |
| 37 | + proxy: 'http://htai.aiboxgo.com/**' | ||
| 30 | }, | 38 | }, |
| 31 | }, | 39 | }, |
| 32 | prerender: { | 40 | prerender: { |
| 33 | routes: ['/sitemap.xml'], | 41 | routes: ['/sitemap.xml'], |
| 34 | // 从预渲染中排除 sitemap.xml,让它动态生成 | 42 | // 从预渲染中排除 sitemap.xml,让它动态生成 |
| 35 | ignore: ['/sitemap.xml'] | 43 | ignore: ['/sitemap.xml'] |
| 36 | - } | 44 | + }, |
| 37 | }, | 45 | }, |
| 38 | css: [ | 46 | css: [ |
| 39 | '~/assets/iconfonts/iconfont.css', | 47 | '~/assets/iconfonts/iconfont.css', |
| @@ -43,25 +51,28 @@ export default defineNuxtConfig({ | @@ -43,25 +51,28 @@ export default defineNuxtConfig({ | ||
| 43 | ], | 51 | ], |
| 44 | app: { | 52 | app: { |
| 45 | head: { | 53 | head: { |
| 46 | - title: 'Annie网站', | 54 | + title: 'Annie网站 - 优质 AI 工具集合、AI 资源网站、AI 导航平台', |
| 47 | htmlAttrs: { | 55 | htmlAttrs: { |
| 48 | - lang: 'en' | 56 | + lang: 'zh-CN' |
| 49 | }, | 57 | }, |
| 50 | meta: [ | 58 | meta: [ |
| 51 | { charset: 'utf-8' }, | 59 | { charset: 'utf-8' }, |
| 52 | - { name: 'viewport', content: 'width=device-width, initial-scale=1' }, | ||
| 53 | - { hid: 'description', name: 'description', content: '提供市面上最简洁的导航系统' }, | ||
| 54 | - { name: 'format-detection', content: 'telephone=no' }, | ||
| 55 | - { name: 'keywords', content: '提供市面上最简洁的导航系统,一个完全免费的导航站'} | 60 | + { name: "renderer", content: "webkit"}, |
| 61 | + { name: "force-rendering", content: "webkit"}, | ||
| 62 | + { "http-equiv":"X-UA-Compatible", content:"IE=edge, chrome=1" }, | ||
| 63 | + { name: 'viewport', content:"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" }, | ||
| 64 | + { name:'robots', content:'max-image-preview:large'} | ||
| 56 | ], | 65 | ], |
| 57 | link: [ | 66 | link: [ |
| 58 | - { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } | 67 | + { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, |
| 68 | + { rel: 'canonical', href: 'https://aiboxgo.com/' } | ||
| 69 | + | ||
| 59 | ], | 70 | ], |
| 60 | - script: [ | ||
| 61 | - { | ||
| 62 | - src: "/js/translate.js", | 71 | + script: [{ src: "/js/translate.js"}] |
| 63 | }, | 72 | }, |
| 64 | - ] | ||
| 65 | - } | 73 | + rootId: 'annie', |
| 66 | }, | 74 | }, |
| 75 | + build: { | ||
| 76 | + transpile: [] | ||
| 77 | + } | ||
| 67 | }) | 78 | }) |
| 1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
| 2 | import type { appListType, appType } from "~/api/types/app"; | 2 | import type { appListType, appType } from "~/api/types/app"; |
| 3 | +import type { adListType } from "~/api/types/ad"; | ||
| 3 | import { getAppList, getAllApp } from "~/api/app"; | 4 | import { getAppList, getAllApp } from "~/api/app"; |
| 5 | +import type { webSiteType } from "~/api/types/webSite"; | ||
| 6 | +import { getAdList } from "~/api/ad"; | ||
| 4 | const recommendList = ref<appType[]>([]); | 7 | const recommendList = ref<appType[]>([]); |
| 5 | const appList = ref<appListType[]>([]); | 8 | const appList = ref<appListType[]>([]); |
| 9 | +const adList = ref<adListType | null>(null); | ||
| 10 | +// 获取轮播广告 | ||
| 11 | +const adRes = await getAdList(); | ||
| 12 | +adList.value = adRes[0]; | ||
| 6 | // 获取推荐应用 | 13 | // 获取推荐应用 |
| 7 | const recommendRes = await getAppList({ | 14 | const recommendRes = await getAppList({ |
| 8 | pageSize: 10, | 15 | pageSize: 10, |
| @@ -13,11 +20,54 @@ recommendList.value = recommendRes.rows; | @@ -13,11 +20,54 @@ recommendList.value = recommendRes.rows; | ||
| 13 | // 获取全部应用 | 20 | // 获取全部应用 |
| 14 | const allRes = await getAllApp(); | 21 | const allRes = await getAllApp(); |
| 15 | appList.value = allRes.data; | 22 | appList.value = allRes.data; |
| 23 | +const webSite = useState<webSiteType>("webSite"); | ||
| 24 | + | ||
| 25 | +useHead({ | ||
| 26 | + title: webSite.value.webname, | ||
| 27 | + meta: [ | ||
| 28 | + { name: "description", content: webSite.value.webdescription }, | ||
| 29 | + { name: "keywords", content: webSite.value.webkeywords }, | ||
| 30 | + | ||
| 31 | + { name: "format-detection", content: "telephone=no" }, | ||
| 32 | + { name: "referrer", content: "origin-when-cross-origin" }, | ||
| 33 | + { | ||
| 34 | + name: "robots", | ||
| 35 | + content: | ||
| 36 | + "follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large", | ||
| 37 | + }, | ||
| 38 | + { property: "og:locale", content: "zh_CN" }, | ||
| 39 | + { | ||
| 40 | + property: "og:title", | ||
| 41 | + content: "Annie网站 - 优质 AI 工具集合、AI 资源网站、AI 导航平台", | ||
| 42 | + }, | ||
| 43 | + { | ||
| 44 | + property: "og:description", | ||
| 45 | + content: | ||
| 46 | + "专业 AI 工具导航网站,汇集全网优质 AI 工具,包含 AI 写作、AI 绘画、AI 视频、AI 对话、AI 代码、AI 设计、AI 办公等各类 AI 资源,让你快速找到好用的 AI 工具。", | ||
| 47 | + }, | ||
| 48 | + // { property: 'og:image', content: 'https://aiboxgo.com/images/logo.png'}, | ||
| 49 | + { property: "og:url", content: "https://aiboxgo.com/" }, | ||
| 50 | + { property: "og:site_name", content: "Annie网站" }, | ||
| 51 | + { property: "og:type", content: "website" }, | ||
| 52 | + { property: "twitter:card", content: "summary_large_image" }, | ||
| 53 | + { | ||
| 54 | + property: "twitter:title", | ||
| 55 | + content: "Annie网站 - 优质 AI 工具集合、AI 资源网站、AI 导航平台", | ||
| 56 | + }, | ||
| 57 | + { | ||
| 58 | + property: "twitter:description", | ||
| 59 | + content: | ||
| 60 | + "专业 AI 工具导航网站,汇集全网优质 AI 工具,包含 AI 写作、AI 绘画、AI 视频、AI 对话、AI 代码、AI 设计、AI 办公等各类 AI 资源,让你快速找到好用的 AI 工具。", | ||
| 61 | + }, | ||
| 62 | + ], | ||
| 63 | +}); | ||
| 16 | </script> | 64 | </script> |
| 17 | 65 | ||
| 18 | <template> | 66 | <template> |
| 19 | <div class="flex flex-col min-h-screen bg-white"> | 67 | <div class="flex flex-col min-h-screen bg-white"> |
| 20 | <main class="flex-grow md:p-6 p-2 bg-white"> | 68 | <main class="flex-grow md:p-6 p-2 bg-white"> |
| 69 | + <!-- 轮播广告区域 --> | ||
| 70 | + <ADSwiperCarousel :adSwiperList="adList" /> | ||
| 21 | <!-- Banner 区域 --> | 71 | <!-- Banner 区域 --> |
| 22 | <HomeBanner /> | 72 | <HomeBanner /> |
| 23 | <!-- 广告区域 --> | 73 | <!-- 广告区域 --> |
| @@ -49,6 +49,8 @@ const detailRes = await getAppDetail(Number(route.params.id)); | @@ -49,6 +49,8 @@ const detailRes = await getAppDetail(Number(route.params.id)); | ||
| 49 | DetailData.value = detailRes.data; | 49 | DetailData.value = detailRes.data; |
| 50 | DetailData.value.types = mergeDuplicates(detailRes.data.types); | 50 | DetailData.value.types = mergeDuplicates(detailRes.data.types); |
| 51 | 51 | ||
| 52 | +console.log("详情数据", DetailData.value); | ||
| 53 | + | ||
| 52 | useHead({ | 54 | useHead({ |
| 53 | title: DetailData.value.popupContent | 55 | title: DetailData.value.popupContent |
| 54 | ? `${DetailData.value.title} - ${DetailData.value.popupContent}` | 56 | ? `${DetailData.value.title} - ${DetailData.value.popupContent}` |
| @@ -56,16 +58,35 @@ useHead({ | @@ -56,16 +58,35 @@ useHead({ | ||
| 56 | meta: [ | 58 | meta: [ |
| 57 | { name: "description", content: DetailData.value.description }, | 59 | { name: "description", content: DetailData.value.description }, |
| 58 | { | 60 | { |
| 59 | - name: "og:title", | ||
| 60 | - content: `${DetailData.value.title}-${DetailData.value.popupContent}`, | 61 | + property: "og:title", |
| 62 | + content: `${DetailData.value.title}${ | ||
| 63 | + DetailData.value.popupContent != null | ||
| 64 | + ? ` - ${DetailData.value.popupContent}` | ||
| 65 | + : `- ${DetailData.value.description} | ${webSite.value.webname.slice( | ||
| 66 | + 0, | ||
| 67 | + 7 | ||
| 68 | + )}` | ||
| 69 | + }`, | ||
| 61 | }, | 70 | }, |
| 62 | - { name: "og:description", content: DetailData.value.description }, | 71 | + { property: "og:description", content: DetailData.value.description }, |
| 72 | + { property: "og:type", content: "article" }, | ||
| 63 | { | 73 | { |
| 64 | - name: "og:image", | 74 | + property: "og:image", |
| 65 | content: config.public.baseUrl + DetailData.value.image, | 75 | content: config.public.baseUrl + DetailData.value.image, |
| 66 | }, | 76 | }, |
| 67 | - { name: "og:url", content: route.fullPath }, | ||
| 68 | - { name: "og:site_name", content: webSite.value.webname }, | 77 | + { property: "og:url", content: config.public.baseUrl + route.fullPath }, |
| 78 | + { property: "og:site_name", content: webSite.value.webname.slice(0, 7) }, | ||
| 79 | + { property: "og:updated_time", content: DetailData.value.updateTime }, | ||
| 80 | + { | ||
| 81 | + property: "article:published_time", | ||
| 82 | + content: DetailData.value.updateTime, | ||
| 83 | + }, | ||
| 84 | + ], | ||
| 85 | + link: [ | ||
| 86 | + { | ||
| 87 | + rel: "canonical", | ||
| 88 | + href: config.public.baseUrl + route.fullPath, | ||
| 89 | + }, | ||
| 69 | ], | 90 | ], |
| 70 | }); | 91 | }); |
| 71 | </script> | 92 | </script> |
| @@ -80,7 +101,7 @@ useHead({ | @@ -80,7 +101,7 @@ useHead({ | ||
| 80 | > | 101 | > |
| 81 | <div class="flex items-center space-x-4"> | 102 | <div class="flex items-center space-x-4"> |
| 82 | <img | 103 | <img |
| 83 | - :src="config.public.baseUrl + DetailData.image" | 104 | + :src="config.public.apiUrl + DetailData.image" |
| 84 | :alt="DetailData.title" | 105 | :alt="DetailData.title" |
| 85 | class="w-16 h-16 object-contain" | 106 | class="w-16 h-16 object-contain" |
| 86 | /> | 107 | /> |
| @@ -156,7 +177,7 @@ useHead({ | @@ -156,7 +177,7 @@ useHead({ | ||
| 156 | </div> | 177 | </div> |
| 157 | </div> --> | 178 | </div> --> |
| 158 | <div class="md:max-w-5xl mx-auto md:p-8 p-2 w-full"> | 179 | <div class="md:max-w-5xl mx-auto md:p-8 p-2 w-full"> |
| 159 | - <div v-html="DetailData.content"></div> | 180 | + <article v-html="DetailData.content"></article> |
| 160 | </div> | 181 | </div> |
| 161 | </main> | 182 | </main> |
| 162 | </main> | 183 | </main> |
不能预览此文件类型
| @@ -6,7 +6,7 @@ const useMyfetch = async (url: any, options?: any, headers?: any) => { | @@ -6,7 +6,7 @@ const useMyfetch = async (url: any, options?: any, headers?: any) => { | ||
| 6 | try { | 6 | try { |
| 7 | loadingInstance = ElLoading.service() | 7 | loadingInstance = ElLoading.service() |
| 8 | const config = useRuntimeConfig() // 3.0正式版环境变量要从useRuntimeConfig里的public拿 | 8 | const config = useRuntimeConfig() // 3.0正式版环境变量要从useRuntimeConfig里的public拿 |
| 9 | - const reqUrl = config.public.baseUrl + url // 你的接口地址 | 9 | + const reqUrl = config.public.apiUrl + url // 你的接口地址 |
| 10 | // 不设置key,始终拿到的都是第一个请求的值,参数一样则不会进行第二次请求 | 10 | // 不设置key,始终拿到的都是第一个请求的值,参数一样则不会进行第二次请求 |
| 11 | 11 | ||
| 12 | // 可以设置默认headers例如 | 12 | // 可以设置默认headers例如 |
-
请 注册 或 登录 后发表评论