Initial commit

This commit is contained in:
tanxin
2026-10-29 10:08:39 +08:00
commit 4c6243a274
124 changed files with 17359 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
<template>
<view class="page-container">
<view class="header-panel"><text class="header-title">预警信息</text><text class="header-subtitle">{{ studentName }}的学习动态</text></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-if="alerts.length === 0" class="status-panel"><text class="status-text">暂无预警信息</text></view>
<view v-else v-for="alert in alerts" :key="alert.id" class="alert-card">
<view class="alert-card-top"><view class="alert-level-dot" :class="levelDotClass(alert.level)"></view><text class="alert-title">{{ alert.title }}</text><text v-if="!alert.isRead" class="unread-mark">未读</text></view>
<text class="alert-content">{{ alert.content }}</text>
<text class="alert-time">{{ formatTime(alert.occurredAt) }}</text>
</view>
</scroll-view>
</view>
</template>
<script setup lang="ts">
import { apiGetStudentAlerts, type StudentAlert, type StudentAlertLevel } from '../../api/student'
import { homeStudentProfile } from '../../store/home'
const alerts = ref<StudentAlert[]>([])
const isLoading = ref(true)
const studentName = computed((): string => homeStudentProfile.value?.name ?? '孩子')
onLoad(() => {
loadAlerts()
})
async function loadAlerts() {
const studentId = homeStudentProfile.value?.id ?? ''
if (!studentId) {
isLoading.value = false
return
}
const res = await apiGetStudentAlerts(studentId, 1, 20)
if (res && res.data) {
alerts.value = res.data.list
}
isLoading.value = false
}
function levelDotClass(level: StudentAlertLevel): string {
return level === 'low' ? 'alert-level-low' : level === 'medium' ? 'alert-level-medium' : 'alert-level-high'
}
function formatTime(value: string): string {
return value.length > 0 ? value.substring(5, 16).replace('T', ' ') : ''
}
</script>
<style>
.page-container { display: flex; flex-direction: column; flex: 1; background-color: #f5f7fb; }
.header-panel { display: flex; flex-direction: column; padding: 18px 20px; background-color: #5d3de8; }
.header-title { font-size: 21px; font-weight: 700; color: #ffffff; }
.header-subtitle { margin-top: 6px; font-size: 13px; color: #e5ddff; }
.content-scroll { flex: 1; padding: 16px 20px; }
.status-panel { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 160px; }
.status-text { font-size: 14px; color: #8992a5; }
.alert-card { display: flex; flex-direction: column; margin-bottom: 12px; padding: 16px; border-radius: 14px; background-color: #ffffff; }
.alert-card-top { display: flex; flex-direction: row; align-items: center; }
.alert-level-dot { width: 9px; height: 9px; margin-right: 8px; border-radius: 5px; }
.alert-level-high { background-color: #e25a5a; }
.alert-level-medium { background-color: #e8a129; }
.alert-level-low { background-color: #4d87cf; }
.alert-title { flex: 1; font-size: 15px; font-weight: 700; color: #30384a; }
.unread-mark { padding: 3px 7px; border-radius: 8px; font-size: 10px; color: #554be9; background-color: #eeefff; }
.alert-content { margin-top: 10px; font-size: 13px; line-height: 20px; color: #626c7e; }
.alert-time { margin-top: 10px; font-size: 11px; color: #9aa2b1; }
</style>