home主页和AiTools页

This commit is contained in:
2025-10-10 10:41:39 +08:00
parent c37c97e97e
commit 672a2f4c90
219 changed files with 20979 additions and 0 deletions

117
components/Footer.vue Normal file
View File

@ -0,0 +1,117 @@
<template>
<div id="footer-container">
<IntegratedLayout>
<div class="container">
<div class="left-container">
<img src="/logo/logo-rect.png" />
<span>AIProdLaunch</span>
</div>
<div class="right-container">
<div>
<img src="/logo/bottom-logo.png" />
</div>
<div class="navigation-bottom">
<span v-for="item in first">
{{item.name}}
</span>
</div>
<div class="navigation-bottom">
<span v-for="item in two" @click="goto(item.path)">
{{item.name}}
</span>
</div>
<div class="bottom-span">
All rights reserved ©2025 AIToolsFinder.
</div>
</div>
</div>
</IntegratedLayout>
</div>
</template>
<script>
export default {
name: "Footer",
data() {
return {
first: [{
name: 'Home'
},
{
name: 'AI Daily News'
},
{
name: 'AI Hub'
},
{
name: 'Learn'
},
{
name: 'About Us'
}
],
two: [{
name: 'Privacy Policy',
path: '/privacy'
},
{
name: 'Terms Of Service',
path: '/service'
},
]
}
},
methods: {
goto(path) {
this.$router.push(path)
}
}
}
</script>
<style lang="scss" scoped>
#footer-container {
width: 100%;
height: $footerBarHeight;
.container {
height: $footerBarHeight;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
}
.left-container {
@include flex-center;
flex-direction: column;
span {
font-size: $larg-font-size;
color: $main-color;
font-weight: bold;
}
}
.right-container {
text-align: right;
}
.bottom-span {
color: $grey-color;
}
.navigation-bottom {
span {
display: inline-block;
padding: 14px;
}
span:last-child {
padding-right: 0;
}
}
</style>

164
components/Header.vue Normal file
View File

