搜索、小助手推荐位
This commit is contained in:
769
schoolNewsWeb/src/views/user/resource-center/SearchView.vue
Normal file
769
schoolNewsWeb/src/views/user/resource-center/SearchView.vue
Normal file
@@ -0,0 +1,769 @@
|
||||
<template>
|
||||
<div class="search-view">
|
||||
<!-- 页面头部 -->
|
||||
<div class="search-header">
|
||||
<div class="header-content">
|
||||
<div class="header-left">
|
||||
<button class="back-button" @click="goBack">
|
||||
<el-icon>
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
<span>返回</span>
|
||||
</button>
|
||||
<div class="header-info">
|
||||
<h1 class="page-title">
|
||||
<el-icon class="title-icon">
|
||||
<Search />
|
||||
</el-icon>
|
||||
搜索结果
|
||||
</h1>
|
||||
<p class="page-desc" v-if="searchKeyword">
|
||||
搜索关键词: <span class="keyword-text">{{ searchKeyword }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<div class="header-search">
|
||||
<el-input
|
||||
v-model="localSearchKeyword"
|
||||
placeholder="搜索文章和课程内容"
|
||||
class="search-input"
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Search"
|
||||
@click="handleSearch"
|
||||
class="search-button"
|
||||
>
|
||||
搜索
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<div class="stats-bar" v-if="!loading && (articles.length > 0 || courses.length > 0)">
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">共找到</span>
|
||||
<span class="stat-value">{{ total }}</span>
|
||||
<span class="stat-label">条结果</span>
|
||||
</div>
|
||||
<div class="stat-divider"></div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">文章</span>
|
||||
<span class="stat-value">{{ articles.length }}</span>
|
||||
</div>
|
||||
<div class="stat-divider"></div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-label">课程</span>
|
||||
<span class="stat-value">{{ courses.length }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 搜索结果 -->
|
||||
<div class="search-results" v-loading="loading">
|
||||
<!-- 空状态 -->
|
||||
<div v-if="!loading && total === 0" class="empty-state">
|
||||
<el-icon class="empty-icon">
|
||||
<DocumentDelete />
|
||||
</el-icon>
|
||||
<h3>未找到相关内容</h3>
|
||||
<p>换个关键词试试吧</p>
|
||||
</div>
|
||||
|
||||
<!-- 文章结果 -->
|
||||
<div v-if="articles.length > 0" class="result-section">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">
|
||||
<el-icon>
|
||||
<Document />
|
||||
</el-icon>
|
||||
文章 ({{ articles.length }})
|
||||
</h2>
|
||||
</div>
|
||||
<div class="articles-grid">
|
||||
<div
|
||||
v-for="article in articles"
|
||||
:key="article.resourceID"
|
||||
class="article-card"
|
||||
@click="handleArticleClick(article)"
|
||||
>
|
||||
<!-- 文章封面 -->
|
||||
<div class="article-cover">
|
||||
<img
|
||||
v-if="article.coverImage"
|
||||
:src="FILE_DOWNLOAD_URL + article.coverImage"
|
||||
:alt="article.resourceName"
|
||||
/>
|
||||
<div v-else class="cover-placeholder">
|
||||
<el-icon>
|
||||
<Document />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="cover-overlay">
|
||||
<span class="view-button">查看详情</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文章信息 -->
|
||||
<div class="article-info">
|
||||
<h3 class="article-title" :title="article.resourceName">
|
||||
{{ article.resourceName }}
|
||||
</h3>
|
||||
|
||||
<!-- 简介 -->
|
||||
<p class="article-summary">{{ article.summary || '暂无简介' }}</p>
|
||||
|
||||
<!-- 底部元信息 -->
|
||||
<div class="article-meta">
|
||||
<div class="meta-item">
|
||||
<el-icon class="meta-icon">
|
||||
<User />
|
||||
</el-icon>
|
||||
<span>{{ article.author || '未知' }}</span>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<el-icon class="meta-icon">
|
||||
<View />
|
||||
</el-icon>
|
||||
<span>{{ formatNumber(article.viewCount) }}</span>
|
||||
</div>
|
||||
<div class="meta-item" v-if="article.publishTime">
|
||||
<el-icon class="meta-icon">
|
||||
<Clock />
|
||||
</el-icon>
|
||||
<span>{{ formatDate(article.publishTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 课程结果 -->
|
||||
<div v-if="courses.length > 0" class="result-section">
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">
|
||||
<el-icon>
|
||||
<Reading />
|
||||
</el-icon>
|
||||
课程 ({{ courses.length }})
|
||||
</h2>
|
||||
</div>
|
||||
<div class="courses-grid">
|
||||
<div
|
||||
v-for="course in courses"
|
||||
:key="course.courseID"
|
||||
class="course-card"
|
||||
@click="handleCourseClick(course)"
|
||||
>
|
||||
<!-- 课程封面 -->
|
||||
<div class="course-cover">
|
||||
<img
|
||||
v-if="course.coverImage"
|
||||
:src="FILE_DOWNLOAD_URL + course.coverImage"
|
||||
:alt="course.courseName"
|
||||
/>
|
||||
<div v-else class="cover-placeholder">
|
||||
<el-icon>
|
||||
<Reading />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="cover-overlay">
|
||||
<span class="view-button">查看课程</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 课程信息 -->
|
||||
<div class="course-info">
|
||||
<h3 class="course-title" :title="course.courseName">
|
||||
{{ course.courseName }}
|
||||
</h3>
|
||||
|
||||
<!-- 简介 -->
|
||||
<p class="course-summary">{{ course.summary || '暂无简介' }}</p>
|
||||
|
||||
<!-- 底部元信息 -->
|
||||
<div class="course-meta">
|
||||
<div class="meta-item">
|
||||
<el-icon class="meta-icon">
|
||||
<User />
|
||||
</el-icon>
|
||||
<span>{{ course.author || '未知' }}</span>
|
||||
</div>
|
||||
<div class="meta-item">
|
||||
<el-icon class="meta-icon">
|
||||
<View />
|
||||
</el-icon>
|
||||
<span>{{ formatNumber(course.viewCount) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div v-if="total > pageSize" class="pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed, watch } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {
|
||||
ArrowLeft,
|
||||
Search,
|
||||
Document,
|
||||
Reading,
|
||||
User,
|
||||
View,
|
||||
Clock,
|
||||
DocumentDelete,
|
||||
} from '@element-plus/icons-vue';
|
||||
import { resourceApi } from '@/apis/resource';
|
||||
import { FILE_DOWNLOAD_URL } from '@/config';
|
||||
import type { TaskItemVO } from '@/types/study';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false);
|
||||
const searchKeyword = ref('');
|
||||
const localSearchKeyword = ref('');
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(20);
|
||||
const total = ref(0);
|
||||
const searchResults = ref<TaskItemVO[]>([]);
|
||||
|
||||
// 计算属性:分离文章和课程
|
||||
const articles = computed(() => {
|
||||
return searchResults.value.filter(item => item.itemType === 1);
|
||||
});
|
||||
|
||||
const courses = computed(() => {
|
||||
return searchResults.value.filter(item => item.itemType === 2);
|
||||
});
|
||||
|
||||
/**
|
||||
* 加载搜索结果
|
||||
*/
|
||||
async function loadSearchResults() {
|
||||
if (!searchKeyword.value.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await resourceApi.searchItems({
|
||||
pageParam: {
|
||||
pageNumber: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
},
|
||||
filter: {
|
||||
title: searchKeyword.value.trim(),
|
||||
status: 1, // 只查询已发布的内容
|
||||
},
|
||||
});
|
||||
|
||||
if (result.success && result.dataList) {
|
||||
searchResults.value = result.dataList;
|
||||
total.value = result.dataList.length;
|
||||
} else {
|
||||
searchResults.value = [];
|
||||
total.value = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('搜索失败:', error);
|
||||
ElMessage.error('搜索失败,请稍后重试');
|
||||
searchResults.value = [];
|
||||
total.value = 0;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行搜索
|
||||
*/
|
||||
function handleSearch() {
|
||||
if (!localSearchKeyword.value.trim()) {
|
||||
ElMessage.warning('请输入搜索关键词');
|
||||
return;
|
||||
}
|
||||
|
||||
searchKeyword.value = localSearchKeyword.value;
|
||||
currentPage.value = 1;
|
||||
|
||||
// 更新URL
|
||||
router.push({
|
||||
path: '/search',
|
||||
query: { keyword: searchKeyword.value },
|
||||
});
|
||||
|
||||
loadSearchResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* 页码变化
|
||||
*/
|
||||
function handlePageChange(page: number) {
|
||||
currentPage.value = page;
|
||||
loadSearchResults();
|
||||
// 滚动到顶部
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
/**
|
||||
* 每页数量变化
|
||||
*/
|
||||
function handleSizeChange(size: number) {
|
||||
pageSize.value = size;
|
||||
currentPage.value = 1;
|
||||
loadSearchResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击文章
|
||||
*/
|
||||
function handleArticleClick(article: TaskItemVO) {
|
||||
router.push(`/article/show?articleId=${article.resourceID}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击课程
|
||||
*/
|
||||
function handleCourseClick(course: TaskItemVO) {
|
||||
router.push(`/study-plan/course-detail?courseId=${course.courseID}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回上一页
|
||||
*/
|
||||
function goBack() {
|
||||
router.back();
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化数字
|
||||
*/
|
||||
function formatNumber(num?: number): string {
|
||||
if (!num) return '0';
|
||||
if (num >= 10000) {
|
||||
return (num / 10000).toFixed(1) + 'w';
|
||||
}
|
||||
return num.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
*/
|
||||
function formatDate(date?: Date | string): string {
|
||||
if (!date) return '';
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
// 监听路由变化
|
||||
watch(
|
||||
() => route.query.keyword,
|
||||
(newKeyword) => {
|
||||
if (newKeyword && typeof newKeyword === 'string') {
|
||||
searchKeyword.value = newKeyword;
|
||||
localSearchKeyword.value = newKeyword;
|
||||
loadSearchResults();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 组件挂载
|
||||
onMounted(() => {
|
||||
const keyword = route.query.keyword;
|
||||
if (keyword && typeof keyword === 'string') {
|
||||
searchKeyword.value = keyword;
|
||||
localSearchKeyword.value = keyword;
|
||||
loadSearchResults();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search-view {
|
||||
min-height: 100vh;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.search-header {
|
||||
background: white;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
padding: 24px 32px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
background: #f5f7fa;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
color: #606266;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
background: #e4e7ed;
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.header-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin: 0 0 8px 0;
|
||||
|
||||
.title-icon {
|
||||
font-size: 28px;
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.page-desc {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
margin: 0;
|
||||
|
||||
.keyword-text {
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.header-search {
|
||||
width: 400px;
|
||||
|
||||
.search-input {
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 24px;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
:deep(.el-input__suffix) {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.search-button {
|
||||
border-radius: 20px;
|
||||
padding: 8px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 16px 32px;
|
||||
background: #f5f7fa;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.stat-divider {
|
||||
width: 1px;
|
||||
height: 16px;
|
||||
background: #dcdfe6;
|
||||
}
|
||||
|
||||
.search-results {
|
||||
padding: 0 32px 32px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80px 20px;
|
||||
text-align: center;
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80px;
|
||||
color: #dcdfe6;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 18px;
|
||||
color: #606266;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.result-section {
|
||||
margin-bottom: 48px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin: 0;
|
||||
|
||||
.el-icon {
|
||||
font-size: 24px;
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.articles-grid,
|
||||
.courses-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.article-card,
|
||||
.course-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 12px rgba(0, 21, 41, 0.12);
|
||||
|
||||
.cover-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.article-cover,
|
||||
.course-cover {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
overflow: hidden;
|
||||
background: #f5f7fa;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.cover-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
|
||||
.el-icon {
|
||||
font-size: 64px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.cover-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
|
||||
.view-button {
|
||||
padding: 8px 24px;
|
||||
background: white;
|
||||
color: #409eff;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.article-info,
|
||||
.course-info {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.article-title,
|
||||
.course-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin: 0 0 12px 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 1.4;
|
||||
min-height: 44.8px;
|
||||
}
|
||||
|
||||
.article-summary,
|
||||
.course-summary {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
margin: 0 0 12px 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 1.5;
|
||||
min-height: 42px;
|
||||
}
|
||||
|
||||
.article-meta,
|
||||
.course-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
|
||||
.meta-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 32px;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.header-search {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.articles-grid,
|
||||
.courses-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.header-content {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.search-results {
|
||||
padding: 0 20px 20px;
|
||||
}
|
||||
|
||||
.articles-grid,
|
||||
.courses-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -45,7 +45,7 @@
|
||||
import { ref, watch, onMounted, nextTick } from 'vue';
|
||||
import { resourceApi } from '@/apis/resource';
|
||||
import { FILE_DOWNLOAD_URL } from '@/config';
|
||||
import type { Resource, ResourceSearchParams } from '@/types/resource';
|
||||
import type { Resource } from '@/types/resource';
|
||||
import type { PageParam } from '@/types';
|
||||
import defaultArticleImg from '@/assets/imgs/article-default.png';
|
||||
|
||||
@@ -83,9 +83,9 @@ async function loadResources() {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const filter: ResourceSearchParams = {
|
||||
const filter: Resource = {
|
||||
tagID: props.tagID,
|
||||
keyword: props.searchKeyword,
|
||||
title: props.searchKeyword,
|
||||
status: 1 // 只加载已发布的
|
||||
};
|
||||
|
||||
|
||||
@@ -17,20 +17,20 @@
|
||||
<div class="records-table" v-loading="tableLoading">
|
||||
<h3>学习记录明细</h3>
|
||||
<el-table :data="tableData" stripe style="width: 100%">
|
||||
<el-table-column prop="resourceTitle" label="资源标题" width="200" />
|
||||
<el-table-column prop="resourceTypeName" label="类型" width="100" />
|
||||
<el-table-column label="学习时长" width="120">
|
||||
<el-table-column prop="resourceTitle" label="资源标题"/>
|
||||
<el-table-column prop="resourceTypeName" label="类型" />
|
||||
<el-table-column label="学习时长">
|
||||
<template #default="{ row }">
|
||||
{{ formatDuration(row.totalDuration) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="learnCount" label="学习次数" width="100" />
|
||||
<el-table-column prop="statDate" label="统计日期" width="150">
|
||||
<el-table-column prop="learnCount" label="学习次数" />
|
||||
<el-table-column prop="statDate" label="统计日期">
|
||||
<template #default="{ row }">
|
||||
{{ row.statDate ? new Date(row.statDate).toLocaleDateString('zh-CN') : '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="完成状态" width="100">
|
||||
<el-table-column label="完成状态">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.isComplete ? 'success' : 'info'">{{ row.isComplete ? '已完成' : '学习中' }}</el-tag>
|
||||
</template>
|
||||
@@ -38,6 +38,7 @@
|
||||
</el-table>
|
||||
|
||||
<el-pagination
|
||||
class="pagination-container"
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:total="totalElements"
|
||||
|
||||
Reference in New Issue
Block a user