完整社会服务web

This commit is contained in:
2025-11-04 11:50:57 +08:00
parent 0b03178feb
commit e614a6895d

View File

@@ -11,7 +11,6 @@
}"
>
<div class="banner-container">
</div>
</div>
@@ -75,7 +74,7 @@
>
<!-- 封面图添加默认占位图 -->
<img
:src="item.cover_url || 'https://picsum.photos/id/237/120/120'"
:src="item.cover_image || 'https://picsum.photos/id/237/120/120'"
:alt="item.title"
class="item-img"
:onerror="defaultImg"
@@ -99,13 +98,13 @@
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
v-model:current-page="pagination[currentTab].currentPage"
v-model:page-size="pagination[currentTab].pageSize"
:current-page="pagination[currentTab].currentPage"
:page-size="pagination[currentTab].pageSize"
:page-sizes="[10, 20, 50]"
@size-change="handlePageSizeChange"
@current-change="handleCurrentPageChange"
:disabled="loading"
></el-pagination>
/>
</div>
</div>
@@ -117,7 +116,7 @@
<!-- 封面图 -->
<div class="article-cover">
<img
:src="currentArticle.cover_url || 'https://picsum.photos/id/237/1200/600'"
:src="currentArticle.cover_image || 'https://picsum.photos/id/237/1200/600'"
:alt="currentArticle.title"
class="cover-img"
:onerror="defaultImg"
@@ -150,7 +149,7 @@
@click="selectMainArticle(item)"
>
<img
:src="item.cover_url || 'https://picsum.photos/id/237/300/180'"
:src="item.cover_image || 'https://picsum.photos/id/237/300/180'"
:alt="item.title"
class="card-img"
:onerror="defaultImg"
@@ -171,21 +170,41 @@
</div>
</main>
<!-- 页脚 -->
</div>
</el-config-provider>
</template>
<script>
<script lang="ts">
import axios from 'axios';
// 导入Element Plus组件和中文语言包
import { ElMessage, ElPagination, ElConfigProvider } from 'element-plus';
import zhCn from 'element-plus/es/locale/lang/zh-cn';
// 基础API地址
const base_url = 'http://localhost:8080/api';
// 定义图片项类型
interface ImageItem {
image_url: string;
sort: number;
}
// 文章类型(与后端字段一致)
type Article = {
id: number;
title: string;
cover_image?: string;
subtitle?: string; // 新增字段
content_summary?: string;
publish_time: string;
content?: string;
};
interface PaginationState {
currentPage: number;
pageSize: number;
}
type TabKey = 'schoolEnterprise' | 'researchInternship' | 'ruralGovernment';
export default {
name: 'WorkstationPage',
components: {
@@ -194,75 +213,63 @@ export default {
},
data() {
return {
zhCn, // 中文语言包
currentTab: 'schoolEnterprise',
// 存储各分类的完整数据
zhCn,
currentTab: 'schoolEnterprise' as TabKey,
articles: {
schoolEnterprise: [],
researchInternship: [],
ruralGovernment: []
schoolEnterprise: [] as Article[],
researchInternship: [] as Article[],
ruralGovernment: [] as Article[]
},
currentArticle: null,
relatedArticles: [],
allArticles: [], // 分页当前页数据
total: 0, // 分页总条数
loading: false,
showAllList: false,
// 每个分类独立的分页状态
currentArticle: null as Article | null,
relatedArticles: [] as Article[],
allArticles: [] as Article[],
total: 0 as number,
loading: false as boolean,
showAllList: false as boolean,
pagination: {
schoolEnterprise: { currentPage: 1, pageSize: 10 },
researchInternship: { currentPage: 1, pageSize: 10 },
ruralGovernment: { currentPage: 1, pageSize: 10 }
},
// 封面图加载失败默认图
defaultImg: "this.src='https://picsum.photos/id/237/120/120'",
// 横幅图片地址
bannerUrl: ''
schoolEnterprise: { currentPage: 1, pageSize: 10 } as PaginationState,
researchInternship: { currentPage: 1, pageSize: 10 } as PaginationState,
ruralGovernment: { currentPage: 1, pageSize: 10 } as PaginationState
} as Record<TabKey, PaginationState>,
defaultImg: "this.src='https://picsum.photos/id/237/120/120'" as string,
bannerUrl: '' as string
};
},
computed: {
currentArticles() {
currentArticles(): Article[] {
return this.articles[this.currentTab] || [];
},
// 当前分类的分页配置
currentPagination() {
currentPagination(): PaginationState {
return this.pagination[this.currentTab];
}
},
watch: {
currentTab: {
immediate: true,
handler(newTab) {
// 切换分类时,加载首页数据
handler(newTab: TabKey) {
this.fetchHomeData(newTab);
this.showAllList = false;
},
},
},
created() {
// 组件创建时获取横幅图片
this.fetchBannerImage();
},
methods: {
switchTab(tab) {
switchTab(tab: TabKey) {
this.currentTab = tab;
},
/**
* 获取横幅图片使用POST请求
*/
async fetchBannerImage() {
try {
const response = await axios.post(
`${base_url}/page-image/get`,
{ page: 'SocialService' }, // 请求参数
{ page: 'SocialService' },
{ headers: { 'Content-Type': 'application/json' } }
);
// 处理返回结果
if (response.data && Array.isArray(response.data.images) && response.data.images.length > 0) {
// 查找排序为1的图片如果有多个
const targetImage = response.data.images.find(img => img.sort === 1) || response.data.images[0];
const targetImage: ImageItem = response.data.images.find((img: ImageItem) => img.sort === 1) || response.data.images[0];
this.bannerUrl = targetImage.image_url;
} else {
ElMessage.warning('未找到横幅图片数据');
@@ -273,17 +280,14 @@ export default {
}
},
// 首页数据加载只加载第一页取前4条用于首页展示
async fetchHomeData(category) {
async fetchHomeData(category: TabKey) {
this.loading = true;
try {
const url = this.getCategoryUrl(category);
const payload = { page: 1, page_size: 4 }; // 首页只查4条1条主文章+3条相关
const payload = { page: 1, page_size: 4 };
const response = await axios.post(url, payload, {
headers: { 'Content-Type': 'application/json' },
});
this.handleResponseData(response, category, true);
} catch (error) {
this.handleFetchError(error, '首页数据');
@@ -292,17 +296,14 @@ export default {
}
},
// 分页数据加载(全部项目页用)
async fetchPagedData(category, page = 1, pageSize = 10) {
async fetchPagedData(category: TabKey, page = 1, pageSize = 10) {
this.loading = true;
try {
const url = this.getCategoryUrl(category);
const payload = { page, page_size: pageSize };
const response = await axios.post(url, payload, {
headers: { 'Content-Type': 'application/json' },
});
this.handleResponseData(response, category, false);
} catch (error) {
this.handleFetchError(error, '分页数据');
@@ -311,35 +312,29 @@ export default {
}
},
// 处理接口响应数据
handleResponseData(response, category, isHome = true) {
handleResponseData(response: any, category: TabKey, isHome = true) {
const resData = response.data || {};
if (resData.code !== 0) throw new Error(resData.message || '接口返回错误');
const rawList = resData.data?.list || [];
if (!Array.isArray(rawList)) throw new Error('list 不是数组');
// 按发布时间倒序排序
const sortedList = rawList.sort((a, b) =>
new Date(b.publish_time) - new Date(a.publish_time)
const sortedList = rawList.sort((a: Article, b: Article) =>
new Date(b.publish_time).getTime() - new Date(a.publish_time).getTime()
);
// 存储总条数(分页用)
this.total = resData.data?.total || 0;
if (isHome) {
// 首页逻辑:存储完整数据,设置主文章和相关文章
this.articles[category] = sortedList;
this.currentArticle = sortedList[0] || null;
this.relatedArticles = sortedList.slice(1, 4) || [];
} else {
// 分页逻辑:存储当前页数据
this.allArticles = sortedList;
}
},
// 获取分类对应的接口URL
getCategoryUrl(category) {
getCategoryUrl(category: TabKey): string {
switch (category) {
case 'schoolEnterprise':
return `${base_url}/social-service/list`;
@@ -352,13 +347,11 @@ export default {
}
},
// 错误处理
handleFetchError(error, type) {
handleFetchError(error: any, type: string) {
console.error(`获取${type}失败:`, error);
const errMsg = error.message || '网络异常';
ElMessage?.error?.(`加载${type}失败:${errMsg}`) || alert(`加载失败:${errMsg}`);
// 重置数据状态
this.allArticles = [];
this.total = 0;
if (type === '首页数据') {
@@ -368,12 +361,9 @@ export default {
}
},
// 查看全部:切换到分页页并加载第一页数据
handleViewAll() {
this.showAllList = true;
// 重置当前分类的分页状态为第一页
this.currentPagination.currentPage = 1;
// 加载分页第一页数据
this.fetchPagedData(
this.currentTab,
this.currentPagination.currentPage,
@@ -381,39 +371,28 @@ export default {
);
},
// 页码切换
handleCurrentPageChange(val) {
handleCurrentPageChange(val: number) {
this.currentPagination.currentPage = val;
this.fetchPagedData(
this.currentTab,
val,
this.currentPagination.pageSize
);
this.fetchPagedData(this.currentTab, val, this.currentPagination.pageSize);
},
// 每页条数切换
handlePageSizeChange(val) {
handlePageSizeChange(val: number) {
this.currentPagination.pageSize = val;
this.currentPagination.currentPage = 1; // 切换条数时重置为第一页
this.fetchPagedData(
this.currentTab,
1,
val
);
this.currentPagination.currentPage = 1;
this.fetchPagedData(this.currentTab, 1, val);
},
selectMainArticle(article) {
selectMainArticle(article: Article) {
this.currentArticle = article;
// 重新筛选相关文章排除当前选中项取前3条
this.relatedArticles = this.currentArticles
.filter(a => a.id !== article.id)
.sort((a, b) => new Date(b.publish_time) - new Date(a.publish_time))
.sort((a: Article, b: Article) => new Date(b.publish_time).getTime() - new Date(a.publish_time).getTime())
.slice(0, 3);
this.showAllList = false;
window.scrollTo({ top: 0, behavior: 'smooth' });
},
formatDate(dateStr) {
formatDate(dateStr: string): string {
if (!dateStr) return '';
const date = new Date(dateStr);
return date.toLocaleDateString('zh-CN', {
@@ -423,8 +402,8 @@ export default {
});
},
getTabName(tab) {
const map = {
getTabName(tab: TabKey): string {
const map: Record<TabKey, string> = {
schoolEnterprise: '校企合作',
researchInternship: '研究实习项目',
ruralGovernment: '乡村政府项目',
@@ -476,9 +455,6 @@ export default {
.empty-state { text-align: center; padding: 4rem 0; color: #9CA3AF; font-size: 1.1rem; }
.footer { background-color: #F7F8FA; padding: 2.5rem 0; margin-top: 5rem; border-top: 1px solid #E5E6EB; }
.copyright { text-align: center; color: #86909C; font-size: 0.95rem; }
.all-articles-page { max-width: 1000px; margin: 0 auto; }
.breadcrumbs { margin-bottom: 2rem; font-size: 0.95rem; color: #6B7280; }
.breadcrumbs a { color: #165DFF; text-decoration: none; margin-right: 0.5rem; }
@@ -496,14 +472,11 @@ export default {
.item-subtitle { color: #4B5563; font-size: 1rem; margin: 0 0 0.75rem; font-style: italic; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
.item-date { color: #9CA3AF; font-size: 0.9rem; }
/* 分页容器样式 */
.pagination-container { margin-top: 3rem; display: flex; justify-content: center; padding-bottom: 2rem; }
/* 适配Element Plus分页组件样式 */
::v-deep .el-pagination { --el-pagination-color: #6B7280; --el-pagination-hover-color: #165DFF; --el-pagination-active-color: #fff; --el-pagination-active-bg-color: #165DFF; }
::v-deep .el-pagination__sizes .el-input__wrapper { width: 100px; }
/* 顶部横幅样式 */
.top-banner {
width: 100%;
background-position: center center;
@@ -532,38 +505,14 @@ export default {
margin: 0 auto;
padding: 0 20px;
}
.banner-content h3 {
font-size: 1.8rem;
margin-bottom: 1rem;
font-weight: 700;
letter-spacing: 0.5px;
}
/* 响应式适配 */
@media (max-width: 768px) {
.top-banner {
padding: 2.5rem 0;
}
.banner-content h3 {
font-size: 1.5rem;
}
}
@media (max-width: 480px) {
.top-banner {
padding: 2rem 0;
}
.banner-content h3 {
font-size: 1.3rem;
}
}
@media (max-width: 768px) {
.top-banner { padding: 2.5rem 0; }
.related-title { flex-direction: column; gap: 1rem; }
.related-articles { grid-template-columns: 1fr; }
.all-articles-header { flex-direction: column; gap: 1.5rem; align-items: flex-start; }
.article-item { flex-direction: column; }
.item-img { width: 100%; height: 180px; }
.pagination-container { padding-bottom: 1rem; }
}
@media (max-width: 480px) {
.article-title { font-size: 1.8rem; }