@ -0,0 +1,164 @@
<template>
<div id="header-container">
<IntegratedLayout>
<div class="navigation-container">
<div class="logo">
<img src="/logo/white-logo.png" />
<span>AIProdLaunch</span>
</div>
<div class="flex">
<div class="navigation-item pointer" v-for="item in navRoutes" :key="item.path"
@click="handleParentClick(item)" @mouseenter="showSubmenu(item)" @mouseleave="hideSubmenu">
<span
:class="{ 'selected-navigation': $route.matched.some(record => record.path === item.path) }">{{
item.meta.navigationName }}
<i class="el-icon-arrow-down" v-if="item.meta.children"></i>
</span>
<div v-if="activeMenu === item.path && item.meta.children" class="submenu">
<div v-for="sub in item.children" :key="sub.path" @click.stop="goto(sub.path)"
class="submenu-item pointer">
<img :src="`/logo/${sub.meta.icon}.png`" />
{{ sub.name }}
</div>
</div>
</div>
</div>
</div>
</IntegratedLayout>
</div>
</template>
<script>
import {
routes
} from '../router';
export default {
name: "Header",
computed: {
/**
* 得到routes的meta里非hidden的路由
*/
navRoutes() {
const r = routes.filter(e => {
if (e.meta) {
return !e.meta.hidden
}
return false
})
return r
},
/**
* 得到当前的路由path
*/
currentRoutePath() {
return this.$route.path
}
},
data() {
return {
activeMenu: null
}
},
methods: {
handleParentClick(item) {
// 只有没有子菜单时才跳转
if (!item.children || item.children.length === 0) {
this.goto(item.path);
}
},
/**
* 编程式导航
* @param {String} path 导航的路径
*/
goto(path) {
console.log(path)
this.$router.push(path)
},
showSubmenu(item) {
if (item.children) {
this.activeMenu = item.path;
}
},
hideSubmenu() {
this.activeMenu = null;
},
}
};
</script>
<style lang="scss" scoped>
#header-container {
width: 100%;
height: $navigationBarHeight;
background: $header-backgroungd;
.navigation-container {
height: $navigationBarHeight;
display: flex;
font-weight: 500;
align-items: center;
justify-content: space-between;
.logo {
@include flex-center;
color: $white;
span {
font-size: $normal-font-size;
}
}
.navigation-item {
margin-left: 20px;
padding: 10px;
position: relative;
span {
color: $grey;
&:hover {
color: $white;
}
&.selected-navigation {
color: $white;
}
}
.submenu {
z-index: 10;
position: absolute;
top: 100%;
left: 50%;
padding: 20px 10px;
transform: translateX(-50%);
background: $white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 6px;
&-item {
white-space: nowrap; // 防止文字换行
padding: 10px;
color: #000000;
@include display-flex;
img {
margin-right: 10px;
}
&:hover {
background: #F5F6F9;
color: $main-color;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,33 @@
<template>
<div id="sub-container">
<el-row>
<el-col :xs="0" :sm="1" :md="2" :lg="3" :xl="4">
<div>&nbsp;</div>
</el-col>
<el-col :xs="24" :sm="22" :md="20" :lg="18" :xl="16">
<!-- <div class="container-content"> -->
<slot></slot>
<!-- </div> -->
</el-col>
<el-col :xs="0" :sm="1" :md="2" :lg="3" :xl="4">
<div>&nbsp;</div>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped>
#sub-container {
.container-content {
height: 100%;
}
// overflow: auto;
}
</style>

105
components/Pagination.vue Normal file
View File

@ -0,0 +1,105 @@
<template>
<div class="pagination">
<!-- 上一页按钮 -->
<button class="pagination-btn" :disabled="currentPage === 1" @click="gotoPage(currentPage - 1)">
<i class="el-icon-arrow-left"></i> </button>
<!-- 页面范围 -->
<span v-for="pageNum in visiblePages" :key="pageNum"
:class="['pagination-number', { active: currentPage === pageNum }]" @click="gotoPage(pageNum)">
{{ pageNum }}
</span>
<!-- 下一页按钮 -->
<button class="pagination-btn" :disabled="currentPage === totalPages" @click="gotoPage(currentPage + 1)">
<i class="el-icon-arrow-right"></i>
</button>
</div>
</template>
<script>
export default {
props: {
currentPage: {
type: Number,
required: true,
default: 1,
},
totalPages: {
type: Number,
required: true,
default: 1,
},
},
methods: {
// 跳转到指定页
gotoPage(pageNum) {
if (pageNum >= 1 && pageNum <= this.totalPages) {
this.$emit("page-change", pageNum);
}
},
},
computed: {
// 计算显示的页码范围
visiblePages() {
const range = 5; // 显示的页码数量
const half = Math.floor(range / 2);
let start = this.currentPage - half;
let end = this.currentPage + half;
// 调整范围,防止超出总页数
if (start < 1) {
start = 1;
end = Math.min(range, this.totalPages);
}
if (end > this.totalPages) {
end = this.totalPages;
start = Math.max(this.totalPages - range + 1, 1);
}
return Array.from({
length: end - start + 1
}, (_, i) => start + i);
},
},
};
</script>
<style scoped lang="scss">
.pagination {
position: relative;
display: flex;
justify-content: flex-end;
align-items: center;
gap: 8px;
margin: 20px;
}
.pagination-btn,
.pagination-number {
width: 32px;
height: 32px;
border: 1px solid #E2E8F0;
border-radius: 6px;
background-color: $white;
color: $main-font-color;
cursor: pointer;
}
.pagination-number {
@include flex-center;
}
.pagination-btn:disabled {
opacity: 0.5;
color: #E2E8F0;
cursor: not-allowed;
}
.pagination-number.active {
border-color: $main-color;
color: $main-color;
font-weight: bold;
}
</style>