<template>
    <ParentPage active="reports" :show-tab="false">
        <view class="detail-page">
            <ParentCard class="hero-card">
                <view class="hero-top">
                    <view>
                        <text class="category-tag">{{ report.category }}</text>
                        <text class="report-title">{{ report.title }}</text>
                        <text class="report-date">{{ report.date }}</text>
                    </view>
                    <text class="subject-text">{{ report.subject }}</text>
                </view>

                <view class="score-grid">
                    <view v-for="item in detail.scoreBlocks" :key="item.label" class="score-item">
                        <text class="score-label">{{ item.label }}</text>
                        <text class="score-value">{{ item.value }}</text>
                        <text class="score-desc">{{ item.desc }}</text>
                    </view>
                </view>
            </ParentCard>

            <ParentCard class="nav-card">
                <view class="tab-row">
                    <view
                        v-for="tab in tabs"
                        :key="tab.key"
                        class="tab-item"
                        :class="{ active: activeTab === tab.key }"
                        @click="switchTab(tab.key)"
                    >
                        {{ tab.label }}
                    </view>
                </view>

                <view class="rank-grid">
                    <view v-for="item in detail.ranks" :key="item.label" class="rank-item">
                        <text class="rank-label">{{ item.label }}</text>
                        <text class="rank-value">{{ item.value }}</text>
                    </view>
                </view>
            </ParentCard>

            <template v-if="activeTab === 'analysis'">
                <ParentCard class="section-card" title="题型分布" subtitle="按题型拆解本次卷面构成">
                    <view v-if="pageLoading && !channelAnalyzeList.length" class="answers-loading">
                        <xy-Empty type="loading" content="加载分析数据..." />
                    </view>
                    <view v-else-if="channelAnalyzeList.length" class="chart-block">
                        <view class="pie-row">
                            <view class="pie">
                                <view class="pie-circle" :style="channelPieStyle"></view>
                                <view class="pie-hole">
                                    <text class="pie-hole-num">{{ totalQuestionCount }}</text>
                                    <text class="pie-hole-label">题</text>
                                </view>
                            </view>
                            <view class="pie-legend">
                                <view
                                    v-for="(item, idx) in channelAnalyzeList"
                                    :key="idx"
                                    class="legend-item"
                                >
                                    <view
                                        class="legend-dot"
                                        :style="{ background: channelPieColors[idx % channelPieColors.length] }"
                                    ></view>
                                    <text class="legend-name">{{ item.chanelTypeName }}</text>
                                    <text class="legend-count">{{ item.titleCount }}题</text>
                                </view>
                            </view>
                        </view>
                        <view class="data-table chart-table">
                            <view class="table-row table-head channel-row">
                                <text>题型</text>
                                <text>题量</text>
                                <text>占比</text>
                            </view>
                            <view v-for="row in analysisRows" :key="row.type" class="table-row channel-row">
                                <text>{{ row.type }}</text>
                                <text class="strong">{{ row.count }}</text>
                                <text class="rate-good">{{ row.rate }}</text>
                            </view>
                        </view>
                    </view>
                    <xy-Empty v-else type="task" content="暂无题型分析数据" />
                </ParentCard>

                <ParentCard class="section-card" title="难度分布" subtitle="各难度档位题量占比">
                    <view v-if="pageLoading && !difficultyAnalyzeList.length" class="answers-loading">
                        <xy-Empty type="loading" content="加载分析数据..." />
                    </view>
                    <view v-else-if="difficultyAnalyzeList.length" class="chart-block">
                        <view class="pie-row">
                            <view class="pie">
                                <view class="pie-circle" :style="difficultyPieStyle"></view>
                                <view class="pie-hole">
                                    <text class="pie-hole-num">{{ totalDifficultyCount }}</text>
                                    <text class="pie-hole-label">题</text>
                                </view>
                            </view>
                            <view class="pie-legend">
                                <view
                                    v-for="(item, idx) in difficultyAnalyzeList"
                                    :key="idx"
                                    class="legend-item"
                                >
                                    <view
                                        class="legend-dot"
                                        :style="{ background: getDifficultyColor(item.difficultyName) }"
                                    ></view>
                                    <text class="legend-name">{{ item.difficultyName }}</text>
                                    <text class="legend-count">{{ item.titleCount }}题</text>
                                </view>
                            </view>
                        </view>
                        <view class="bars">
                            <view
                                v-for="(item, idx) in difficultyAnalyzeList"
                                :key="idx"
                                class="bar-row"
                            >
                                <view class="bar-name">{{ item.difficultyName }}</view>
                                <view class="bar-track">
                                    <view
                                        class="bar-fill"
                                        :style="{
                                            width: getDifficultyBarWidth(item.score) + '%',
                                            background: getDifficultyColor(item.difficultyName),
                                        }"
                                    ></view>
                                </view>
                                <view class="bar-value">{{ item.score }}<text class="bar-value-unit">分</text></view>
                            </view>
                        </view>
                    </view>
                    <xy-Empty v-else type="task" content="暂无难度分析数据" />
                </ParentCard>

                <ParentCard class="section-card" title="难度得分" subtitle="关注中难题稳定性，决定后续练习重点">
                    <view v-if="pageLoading && !difficultyRows.length" class="answers-loading">
                        <xy-Empty type="loading" content="加载分析数据..." />
                    </view>
                    <view v-else-if="difficultyRows.length" class="data-table">
                        <view class="table-row table-head">
                            <text>难度</text>
                            <text>题量</text>
                            <text>得分</text>
                            <text>得分率</text>
                        </view>
                        <view v-for="row in difficultyRows" :key="row.difficulty" class="table-row">
                            <text>{{ row.difficulty }}</text>
                            <text>{{ row.count }}</text>
                            <text class="strong">{{ row.score }}</text>
                            <text :class="row.rateValue >= 80 ? 'rate-good' : 'rate-warn'">{{ row.rate }}</text>
                        </view>
                    </view>
                    <xy-Empty v-else type="task" content="暂无难度得分数据" />
                </ParentCard>

                <ParentCard
                    v-if="classRankList.length"
                    class="section-card"
                    title="班级排名"
                    subtitle="本次作业班级得分排行"
                >
                    <view class="rank-list">
                        <view
                            v-for="item in classRankList"
                            :key="`${item.rankNum}-${item.stuName}`"
                            class="rank-list-item"
                            :class="{ self: item.selfFlag === 1 }"
                        >
                            <text class="rank-no">{{ item.rankNum }}</text>
                            <text class="rank-name">{{ item.stuName }}</text>
                            <text class="rank-score">{{ item.markScore }}/{{ item.paperScore }}</text>
                            <text class="rank-rate">{{ formatScoreRate(item.scoreRate) }}</text>
                        </view>
                    </view>
                </ParentCard>
            </template>

            <view v-if="activeTab === 'answers'" class="answers-panel">
                <ParentCard class="section-card" title="答题卡详情" subtitle="点击题号查看每道题的答题情况">
                    <view class="answer-legend">
                        <view><text class="legend-dot correct"></text>正确</view>
                        <view><text class="legend-dot wrong"></text>错误</view>
                        <view><text class="legend-dot unanswered"></text>未答</view>
                    </view>
                    <view v-if="pageLoading && !questionSummaries.length" class="answers-loading">
                        <xy-Empty type="loading" content="加载答题卡..." />
                    </view>
                    <view v-else-if="questionSummaries.length" class="question-grid">
                        <view
                            v-for="question in questionSummaries"
                            :key="question.no"
                            class="question-no"
                            :class="[question.status, { active: selectedNo === question.no }]"
                            @click="selectQuestion(question.no)"
                        >
                            {{ question.no }}
                        </view>
                    </view>
                    <xy-Empty v-else type="task" content="暂无题目数据" />
                </ParentCard>

                <ParentCard v-if="selectedNo && selectedQuestionSummary" class="section-card" title="当前题目详情">
                    <view class="question-head">
                        <text>第 {{ selectedQuestionSummary.no }} 题</text>
                        <text>{{ selectedQuestionSummary.type }}</text>
                        <text :class="statusClass(selectedQuestionSummary.status)">
                            {{ statusLabel(selectedQuestionSummary.status) }}
                        </text>
                    </view>
                    <view v-if="detailLoadingNo === selectedNo" class="answers-loading">
                        <xy-Empty type="loading" content="加载题目详情..." />
                    </view>
                    <view v-else-if="selectedQuestionDetail" class="detail-fields">
                        <view class="field-card">
                            <text class="field-label">题干</text>
                            <view v-if="selectedQuestionDetail.stemHtml" class="field-content rich-content">
                                <rich-text :nodes="selectedQuestionDetail.stemHtml" />
                            </view>
                            <view v-if="selectedQuestionDetail.stemImages?.length" class="stem-images">
                                <image
                                    v-for="(img, imgIdx) in selectedQuestionDetail.stemImages"
                                    :key="imgIdx"
                                    :src="img"
                                    mode="widthFix"
                                    class="stem-image"
                                    @click="previewStemImage(imgIdx)"
                                />
                            </view>
                            <text
                                v-if="!selectedQuestionDetail.stemHtml && !selectedQuestionDetail.stemImages?.length"
                                class="field-content"
                            >
                                暂无题干
                            </text>
                        </view>
                        <!-- 选项模块（参考 web 端 Subject/doWork 的 SingleChoice/MultipleChoice 组件） -->
                        <view
                            v-if="selectedQuestionDetail.options?.length"
                            class="field-card options-card"
                        >
                            <text class="field-label">选项</text>
                            <view class="option-list">
                                <view
                                    v-for="(opt, optIdx) in selectedQuestionDetail.options"
                                    :key="optIdx"
                                    class="option-item"
                                    :class="optionItemClass(opt, optIdx)"
                                >
                                    <text class="option-label">{{ opt.label }}</text>
                                    <view class="option-value">
                                        <rich-text
                                            v-if="isHtmlContent(opt.value)"
                                            :nodes="opt.value"
                                        />
                                        <text v-else>{{ opt.value }}</text>
                                    </view>
                                </view>
                            </view>
                        </view>
                        <view class="field-card success">
                            <text class="field-label">正确答案</text>
                            <view v-if="selectedQuestionDetail.correctAnswerHtml" class="field-content rich-content">
                                <rich-text :nodes="selectedQuestionDetail.correctAnswerHtml" />
                            </view>
                            <text v-else class="field-content">--</text>
                        </view>
                        <view class="field-card student">
                            <text class="field-label">学员答案</text>
                            <view v-if="selectedQuestionDetail.studentAnswerImages?.length" class="answer-images">
                                <image
                                    v-for="(img, imgIdx) in selectedQuestionDetail.studentAnswerImages"
                                    :key="imgIdx"
                                    :src="img"
                                    mode="widthFix"
                                    class="answer-image"
                                    @click="previewStudentImage(imgIdx)"
                                />
                            </view>
                            <view v-if="selectedQuestionDetail.studentAnswerHtml" class="field-content rich-content">
                                <rich-text :nodes="selectedQuestionDetail.studentAnswerHtml" />
                            </view>
                            <text
                                v-else-if="selectedQuestionDetail.studentAnswer"
                                class="field-content"
                            >{{ selectedQuestionDetail.studentAnswer }}</text>
                            <text
                                v-else-if="!selectedQuestionDetail.studentAnswerImages?.length"
                                class="field-content"
                            >未作答</text>
                        </view>
                        <view class="field-card">
                            <text class="field-label">得分情况</text>
                            <text class="field-content">{{ selectedQuestionSummary.score }}</text>
                        </view>
                        <view class="field-card">
                            <text class="field-label">班级得分率</text>
                            <text class="field-content">{{ selectedQuestionSummary.classRate }}</text>
                        </view>
                        <view class="field-card">
                            <text class="field-label">学校得分率</text>
                            <text class="field-content">{{ selectedQuestionSummary.schoolRate }}</text>
                        </view>
                    </view>
                </ParentCard>

                <ParentCard class="section-card" title="每道题具体情况">
                    <view class="table-toggle" @click="showQuestionTable = !showQuestionTable">
                        <text>{{ showQuestionTable ? '收起列表' : '展开查看全部题目' }}</text>
                        <text class="table-toggle-icon">{{ showQuestionTable ? '▲' : '▼' }}</text>
                    </view>
                    <scroll-view v-if="showQuestionTable" scroll-x class="question-table-scroll">
                        <view class="question-table">
                            <view class="question-row table-head">
                                <text>题号</text>
                                <text>题型</text>
                                <text>得分</text>
                                <text>状态</text>
                                <text>知识点</text>
                                <text>班级得分率</text>
                                <text>学校得分率</text>
                            </view>
                            <view
                                v-for="question in questionSummaries"
                                :key="`row-${question.no}`"
                                class="question-row"
                                @click="selectQuestion(question.no)"
                            >
                                <text>{{ question.no }}</text>
                                <text>{{ question.type }}</text>
                                <text>{{ question.score }}</text>
                                <text :class="statusClass(question.status)">
                                    {{ statusLabel(question.status) }}
                                </text>
                                <text>{{ question.knowledge }}</text>
                                <text>{{ question.classRate }}</text>
                                <text>{{ question.schoolRate }}</text>
                            </view>
                        </view>
                    </scroll-view>
                </ParentCard>
            </view>

            <template v-if="activeTab === 'knowledge'">
                <ParentCard class="section-card" title="错题知识点占比" subtitle="用于判断最近应优先补强的知识点">
                    <view v-if="pageLoading && !knowledgeList.length" class="answers-loading">
                        <xy-Empty type="loading" content="加载知识点..." />
                    </view>
                    <view v-else-if="knowledgeRatios.length" class="knowledge-summary">
                        <view class="wrong-total">
                            <text class="wrong-number">{{ knowledgeWeakCount }}</text>
                            <text class="wrong-label">薄弱知识点</text>
                        </view>
                        <scroll-view
                            scroll-y
                            class="ratio-list"
                            :style="{ height: ratioListHeight }"
                            :show-scrollbar="false"
                        >
                            <view v-for="item in knowledgeRatios" :key="item.name" class="ratio-row">
                                <view class="ratio-meta">
                                    <text>{{ item.name }}</text>
                                    <text>{{ item.percent }}%</text>
                                </view>
                                <view class="ratio-track">
                                    <view class="ratio-fill" :class="item.tone" :style="{ width: `${item.percent}%` }"></view>
                                </view>
                            </view>
                        </scroll-view>
                    </view>
                    <xy-Empty v-else type="learn" content="暂无知识点占比数据" />
                </ParentCard>

                <ParentCard class="section-card" title="知识点得分">
                    <view v-if="pageLoading && !knowledgeList.length" class="answers-loading">
                        <xy-Empty type="loading" content="加载知识点..." />
                    </view>
                    <template v-else-if="knowledgeList.length">
                    <view class="level-tabs">
                        <view
                            v-for="level in knowledgeTabs"
                            :key="level.key"
                            class="level-tab"
                            :class="{ active: activeKnowledgeLevel === level.key }"
                            @click="activeKnowledgeLevel = level.key"
                        >
                            {{ level.label }}
                        </view>
                    </view>
                    <view class="data-table">
                        <view class="table-row table-head knowledge-row">
                            <text>知识点</text>
                            <text>满分</text>
                            <text>得分</text>
                        </view>
                        <view v-for="item in filteredKnowledgeScores" :key="item.name" class="table-row knowledge-row">
                            <text class="knowledge-name">{{ item.name }}</text>
                            <text>{{ item.fullScore }}</text>
                            <text :class="knowledgeScoreClass(item)">{{ item.score }}[{{ knowledgeRate(item) }}%]</text>
                        </view>
                    </view>
                    <xy-Empty v-if="!filteredKnowledgeScores.length" type="learn" content="当前分段暂无知识点" />
                    </template>
                    <xy-Empty v-else type="learn" content="暂无知识点数据" />
                </ParentCard>
            </template>
        </view>

        <view v-if="showDownloadReport" class="bottom-actions">
            <button class="download-btn" @click="downloadReport">下载报告</button>
            <!-- <view class="home-btn" @click="goHome">
                <text class="home-roof"></text>
                <text class="home-body"></text>
            </view> -->
        </view>
    </ParentPage>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { getJobAnalyse, getKnowledgeAnalyse, getPaperRecordDetail, type JobAnalyseVo, type KnowledgeAnalyzeItem } from '@/api/homework';
