作者 xiaoqiu

优化了seo搜索引擎

1 # API地址 1 # API地址
2 NUXT_API_URL="/dev-api" 2 NUXT_API_URL="/dev-api"
  3 +
  4 +NUXT_BASE_URL="http://localhost:3666"
1 # API地址 1 # API地址
2 NUXT_API_URL="http://htai.aiboxgo.com" 2 NUXT_API_URL="http://htai.aiboxgo.com"
  3 +
  4 +NUXT_BASE_URL="http://htai.aiboxgo.com"
不能预览此文件类型
  1 +// 获取广告信息
  2 +import { useGet } from "~/utils/request";
  3 +export const getAdList = async () => {
  4 + const {rows} = await useGet('/dh/ad/listFrontAd')
  5 + return rows
  6 +}
  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>
  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 >查看更多 &gt;&gt;</a 44 >查看更多 &gt;&gt;</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 >&gt;&gt;</a 49 >&gt;&gt;</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 >查看更多 &gt;&gt;</a 17 >查看更多 &gt;&gt;</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 >&gt;&gt;</a 22 >&gt;&gt;</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>
@@ -4,7 +4,9 @@ @@ -4,7 +4,9 @@
4 <AppSidebar /> 4 <AppSidebar />
5 5
6 <div class="w-full flex-1"> 6 <div class="w-full flex-1">
  7 + <main class="w-full">
7 <slot></slot> 8 <slot></slot>
  9 + </main>
8 <AppFooter /> 10 <AppFooter />
9 </div> 11 </div>
10 </div> 12 </div>
@@ -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例如