feat: 初始化项目

This commit is contained in:
王天骄
2026-05-29 17:40:10 +08:00
parent 185ccb260e
commit 873c3e98fb
21 changed files with 7801 additions and 67 deletions
+563
View File
@@ -0,0 +1,563 @@
<template>
<view class="assessment-page">
<view class="top-nav">
<button class="icon-button" aria-label="设置" @click="emit('open-settings')">
<view class="settings-icon"></view>
</button>
<button class="icon-button home-button" aria-label="首页" @click="emit('go-home')">
<view class="home-icon"></view>
</button>
<view class="nav-spacer"></view>
<button class="icon-button" aria-label="个人中心" @click="emit('open-profile')">
<view class="account-icon"></view>
</button>
</view>
<scroll-view class="assessment-content" scroll-y>
<view class="score-section">
<view class="score-gauge">
<view class="gauge-bg"></view>
<view class="gauge-fill"></view>
<view class="score-center">
<text class="score-value">88</text>
<text class="score-label">总分/100</text>
</view>
</view>
<view class="score-copy">
<text class="score-title">本次考核评价优良</text>
<text class="score-subtitle">临床思维严谨诊疗流程规范</text>
</view>
</view>
<view class="dimension-card">
<view class="section-title">
<view class="insights-icon"></view>
<text>临床能力维度评估</text>
</view>
<view class="radar-wrap">
<svg class="radar-svg" viewBox="0 0 200 200">
<polygon fill="none" points="100,20 176,76 147,166 53,166 24,76" stroke="#c2c6d4" stroke-width="0.5"></polygon>
<polygon fill="none" points="100,40 160,84 137,152 63,152 40,84" stroke="#c2c6d4" stroke-width="0.5"></polygon>
<polygon fill="none" points="100,60 144,92 127,138 73,138 56,92" stroke="#c2c6d4" stroke-width="0.5"></polygon>
<polygon fill="rgba(0, 71, 141, 0.2)" points="100,30 165,80 135,155 75,145 45,70" stroke="#00478d" stroke-width="2"></polygon>
<text class="radar-label" text-anchor="middle" x="100" y="15">病史采集</text>
<text class="radar-label" text-anchor="start" x="180" y="75">体格检查</text>
<text class="radar-label" text-anchor="start" x="150" y="180">临床思维</text>
<text class="radar-label" text-anchor="end" x="50" y="180">诊断准确性</text>
<text class="radar-label" text-anchor="end" x="20" y="75">治疗方案</text>
</svg>
</view>
<view class="mentor-review">
<view class="mentor-head">
<view class="mentor-avatar">
<image src="/static/config-doctor.png" mode="aspectFill"></image>
</view>
<view>
<text class="mentor-name">王主任点评</text>
<text class="mentor-role">资深临床导师</text>
</view>
</view>
<view class="mentor-bubble">
<view class="bubble-tail"></view>
<text>你在病史采集环节表现出色逻辑清晰但在鉴别诊断方面稍欠全面建议加强对心血管急症鉴别诊断的学习</text>
</view>
</view>
<view class="bar-list">
<view
v-for="item in dimensions"
:key="item.label"
class="bar-item"
>
<view class="bar-head">
<text>{{ item.label }}</text>
<text class="bar-score">{{ item.score }}/100</text>
</view>
<view class="bar-track">
<view class="bar-fill" :style="{ width: `${item.score}%` }"></view>
</view>
</view>
</view>
</view>
<view class="action-area">
<button class="primary-action" @click="showToast('病例详情暂未开放')">
<view class="description-icon"></view>
<text>查看病例详情</text>
</button>
<button class="secondary-action" @click="emit('go-home')">
<view class="map-icon"></view>
<text>返回路径</text>
</button>
</view>
</scroll-view>
<view class="toast" :class="{ visible: toastVisible }">{{ toastMessage }}</view>
</view>
</template>
<script setup lang="ts">
import { onUnmounted, ref } from 'vue'
const emit = defineEmits<{
(event: 'open-settings'): void
(event: 'open-profile'): void
(event: 'go-home'): void
}>()
const dimensions = [
{ label: '病史采集', score: 92 },
{ label: '体格检查', score: 85 },
{ label: '临床思维', score: 90 },
{ label: '诊断准确性', score: 88 },
{ label: '治疗方案', score: 82 }
]
const toastMessage = ref('')
const toastVisible = ref(false)
let toastTimer: ReturnType<typeof setTimeout> | null = null
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)
}
onUnmounted(() => {
if (toastTimer) clearTimeout(toastTimer)
})
</script>
<style scoped>
page {
min-height: 100%;
background: #f9f9ff;
}
.assessment-page {
width: 390px;
max-width: 100vw;
height: 884px;
min-height: 884px;
margin: 0 auto;
overflow: hidden;
background: #f9f9ff;
color: #191c21;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
-webkit-tap-highlight-color: transparent;
}
.assessment-page view,
.assessment-page text,
.assessment-page button,
.assessment-page scroll-view {
box-sizing: border-box;
}
.top-nav {
position: fixed;
left: 0;
right: 0;
top: 0;
z-index: 50;
height: 56px;
padding: 0 20px;
border-bottom: 1px solid rgba(194, 198, 212, 0.3);
background: #ffffff;
box-shadow: 0 2px 8px rgba(25, 28, 33, 0.04);
display: flex;
align-items: center;
}
.nav-spacer {
flex: 1;
}
.icon-button {
width: 40px;
height: 40px;
min-height: 40px;
margin: 0;
padding: 0;
border: 0;
border-radius: 50%;
background: transparent;
display: flex;
align-items: center;
justify-content: center;
}
.home-button {
margin-left: 4px;
}
.icon-button::after,
.primary-action::after,
.secondary-action::after {
border: 0;
}
.settings-icon,
.home-icon,
.account-icon,
.insights-icon,
.description-icon,
.map-icon {
background: #424752;
}
.settings-icon {
width: 22px;
height: 22px;
-webkit-mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M19.43%2012.98c.04-.32.07-.65.07-.98s-.02-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.37-.31-.6-.22l-2.49%201c-.52-.4-1.08-.73-1.69-.98L14.5%202.42C14.47%202.18%2014.25%202%2014%202h-4c-.25%200-.46.18-.5.42l-.38%202.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.08-.48%200-.6.22l-2%203.46c-.13.22-.07.49.12.64l2.11%201.65c-.04.32-.08.65-.08.98s.03.66.08.98l-2.11%201.65c-.19.15-.24.42-.12.64l2%203.46c.12.22.37.31.6.22l2.49-1c.52.4%201.08.73%201.69.98l.38%202.65c.04.24.25.42.5.42h4c.25%200%20.46-.18.5-.42l.38-2.65c.61-.25%201.17-.58%201.69-.98l2.49%201c.23.08.48%200%20.6-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12%2015.5A3.5%203.5%200%201%201%2012%208a3.5%203.5%200%200%201%200%207.5z'/%3E%3C/svg%3E") center / contain no-repeat;
mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M19.43%2012.98c.04-.32.07-.65.07-.98s-.02-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.37-.31-.6-.22l-2.49%201c-.52-.4-1.08-.73-1.69-.98L14.5%202.42C14.47%202.18%2014.25%202%2014%202h-4c-.25%200-.46.18-.5.42l-.38%202.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.08-.48%200-.6.22l-2%203.46c-.13.22-.07.49.12.64l2.11%201.65c-.04.32-.08.65-.08.98s.03.66.08.98l-2.11%201.65c-.19.15-.24.42-.12.64l2%203.46c.12.22.37.31.6.22l2.49-1c.52.4%201.08.73%201.69.98l.38%202.65c.04.24.25.42.5.42h4c.25%200%20.46-.18.5-.42l.38-2.65c.61-.25%201.17-.58%201.69-.98l2.49%201c.23.08.48%200%20.6-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12%2015.5A3.5%203.5%200%201%201%2012%208a3.5%203.5%200%200%201%200%207.5z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.home-icon,
.account-icon {
width: 24px;
height: 24px;
}
.home-icon {
-webkit-mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M10%2020v-6h4v6h5v-8h3L12%203%202%2012h3v8h5z'/%3E%3C/svg%3E") center / contain no-repeat;
mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M10%2020v-6h4v6h5v-8h3L12%203%202%2012h3v8h5z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.account-icon {
-webkit-mask: 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-20zm0%203a3.5%203.5%200%201%201%200%207%203.5%203.5%200%200%201%200-7zm0%2015a8%208%200%200%201-6.4-3.2c1.18-2.02%203.57-3.3%206.4-3.3s5.22%201.28%206.4%203.3A8%208%200%200%201%2012%2020z'/%3E%3C/svg%3E") center / contain no-repeat;
mask: 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-20zm0%203a3.5%203.5%200%201%201%200%207%203.5%203.5%200%200%201%200-7zm0%2015a8%208%200%200%201-6.4-3.2c1.18-2.02%203.57-3.3%206.4-3.3s5.22%201.28%206.4%203.3A8%208%200%200%201%2012%2020z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.assessment-content {
height: 884px;
padding: 80px 20px 24px;
}
.score-section {
padding: 16px 0;
display: flex;
flex-direction: column;
align-items: center;
}
.score-gauge {
position: relative;
width: 128px;
height: 128px;
display: flex;
align-items: center;
justify-content: center;
}
.gauge-bg,
.gauge-fill {
position: absolute;
inset: 0;
border-radius: 50%;
}
.gauge-bg {
border: 8px solid #e1e2ea;
}
.gauge-fill {
background: conic-gradient(#00478d 0deg 317deg, transparent 317deg 360deg);
-webkit-mask: radial-gradient(circle, transparent 43px, #000 44px);
mask: radial-gradient(circle, transparent 43px, #000 44px);
transform: rotate(-90deg);
}
.score-center {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.score-value {
color: #00478d;
font-size: 32px;
line-height: 40px;
font-weight: 700;
}
.score-label {
color: #727783;
font-size: 12px;
line-height: 16px;
font-weight: 500;
}
.score-copy {
margin-top: 16px;
text-align: center;
display: flex;
flex-direction: column;
gap: 4px;
}
.score-title {
color: #191c21;
font-size: 24px;
line-height: 32px;
font-weight: 600;
}
.score-subtitle {
color: #424752;
font-size: 14px;
line-height: 20px;
}
.dimension-card {
padding: 16px;
border: 1px solid rgba(194, 198, 212, 0.3);
border-radius: 8px;
background: #ffffff;
box-shadow: 0 2px 8px rgba(25, 28, 33, 0.04);
}
.section-title {
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 8px;
color: #191c21;
font-size: 14px;
line-height: 20px;
font-weight: 600;
}
.insights-icon {
width: 20px;
height: 20px;
background: #00478d;
-webkit-mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M3%2017h3v-7H3v7zm5%200h3V7H8v10zm5%200h3v-4h-3v4zm5%200h3V4h-3v13z'/%3E%3C/svg%3E") center / contain no-repeat;
mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M3%2017h3v-7H3v7zm5%200h3V7H8v10zm5%200h3v-4h-3v4zm5%200h3V4h-3v13z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.radar-wrap {
position: relative;
width: 100%;
aspect-ratio: 1 / 1;
margin-bottom: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.radar-svg {
width: 100%;
height: 100%;
}
.radar-label {
fill: #424752;
font-size: 10px;
font-weight: 500;
}
.mentor-review {
margin-bottom: 24px;
padding: 16px;
border: 1px solid rgba(0, 71, 141, 0.1);
border-radius: 12px;
background: #f2f3fb;
}
.mentor-head {
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 12px;
}
.mentor-avatar {
width: 48px;
height: 48px;
border: 2px solid #ffffff;
border-radius: 50%;
overflow: hidden;
box-shadow: 0 2px 8px rgba(25, 28, 33, 0.08);
}
.mentor-avatar image {
width: 100%;
height: 100%;
}
.mentor-name {
display: block;
color: #00478d;
font-size: 14px;
line-height: 20px;
font-weight: 600;
}
.mentor-role {
display: block;
color: #424752;
font-size: 10px;
line-height: 14px;
}
.mentor-bubble {
position: relative;
padding: 12px;
border: 1px solid rgba(194, 198, 212, 0.2);
border-radius: 8px;
border-top-left-radius: 0;
background: #ffffff;
box-shadow: 0 2px 8px rgba(25, 28, 33, 0.04);
color: #191c21;
font-size: 14px;
line-height: 20px;
}
.bubble-tail {
position: absolute;
left: -8px;
top: 0;
width: 0;
height: 0;
border-top: 8px solid #ffffff;
border-left: 8px solid transparent;
}
.bar-list {
display: flex;
flex-direction: column;
gap: 16px;
}
.bar-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.bar-head {
display: flex;
justify-content: space-between;
color: #424752;
font-size: 12px;
line-height: 16px;
font-weight: 500;
}
.bar-score {
color: #00478d;
}
.bar-track {
width: 100%;
height: 6px;
border-radius: 999px;
background: #e1e2ea;
overflow: hidden;
}
.bar-fill {
height: 100%;
background: #00478d;
}
.action-area {
margin-top: 8px;
padding-bottom: 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.primary-action,
.secondary-action {
width: 100%;
height: 56px;
min-height: 56px;
margin: 0;
border-radius: 8px;
font-size: 16px;
line-height: 24px;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.primary-action {
border: 0;
background: #00478d;
box-shadow: 0 4px 12px rgba(0, 71, 141, 0.22);
color: #ffffff;
}
.secondary-action {
border: 2px solid rgba(0, 71, 141, 0.2);
background: #ffffff;
color: #00478d;
}
.description-icon,
.map-icon {
width: 20px;
height: 20px;
}
.primary-action .description-icon {
background: #ffffff;
}
.secondary-action .map-icon {
background: #00478d;
}
.description-icon {
-webkit-mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M14%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V8l-6-6zm-1%207V3.5L18.5%209H13zm-5%204h8v2H8v-2zm0%204h8v2H8v-2z'/%3E%3C/svg%3E") center / contain no-repeat;
mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='M14%202H6a2%202%200%200%200-2%202v16a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V8l-6-6zm-1%207V3.5L18.5%209H13zm-5%204h8v2H8v-2zm0%204h8v2H8v-2z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.map-icon {
-webkit-mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='m20.5%203-.16.03L15%205.1%209%203%203.36%204.9c-.21.07-.36.25-.36.48V20.5c0 .28.22.5.5.5l.16-.03L9%2018.9l6%202.1%205.64-1.9c.21-.07.36-.25.36-.48V3.5c0-.28-.22-.5-.5-.5zM15%2019l-6-2.11V5l6%202.11V19z'/%3E%3C/svg%3E") center / contain no-repeat;
mask: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3E%3Cpath%20d='m20.5%203-.16.03L15%205.1%209%203%203.36%204.9c-.21.07-.36.25-.36.48V20.5c0 .28.22.5.5.5l.16-.03L9%2018.9l6%202.1%205.64-1.9c.21-.07.36-.25.36-.48V3.5c0-.28-.22-.5-.5-.5zM15%2019l-6-2.11V5l6%202.11V19z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.toast {
position: fixed;
left: 50%;
bottom: 96px;
z-index: 100;
max-width: 320px;
padding: 12px 24px;
border-radius: 999px;
background: #2e3037;
color: #eff0f8;
font-size: 14px;
line-height: 20px;
font-weight: 600;
text-align: center;
pointer-events: none;
opacity: 0;
transform: translate(-50%, 16px);
transition: opacity 0.3s ease, transform 0.3s ease;
}
.toast.visible {
opacity: 1;
transform: translate(-50%, 0);
}
</style>