import { useParentStore } from '@/state/modules/parent';
import { storeToRefs } from 'pinia';
import ParentCard from '../components/ParentCard.vue';
import ParentPage from '../components/ParentPage.vue';
import {
    reportDetails,
    type ReportKnowledgeScore,
    type ReportQuestion,
    type ReportQuestionSummary,
    type ReportScoreBlock,
    type ReportKnowledgeRatio,
} from '../utils/data';
import {
    mapPaperQuestion,
    mapPaperQuestionSummaries,
    normalizeLegacyQuestion,
} from '../utils/paperDetail';
import { isHtmlContent } from '@/utils/questionHtml';

type DetailTab = 'analysis' | 'answers' | 'knowledge';
type KnowledgeLevel = 'all' | 'weak' | 'pass' | 'good';

const tabs: { key: DetailTab; label: string }[] = [
    { key: 'analysis', label: '试卷分析' },
    { key: 'answers', label: '答题卡' },
    { key: 'knowledge', label: '知识点' },
];

const knowledgeTabs: { key: KnowledgeLevel; label: string }[] = [
    { key: 'all', label: '全部' },
    { key: 'weak', label: '薄弱' },
    { key: 'pass', label: '合格' },
    { key: 'good', label: '良好' },
];

const REPORT_FLAG = 1;
const showDownloadReport = false;

