CheckinDetailPage.vue 6.8 KB
<template>
    <div class="checkin-detail-page">
        <!-- 页面内容 -->
        <div class="page-content">
            <!-- 作业描述 -->
            <div class="section-wrapper">
                <div class="section-title">作业描述</div>
                <div class="section-content">
                    <div v-if="taskDetail.description" class="description-text">
                        {{ taskDetail.description }}
                    </div>
                    <div v-else class="no-description">
                        暂无作业描述
                    </div>
                </div>
            </div>

            <!-- 打卡类型选择 -->
            <div v-if="!taskDetail.is_finish" class="section-wrapper">
                <div class="section-title">选择打卡类型</div>
                <div class="section-content">
                    <div class="checkin-types">
                        <div
                            v-for="option in attachmentTypeOptions"
                            :key="option.key"
                            @click="handleCheckinTypeClick(option.key)"
                            class="checkin-type-item"
                        >
                            <van-icon
                                :name="getIconName(option.key)"
                                size="2rem"
                                color="#4caf50"
                            />
                            <span class="type-text">{{ option.value }}</span>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 已完成提示 -->
            <div v-else class="section-wrapper">
                <div class="finished-notice">
                    <van-icon name="success" size="3rem" color="#4caf50" />
                    <div class="finished-text">作业已完成</div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getTaskDetailAPI } from "@/api/checkin";
import { getTeacherFindSettingsAPI } from '@/api/teacher'
import { useTitle } from '@vueuse/core';
import dayjs from 'dayjs'

const route = useRoute()
const router = useRouter()
useTitle('打卡详情');

// 任务详情数据
const taskDetail = ref({});

// 作品类型选项
const attachmentTypeOptions = ref([]);

/**
 * 返回上一页
 */
const onClickLeft = () => {
    router.back()
}

/**
 * 根据打卡类型获取对应的图标名称
 * @param {string} type - 打卡类型
 * @returns {string} 图标名称
 */
const getIconName = (type) => {
    const iconMap = {
        'text': 'edit',
        'image': 'photo',
        'video': 'video',
        'audio': 'music'
    };
    return iconMap[type] || 'edit';
};

/**
 * 处理打卡类型点击事件
 * @param {string} type - 打卡类型
 */
const handleCheckinTypeClick = (type) => {
    switch (type) {
        case 'text':
            goToCheckinTextPage();
            break;
        case 'image':
            goToCheckinImagePage();
            break;
        case 'video':
            goToCheckinVideoPage();
            break;
        case 'audio':
            goToCheckinAudioPage();
            break;
        default:
            console.warn('未知的打卡类型:', type);
    }
};

/**
 * 跳转到文本打卡页面
 */
const goToCheckinTextPage = () => {
    router.push({
        path: '/checkin/text',
        query: {
            id: route.query.id,
            type: 'text'
        }
    })
}

/**
 * 跳转到图片打卡页面
 */
const goToCheckinImagePage = () => {
    router.push({
        path: '/checkin/image',
        query: {
            id: route.query.id,
            type: 'image'
        }
    })
}

/**
 * 跳转到视频打卡页面
 */
const goToCheckinVideoPage = () => {
    router.push({
        path: '/checkin/video',
        query: {
            id: route.query.id,
            type: 'video',
        }
    })
}

/**
 * 跳转到音频打卡页面
 */
const goToCheckinAudioPage = () => {
    router.push({
        path: '/checkin/audio',
        query: {
            id: route.query.id,
            type: 'audio',
        }
    })
}

/**
 * 获取任务详情
 */
const getTaskDetail = async (month) => {
    const { code, data } = await getTaskDetailAPI({ i: route.query.id, month });
    if (code) {
        taskDetail.value = data;
    }
}

/**
 * 页面挂载时的初始化逻辑
 */
onMounted(async () => {
    // 获取任务详情
    getTaskDetail(dayjs().format('YYYY-MM'));

    // 获取作品类型数据
    try {
        const { code, data } = await getTeacherFindSettingsAPI();
        if (code && data.task_attachment_type) {
            attachmentTypeOptions.value = Object.entries(data.task_attachment_type).map(([key, value]) => ({
                key,
                value
            }));
        }
    } catch (error) {
        console.error('获取作品类型数据失败:', error);
    }
})
</script>

<style lang="less" scoped>
.checkin-detail-page {
    min-height: 100vh;
    background: linear-gradient(to bottom right, #f0fdf4, #f0fdfa, #eff6ff);
}

.page-content {
    padding: 1rem;
}

.section-wrapper {
    background-color: #fff;
    border-radius: 12px;
    margin-bottom: 1rem;
    overflow: hidden;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

.section-title {
    font-size: 1.1rem;
    font-weight: 600;
    color: #4caf50;
    padding: 1rem 1rem 0.5rem;
    border-bottom: 1px solid #f0f0f0;
}

.section-content {
    padding: 1rem;
}

.description-text {
    color: #666;
    line-height: 1.6;
    font-size: 0.95rem;
}

.no-description {
    color: #999;
    font-style: italic;
    text-align: center;
    padding: 2rem 0;
}

.class-status {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.status-text {
    font-size: 0.85rem;
    color: #666;
}

.checkin-types {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1rem;
}

.checkin-type-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1.5rem 1rem;
    border: 2px solid #e8f5e8;
    border-radius: 12px;
    background-color: #fafffe;
    cursor: pointer;
    transition: all 0.3s ease;

    &:hover {
        border-color: #4caf50;
        background-color: #f0fdf4;
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(76, 175, 80, 0.15);
    }

    &:active {
        transform: translateY(0);
    }
}

.type-text {
    margin-top: 0.5rem;
    font-size: 0.9rem;
    color: #4caf50;
    font-weight: 500;
}

.finished-notice {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 3rem 1rem;
    text-align: center;
}

.finished-text {
    margin-top: 1rem;
    font-size: 1.1rem;
    color: #4caf50;
    font-weight: 600;
}
</style>