项目列表

This commit is contained in:
2025-05-07 23:12:06 +08:00
parent f65bcd59f7
commit cfc763decf
4 changed files with 130 additions and 59 deletions

View File

@@ -10,6 +10,14 @@ const prefix = 'home'
export function homeProjectListApi(credentials) {
return get(`${prefix}/list`, credentials)
}
/**
* 获取项目列表
* @param credentials
* @returns {Promise<axios.AxiosResponse<any>>}
*/
export function projectListApi(credentials) {
return get(`${prefix}/project-list`, credentials)
}
/**
* 获取首页轮播图列表

View File

@@ -77,6 +77,7 @@ const paginatedData = computed(() => {
const changePage = (page) => {
currentPage.value = page
getList();
}
// 模态框
@@ -121,8 +122,6 @@ const handleUploadChange = (info) => {
}
if (info.file.status === "done") {
// 模拟上传成功后获取图片URL
currentItem.value.cover =
"https://img1.baidu.com/it/u=2172818577,3783888802&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422"
uploading.value = false
message.success("封面上传成功")
}
@@ -206,6 +205,14 @@ const beforeVideoUpload = (file) => {
return isVideo && isLt50M
}
const customCoverRequest = ({ file, onSuccess }) => {
// 模拟上传
uploadImageApi(file).then((res) => {
currentItem.value.cover = res.url;
onSuccess("ok", { status: "done" })
})
}
const customRequest = ({ file, onSuccess }) => {
// 模拟上传
uploadImageApi(file).then((res) => {
@@ -843,7 +850,7 @@ getList();
v-model:file-list="fileList"
list-type="picture-card"
:before-upload="beforeUpload"
:custom-request="customRequest"
:custom-request="customCoverRequest"
@preview="handlePreview"
@change="handleUploadChange"
:show-upload-list="{ showPreviewIcon: true, showRemoveIcon: true }"

View File

@@ -219,6 +219,7 @@ const breakpoints = {
<p
class="text-lg md:text-xl text-white/80 max-w-2xl line-clamp-3 mb-8"
style="text-indent: 2em"
data-aos="fade-up"
data-aos-delay="100"
>

View File

@@ -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>
<!-- &lt;!&ndash; 分类选择 &ndash;&gt;-->
<!-- <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>
<!-- &lt;!&ndash; 排序选择 &ndash;&gt;-->
<!-- <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>