const parentStore = useParentStore();
const { activeChild } = storeToRefs(parentStore);

const channelPieColors = ['#2563eb', '#22c55e', '#f59e0b', '#ef4444', '#0ea5e9', '#a855f7', '#ec4899'];
const difficultyBaseColorMap: Record<string, string> = {
    容易: '#22c55e',
    较易: '#0ea5e9',
    一般: '#f59e0b',
    普通: '#f59e0b',
    中等: '#f59e0b',
    较难: '#f97316',
    困难: '#ef4444',
};
const difficultyFallbackColors = ['#6366f1', '#14b8a6', '#f472b6', '#84cc16'];

const recordId = ref('');
const childUserId = ref('');
const reportName = ref('');
const reportSubject = ref('');
const reportCategory = ref('');
const reportDate = ref('');
const reportScoreRate = ref('');

const activeTab = ref<DetailTab>('analysis');
const selectedNo = ref(0);
const activeKnowledgeLevel = ref<KnowledgeLevel>('all');
const pageLoading = ref(false);
const showQuestionTable = ref(false);
const detailLoadingNo = ref(0);
const rawTitleItems = ref<Record<string, unknown>[]>([]);
const questionSummaries = ref<ReportQuestionSummary[]>([]);
const questionDetailCache = ref<Record<number, ReportQuestion>>({});
const paperDetail = ref<Record<string, unknown>>({});
const jobAnalyse = ref<JobAnalyseVo>({});
const knowledgeList = ref<KnowledgeAnalyzeItem[]>([]);

