Files
vueapp/pages/profile/profile-analysis.vue
T
2026-06-08 17:34:22 +08:00

834 lines
20 KiB
Vue
Raw 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 class="trend-chip">
<view class="trend-icon"></view>
<text>+12%</text>
</view>
</view>
<text class="summary-score">84.5</text>
<text class="summary-desc">相较于上周您的临床推理能力有显著提升</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"
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>
</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 class="radar-label label-top">病史采集</view>
<view class="radar-label label-right-top">体格检查</view>
<view class="radar-label label-right-bottom">诊断能力</view>
<view class="radar-label label-bottom">治疗决策</view>
<view class="radar-label label-left-bottom">沟通技巧</view>
<view class="radar-label label-left-top">临床推理</view>
<svg class="radar-svg" viewBox="0 0 100 100">
<polygon
class="radar-polygon"
points="50,15 85,35 80,75 50,85 25,70 20,40"
></polygon>
<circle cx="50" cy="15" r="3"></circle>
<circle cx="85" cy="35" r="3"></circle>
<circle cx="80" cy="75" r="3"></circle>
<circle cx="50" cy="85" r="3"></circle>
<circle cx="25" cy="70" r="3"></circle>
<circle cx="20" cy="40" r="3"></circle>
</svg>
</view>
<view class="analysis-note">
<text>您的</text>
<text class="strong-text">诊断能力</text>
<text></text>
<text class="strong-text">治疗决策</text>
<text>表现突出</text>
<text class="secondary-text">病史采集</text>
<text>仍有提升空间建议增加相关模拟训练</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">重点回顾心血管查体</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">推荐参与难度等级高级</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>“你的进步非常扎实。今天休息一下,明天我们来挑战一个更复杂的病例如何?”</text>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
const trendItems = [
{ label: '周一', height: '60%', highlight: false },
{ label: '周二', height: '70%', highlight: false },
{ label: '周三', height: '65%', highlight: false },
{ label: '周四', height: '80%', highlight: false },
{ label: '周五', height: '85%', highlight: true },
{ label: '周六', height: '90%', highlight: false },
{ label: '周日', height: '95%', highlight: false }
]
const fadeVisible = ref(false)
const toastMessage = ref('')
const toastVisible = ref(false)
let fadeTimer: ReturnType<typeof setTimeout> | null = null
let toastTimer: ReturnType<typeof setTimeout> | null = null
function goBack() {
if (typeof getCurrentPages === 'function' && getCurrentPages().length > 1) {
uni.navigateBack()
return
}
uni.reLaunch({
url: '/pages/profile/profile'
})
}
function showToast(message: string) {
if (toastTimer) clearTimeout(toastTimer)
toastMessage.value = message
toastVisible.value = true
uni.showToast({
title: message,
icon: 'none'
})
toastTimer = setTimeout(() => {
toastVisible.value = false
}, 2200)
}
onMounted(() => {
fadeTimer = setTimeout(() => {
fadeVisible.value = true
}, 60)
})
onUnmounted(() => {
if (fadeTimer) clearTimeout(fadeTimer)
if (toastTimer) clearTimeout(toastTimer)
})
</script>
<style scoped>
page {
min-height: 100%;
background: #f9f9ff;
}
.analysis-page {
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: 380px;
max-width: 100vw;
min-height: 922px;
margin: 0 auto;
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 {
max-width: 390px;
margin: 0 auto;
padding: 24px 16px 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-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;
}
.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;
}
.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;
}
.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);
}
.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 {
box-shadow: 0 24px 64px rgba(25, 28, 33, 0.18);
border-left: 1px solid #c2c6d4;
border-right: 1px solid #c2c6d4;
}
}
</style>