peixue-dev/peidu/uniapp/user-package/pages/user/learning-record.vue

381 lines
8.3 KiB
Vue

<template>
<view class="learning-record-page">
<!-- 统计卡片 -->
<view class="stats-card">
<view class="stat-item">
<text class="stat-value">{{ stats.totalHours }}</text>
<text class="stat-label">累计学习(小时)</text>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value">{{ stats.totalSessions }}</text>
<text class="stat-label">学习次数</text>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value">{{ stats.avgScore }}</text>
<text class="stat-label">平均评分</text>
</view>
</view>
<!-- 筛选标签 -->
<view class="filter-tabs">
<view
v-for="tab in tabs"
:key="tab.value"
class="tab-item"
:class="{ active: currentTab === tab.value }"
@click="changeTab(tab.value)">
{{ tab.label }}
</view>
</view>
<!-- 学习记录列表 -->
<scroll-view scroll-y class="record-list">
<view class="record-item" v-for="record in recordList" :key="record.id" @click="goDetail(record.id)">
<view class="record-header">
<view class="record-date">
<text class="date-day">{{ getDay(record.date) }}</text>
<text class="date-month">{{ getMonth(record.date) }}</text>
</view>
<view class="record-info">
<view class="record-title">{{ record.serviceName }}</view>
<view class="record-meta">
<text class="meta-item">👨‍🏫 {{ record.teacherName }}</text>
<text class="meta-item">⏱️ {{ record.duration }}分钟</text>
</view>
</view>
</view>
<view class="record-content">
<view class="content-item">
<text class="item-label">学习内容:</text>
<text class="item-value">{{ record.content }}</text>
</view>
<view class="content-item" v-if="record.homework">
<text class="item-label">作业情况:</text>
<text class="item-value">{{ record.homework }}</text>
</view>
<view class="content-item" v-if="record.feedback">
<text class="item-label">老师评价:</text>
<text class="item-value">{{ record.feedback }}</text>
</view>
</view>
<view class="record-footer">
<view class="rating" v-if="record.rating">
<text class="rating-label">评分:</text>
<text class="rating-stars">{{ '⭐'.repeat(record.rating) }}</text>
</view>
<view class="record-status" :class="'status-' + record.status">
{{ getStatusText(record.status) }}
</view>
</view>
</view>
<view class="empty-state" v-if="recordList.length === 0">
<text class="empty-icon">📚</text>
<text class="empty-text">暂无学习记录</text>
</view>
</scroll-view>
</view>
</template>
<script>
import { recordApi } from '@/api/index.js'
export default {
data() {
return {
stats: {
totalHours: 0,
totalSessions: 0,
avgScore: 0
},
currentTab: 'all',
tabs: [
{ label: '全部', value: 'all' },
{ label: '本周', value: 'week' },
{ label: '本月', value: 'month' }
],
recordList: []
}
},
onLoad() {
this.loadStats()
this.loadRecordList()
},
methods: {
async loadStats() {
try {
const res = await recordApi.getStats()
if (res && res.code === 200 && res.data) {
this.stats = res.data
}
} catch (e) {
console.error('加载统计失败', e)
}
},
async loadRecordList() {
try {
const res = await recordApi.getRecordList({ period: this.currentTab })
if (res && res.code === 200 && res.data) {
this.recordList = res.data
}
} catch (e) {
console.error('加载记录失败', e)
}
},
changeTab(value) {
this.currentTab = value
this.loadRecordList()
},
getDay(date) {
return date.split('-')[2]
},
getMonth(date) {
const month = date.split('-')[1]
return `${month}`
},
getStatusText(status) {
const statusMap = {
'completed': '已完成',
'cancelled': '已取消',
'pending': '待完成'
}
return statusMap[status] || ''
},
goDetail(id) {
uni.navigateTo({
url: `/pages/learning/detail?id=${id}`
})
}
}
}
</script>
<style lang="scss" scoped>
$primary-green: #5fc9ba;
$white: #fff;
$black: #333;
$gray: #999;
$light-gray: #f5f5f5;
.learning-record-page {
min-height: 100vh;
background: $light-gray;
}
.stats-card {
background: linear-gradient(135deg, #5fc9ba 0%, #7dd9ca 100%);
padding: 60rpx 40rpx;
display: flex;
justify-content: space-around;
align-items: center;
.stat-item {
flex: 1;
text-align: center;
.stat-value {
display: block;
font-size: 48rpx;
font-weight: bold;
color: $white;
margin-bottom: 12rpx;
}
.stat-label {
display: block;
font-size: 24rpx;
color: rgba(255, 255, 255, 0.9);
}
}
.stat-divider {
width: 2rpx;
height: 80rpx;
background: rgba(255, 255, 255, 0.3);
}
}
.filter-tabs {
display: flex;
background: $white;
padding: 20rpx 30rpx;
.tab-item {
flex: 1;
text-align: center;
padding: 16rpx 0;
font-size: 28rpx;
color: #666;
border-radius: 8rpx;
transition: all 0.3s;
&.active {
color: $primary-green;
background: rgba(95, 201, 186, 0.1);
font-weight: bold;
}
}
}
.record-list {
padding: 20rpx 30rpx;
}
.record-item {
background: $white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.record-header {
display: flex;
gap: 20rpx;
margin-bottom: 20rpx;
.record-date {
width: 100rpx;
height: 100rpx;
background: rgba(95, 201, 186, 0.1);
border-radius: 12rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-shrink: 0;
.date-day {
font-size: 40rpx;
font-weight: bold;
color: $primary-green;
line-height: 1;
margin-bottom: 4rpx;
}
.date-month {
font-size: 22rpx;
color: $primary-green;
}
}
.record-info {
flex: 1;
.record-title {
font-size: 32rpx;
font-weight: bold;
color: $black;
margin-bottom: 12rpx;
}
.record-meta {
display: flex;
gap: 20rpx;
.meta-item {
font-size: 24rpx;
color: $gray;
}
}
}
}
.record-content {
padding: 20rpx 0;
border-top: 1rpx solid #f0f0f0;
border-bottom: 1rpx solid #f0f0f0;
margin-bottom: 20rpx;
.content-item {
margin-bottom: 12rpx;
&:last-child {
margin-bottom: 0;
}
.item-label {
font-size: 26rpx;
color: $gray;
}
.item-value {
font-size: 26rpx;
color: #666;
line-height: 1.6;
}
}
}
.record-footer {
display: flex;
justify-content: space-between;
align-items: center;
.rating {
display: flex;
align-items: center;
.rating-label {
font-size: 24rpx;
color: $gray;
margin-right: 8rpx;
}
.rating-stars {
font-size: 24rpx;
}
}
.record-status {
padding: 6rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
&.status-completed {
background: rgba(95, 201, 186, 0.1);
color: $primary-green;
}
&.status-cancelled {
background: #f0f0f0;
color: $gray;
}
&.status-pending {
background: rgba(255, 193, 7, 0.1);
color: #ffc107;
}
}
}
}
.empty-state {
text-align: center;
padding: 120rpx 0;
.empty-icon {
display: block;
font-size: 120rpx;
margin-bottom: 30rpx;
opacity: 0.3;
}
.empty-text {
font-size: 28rpx;
color: $gray;
}
}
</style>