onLoad((query) => {
    recordId.value = String(query?.id || '');
    childUserId.value = String(query?.userId || '');
    reportName.value = query?.name ? decodeURIComponent(String(query.name)) : '';
    reportSubject.value = query?.subject ? decodeURIComponent(String(query.subject)) : '';
    reportCategory.value = query?.category ? decodeURIComponent(String(query.category)) : '';
    reportDate.value = String(query?.date || '');
    reportScoreRate.value = query?.score != null ? String(query.score) : '';
    loadReportData();
});

const mockDetail = computed(() => reportDetails[recordId.value] || reportDetails.r1);


const formatScoreRate = (value?: number) => {
    if (value == null) return '--';
    const rate = value <= 1 ? value * 100 : value;
    return `${Math.round(rate * 10) / 10}%`;
};

const formatDifficultyScoreRate = (actual?: number, total?: number) => {
    const score = Number(total) || 0;
    if (score <= 0) return { text: '--', value: 0 };
    const rate = ((Number(actual) || 0) / score) * 100;
    return { text: `${Math.round(rate * 10) / 10}%`, value: rate };
};

const channelAnalyzeList = computed(() => jobAnalyse.value.paperChanelAnalyzeList || []);
const difficultyAnalyzeList = computed(() => jobAnalyse.value.paperDifficultyAnalyzeList || []);

const getDifficultyColor = (name?: string) => {
    if (!name) return difficultyFallbackColors[0];
    return difficultyBaseColorMap[name] || difficultyFallbackColors[name.length % difficultyFallbackColors.length];
};

const totalQuestionCount = computed(() =>
    channelAnalyzeList.value.reduce((sum, item) => sum + (Number(item.titleCount) || 0), 0),
);

const totalDifficultyCount = computed(() =>
    difficultyAnalyzeList.value.reduce((sum, item) => sum + (Number(item.titleCount) || 0), 0),
);

const buildPieStyle = (
    list: { titleCount?: number }[],
    colorFn: (idx: number) => string,
) => {
    if (!list.length) return {};
    const total = list.reduce((sum, item) => sum + (Number(item.titleCount) || 0), 0);
    if (total <= 0) return {};

    const parts: string[] = [];
    let cur = 0;
    list.forEach((item, idx) => {
        const pct = ((Number(item.titleCount) || 0) / total) * 100;
        const color = colorFn(idx);
        const next = cur + pct;
        parts.push(`${color} ${cur}% ${next}%`);
        cur = next;
    });
    return { background: `conic-gradient(${parts.join(', ')})` };
};

const channelPieStyle = computed(() =>
    buildPieStyle(channelAnalyzeList.value, (idx) => channelPieColors[idx % channelPieColors.length]),
);

const difficultyPieStyle = computed(() =>
    buildPieStyle(difficultyAnalyzeList.value, (idx) =>
        getDifficultyColor(difficultyAnalyzeList.value[idx]?.difficultyName),
    ),
);

const getDifficultyBarWidth = (score?: number) => {
    const max = Math.max(...difficultyAnalyzeList.value.map((item) => Number(item.score) || 0), 1);
    return Math.round(((Number(score) || 0) / max) * 100);
};

const scoreBlocks = computed<ReportScoreBlock[]>(() => {
    const vo = jobAnalyse.value.jobReportVo || {};
    const mark = Number(vo.actualScore ?? vo.markScore ?? paperDetail.value.score ?? 0);
    const total = Number(vo.totalScore ?? paperDetail.value.totalScore ?? 0);
    const rateFromScore =
        total > 0 ? `${Math.round((mark / total) * 1000) / 10}%` : reportScoreRate.value ? `${reportScoreRate.value}%` : '--';

    return [
        { label: '我的得分', value: String(mark), desc: `总分 ${total || '--'}` },
        { label: '满分', value: String(total || '--'), desc: '本次卷面' },
        { label: '得分率', value: rateFromScore, desc: total > 0 && mark / total >= 0.8 ? '超过多数同学' : '' },
    ];
});

const classRankList = computed(() => jobAnalyse.value.stuRankVoList || []);

const ranks = computed(() => {
    const rankList = classRankList.value;
    const selfRank = rankList.find((item) => item.selfFlag === 1);
    const classRank =
        selfRank?.rankNum != null && rankList.length
            ? `${selfRank.rankNum}/${rankList.length}`
            : '';

    return [
        { label: '班级排名', value: classRank || '--' },
        { label: '年级排名', value: '--' },
    ];
});

const analysisRows = computed(() => {
    const list = channelAnalyzeList.value;
    const totalCount = list.reduce((sum, item) => sum + (Number(item.titleCount) || 0), 0);
    return list.map((item) => {
        const count = Number(item.titleCount) || 0;
        const rate =
            totalCount > 0 ? `${Math.round((count / totalCount) * 1000) / 10}%` : '--';
        return {
            type: item.chanelTypeName || '--',
            count: String(count),
            rate,
        };
    });
});

const difficultyRows = computed(() =>
    (jobAnalyse.value.paperDifficultyAnalyzeList || []).map((item) => {
        const actual = Number(item.actualScore) || 0;
        const total = Number(item.score) || 0;
        const { text, value } = formatDifficultyScoreRate(actual, total);
        return {
            difficulty: item.difficultyName || '--',
            count: String(Number(item.titleCount) || 0),
            score: total > 0 ? `${actual}/${total}` : String(actual),
            rate: text,
            rateValue: value,
        };
    }),
);

const report = computed(() => ({
    category: reportCategory.value || getPaperTestTypeLabelFromPaper(),
    title:
        reportName.value ||
        jobAnalyse.value.jobReportVo?.jobName ||
        String(paperDetail.value.paperName || '作业详情'),
    date: reportDate.value,
    subject: reportSubject.value || String(paperDetail.value.subjectName || '多科'),
}));

