|
|
|
|
@@ -2,6 +2,7 @@
|
|
|
|
|
import { ref, computed, onMounted } from 'vue'
|
|
|
|
|
import AOS from 'aos'
|
|
|
|
|
import 'aos/dist/aos.css'
|
|
|
|
|
import {projectListApi} from "@/api/request/home.js";
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
AOS.init({
|
|
|
|
|
@@ -45,7 +46,24 @@ const projects = ref(Array.from({ length: 12 }, (_, i) => ({
|
|
|
|
|
createdAt: new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toISOString(),
|
|
|
|
|
description: '这是一个示例项目描述,包含了项目的主要功能和技术特点。实际项目中会有更详细的描述信息。'
|
|
|
|
|
})))
|
|
|
|
|
// 分页
|
|
|
|
|
const currentPage = ref(1)
|
|
|
|
|
const pageSize = ref(8)
|
|
|
|
|
const totalItems = ref(0)
|
|
|
|
|
const pageCount = ref(0)
|
|
|
|
|
|
|
|
|
|
const getList = () => {
|
|
|
|
|
projectListApi({
|
|
|
|
|
page: currentPage.value,
|
|
|
|
|
pageSize: pageSize.value,
|
|
|
|
|
}).then((res) => {
|
|
|
|
|
projects.value = res.items
|
|
|
|
|
currentPage.value = res.page;
|
|
|
|
|
pageSize.value = res.size;
|
|
|
|
|
totalItems.value = res.total;
|
|
|
|
|
pageCount.value = res.page_count;
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// 筛选排序逻辑
|
|
|
|
|
const selectedCategory = ref('all')
|
|
|
|
|
const sortBy = ref('date')
|
|
|
|
|
@@ -104,6 +122,28 @@ const getAosEffect = (index) => {
|
|
|
|
|
];
|
|
|
|
|
return aosEffects[rowIndex % aosEffects.length][colIndex % aosEffects[0].length];
|
|
|
|
|
}
|
|
|
|
|
getList()
|
|
|
|
|
// 计算可见的页码
|
|
|
|
|
const visiblePages = computed(() => {
|
|
|
|
|
const maxVisiblePages = 3;
|
|
|
|
|
let startPage = Math.max(currentPage.value - Math.floor(maxVisiblePages / 2), 1);
|
|
|
|
|
let endPage = startPage + maxVisiblePages - 1;
|
|
|
|
|
|
|
|
|
|
if (endPage > pageCount.value) {
|
|
|
|
|
endPage = pageCount.value;
|
|
|
|
|
startPage = Math.max(endPage - maxVisiblePages + 1, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 是否显示省略号
|
|
|
|
|
const showEllipsisBefore = computed(() => visiblePages.value[0] > 1);
|
|
|
|
|
const showEllipsisAfter = computed(() => visiblePages.value[visiblePages.value.length - 1] < pageCount.value - 1);
|
|
|
|
|
const changePage = (page) => {
|
|
|
|
|
currentPage.value = page
|
|
|
|
|
getList();
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
@@ -126,7 +166,7 @@ const getAosEffect = (index) => {
|
|
|
|
|
<!-- 过滤排序栏 -->
|
|
|
|
|
<div class="mb-10" data-aos="fade-up">
|
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-1 gap-6">
|
|
|
|
|
<!-- 搜索框 -->
|
|
|
|
|
<div class="relative">
|
|
|
|
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
|
|
|
@@ -144,41 +184,44 @@ const getAosEffect = (index) => {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 分类选择 -->
|
|
|
|
|
<div>
|
|
|
|
|
<select
|
|
|
|
|
v-model="selectedCategory"
|
|
|
|
|
class="w-full bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl px-4 py-2 focus:ring-rose-500 focus:border-rose-500 dark:text-white"
|
|
|
|
|
>
|
|
|
|
|
<option
|
|
|
|
|
v-for="category in categories"
|
|
|
|
|
:key="category.id"
|
|
|
|
|
:value="category.value"
|
|
|
|
|
>
|
|
|
|
|
{{ category.name }}
|
|
|
|
|
</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- <!– 分类选择 –>-->
|
|
|
|
|
<!-- <div>-->
|
|
|
|
|
<!-- <select-->
|
|
|
|
|
<!-- v-model="selectedCategory"-->
|
|
|
|
|
<!-- class="w-full bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl px-4 py-2 focus:ring-rose-500 focus:border-rose-500 dark:text-white"-->
|
|
|
|
|
<!-- >-->
|
|
|
|
|
<!-- <option-->
|
|
|
|
|
<!-- v-for="category in categories"-->
|
|
|
|
|
<!-- :key="category.id"-->
|
|
|
|
|
<!-- :value="category.value"-->
|
|
|
|
|
<!-- >-->
|
|
|
|
|
<!-- {{ category.name }}-->
|
|
|
|
|
<!-- </option>-->
|
|
|
|
|
<!-- </select>-->
|
|
|
|
|
<!-- </div>-->
|
|
|
|
|
|
|
|
|
|
<!-- 排序选择 -->
|
|
|
|
|
<div>
|
|
|
|
|
<select
|
|
|
|
|
v-model="sortBy"
|
|
|
|
|
class="w-full bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl px-4 py-2 focus:ring-rose-500 focus:border-rose-500 dark:text-white"
|
|
|
|
|
>
|
|
|
|
|
<option
|
|
|
|
|
v-for="option in sortOptions"
|
|
|
|
|
:key="option.value"
|
|
|
|
|
:value="option.value"
|
|
|
|
|
>
|
|
|
|
|
{{ option.label }}
|
|
|
|
|
</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- <!– 排序选择 –>-->
|
|
|
|
|
<!-- <div>-->
|
|
|
|
|
<!-- <select-->
|
|
|
|
|
<!-- v-model="sortBy"-->
|
|
|
|
|
<!-- class="w-full bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl px-4 py-2 focus:ring-rose-500 focus:border-rose-500 dark:text-white"-->
|
|
|
|
|
<!-- >-->
|
|
|
|
|
<!-- <option-->
|
|
|
|
|
<!-- v-for="option in sortOptions"-->
|
|
|
|
|
<!-- :key="option.value"-->
|
|
|
|
|
<!-- :value="option.value"-->
|
|
|
|
|
<!-- >-->
|
|
|
|
|
<!-- {{ option.label }}-->
|
|
|
|
|
<!-- </option>-->
|
|
|
|
|
<!-- </select>-->
|
|
|
|
|
<!-- </div>-->
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="text-rose-900 mb-6 font-bold">
|
|
|
|
|
共 {{ totalItems }} 个项目
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 项目卡片网格 -->
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
|
|
|
<div
|
|
|
|
|
@@ -243,42 +286,54 @@ const getAosEffect = (index) => {
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 分页 -->
|
|
|
|
|
<!-- 分页 -->
|
|
|
|
|
<div class="mt-16 flex justify-center" data-aos="fade-up">
|
|
|
|
|
<nav class="flex items-center space-x-2">
|
|
|
|
|
<!-- 上一页按钮 -->
|
|
|
|
|
<button
|
|
|
|
|
class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
|
|
|
|
|
stroke="currentColor">
|
|
|
|
|
:disabled="currentPage === 1"
|
|
|
|
|
@click="changePage(currentPage - 1)"
|
|
|
|
|
class="cursor-pointer w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<button class="w-10 h-10 rounded-full bg-rose-600 text-white flex items-center justify-center">
|
|
|
|
|
1
|
|
|
|
|
<!-- 动态生成页码按钮 -->
|
|
|
|
|
<template v-for="page in visiblePages" :key="page">
|
|
|
|
|
<button
|
|
|
|
|
:class="{
|
|
|
|
|
'w-10 h-10 rounded-full bg-rose-600 text-white flex items-center justify-center cursor-pointer': page === currentPage,
|
|
|
|
|
'cursor-pointer w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors': page !== currentPage
|
|
|
|
|
}"
|
|
|
|
|
@click="changePage(currentPage = page)"
|
|
|
|
|
>
|
|
|
|
|
{{ page }}
|
|
|
|
|
</button>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- 省略号 -->
|
|
|
|
|
<span v-if="showEllipsisBefore" class="text-gray-500 dark:text-gray-400 cursor-pointer">...</span>
|
|
|
|
|
<span v-if="showEllipsisAfter" class="text-gray-500 dark:text-gray-400 cursor-pointer">...</span>
|
|
|
|
|
|
|
|
|
|
<!-- 最后一页按钮 -->
|
|
|
|
|
<button
|
|
|
|
|
v-if="pageCount > visiblePages[visiblePages.length - 1]"
|
|
|
|
|
@click="changePage(currentPage = pageCount)"
|
|
|
|
|
class="cursor-pointer w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
{{ pageCount }}
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<!-- 下一页按钮 -->
|
|
|
|
|
<button
|
|
|
|
|
class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
|
|
|
2
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
|
|
|
3
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<span class="text-gray-500 dark:text-gray-400">...</span>
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
|
|
|
10
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
class="w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
|
|
|
|
|
stroke="currentColor">
|
|
|
|
|
:disabled="currentPage === pageCount"
|
|
|
|
|
@click="changePage(currentPage + 1)"
|
|
|
|
|
class="cursor-pointer w-10 h-10 rounded-full bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 flex items-center justify-center text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
|