项目列表
This commit is contained in:
@@ -10,6 +10,14 @@ const prefix = 'home'
|
|||||||
export function homeProjectListApi(credentials) {
|
export function homeProjectListApi(credentials) {
|
||||||
return get(`${prefix}/list`, credentials)
|
return get(`${prefix}/list`, credentials)
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 获取项目列表
|
||||||
|
* @param credentials
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export function projectListApi(credentials) {
|
||||||
|
return get(`${prefix}/project-list`, credentials)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取首页轮播图列表
|
* 获取首页轮播图列表
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ const paginatedData = computed(() => {
|
|||||||
|
|
||||||
const changePage = (page) => {
|
const changePage = (page) => {
|
||||||
currentPage.value = page
|
currentPage.value = page
|
||||||
|
getList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 模态框
|
// 模态框
|
||||||
@@ -121,8 +122,6 @@ const handleUploadChange = (info) => {
|
|||||||
}
|
}
|
||||||
if (info.file.status === "done") {
|
if (info.file.status === "done") {
|
||||||
// 模拟上传成功后获取图片URL
|
// 模拟上传成功后获取图片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
|
uploading.value = false
|
||||||
message.success("封面上传成功")
|
message.success("封面上传成功")
|
||||||
}
|
}
|
||||||
@@ -206,6 +205,14 @@ const beforeVideoUpload = (file) => {
|
|||||||
return isVideo && isLt50M
|
return isVideo && isLt50M
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customCoverRequest = ({ file, onSuccess }) => {
|
||||||
|
// 模拟上传
|
||||||
|
uploadImageApi(file).then((res) => {
|
||||||
|
currentItem.value.cover = res.url;
|
||||||
|
onSuccess("ok", { status: "done" })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const customRequest = ({ file, onSuccess }) => {
|
const customRequest = ({ file, onSuccess }) => {
|
||||||
// 模拟上传
|
// 模拟上传
|
||||||
uploadImageApi(file).then((res) => {
|
uploadImageApi(file).then((res) => {
|
||||||
@@ -843,7 +850,7 @@ getList();
|
|||||||
v-model:file-list="fileList"
|
v-model:file-list="fileList"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
:custom-request="customRequest"
|
:custom-request="customCoverRequest"
|
||||||
@preview="handlePreview"
|
@preview="handlePreview"
|
||||||
@change="handleUploadChange"
|
@change="handleUploadChange"
|
||||||
:show-upload-list="{ showPreviewIcon: true, showRemoveIcon: true }"
|
:show-upload-list="{ showPreviewIcon: true, showRemoveIcon: true }"
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ const breakpoints = {
|
|||||||
|
|
||||||
<p
|
<p
|
||||||
class="text-lg md:text-xl text-white/80 max-w-2xl line-clamp-3 mb-8"
|
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="fade-up"
|
||||||
data-aos-delay="100"
|
data-aos-delay="100"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import AOS from 'aos'
|
import AOS from 'aos'
|
||||||
import 'aos/dist/aos.css'
|
import 'aos/dist/aos.css'
|
||||||
|
import {projectListApi} from "@/api/request/home.js";
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
AOS.init({
|
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(),
|
createdAt: new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toISOString(),
|
||||||
description: '这是一个示例项目描述,包含了项目的主要功能和技术特点。实际项目中会有更详细的描述信息。'
|
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 selectedCategory = ref('all')
|
||||||
const sortBy = ref('date')
|
const sortBy = ref('date')
|
||||||
@@ -104,6 +122,28 @@ const getAosEffect = (index) => {
|
|||||||
];
|
];
|
||||||
return aosEffects[rowIndex % aosEffects.length][colIndex % aosEffects[0].length];
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -126,7 +166,7 @@ const getAosEffect = (index) => {
|
|||||||
<!-- 过滤排序栏 -->
|
<!-- 过滤排序栏 -->
|
||||||
<div class="mb-10" data-aos="fade-up">
|
<div class="mb-10" data-aos="fade-up">
|
||||||
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
|
<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="relative">
|
||||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
<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>
|
||||||
|
|
||||||
<!-- 分类选择 -->
|
<!-- <!– 分类选择 –>-->
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<select
|
<!-- <select-->
|
||||||
v-model="selectedCategory"
|
<!-- 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"
|
<!-- 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
|
<!-- <option-->
|
||||||
v-for="category in categories"
|
<!-- v-for="category in categories"-->
|
||||||
:key="category.id"
|
<!-- :key="category.id"-->
|
||||||
:value="category.value"
|
<!-- :value="category.value"-->
|
||||||
>
|
<!-- >-->
|
||||||
{{ category.name }}
|
<!-- {{ category.name }}-->
|
||||||
</option>
|
<!-- </option>-->
|
||||||
</select>
|
<!-- </select>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
|
|
||||||
<!-- 排序选择 -->
|
<!-- <!– 排序选择 –>-->
|
||||||
<div>
|
<!-- <div>-->
|
||||||
<select
|
<!-- <select-->
|
||||||
v-model="sortBy"
|
<!-- 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"
|
<!-- 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
|
<!-- <option-->
|
||||||
v-for="option in sortOptions"
|
<!-- v-for="option in sortOptions"-->
|
||||||
:key="option.value"
|
<!-- :key="option.value"-->
|
||||||
:value="option.value"
|
<!-- :value="option.value"-->
|
||||||
>
|
<!-- >-->
|
||||||
{{ option.label }}
|
<!-- {{ option.label }}-->
|
||||||
</option>
|
<!-- </option>-->
|
||||||
</select>
|
<!-- </select>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
</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 class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
<div
|
<div
|
||||||
@@ -243,42 +286,54 @@ const getAosEffect = (index) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<div class="mt-16 flex justify-center" data-aos="fade-up">
|
<div class="mt-16 flex justify-center" data-aos="fade-up">
|
||||||
<nav class="flex items-center space-x-2">
|
<nav class="flex items-center space-x-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-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
:disabled="currentPage === 1"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
|
@click="changePage(currentPage - 1)"
|
||||||
stroke="currentColor">
|
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"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</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>
|
||||||
|
|
||||||
|
<!-- 下一页按钮 -->
|
||||||
<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">
|
:disabled="currentPage === pageCount"
|
||||||
2
|
@click="changePage(currentPage + 1)"
|
||||||
</button>
|
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"
|
||||||
|
>
|
||||||
<button
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
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">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user