const getPaperTestTypeLabelFromPaper = () => {
    const type = Number(paperDetail.value.type);
    if (!type) return '';
    const map: Record<number, string> = {
        1: '单元测试',
        2: '周测',
        3: '月测',
        4: '随堂练习',
        5: '课前预习',
    };
    return map[type] || '';
};

const detail = computed(() => ({
    ...mockDetail.value,
    scoreBlocks: scoreBlocks.value,
    ranks: ranks.value,
}));

const knowledgeScores = computed<ReportKnowledgeScore[]>(() =>
    knowledgeList.value.map((item) => ({
        name: item.knowledgeName || '--',
        fullScore: Number(item.titleScore) || 0,
        score: Number(item.answerScore) || 0,
    })),
);

const ratioTones: ReportKnowledgeRatio['tone'][] = ['blue', 'orange', 'green'];

const knowledgeRatios = computed<ReportKnowledgeRatio[]>(() => {
    const lostItems = knowledgeList.value
        .map((item) => ({
            name: item.knowledgeName || '--',
            lost: Math.max(0, (Number(item.titleScore) || 0) - (Number(item.answerScore) || 0)),
        }))
        .filter((item) => item.lost > 0)
        .sort((a, b) => b.lost - a.lost);

    const totalLost = lostItems.reduce((sum, item) => sum + item.lost, 0);
    if (totalLost <= 0) return [];

    return lostItems.map((item, idx) => ({
        name: item.name,
        percent: Math.round((item.lost / totalLost) * 100),
        tone: ratioTones[idx % ratioTones.length],
    }));
});

const knowledgeWeakCount = computed(
    () =>
        knowledgeList.value.filter(
            (item) => (Number(item.answerScore) || 0) < (Number(item.titleScore) || 0),
        ).length,
);

const RATIO_ROW_HEIGHT = 72;
const RATIO_LIST_MIN = 200;
const RATIO_LIST_MAX = 480;

const ratioListHeight = computed(() => {
    const count = knowledgeRatios.value.length || 1;
    const height = Math.min(Math.max(count * RATIO_ROW_HEIGHT, RATIO_LIST_MIN), RATIO_LIST_MAX);
    return `${height}rpx`;
});

const selectedQuestionSummary = computed(
    () => questionSummaries.value.find((item) => item.no === selectedNo.value) || null,
);
const selectedQuestionDetail = computed(() =>
    selectedNo.value ? questionDetailCache.value[selectedNo.value] : undefined,
);
const wrongCount = computed(
    () =>
        questionSummaries.value.filter((item) => item.status === 'wrong' || item.status === 'unanswered').length,
);

const statusLabel = (status?: ReportQuestion['status']) => {
    if (status === 'correct') return '正确';
    if (status === 'unanswered') return '未答';
    return '错误';
};

const statusClass = (status?: ReportQuestion['status']) => {
    if (status === 'correct') return 'status-correct';
    if (status === 'unanswered') return 'status-muted';
    return 'status-wrong';
};

/** 从正确答案 HTML 中提取选项字母（如 "A"、"ABD"、"C"），与 web 版 extractChoiceLettersFromAnswerHtml 逻辑一致 */
const extractCorrectAnswerLetters = (): string[] => {
    const detail = selectedQuestionDetail.value;
    if (!detail) return [];
    // 优先从 correctAnswerHtml 提取纯字母
    const answerHtml = detail.correctAnswerHtml || '';
    const stripped = answerHtml.replace(/<[^>]*>/g, '').replace(/&nbsp;/gi, ' ').toUpperCase();
    const letters = stripped.match(/[A-Z]/g);
    if (letters?.length) return [...new Set(letters)];
    // 退而求其次从 studentAnswer 反推（仅当状态为正确时）
    if (detail.status === 'correct') {
        const stuAns = (detail.studentAnswer || '').toUpperCase().match(/[A-Z]/g);
        if (stuAns?.length) return [...new Set(stuAns)];
    }
    return [];
};

/** 从学员答案中提取选项字母 */
const extractStudentAnswerLetters = (): string[] => {
    const detail = selectedQuestionDetail.value;
    if (!detail) return [];
    const ans = (detail.studentAnswer || '').toUpperCase();
    const letters = ans.match(/[A-Z]/g);
    return letters ? [...new Set(letters)] : [];
};

/** 计算单个选项的样式类名，参考 web 端 SingleChoice/MultipleChoice 的 success/fail 样式 */
const optionItemClass = (opt: { label: string }, _optIdx: number) => {
    const correctLetters = extractCorrectAnswerLetters();
    const studentLetters = extractStudentAnswerLetters();
    const label = opt.label.toUpperCase();

    const isCorrect = correctLetters.includes(label);
    const studentSelected = studentLetters.includes(label);

    if (isCorrect) return 'option-correct';
    if (studentSelected) return 'option-wrong';
    return '';
};

const switchTab = (key: DetailTab) => {
    activeTab.value = key;
    if (key === 'answers') {
        ensureDefaultQuestion();
    }
};

/** 进入答题卡时默认选中并加载第一题 */
const ensureDefaultQuestion = () => {
    if (!questionSummaries.value.length) return;
    if (!selectedNo.value) {
        selectedNo.value = questionSummaries.value[0].no;
    }
    loadQuestionDetail(selectedNo.value);
};

const loadQuestionDetail = (no: number) => {
    if (questionDetailCache.value[no]) {
        if (detailLoadingNo.value === no) detailLoadingNo.value = 0;
        return;
    }
    if (detailLoadingNo.value === no) return;

    detailLoadingNo.value = no;
    try {
        const index = questionSummaries.value.findIndex((item) => item.no === no);
        if (index >= 0 && rawTitleItems.value[index]) {
            questionDetailCache.value = {
                ...questionDetailCache.value,
                [no]: mapPaperQuestion(rawTitleItems.value[index], index),
            };
        } else {
            const mockQuestion = mockDetail.value.questions.find((item) => Number(item.no) === no);
            if (mockQuestion) {
                questionDetailCache.value = {
                    ...questionDetailCache.value,
                    [no]: normalizeLegacyQuestion(mockQuestion as unknown as Record<string, unknown>),
                };
            }
        }
    } finally {
        if (detailLoadingNo.value === no) {
            detailLoadingNo.value = 0;
        }
    }
};

const selectQuestion = (no: number) => {
    selectedNo.value = no;
    loadQuestionDetail(no);
};

