完整社会服务web
This commit is contained in:
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user