| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- <template>
- <view class="container">
- <scroll-view class="records-scroll" scroll-y>
- <view v-if="loading" class="state-box">
- <text class="state-text">加载中...</text>
- </view>
- <view v-else-if="records.length === 0" class="state-box">
- <text class="state-text">暂无测评记录</text>
- </view>
- <view v-else class="records-list">
- <view v-for="(record, index) in records" :key="index" class="record-card">
- <view class="card-header">
- <view class="header-item">
- <text class="score">{{ record.score }}</text>
- <text class="label">得分</text>
- </view>
- <view class="header-item">
- <text class="time">{{ record.duration }}</text>
- <text class="label">答题用时</text>
- </view>
- <view class="detail-link" @click="viewDetail(record)">
- <text>测评情况</text>
- <image src="/static/icons/chevron-right-blue.svg" class="arrow"></image>
- </view>
- </view>
-
- <view class="card-footer">
- <view class="type-box">
- <text class="type-name">{{ record.typeName }}</text>
- <text :class="['status-tag', record.status]">{{ record.statusText }}</text>
- </view>
- <text class="date">{{ record.date }}</text>
- </view>
- </view>
- </view>
-
- <view v-if="!loading && records.length > 0" class="no-more">—— 已到底啦~ ——</view>
- </scroll-view>
- </view>
- </template>
- <script setup>
- import { ref } from 'vue';
- import { onShow, onPullDownRefresh } from '@dcloudio/uni-app';
- import { getAssessmentRecordList } from '../../api/assessment.js';
- const loading = ref(false);
- const records = ref([]);
- const getStatusMeta = (item) => {
- if (item.statusType && item.statusText) {
- return {
- status: item.statusType,
- statusText: item.statusText
- };
- }
- if (item.finalResult === '1') {
- return { status: 'pass', statusText: '通过' };
- }
- if (item.finalResult === '2') {
- return { status: 'fail', statusText: '未通过' };
- }
- if (item.applyStatus === '2') {
- return { status: 'pending', statusText: '待评分' };
- }
- if (item.applyStatus === '1') {
- return { status: 'pending', statusText: '测评中' };
- }
- return { status: 'pending', statusText: '待测评' };
- };
- const formatDuration = (value) => {
- if (value === null || value === undefined || value === '') {
- return '--';
- }
- const duration = String(value).trim();
- if (duration.includes(':')) {
- return duration;
- }
- const totalMinutes = Number(duration);
- if (Number.isNaN(totalMinutes)) {
- return duration;
- }
- const hours = Math.floor(totalMinutes / 60);
- const minutes = totalMinutes % 60;
- if (hours > 0) {
- return `${hours}小时${minutes}分钟`;
- }
- return `${minutes}分钟`;
- };
- const pickRecordDate = (item) => {
- return item.finishedTime || item.deadlineTime || item.scheduleStartTime || item.createTime || '--';
- };
- const calcDuration = (item) => {
- const start = item.scheduleStartTime;
- const end = item.finishedTime;
- if (!start || !end) return '--';
- const ms = new Date(end) - new Date(start);
- if (isNaN(ms) || ms < 0) return '--';
- const totalMinutes = Math.floor(ms / 60000);
- const hours = Math.floor(totalMinutes / 60);
- const minutes = totalMinutes % 60;
- if (hours > 0) {
- return `${hours}小时${minutes}分钟`;
- }
- return `${minutes}分钟`;
- };
- const normalizeRecord = (item) => {
- const statusMeta = getStatusMeta(item);
- return {
- ...item,
- score: item.finalResult === '1' ? '通过' : item.finalResult === '2' ? '未通过' : '--',
- duration: calcDuration(item),
- typeName: item.evaluationName || '未命名测评',
- status: statusMeta.status,
- statusText: statusMeta.statusText,
- date: pickRecordDate(item)
- };
- };
- const loadRecords = async () => {
- const userInfo = uni.getStorageSync('userInfo') || {};
- const userId = userInfo.studentId || userInfo.id;
- if (!userId) {
- records.value = [];
- uni.showToast({ title: '用户信息失效,请重新登录', icon: 'none' });
- return;
- }
- loading.value = true;
- try {
- const res = await getAssessmentRecordList(userId);
- const rows = Array.isArray(res?.data) ? res.data : [];
- records.value = rows.map(normalizeRecord);
- } catch (error) {
- console.error('加载测评记录失败:', error);
- records.value = [];
- } finally {
- loading.value = false;
- }
- };
- onShow(() => {
- loadRecords();
- });
- onPullDownRefresh(async () => {
- await loadRecords();
- uni.stopPullDownRefresh();
- });
- const viewDetail = (record) => {
- if (!record.evaluationId) {
- uni.showToast({ title: '数据异常', icon: 'none' });
- return;
- }
- // 跳转到图形化报告页,传入测评ID
- uni.navigateTo({
- url: `/pages/assessment/report?id=${record.evaluationId}`
- });
- };
- </script>
- <style lang="scss" scoped>
- .container {
- min-height: 100vh;
- background-color: #F8F9FB;
- }
- .state-box {
- display: flex;
- justify-content: center;
- align-items: center;
- min-height: 320rpx;
- }
- .state-text {
- font-size: 28rpx;
- color: #999;
- }
- .records-list {
- padding: 30rpx;
- }
- .record-card {
- background: #FFF;
- border-radius: 20rpx;
- padding: 30rpx;
- margin-bottom: 30rpx;
- box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.02);
-
- .card-header {
- display: flex;
- align-items: center;
- padding-bottom: 24rpx;
- border-bottom: 1rpx solid #F0F2F5;
- margin-bottom: 24rpx;
-
- .header-item {
- flex: 1;
- display: flex;
- flex-direction: column;
-
- .score, .time {
- font-size: 36rpx;
- font-weight: bold;
- color: #1A1A1A;
- margin-bottom: 4rpx;
- }
- .label {
- font-size: 24rpx;
- color: #999;
- }
- }
-
- .detail-link {
- display: flex;
- align-items: center;
- font-size: 26rpx;
- color: #1F6CFF;
- .arrow { width: 24rpx; height: 24rpx; margin-left: 4rpx; }
- }
- }
-
- .card-footer {
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- .type-box {
- display: flex;
- align-items: center;
- .type-name { font-size: 28rpx; color: #333; font-weight: 500; margin-right: 16rpx; }
- .status-tag {
- font-size: 22rpx;
- padding: 4rpx 16rpx;
- border-radius: 8rpx;
- &.pending { background: #FFF7E6; color: #FAAD14; }
- &.pass { background: #F6FFED; color: #52C41A; }
- &.fail { background: #FFF1F0; color: #FF4D4F; }
- }
- }
-
- .date { font-size: 24rpx; color: #CCC; }
- }
- }
- .no-more {
- text-align: center;
- font-size: 24rpx;
- color: #CCC;
- padding: 40rpx 0 80rpx;
- }
- </style>
|