const loadReportData = async () => {
    if (!recordId.value) return;

    pageLoading.value = true;
    try {
        const analyseParams: { recordId: string; userId?: string } = {
            recordId: recordId.value,
        };
        const studentId = activeChild.value.id || childUserId.value;
        if (studentId) {
            analyseParams.userId = studentId;
        }

        const detailRes = await getPaperRecordDetail({ recordId: recordId.value, reportFlag: REPORT_FLAG });
        paperDetail.value = (detailRes.data || {}) as Record<string, unknown>;

        try {
            const analyseRes = await getJobAnalyse(analyseParams);
            jobAnalyse.value = analyseRes.data || {};
        } catch (analyseErr) {
            console.error('[parent-report-detail] analyse err', analyseErr);
            jobAnalyse.value = {};
        }

        try {
            const knowledgeRes = await getKnowledgeAnalyse(analyseParams);
            knowledgeList.value = Array.isArray(knowledgeRes.data) ? knowledgeRes.data : [];
        } catch (knowledgeErr) {
            console.error('[parent-report-detail] knowledge err', knowledgeErr);
            knowledgeList.value = [];
        }

        const titleList = paperDetail.value.titleVoList || paperDetail.value.subjectTitleVoList;
        rawTitleItems.value = Array.isArray(titleList) ? (titleList as Record<string, unknown>[]) : [];
        questionSummaries.value = mapPaperQuestionSummaries(rawTitleItems.value);

        if (!reportName.value) {
            reportName.value = String(paperDetail.value.paperName || '');
        }
        if (!reportSubject.value) {
            reportSubject.value = String(paperDetail.value.subjectName || '');
        }
        if (questionSummaries.value.length && !selectedNo.value) {
            selectedNo.value = questionSummaries.value[0].no;
        }
    } catch (err) {
        console.error('[parent-report-detail] load err', err);
        uni.showToast({ title: '报告加载失败', icon: 'none' });
    } finally {
        pageLoading.value = false;
    }
};

const knowledgeRate = (item: ReportKnowledgeScore) => {
    if (!item.fullScore) return 0;
    return Math.round((item.score / item.fullScore) * 100);
};

const knowledgeScoreClass = (item: ReportKnowledgeScore) => {
    const rate = knowledgeRate(item);
    if (rate >= 80) return 'rate-good';
    if (rate >= 60) return 'rate-warn';
    return 'score-danger';
};

const knowledgeLevelOf = (item: ReportKnowledgeScore): KnowledgeLevel => {
    const rate = knowledgeRate(item);
    if (rate < 60) return 'weak';
    if (rate < 80) return 'pass';
    return 'good';
};

const filteredKnowledgeScores = computed(() => {
    if (activeKnowledgeLevel.value === 'all') return knowledgeScores.value;
    return knowledgeScores.value.filter((item) => knowledgeLevelOf(item) === activeKnowledgeLevel.value);
});

const previewStemImage = (index: number) => {
    const urls = selectedQuestionDetail.value?.stemImages || [];
    if (!urls.length) return;
    uni.previewImage({ urls, current: urls[index] });
};

const previewStudentImage = (index: number) => {
    const urls = selectedQuestionDetail.value?.studentAnswerImages || [];
    if (!urls.length) return;
    uni.previewImage({ urls, current: urls[index] });
};

const downloadReport = () => {
    uni.showToast({
        title: '报告生成中',
        icon: 'none',
    });
};

const goHome = () => {
    uni.reLaunch({ url: '/pages/parent/home/index' });
};
</script>

<style lang="scss" scoped>
.detail-page {
    display: flex;
    flex-direction: column;
    gap: 36rpx;
    padding-bottom: calc(144rpx + env(safe-area-inset-bottom));
    overflow-x: hidden;
    width: 100%;
    box-sizing: border-box;
}

.hero-card {
    background:
        linear-gradient(135deg, rgba(37, 99, 235, 0.08), rgba(20, 184, 166, 0.08)),
        rgba(255, 255, 255, 0.96);
}

.hero-top {
    display: flex;
    justify-content: space-between;
    gap: 22rpx;
}

.category-tag {
    display: inline-flex;
    padding: 8rpx 16rpx;
    border-radius: 999rpx;
    color: #1d4ed8;
    background: #dbeafe;
    font-size: 22rpx;
    font-weight: 800;
}

.report-title {
    display: block;
    margin-top: 18rpx;
    color: #0f172a;
    font-size: 34rpx;
    font-weight: 900;
    line-height: 1.35;
}

.report-date {
    display: block;
    margin-top: 12rpx;
    color: #64748b;
    font-size: 24rpx;
}

.subject-text {
    color: #0f172a;
    font-size: 28rpx;
    font-weight: 900;
    flex-shrink: 0;
}

.score-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 18rpx;
    margin-top: 30rpx;
}

.score-item {
    min-height: 138rpx;
    border-radius: 28rpx;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: #ffffff;
    box-shadow: inset 0 -2rpx 0 rgba(191, 219, 254, 0.7);
}

.score-label,
.score-desc {
    color: #64748b;
    font-size: 22rpx;
}

.score-value {
    margin: 8rpx 0 4rpx;
    color: #2563eb;
    font-size: 42rpx;
    font-weight: 900;
}


.tab-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12rpx;
    padding: 8rpx;
    border-radius: 28rpx;
    background: #f1f5f9;
}

.tab-item {
    height: 70rpx;
    border-radius: 22rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #475569;
    font-size: 25rpx;
    font-weight: 800;
}

.tab-item.active {
    color: #1d4ed8;
    background: #ffffff;
    box-shadow: 0 10rpx 22rpx rgba(37, 99, 235, 0.12);
}

.rank-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 18rpx;
    margin-top: 24rpx;
}

.rank-item {
    min-height: 110rpx;
    border-radius: 28rpx;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: #f8fafc;
}

.rank-label {
    color: #64748b;
    font-size: 22rpx;
}

.rank-value {
    margin-top: 6rpx;
    color: #2563eb;
    font-size: 38rpx;
    font-weight: 900;
}

.data-table {
    overflow: hidden;
    border: 2rpx solid #e2e8f0;
    border-radius: 26rpx;
}

.chart-block {
    display: flex;
    flex-direction: column;
    gap: 28rpx;
}

.chart-table {
    margin-top: 4rpx;
}

.pie-row {
    display: flex;
    align-items: center;
    gap: 24rpx;
}

