Files
vueapp/pages/profile/profile-analysis.vue
2026-06-13 06:05:37 +08:00

999 lines
24 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="analysis-page">
<view class="analysis-shell">
<header class="top-bar">
<button class="icon-button" aria-label="返回" @click="goBack">
<view class="back-icon"></view>
</button>
<text class="page-title">智能分析</text>
</header>
<scroll-view class="analysis-scroll" scroll-y>
<view class="analysis-main">
<view class="fade-section" :class="{ visible: fadeVisible }">
<view class="summary-card">
<view class="summary-copy">
<view class="summary-head">
<text class="summary-label">当前能力评分</text>
<view v-if="scoreDeltaText" class="trend-chip" :class="{ down: isScoreDeltaDown }">
<view class="trend-icon"></view>
<text>{{ scoreDeltaText }}</text>
</view>
</view>
<text class="summary-score">{{ currentScoreText }}</text>
<text class="summary-desc">{{ summaryDesc }}</text>
</view>
</view>
</view>
<view class="fade-section" :class="{ visible: fadeVisible }">
<view class="chart-card">
<view class="section-head">
<text class="section-title">近期分数趋势</text>
<view class="section-icon">
<view class="chart-icon"></view>
</view>
</view>
<view class="bar-chart">
<view
v-for="item in trendItems"
:key="`${item.label}-${item.score}`"
class="bar-column"
>
<view class="bar-track">
<view
class="bar-fill"
:class="{ highlighted: item.highlight }"
:style="{ height: item.height }"
></view>
</view>
<text class="bar-label" :class="{ active: item.highlight }">{{ item.label }}</text>
</view>
</view>
<view v-if="trendItems.length === 0" class="empty-card-text">{{ emptyAnalysisText }}</view>
</view>
</view>
<view class="fade-section" :class="{ visible: fadeVisible }">
<view class="chart-card">
<view class="section-head">
<text class="section-title">临床胜任力雷达图</text>
<view class="section-icon">
<view class="radar-icon"></view>
</view>
</view>
<view class="radar-wrap">
<view class="radar-background">
<view class="radar-ring ring-one"></view>
<view class="radar-ring ring-two"></view>
<view class="radar-ring ring-three"></view>
<view class="radar-ring ring-four"></view>
<view class="radar-axis axis-vertical"></view>
<view class="radar-axis axis-diagonal-one"></view>
<view class="radar-axis axis-diagonal-two"></view>
<view class="radar-axis axis-diagonal-three"></view>
<view class="radar-axis axis-diagonal-four"></view>
</view>
<view
v-for="item in radarItems"
:key="item.dimension"
class="radar-label dynamic-label"
:style="{ left: item.labelLeft, top: item.labelTop }"
>
{{ item.dimension }}
</view>
<svg class="radar-svg" viewBox="0 0 100 100">
<polygon
v-if="radarPolygonPoints"
class="radar-polygon"
:points="radarPolygonPoints"
></polygon>
<circle
v-for="item in radarItems"
:key="`${item.dimension}-point`"
:cx="item.pointX"
:cy="item.pointY"
r="3"
></circle>
</svg>
</view>
<view class="analysis-note">
<text>{{ analysisComment }}</text>
</view>
</view>
</view>
<view class="fade-section" :class="{ visible: fadeVisible }">
<text class="mini-title">分项提升建议</text>
<view class="suggestion-list">
<view class="suggestion-card" @click="showToast('重点回顾内容即将开放')">
<view class="suggestion-icon-wrap secondary-tone">
<view class="book-icon"></view>
</view>
<view class="suggestion-copy">
<text class="suggestion-title">重点回顾{{ primaryWeakDimension }}</text>
<text class="suggestion-desc">基于当前能力雷达图的薄弱项推荐</text>
</view>
<view class="chevron-icon"></view>
</view>
<view class="suggestion-card" @click="showToast('专项挑战即将开放')">
<view class="suggestion-icon-wrap tertiary-tone">
<view class="brain-icon"></view>
</view>
<view class="suggestion-copy">
<text class="suggestion-title">临床思维专项挑战</text>
<text class="suggestion-desc">推荐参与难度等级{{ challengeLevel }}</text>
</view>
<view class="chevron-icon"></view>
</view>
</view>
</view>
<view class="fade-section mentor-section" :class="{ visible: fadeVisible }">
<view class="mentor-card">
<view class="mentor-head">
<image class="mentor-avatar" src="/static/config-doctor.png" mode="aspectFill"></image>
<view>
<text class="mentor-name">王主任的建议</text>
<text class="mentor-role">Director's Mentorship</text>
</view>
</view>
<view class="mentor-bubble">
<text>{{ mentorAdvice }}</text>
</view>
</view>
</view>
</view>
</scroll-view>
<view class="toast" :class="{ visible: toastVisible }">{{ toastMessage }}</view>
</view>
</view>
</template>
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { fetchUserAnalysis, type UserAnalysis } from '../../api/profile'
const fadeVisible = ref(false)
const toastMessage = ref('')
const toastVisible = ref(false)
const analysis = ref<UserAnalysis | null>(null)
const loadingAnalysis = ref(false)
const analysisLoaded = ref(false)
const analysisFailed = ref(false)
let fadeTimer: ReturnType<typeof setTimeout> | null = null
let toastTimer: ReturnType<typeof setTimeout> | null = null
const currentScoreText = computed(() => {
const score = analysis.value?.current_score
if (typeof score !== 'number' || !Number.isFinite(score)) return '--'
return Number.isInteger(score) ? String(score) : score.toFixed(1)
})
const scoreDeltaText = computed(() => {
const delta = analysis.value?.score_delta_pct
if (typeof delta !== 'number' || !Number.isFinite(delta)) return ''
const prefix = delta > 0 ? '+' : ''
return `${prefix}${delta}%`
})
const isScoreDeltaDown = computed(() => {
const delta = analysis.value?.score_delta_pct
return typeof delta === 'number' && delta < 0
})
const summaryDesc = computed(() => {
if (analysisFailed.value) return '智能分析加载失败请稍后重试'
if (!analysisLoaded.value) return '正在加载您的临床能力分析'
const delta = analysis.value?.score_delta_pct
if (typeof delta === 'number' && Number.isFinite(delta)) {
if (delta > 0) return '相较于近期表现您的临床能力评分有所提升'
if (delta < 0) return '相较于近期表现当前评分略有回落建议继续专项练习'
}
return '当前已生成您的临床能力评分'
})
const trendItems = computed(() => {
const items = analysis.value?.recent_trend || []
const lastIndex = items.length - 1
return items.map((item, index) => ({
label: item.label,
score: item.score,
height: `${clampScore(item.score)}%`,
highlight: index === lastIndex
}))
})
const radarItems = computed(() => {
const items = (analysis.value?.radar || []).slice(0, 6)
const total = items.length
if (total < 3) return []
return items.map((item, index) => {
const angle = -Math.PI / 2 + (Math.PI * 2 * index) / total
const pointRadius = 35 * (clampScore(item.score) / 100)
const labelRadius = 47
const labelX = 50 + Math.cos(angle) * labelRadius
const labelY = 50 + Math.sin(angle) * labelRadius
const boundedLabelX = clampLabelPosition(labelX, 14, 86)
const boundedLabelY = clampLabelPosition(labelY, 6, 94)
return {
dimension: item.dimension,
pointX: roundSvgValue(50 + Math.cos(angle) * pointRadius),
pointY: roundSvgValue(50 + Math.sin(angle) * pointRadius),
labelLeft: `${boundedLabelX}%`,
labelTop: `${boundedLabelY}%`
}
})
})
const radarPolygonPoints = computed(() => {
return radarItems.value.map(item => `${item.pointX},${item.pointY}`).join(' ')
})
const emptyAnalysisText = computed(() => {
if (loadingAnalysis.value) return '分析数据加载中...'
if (analysisFailed.value) return '分析数据加载失败'
return '暂无趋势数据'
})
const analysisComment = computed(() => {
return analysis.value?.comment || emptyAnalysisText.value
})
const primaryWeakDimension = computed(() => {
return analysis.value?.weak_dimensions?.[0] || '病史采集'
})
const challengeLevel = computed(() => {
const score = analysis.value?.current_score || 0
if (score >= 85) return '高级'
if (score >= 70) return '中级'
return '基础'
})
const mentorAdvice = computed(() => {
if (analysis.value?.comment) return `“${analysis.value.comment}”`
if (analysisFailed.value) return '分析数据暂时未能加载请稍后再试'
return '正在读取你的训练表现稍后给出更具体的强化建议'
})
function goBack() {
if (typeof getCurrentPages === 'function' && getCurrentPages().length > 1) {
uni.navigateBack()
return
}
uni.reLaunch({
url: '/pages/profile/profile'
})
}
async function loadAnalysis() {
loadingAnalysis.value = true
analysisFailed.value = false
try {
analysis.value = await fetchUserAnalysis()
analysisLoaded.value = true
} catch (error) {
analysisFailed.value = true
showToast(error instanceof Error ? error.message : '智能分析加载失败')
} finally {
loadingAnalysis.value = false
}
}
function showToast(message: string) {
if (toastTimer) clearTimeout(toastTimer)
toastMessage.value = message
toastVisible.value = true
toastTimer = setTimeout(() => {
toastVisible.value = false
}, 2200)
}
function clampScore(value: number) {
if (!Number.isFinite(value)) return 0
return Math.max(0, Math.min(100, Math.round(value)))
}
function roundSvgValue(value: number) {
return Math.round(value * 100) / 100
}
function clampLabelPosition(value: number, min: number, max: number) {
return Math.max(min, Math.min(max, Math.round(value * 100) / 100))
}
onMounted(() => {
fadeTimer = setTimeout(() => {
fadeVisible.value = true
}, 60)
void loadAnalysis()
})
onUnmounted(() => {
if (fadeTimer) clearTimeout(fadeTimer)
if (toastTimer) clearTimeout(toastTimer)
})
</script>
<style scoped>
page {
min-height: 100%;
background: #f9f9ff;
}
.analysis-page {
width: 100%;
min-height: 100vh;
background: #f9f9ff;
color: #191c21;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
-webkit-tap-highlight-color: transparent;
}
.analysis-shell {
position: relative;
width: 100%;
max-width: none;
min-height: 100vh;
margin: 0;
background: #f9f9ff;
overflow: hidden;
display: flex;
flex-direction: column;
}
.analysis-page view,
.analysis-page text,
.analysis-page button,
.analysis-page scroll-view {
box-sizing: border-box;
}
.analysis-page ::-webkit-scrollbar {
width: 0;
height: 0;
background: transparent;
}
.top-bar {
position: sticky;
top: 0;
z-index: 50;
height: 56px;
padding: 0 16px;
border-bottom: 1px solid rgba(194, 198, 212, 0.3);
background: rgba(249, 249, 255, 0.82);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
}
.page-title {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: #00478d;
font-size: 20px;
line-height: 28px;
font-weight: 600;
letter-spacing: 0;
}
.icon-button {
position: absolute;
left: 16px;
top: 8px;
width: 40px;
height: 40px;
padding: 0;
border: 0;
border-radius: 50%;
background: transparent;
display: flex;
align-items: center;
justify-content: center;
}
.icon-button::after {
border: 0;
}
.icon-button:active {
background: rgba(225, 226, 234, 0.5);
}
.back-icon,
.trend-icon,
.chart-icon,
.radar-icon,
.book-icon,
.brain-icon,
.chevron-icon {
background: #00478d;
-webkit-mask-position: center;
-webkit-mask-repeat: no-repeat;
-webkit-mask-size: contain;
mask-position: center;
mask-repeat: no-repeat;
mask-size: contain;
}
.back-icon {
width: 24px;
height: 24px;
-webkit-mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M20%2011H7.83l5.59-5.59L12%204l-8%208%208%208%201.42-1.41L7.83%2013H20v-2z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M20%2011H7.83l5.59-5.59L12%204l-8%208%208%208%201.42-1.41L7.83%2013H20v-2z'/%3E%3C/svg%3E");
}
.analysis-scroll {
flex: 1 1 auto;
min-height: 0;
}
.analysis-main {
width: 100%;
max-width: none;
margin: 0;
padding: 24px 24px 96px;
display: flex;
flex-direction: column;
gap: 24px;
}
.fade-section {
opacity: 0;
transform: translateY(10px);
transition: 0.4s ease-out;
}
.fade-section.visible {
opacity: 1;
transform: translateY(0);
}
.summary-card,
.chart-card,
.mentor-card {
border: 1px solid rgba(194, 198, 212, 0.3);
border-radius: 8px;
background: #ffffff;
box-shadow: 0 1px 4px rgba(25, 28, 33, 0.04);
}
.summary-card {
padding: 24px;
background: #005eb8;
color: #c8daff;
}
.summary-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 4px;
}
.summary-label {
font-size: 12px;
line-height: 16px;
font-weight: 500;
}
.summary-score {
display: block;
font-size: 32px;
line-height: 40px;
font-weight: 700;
color: #ffffff;
}
.summary-desc {
color: rgba(255, 255, 255, 0.8);
font-size: 14px;
line-height: 20px;
}
.trend-chip {
min-height: 24px;
padding: 0 8px;
border-radius: 8px;
background: #00478d;
color: #ffffff;
font-size: 12px;
line-height: 16px;
font-weight: 500;
display: flex;
align-items: center;
gap: 4px;
}
.trend-chip.down {
background: #793100;
}
.trend-icon {
width: 16px;
height: 16px;
background: #ffffff;
-webkit-mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M16%206l2.29%202.29-4.88%204.88-4-4L2%2016.59%203.41%2018l6-6%204%204%206.3-6.29L22%2012V6h-6z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M16%206l2.29%202.29-4.88%204.88-4-4L2%2016.59%203.41%2018l6-6%204%204%206.3-6.29L22%2012V6h-6z'/%3E%3C/svg%3E");
}
.section-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.section-title {
color: #191c21;
font-size: 20px;
line-height: 28px;
font-weight: 600;
letter-spacing: 0;
}
.section-icon {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.chart-icon {
width: 18px;
height: 18px;
-webkit-mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M3%203h2v18H3V3zm16%207h2v11h-2V10zM8%2013h2v8H8v-8zm5-6h2v14h-2V7z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M3%203h2v18H3V3zm16%207h2v11h-2V10zM8%2013h2v8H8v-8zm5-6h2v14h-2V7z'/%3E%3C/svg%3E");
}
.radar-icon {
width: 18px;
height: 18px;
-webkit-mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M12%202a10%2010%200%201%200%200%2020%2010%2010%200%200%200%200-20zm4.9%203.1l1.4%201.4-3.1%203.1-2.2-2.2 3.9-2.3zm-9.8%200l3.9%202.3-2.2%202.2-3.1-3.1%201.4-1.4zM12%207a5%205%200%201%201%200%2010%205%205%200%200%201%200-10zm6.9%202.1l.1%201.9-4.2.3-.2-3.1%204.3.9zM5.1%209.1l4.3-.9-.2%203.1-4.2-.3.1-1.9zM7.2%2016.8l2.2-2.2%203.1%203.1-1.9%201.1-3.4-2zM16.8%2016.8l-3.4%202-1.9-1.1%203.1-3.1%202.2%202.2z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M12%202a10%2010%200%201%200%200%2020%2010%2010%200%200%200%200-20zm4.9%203.1l1.4%201.4-3.1%203.1-2.2-2.2 3.9-2.3zm-9.8%200l3.9%202.3-2.2%202.2-3.1-3.1%201.4-1.4zM12%207a5%205%200%201%201%200%2010%205%205%200%200%201%200-10zm6.9%202.1l.1%201.9-4.2.3-.2-3.1%204.3.9zM5.1%209.1l4.3-.9-.2%203.1-4.2-.3.1-1.9zM7.2%2016.8l2.2-2.2%203.1%203.1-1.9%201.1-3.4-2zM16.8%2016.8l-3.4%202-1.9-1.1%203.1-3.1%202.2%202.2z'/%3E%3C/svg%3E");
}
.chart-card,
.mentor-card {
padding: 20px;
}
.bar-chart {
height: 200px;
display: flex;
align-items: flex-end;
gap: 8px;
}
.empty-card-text {
min-height: 80px;
color: #727783;
font-size: 14px;
line-height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.bar-column {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.bar-track {
width: 100%;
height: 160px;
display: flex;
align-items: flex-end;
}
.bar-fill {
width: 100%;
border-radius: 8px 8px 0 0;
background: #d6e3ff;
transition: height 0.6s ease;
}
.bar-fill.highlighted {
background: #00478d;
box-shadow: 0 0 0 2px rgba(0, 71, 141, 0.08);
}
.bar-label {
color: #424752;
font-size: 12px;
line-height: 16px;
font-weight: 500;
}
.bar-label.active {
color: #00478d;
font-weight: 700;
}
.radar-wrap {
position: relative;
height: 300px;
overflow: hidden;
}
.radar-background {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
.radar-ring {
position: absolute;
border: 1px solid rgba(194, 198, 212, 0.2);
border-radius: 50%;
}
.ring-one {
width: 240px;
height: 240px;
}
.ring-two {
width: 160px;
height: 160px;
}
.ring-three {
width: 80px;
height: 80px;
}
.ring-four {
width: 40px;
height: 40px;
}
.radar-axis {
position: absolute;
width: 1px;
height: 240px;
background: rgba(194, 198, 212, 0.2);
}
.axis-vertical {
transform: rotate(0deg);
}
.axis-diagonal-one {
transform: rotate(60deg);
}
.axis-diagonal-two {
transform: rotate(120deg);
}
.axis-diagonal-three {
transform: rotate(180deg);
}
.axis-diagonal-four {
transform: rotate(240deg);
}
.radar-label {
position: absolute;
color: #424752;
font-size: 16px;
line-height: 24px;
font-weight: 500;
letter-spacing: 0;
}
.dynamic-label {
width: 68px;
max-width: 68px;
text-align: center;
word-break: break-all;
transform: translate(-50%, -50%);
}
.label-top {
top: -2px;
left: 50%;
transform: translateX(-50%);
}
.label-right-top {
top: 78px;
right: 0;
}
.label-right-bottom {
top: 186px;
right: 6px;
}
.label-bottom {
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.label-left-bottom {
top: 186px;
left: 12px;
}
.label-left-top {
top: 78px;
left: 0;
}
.radar-svg {
position: absolute;
left: 50%;
top: 50%;
width: 240px;
height: 240px;
transform: translate(-50%, -50%);
}
.radar-svg polygon {
fill: rgba(0, 71, 141, 0.15);
stroke: #00478d;
stroke-width: 2;
}
.radar-svg circle {
fill: #00478d;
}
.analysis-note {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid rgba(194, 198, 212, 0.3);
color: #424752;
font-size: 14px;
line-height: 22px;
}
.strong-text {
color: #00478d;
font-weight: 700;
}
.secondary-text {
color: #006970;
font-weight: 700;
}
.mini-title {
display: block;
margin-bottom: 12px;
color: #727783;
font-size: 12px;
line-height: 16px;
font-weight: 500;
letter-spacing: 0;
}
.suggestion-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.suggestion-card {
padding: 16px;
border: 1px solid #c2c6d4;
border-radius: 8px;
background: #ffffff;
display: flex;
align-items: center;
gap: 16px;
}
.suggestion-card:active {
transform: scale(0.99);
}
.suggestion-icon-wrap {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
}
.secondary-tone {
background: #7af1fc;
color: #006970;
}
.tertiary-tone {
background: #ffdbcb;
color: #793100;
}
.book-icon,
.brain-icon {
width: 22px;
height: 22px;
}
.book-icon {
background: #006970;
-webkit-mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M18%202H6a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V4a2%202%200%200%200-2-2zM8%206h8v2H8V6zm0%204h8v2H8v-2zm0%204h5v2H8v-2z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M18%202H6a2%202%200%200%200-2%202v14a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V4a2%202%200%200%200-2-2zM8%206h8v2H8V6zm0%204h8v2H8v-2zm0%204h5v2H8v-2z'/%3E%3C/svg%3E");
}
.brain-icon {
background: #793100;
-webkit-mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M10 3a4 4 0 0 0-4 4v1H5a3 3 0 0 0 0 6h1v1a4 4 0 0 0 4 4h1V3h-1zm4 0v16h1a4 4 0 0 0 4-4v-1h1a3 3 0 0 0 0-6h-1V7a4 4 0 0 0-4-4h-1z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M10 3a4 4 0 0 0-4 4v1H5a3 3 0 0 0 0 6h1v1a4 4 0 0 0 4 4h1V3h-1zm4 0v16h1a4 4 0 0 0 4-4v-1h1a3 3 0 0 0 0-6h-1V7a4 4 0 0 0-4-4h-1z'/%3E%3C/svg%3E");
}
.suggestion-copy {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.suggestion-title {
color: #191c21;
font-size: 14px;
line-height: 20px;
font-weight: 600;
}
.suggestion-desc {
color: #424752;
font-size: 13px;
line-height: 18px;
}
.chevron-icon {
width: 24px;
height: 24px;
background: #424752;
-webkit-mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6-6-6z'/%3E%3C/svg%3E");
mask-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6-6-6z'/%3E%3C/svg%3E");
}
.mentor-section {
padding: 0;
border: 0;
box-shadow: none;
background: transparent;
}
.mentor-card {
padding: 16px;
background: #e7e8f0;
}
.mentor-head {
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 12px;
}
.mentor-avatar {
width: 56px;
height: 56px;
border: 2px solid #ffffff;
border-radius: 50%;
box-shadow: 0 1px 4px rgba(25, 28, 33, 0.12);
}
.mentor-name {
display: block;
color: #00478d;
font-size: 14px;
line-height: 20px;
font-weight: 700;
}
.mentor-role {
color: #424752;
font-size: 10px;
line-height: 14px;
}
.mentor-bubble {
position: relative;
padding: 16px;
border: 1px solid rgba(0, 71, 141, 0.05);
border-radius: 8px;
background: #ffffff;
box-shadow: 0 1px 4px rgba(25, 28, 33, 0.04);
color: #191c21;
font-size: 14px;
line-height: 22px;
font-style: italic;
}
.mentor-bubble::before {
content: '';
position: absolute;
left: 24px;
top: -7px;
width: 12px;
height: 12px;
border-left: 1px solid rgba(0, 71, 141, 0.05);
border-top: 1px solid rgba(0, 71, 141, 0.05);
background: #ffffff;
transform: rotate(45deg);
}
.toast {
position: absolute;
left: 50%;
bottom: 24px;
z-index: 80;
max-width: 300px;
padding: 8px 12px;
border-radius: 12px;
background: rgba(46, 48, 55, 0.9);
color: #eff0f8;
font-size: 12px;
line-height: 16px;
opacity: 0;
pointer-events: none;
transform: translate(-50%, 8px);
transition: opacity 0.2s ease, transform 0.2s ease;
}
.toast.visible {
opacity: 1;
transform: translate(-50%, 0);
}
.analysis-page .analysis-main .fade-section {
opacity: 1;
transform: translateY(0);
}
.analysis-page .analysis-main .fade-section:first-child {
padding-top: 0;
}
@media (min-width: 768px) {
.analysis-page {
display: flex;
justify-content: center;
background: #d8dae2;
}
.analysis-shell {
width: 480px;
max-width: 100vw;
margin: 0 auto;
box-shadow: 0 24px 64px rgba(25, 28, 33, 0.18);
border-left: 1px solid #c2c6d4;
border-right: 1px solid #c2c6d4;
}
}
</style>