85 lines
7.1 KiB
Plaintext
85 lines
7.1 KiB
Plaintext
<template>
|
|
<view class="page-container">
|
|
<view class="header-panel"><view class="header-back" @tap="goHome"><UniIcons type="back" class="header-back-icon"></UniIcons></view><view class="header-copy"><text class="header-title">成长激励</text><text class="header-subtitle">{{ homeStudentProfile?.name ?? growth.studentName }} · {{ homeStudentProfile?.school ?? '' }} {{ homeStudentProfile?.className ?? growth.studentClass }}</text></view><view class="header-action"><UniIcons type="person-filled" class="header-action-icon"></UniIcons></view></view>
|
|
<scroll-view class="content-scroll" direction="vertical" scroll-y="true"><view v-if="isLoading" class="status-panel"><text class="status-text">成长数据加载中</text></view><view v-else class="content-panel"><view class="points-card"><view class="points-heading"><view class="points-copy"><text class="points-label">积分余额</text><text class="points-value">{{ growth.pointsBalance }}</text></view><view class="level-badge"><text class="level-label">等级</text><text class="level-value">Lv.{{ growth.level }}</text></view></view><view class="points-stats"><view class="points-stat"><text class="points-stat-value">{{ growth.rank }}</text><text class="points-stat-label">班级排名</text></view><view class="points-stat points-stat-middle"><text class="points-stat-value">{{ growth.streakDays }}</text><text class="points-stat-label">未能连续</text></view><view class="points-stat"><text class="points-stat-value">{{ growth.totalPoints }}</text><text class="points-stat-label">获得总量</text></view></view></view><view class="flow-card"><text class="section-title">积分流水</text><text class="section-description">记录孩子每天做了哪些正向行为</text><view class="flow-list"><view v-for="record in growth.records" :key="record.id" class="flow-item"><view class="flow-icon" :class="'flow-icon-' + record.icon"><UniIcons :type="record.icon === 'calendar' ? 'calendar' : record.icon === 'assignment' ? 'checkbox' : record.icon === 'streak' ? 'fire' : record.icon === 'accuracy' ? 'circle-filled' : record.icon === 'mastery' ? 'star-filled' : 'compose'" class="flow-icon-glyph"></UniIcons></view><view class="flow-copy"><text class="flow-title">{{ record.title }}</text><text class="flow-time">{{ record.timeText }}</text></view><text class="flow-points">+{{ record.points }}</text></view></view></view></view></scroll-view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import UniIcons from '../../uni_modules/uni-icons-x/components/uni-icons/uni-icons.uvue'
|
|
import { apiGetStudentGrowth, apiGetStudentHomeProfile, type StudentGrowth } from '../../api/student'
|
|
import { homeStudentProfile, selectedStudentChangeVersion, setHomeStudentProfile } from '../../store/home'
|
|
|
|
const growth = ref<StudentGrowth>({ studentId: '', studentName: '', studentGrade: '', studentClass: '', pointsBalance: 0, level: 0, rank: 0, streakDays: 0, totalPoints: 0, records: [] })
|
|
const isLoading = ref(true)
|
|
const observedStudentVersion = ref(selectedStudentChangeVersion.value)
|
|
|
|
onLoad(() => { loadGrowth() })
|
|
|
|
onShow(() => {
|
|
if (observedStudentVersion.value !== selectedStudentChangeVersion.value) {
|
|
observedStudentVersion.value = selectedStudentChangeVersion.value
|
|
loadGrowth()
|
|
}
|
|
})
|
|
|
|
async function loadGrowth() {
|
|
isLoading.value = true
|
|
let studentId = homeStudentProfile.value?.id ?? ''
|
|
if (!studentId) {
|
|
const profileRes = await apiGetStudentHomeProfile(undefined, false)
|
|
if (profileRes && profileRes.data) {
|
|
setHomeStudentProfile(profileRes.data)
|
|
studentId = profileRes.data.id
|
|
}
|
|
}
|
|
if (studentId) {
|
|
const res = await apiGetStudentGrowth(studentId)
|
|
if (res && res.data) growth.value = res.data
|
|
}
|
|
isLoading.value = false
|
|
}
|
|
|
|
function goHome() { uni.reLaunch({ url: '/pages/index/index' }) }
|
|
</script>
|
|
|
|
<style>
|
|
.page-container { display: flex; flex-direction: column; flex: 1; background-color: #f5f7fb; }
|
|
.header-panel { display: flex; flex-direction: row; align-items: center; padding: 12px 18px; background-color: #ffffff; }
|
|
.header-back { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 18px; background-color: #f1f4f8; }
|
|
.header-back-icon { font-size: 18px; color: #66758d; }
|
|
.header-copy { display: flex; flex-direction: column; flex: 1; margin-left: 12px; }
|
|
.header-title { font-size: 17px; font-weight: 700; color: #22283a; }
|
|
.header-subtitle { margin-top: 3px; font-size: 12px; color: #8992a5; }
|
|
.header-action { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 18px; background-color: #f0f1ff; }
|
|
.header-action-icon { font-size: 18px; color: #554be9; }
|
|
.content-scroll { flex: 1; }
|
|
.content-panel { display: flex; flex-direction: column; padding: 16px 20px 28px; }
|
|
.status-panel { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 260px; }
|
|
.status-text { font-size: 13px; color: #8992a5; }
|
|
.points-card { display: flex; flex-direction: column; padding: 16px; border-radius: 16px; background-color: #ff9e19; }
|
|
.points-heading { display: flex; flex-direction: row; justify-content: space-between; }
|
|
.points-copy { display: flex; flex-direction: column; }
|
|
.points-label { font-size: 12px; color: #fff4d8; }
|
|
.points-value { margin-top: 2px; font-size: 31px; font-weight: 700; color: #ffffff; }
|
|
.level-badge { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 54px; height: 54px; border-radius: 18px; background-color: rgba(255, 255, 255, 0.22); }
|
|
.level-label { font-size: 10px; color: #fff4d8; }
|
|
.level-value { margin-top: 2px; font-size: 15px; font-weight: 700; color: #ffffff; }
|
|
.points-stats { display: flex; flex-direction: row; margin-top: 11px; padding: 10px 0; border-radius: 12px; background-color: rgba(255, 255, 255, 0.18); }
|
|
.points-stat { display: flex; flex-direction: column; align-items: center; flex: 1; }
|
|
.points-stat-middle { border-left: 1px solid rgba(255, 255, 255, 0.3); border-right: 1px solid rgba(255, 255, 255, 0.3); }
|
|
.points-stat-value { font-size: 16px; font-weight: 700; color: #ffffff; }
|
|
.points-stat-label { margin-top: 4px; font-size: 10px; color: #fff4d8; }
|
|
.flow-card { display: flex; flex-direction: column; margin-top: 16px; padding: 16px; border-radius: 16px; background-color: #ffffff; }
|
|
.section-title { font-size: 16px; font-weight: 700; color: #242b3d; }
|
|
.section-description { margin-top: 6px; font-size: 11px; color: #8992a5; }
|
|
.flow-list { display: flex; flex-direction: column; margin-top: 12px; }
|
|
.flow-item { display: flex; flex-direction: row; align-items: center; margin-bottom: 8px; padding: 10px; border-radius: 12px; background-color: #f6f8fb; }
|
|
.flow-icon { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 8px; background-color: #ffffff; }
|
|
.flow-icon-glyph { font-size: 16px; color: #ff9e19; }
|
|
.flow-copy { display: flex; flex-direction: column; flex: 1; margin-left: 10px; }
|
|
.flow-title { font-size: 13px; color: #242b3d; }
|
|
.flow-time { margin-top: 3px; font-size: 10px; color: #94a0b1; }
|
|
.flow-points { font-size: 13px; font-weight: 700; color: #f29900; }
|
|
</style>
|