.pie {
    position: relative;
    width: 200rpx;
    height: 200rpx;
    flex-shrink: 0;
}

.pie-circle {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    box-shadow: 0 8rpx 16rpx rgba(37, 99, 235, 0.12);
}

.pie-hole {
    position: absolute;
    inset: 28rpx;
    border-radius: 50%;
    background: #ffffff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    box-shadow:
        inset 0 4rpx 8rpx rgba(0, 0, 0, 0.06),
        0 2rpx 4rpx rgba(0, 0, 0, 0.04);
}

.pie-hole-num {
    font-size: 44rpx;
    font-weight: 900;
    color: #0f172a;
    line-height: 1;
}

.pie-hole-label {
    font-size: 20rpx;
    color: #94a3b8;
    margin-top: 4rpx;
}

.pie-legend {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 12rpx;
    min-width: 0;
}

.legend-item {
    display: flex;
    align-items: center;
    gap: 12rpx;
}

.legend-name {
    flex: 1;
    font-size: 24rpx;
    color: #475569;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.legend-count {
    font-size: 24rpx;
    color: #2563eb;
    font-weight: 800;
    flex-shrink: 0;
}

.bars {
    display: flex;
    flex-direction: column;
    gap: 20rpx;
}

.bar-row {
    display: flex;
    align-items: center;
    gap: 16rpx;
}

.bar-name {
    width: 88rpx;
    flex-shrink: 0;
    font-size: 24rpx;
    color: #475569;
    font-weight: 700;
    text-align: right;
}

.bar-track {
    flex: 1;
    height: 24rpx;
    border-radius: 999rpx;
    background: #f1f5f9;
    overflow: hidden;
}

.bar-fill {
    height: 100%;
    border-radius: 999rpx;
    transition: width 0.3s ease;
}

.bar-value {
    width: 88rpx;
    flex-shrink: 0;
    font-size: 26rpx;
    font-weight: 900;
    color: #0f172a;
    text-align: right;
}

.bar-value-unit {
    font-size: 20rpx;
    font-weight: 600;
    color: #94a3b8;
}

.table-row.channel-row {
    grid-template-columns: repeat(3, 1fr);
}

.table-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    min-height: 74rpx;
    align-items: center;
    color: #334155;
    font-size: 24rpx;
    text-align: center;
    border-top: 2rpx solid #f1f5f9;
}

.table-row:first-child {
    border-top: 0;
}

.table-head {
    color: #475569;
    background: #f8fafc;
    font-weight: 900;
}

.strong,
.rate-good,
.status-correct {
    color: #16a34a;
    font-weight: 900;
}

.rate-warn,
.score-danger,
.status-wrong {
    color: #ef4444;
    font-weight: 900;
}

.status-muted {
    color: #64748b;
    font-weight: 900;
}

.answer-legend {
    display: flex;
    gap: 28rpx;
    color: #475569;
    font-size: 24rpx;
}

.answer-legend view {
    display: flex;
    align-items: center;
    gap: 10rpx;
}

.legend-dot {
    width: 16rpx;
    height: 16rpx;
    border-radius: 50%;
}

.legend-dot.correct {
    background: #22c55e;
}

.legend-dot.wrong {
    background: #ef4444;
}

.legend-dot.unanswered {
    background: #94a3b8;
}

.answers-loading {
    min-height: 220rpx;
    margin-top: 24rpx;
}

.answers-panel {
    display: flex;
    flex-direction: column;
    gap: 36rpx;
}

.table-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8rpx;
    margin-bottom: 16rpx;
    padding: 16rpx 0;
    color: #2563eb;
    font-size: 26rpx;
    font-weight: 800;
}

.table-toggle-icon {
    font-size: 20rpx;
}

.question-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 16rpx;
    margin-top: 24rpx;
}

.question-no {
    height: 58rpx;
    border: 2rpx solid #bbf7d0;
    border-radius: 18rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #15803d;
    background: #f0fdf4;
    font-size: 24rpx;
    font-weight: 900;
}

.question-no.wrong {
    border-color: #fecaca;
    color: #dc2626;
    background: #fef2f2;
}

.question-no.unanswered {
    border-color: #e2e8f0;
    color: #64748b;
    background: #f8fafc;
}

.question-no.active {
    border-color: #2563eb;
    box-shadow: 0 0 0 4rpx rgba(37, 99, 235, 0.1);
}

.question-head {
    display: flex;
    align-items: center;
    gap: 20rpx;
    color: #0f172a;
    font-size: 26rpx;
    font-weight: 900;
}

.detail-fields {
    display: grid;
    gap: 18rpx;
    margin-top: 22rpx;
    min-width: 0;
}

.field-card {
    padding: 18rpx 20rpx;
    border: 2rpx solid #dbeafe;
    border-radius: 18rpx;
    background: #ffffff;
    overflow: hidden;
    min-width: 0;
    box-sizing: border-box;
}

.field-card.success {
    border-color: #bbf7d0;
}

.field-card.student {
    border-color: #ddd6fe;
}

/* 选项模块样式（参考 web 端 SingleChoice / MultipleChoice 组件） */
.options-card {
    border-color: #c7d2fe;
}

.options-card .field-label {
    background: #6366f1;
}

.option-list {
    display: flex;
    flex-direction: column;
    gap: 14rpx;
    margin-top: 4rpx;
}

.option-item {
    display: flex;
    align-items: flex-start;
    padding: 14rpx 16rpx;
    border-radius: 14rpx;
    border: 2rpx solid #e0e7ff;
    background: #f8faff;
    gap: 12rpx;
    transition: all 0.2s;
}

.option-item.option-correct {
    border-color: #86efac;
    background: #f0fdf4;
}

.option-item.option-correct .option-label {
    background: #22c55e;
    color: #ffffff;
}

.option-item.option-wrong {
    border-color: #fca5a5;
    background: #fef2f2;
}

.option-item.option-wrong .option-label {
    background: #ef4444;
    color: #ffffff;
}

.option-label {
    flex-shrink: 0;
    width: 40rpx;
    height: 40rpx;
    border-radius: 10rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #e0e7ff;
    color: #6366f1;
    font-size: 22rpx;
    font-weight: 900;
    line-height: 1;
}

.option-value {
    flex: 1;
    min-width: 0;
    color: #334155;
    font-size: 24rpx;
    line-height: 1.55;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.option-value rich-text {
    width: 100%;
    max-width: 100%;
}

.field-label {
    display: inline-flex;
    margin-bottom: 8rpx;
    padding: 6rpx 12rpx;
    border-radius: 12rpx;
    color: #ffffff;
    background: #2563eb;
    font-size: 22rpx;
    font-weight: 800;
}

.field-card.success .field-label {
    background: #22c55e;
}

.field-card.student .field-label {
    background: #7c3aed;
}

.field-content {
    display: block;
    color: #334155;
    font-size: 25rpx;
    line-height: 1.55;
    max-width: 100%;
    overflow-wrap: anywhere;
    word-break: break-all;
    box-sizing: border-box;
}

.rich-content {
    width: 100%;
    max-width: 100%;
    overflow: hidden;
    word-break: break-word;
    box-sizing: border-box;
}

.rich-content :deep(.formula-text) {
    font-size: 24rpx;
    font-family: 'Times New Roman', 'STIXGeneral', Georgia, serif;
    font-style: italic;
    color: #1e1b4b;
}

.rich-content :deep(.formula-img) {
    max-width: 100%;
    vertical-align: middle;
}

.rich-content :deep(.fill-blank) {
    display: inline-block;
    min-width: 60rpx;
    border-bottom: 3rpx solid #2563eb;
}

.stem-images {
    display: flex;
    flex-direction: column;
    gap: 16rpx;
    margin-top: 12rpx;
}

.stem-image {
    width: 100%;
    max-width: 100%;
    border-radius: 12rpx;
}

.answer-images {
    display: flex;
    flex-direction: column;
    gap: 16rpx;
    margin-top: 8rpx;
    max-width: 100%;
}

.answer-image {
    width: 100%;
    max-width: 100%;
    border-radius: 12rpx;
    background: #f8fafc;
}

.question-table-scroll {
    width: 100%;
}

.question-table {
    width: 1060rpx;
    border: 2rpx solid #e2e8f0;
    border-radius: 24rpx;
    overflow: hidden;
}

.question-row {
    display: grid;
    grid-template-columns: 90rpx 140rpx 110rpx 110rpx 210rpx 190rpx 190rpx;
    min-height: 72rpx;
    align-items: center;
    color: #334155;
    font-size: 23rpx;
    text-align: center;
    border-top: 2rpx solid #f1f5f9;
}

.question-row:first-child {
    border-top: 0;
}

.knowledge-summary {
    display: flex;
    align-items: flex-start;
    gap: 28rpx;
}

.wrong-total {
    width: 170rpx;
    height: 170rpx;
    border-radius: 50%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: linear-gradient(180deg, #eff6ff 0%, #ffffff 100%);
    box-shadow: inset 0 0 0 16rpx #dbeafe;
    flex-shrink: 0;
}

.wrong-number {
    color: #2563eb;
    font-size: 46rpx;
    font-weight: 900;
}

.wrong-label {
    color: #64748b;
    font-size: 22rpx;
}

.ratio-list {
    flex: 1;
    min-width: 0;
    min-height: 200rpx;
    max-height: 480rpx;
}

.ratio-row + .ratio-row {
    margin-top: 18rpx;
}

.ratio-row:last-child {
    padding-bottom: 4rpx;
}

.ratio-meta {
    display: flex;
    justify-content: space-between;
    color: #334155;
    font-size: 24rpx;
    font-weight: 800;
}

.ratio-track {
    height: 16rpx;
    margin-top: 10rpx;
    border-radius: 999rpx;
    overflow: hidden;
    background: #e2e8f0;
}

.ratio-fill {
    height: 100%;
    border-radius: 999rpx;
}

.ratio-fill.blue {
    background: #2563eb;
}

.ratio-fill.orange {
    background: #f97316;
}

.ratio-fill.green {
    background: #22c55e;
}

.level-tabs {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14rpx;
    margin-bottom: 20rpx;
}

.level-tab {
    height: 62rpx;
    border: 2rpx solid #e2e8f0;
    border-radius: 20rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #475569;
    background: #ffffff;
    font-size: 24rpx;
    font-weight: 800;
}

.level-tab.active {
    border-color: #2563eb;
    color: #ffffff;
    background: #2563eb;
}

.knowledge-row {
    grid-template-columns: 1fr 120rpx 180rpx;
}

.knowledge-name {
    text-align: left;
    padding-left: 24rpx;
}

.rank-list {
    border: 2rpx solid #e2e8f0;
    border-radius: 26rpx;
    overflow: hidden;
}

.rank-list-item {
    display: grid;
    grid-template-columns: 80rpx 1fr 140rpx 120rpx;
    min-height: 74rpx;
    align-items: center;
    padding: 0 20rpx;
    color: #334155;
    font-size: 24rpx;
    border-top: 2rpx solid #f1f5f9;
}

.rank-list-item:first-child {
    border-top: 0;
}

.rank-list-item.self {
    color: #1d4ed8;
    background: #eff6ff;
    font-weight: 900;
}

.rank-no {
    text-align: center;
    font-weight: 900;
}

.rank-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rank-score,
.rank-rate {
    text-align: center;
}

.bottom-actions {
    position: fixed;
    left: 28rpx;
    right: 28rpx;
    bottom: calc(22rpx + env(safe-area-inset-bottom));
    z-index: 20;
    display: flex;
    align-items: center;
}

.download-btn {
    flex: 1;
    height: 84rpx;
    border: 0;
    border-radius: 22rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    background: linear-gradient(135deg, #2563eb 0%, #0891b2 100%);
    font-size: 30rpx;
    font-weight: 900;
    box-shadow: 0 16rpx 32rpx rgba(37, 99, 235, 0.22);
}

.download-btn::after {
    border: 0;
}

.home-btn {
    width: 88rpx;
    height: 88rpx;
    margin-left: -12rpx;
    border-radius: 32rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #2563eb;
    box-shadow: 0 16rpx 32rpx rgba(37, 99, 235, 0.26);
}

.home-roof {
    position: absolute;
    width: 28rpx;
    height: 28rpx;
    border-top: 5rpx solid #ffffff;
    border-left: 5rpx solid #ffffff;
    transform: translateY(-8rpx) rotate(45deg);
}

.home-body {
    width: 34rpx;
    height: 28rpx;
    margin-top: 16rpx;
    border: 5rpx solid #ffffff;
    border-top: 0;
    border-radius: 4rpx;
}
</style>
