2026-05-04 00:17:44 +08:00

654 lines
17 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>
<div class="step4-shell">
<Transition :name="transitionName">
<!-- 报告页 step4 -->
<div v-if="view === 'report'" key="report" class="step4 step4--report">
<div class="top">
<div class="l"></div>
<div class="title">
我的检测报告
</div>
<div class="r" @click="router.replace('/')"><img src="@/assets/close.png" alt=""></div>
</div>
<div class="time"> 检测时间<span>{{ creatTime }}</span></div>
<div class="main">
<div class="ip">
<div class="ip-top" @click="toStep5()">
<div class="top-l">
<div class="value">{{ data?.metrics?.skin_status?.skin_age?.value }}<span></span></div>
<div class="label">皮肤年龄</div>
</div>
<div class="line"></div>
<div class="top-r">
<div class="value">{{ data?.metrics?.mental_health?.mental_score?.value }}<span></span></div>
<div class="label">心理健康指数</div>
</div>
</div>
<div class="l" @click="toStep5()">
<ReportMetricCard v-for="(item, index) in list1" :key="index" v-bind="item" />
</div>
<div class="r" @click="toStep5()">
<ReportMetricCard v-for="(item, index) in list2" :key="index" v-bind="item" />
</div>
<img src="@/assets/step1/ip.png" alt="">
</div>
</div>
<div class="bottom" @click="toStep5()">
<ReportMetricCard v-for="(item, index) in list3" :key="index" v-bind="item" />
</div>
</div>
<!-- 详情页 step5 -->
<div v-else key="detail" class="step5 step4--detail">
<div class="top">
<div class="l" @click="backToReport()"> <img src="@/assets/back.png" alt=""></div>
<div class="title">
心理压力指数MSI指标
</div>
<div class="r" @click="router.replace('/')"><img src="@/assets/close.png" alt=""></div>
</div>
<div v-html="summaryText" class="summary-text"> </div>
<!-- <div class="main">
<img class="tips" src="@/assets/step5/tips.png" alt="">
<img class="ip" src="@/assets/step1/ip.png" alt="">
</div> -->
<!-- <div class="info">
<div class="title">以下是你的心理压力指数MSI指标</div>
<div class="msi-card">
<div class="msi-score">
<span class="value">{{ msiScore.toFixed(1) }}</span>
<span class="total">/{{ msiMax.toFixed(1) }}</span>
</div>
<div class="msi-gauge">
<div class="track" />
<div class="pointer" :style="{ left: msiPointerLeft }" />
</div>
<div class="msi-labels">
<span>1-2</span>
<span>2-3</span>
<span>3-4</span>
<span>4-5</span>
<span>5-6</span>
</div>
</div>
<div class="text">
<p> 结合总分与各维度得分测评对象当前压力状态呈现以下核心特征</p>
<p> <span>1. 情绪与行为层面问题突出</span>情绪易怒性回避行为两个维度得分偏高是当前压力的主要表现形式易导致工作效率下降人际沟通不畅等问题</p>
<p> <span>2. 身心基础能力偏弱</span>幸福感与适应能力得分偏低反映出个体身心能量不足对工作环境变化的适应力较弱难以快速缓冲压力带来的负面影响</p>
<p>
<span>3.社会支持存在提升空间</span>社会支持维度处于中等水平外部支持未被充分利用主动求助联结支持系统的行为不足进一步加剧了压力应对的难度基于测评结果结合职场场景与个体需求制定以下分层干预建议可根据实际情况逐步落实
每日开展 10-15 分钟情绪调节练习如正念呼吸渐进式肌肉放松或轻量冥想每日固定时段完成逐步提升情绪自控力
建立 情绪记录清单当出现烦躁焦虑情绪时及时记录情绪触发点与自身感受分析情绪来源针对性调整思维方式减少冲动反应
</p>
<p> 适度参与户外活动如散步慢跑瑜伽每周 2-3 每次 30 分钟以上通过运动释放负面情绪提升身心愉悦感</p>
</div>
</div> -->
</div>
</Transition>
</div>
</template>
<script setup lang="ts">
//@ts-nocheck
import ReportMetricCard from '@/components/ReportMetricCard/index.vue';
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { format } from 'silly-datetime';
const router = useRouter();
const view = ref<'report' | 'detail'>('report');
const direction = ref<'forward' | 'back'>('forward');
const transitionName = ref('step4-slide-up');
const summaryText = ref('');
const creatTime = ref<Date>(new Date());
const data = ref<any>({});
// MSI 指数(详情页进度条)
const msiScore = ref(3.1);
const msiMax = ref(6.0);
const msiPointerLeft = computed(() => {
const ratio = Math.min(Math.max(msiScore.value / msiMax.value, 0), 1);
return `${ratio * 100}%`;
});
const toStep5 = () => {
direction.value = 'forward';
transitionName.value = 'step4-slide-up';
view.value = 'detail';
}
const backToReport = () => {
direction.value = 'back';
transitionName.value = 'step4-slide-down';
view.value = 'report';
};
const list1 = ref<any[]>([]);
const list2 = ref<any[]>([]);
const list3 = ref<any[]>([]);
/** 底部四个指标:`type` 决定布局,`iconType` 对应 icons/1~11.png */
//真实数据
const arkResult = sessionStorage.getItem('step2_ark_result');
if (arkResult) {
const result = JSON.parse(arkResult);
console.log(result);
// summaryText.value = result?.output[0]?.summary[0]?.text;
// console.log(summaryText.value); //文本
data.value = JSON.parse(result?.output[1]?.content[0]?.text);
creatTime.value = format(new Date(result.created_at ? result.created_at * 1000 : new Date()), 'YYYY-MM-DD HH:mm:ss')
summaryText.value = data.value?.brief_report?.summary_text;
list1.value = [
{
type: 4 as const,
iconType: 1 as const,
title: '心率',
mainValue: data.value?.metrics?.vital_signs?.heart_rate?.value,
unit: 'bpm次/分钟)',
}, {
type: 4 as const,
iconType: 2 as const,
title: '呼吸频率',
mainValue: data.value?.metrics?.vital_signs?.respiratory_rate?.value,
unit: '12-20次/分',
},
{
type: 4 as const,
iconType: 3 as const,
title: '舒张压',
mainValue: data.value?.metrics?.vital_signs?.diastolic_bp?.value,
unit: '85~89 mmHg',
},
{
type: 4 as const,
iconType: 4 as const,
title: '收缩压',
mainValue: data.value?.metrics?.vital_signs?.systolic_bp?.value,
unit: '120139 mmHg',
},
];
list2.value = [
{
type: 4 as const,
iconType: 5 as const,
title: '血糖',
mainValue: data.value?.metrics?.blood_health?.glucose?.value,
unit: '≥7.0 mmol/L',
}, {
type: 4 as const,
iconType: 6 as const,
title: '血红蛋白',
mainValue: data.value?.metrics?.blood_health?.hemoglobin?.value,
unit: 'bmp次/分钟)',
},
{
type: 4 as const,
iconType: 7 as const,
title: '甘油三酯',
mainValue: data.value?.metrics?.blood_health?.triglycerides?.value,
unit: '12-15 mmol/L',
},
];
list3.value = [
// {
// type: 1 as const,
// title: '心理检测指数',
// score: 3.1,
// max: 6,
// },
{
type: 8 as const,
iconType: 1 as const,
title: '心理检测指数',
mainValue: data.value?.metrics?.mental_health?.mental_score?.value,
},
// {
// type: 3 as const,
// iconType: 8 as const,
// title: '当前情绪',
// highlightText: '快乐',
// highlightColor: '#fb7185',
// },
{
type: 2 as const,
iconType: 9 as const,
title: '压力指数',
mainValue: data.value?.metrics?.mental_health?.stress?.value,
},
{
type: 2 as const,
iconType: 10 as const,
title: '抑郁指数',
mainValue: data.value?.metrics?.mental_health?.depression?.value,
},
{
type: 2 as const,
iconType: 11 as const,
title: '焦虑指数',
mainValue: data.value?.metrics?.mental_health?.anxiety?.value,
},
];
}
// data.value ={"visual_quality_check": {"lighting": "good", "face_clarity": "high", "signal_reliability": "valid"}, "metrics": {"vital_signs": {"heart_rate": {"value": 76, "unit": "bpm", "status": "normal", "desc": "心率"}, "respiratory_rate": {"value": 15, "unit": "rpm", "status": "normal", "desc": "呼吸频率"}, "systolic_bp": {"value": 122, "unit": "mmHg", "status": "normal", "desc": "收缩压"}, "diastolic_bp": {"value": 80, "unit": "mmHg", "status": "normal", "desc": "舒张压"}}, "blood_health": {"glucose": {"value": 5.2, "unit": "mmol/L", "status": "normal", "desc": "血糖"}, "hemoglobin": {"value": 132, "unit": "g/L", "status": "normal", "desc": "血红蛋白"}, "triglycerides": {"value": 1.1, "unit": "mmol/L", "status": "normal", "desc": "甘油三酯"}}, "skin_status": {"skin_age": {"value": 28, "unit": "years", "status": "normal", "desc": "皮肤年龄"}}, "mental_health": {"mental_score": {"value": 82, "unit": "score", "status": "normal", "desc": "心理健康指数"}, "stress": {"value": 3, "unit": "score", "status": "normal", "desc": "压力指数"}, "depression": {"value": 2, "unit": "score", "status": "normal", "desc": "抑郁指数"}, "anxiety": {"value": 2, "unit": "score", "status": "normal", "desc": "焦虑指数"}}}, "brief_report": {"personality": "沉稳内敛", "emotion": "平和", "overall_status": "良好", "abnormal_items": [], "summary_text": "检测显示您的生理机能处于正常状态,皮肤状况符合年龄特征,心理压力较低,整体状态良好。"}}
</script>
<style scoped lang="scss">
.step4-shell {
position: relative;
height: 100vh;
overflow: hidden;
/* 过渡时底层兜底背景,避免透明时露出白屏 */
// background: url('@/assets/step1/bg.png') no-repeat center center/cover;
background: #F3F3F3;
}
.step4,
.step5 {
min-height: 100vh;
// background: url('@/assets/step1/bg.png') no-repeat center center/cover ;
background: #F3F3F3;
}
.step4 {
padding-bottom: 166px;
position: relative;
padding-top: 52px;
display: flex;
flex-direction: column;
// justify-content: space-between;
min-height: 100vh;
.top {
padding: 0 30px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 50px;
.l {
width: 60px;
height: 60px;
}
.r {
width: 60px;
height: 60px;
img {
width: 100%;
}
}
.title {
flex: 1;
text-align: center;
}
}
.time {
line-height: 33px;
margin-top: 3px;
text-align: center;
font-size: 24px;
color: #000;
span {
color: #797979;
}
}
.main {
flex: 1;
position: relative;
.ip {
position: absolute;
top: 258px;
left: 50%;
transform: translate(-50%, 0);
width: 485.04px;
height: 1309px;
img {
width: 100%;
height: 100%;
}
.ip-top {
border-radius: 24px;
position: absolute;
top: -187px;
left: 50%;
transform: translateX(-50%);
width: 335px;
height: 105px;
background: #fff;
display: flex;
justify-content: space-between;
align-items: center;
.top-l,
.top-r {
flex: 1;
text-align: center;
.value {
font-size: 50px;
span {
font-size: 18px;
}
}
.label {
font-size: 18px;
}
}
.line {
width: 2px;
background: #D8D8D8;
height: 60%;
}
}
.l {
position: absolute;
width: 168px;
top: 125px;
left: -222px;
display: flex;
flex-wrap: wrap;
gap: 17px;
}
.r {
position: absolute;
width: 168px;
top: 125px;
right: -222px;
display: flex;
flex-wrap: wrap;
gap: 17px;
}
}
}
.bottom {
z-index: 2;
position: absolute;
bottom: 500px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 17px;
padding: 0 24px;
box-sizing: border-box;
}
}
/* 详情页(原 step5的样式直接复用 */
.step5 {
padding-top: 52px;
display: flex;
flex-direction: column;
// justify-content: space-between;
.top {
position: relative;
z-index: 2;
padding: 0 30px;
display: flex;
justify-content: space-between;
align-items: center;
.l {
width: 60px;
height: 60px;
}
.r {
width: 60px;
height: 60px;
img {
width: 100%;
}
}
.title {
height: 60px;
margin: 0 auto;
font-size: 50px;
}
}
.main {
transform: translateY(-200px);
flex: 1;
flex-direction: column;
display: flex;
justify-content: center;
align-items: center;
.ip {
margin-top: 61px;
width: 485.04px;
height: 1309px;
img {
width: 100%;
}
}
.tips {
display: block;
width: 404px;
height: 33px;
margin: 100px auto 0;
}
}
.info {
left: 50%;
transform: translateX(-50%);
border-radius: 20px;
position: absolute;
bottom: 43px;
width: 956px;
height: 888px;
background: rgba(255, 255, 255, 0.95);
padding: 24px 26px;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
.title {
font-size: 30px;
font-weight: 650;
}
.msi-card {
margin-top: 22px;
width: 452px;
height: 202px;
background: #fff;
border-radius: 24px;
padding: 34px 34px 28px;
box-sizing: border-box;
}
.msi-score {
display: flex;
align-items: baseline;
justify-content: center;
gap: 10px;
.value {
font-size: 63px;
font-weight: 800;
color: #111827;
line-height: 1;
}
.total {
font-size: 43px;
font-weight: 600;
color: rgba(17, 24, 39, 0.45);
line-height: 1;
}
}
.msi-gauge {
position: relative;
margin-top: 26px;
padding-top: 18px;
}
.track {
height: 18px;
border-radius: 999px;
background: linear-gradient(90deg,
#22c55e 0%,
#eab308 50%,
#ff7a00 78%,
#ff3b30 100%);
}
.pointer {
position: absolute;
top: 0;
width: 40px;
height: 28px;
transform: translateX(-50%);
background: url('@/components/ReportMetricCard/icons/dot.png') no-repeat center center / contain;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.18));
}
.msi-labels {
margin-top: 18px;
display: flex;
justify-content: space-between;
font-size: 32px;
line-height: 1;
font-weight: 500;
span:nth-child(1),
span:nth-child(2) {
color: #22c55e;
}
span:nth-child(3) {
color: #eab308;
}
span:nth-child(4) {
color: #ff7a00;
}
span:nth-child(5) {
color: #ff3b30;
}
}
.text {
margin-top: 25px;
font-size: 30px;
color: #000;
line-height: 48px;
p {
span {
font-weight: 700;
}
}
}
}
.summary-text{
padding: 50px;
}
}
/* 内部切换动画:上下滑 + 淡入淡出(支持正/反向) */
.step4-slide-up-enter-active,
.step4-slide-down-enter-active {
transition: opacity 1100ms cubic-bezier(0.2, 0.9, 0.2, 1),
transform 1100ms cubic-bezier(0.2, 0.9, 0.2, 1);
will-change: opacity, transform;
position: absolute;
inset: 0;
width: 100%;
height: 100%;
z-index: 2;
// background: url('@/assets/step1/bg.png') no-repeat center center/cover;
background: #F3F3F3;
}
.step4-slide-up-leave-active,
.step4-slide-down-leave-active {
transition: opacity 1100ms cubic-bezier(0.2, 0.9, 0.2, 1),
transform 1100ms cubic-bezier(0.2, 0.9, 0.2, 1);
will-change: opacity, transform;
position: absolute;
inset: 0;
width: 100%;
height: 100%;
z-index: 1;
pointer-events: none;
/* 叠层时也保持背景,避免透明叠加时出现白边/白屏 */
// background: url('@/assets/step1/bg.png') no-repeat center center/cover;
background: #F3F3F3;
}
.step4-slide-up-enter-to,
.step4-slide-up-leave-from,
.step4-slide-down-enter-to,
.step4-slide-down-leave-from {
opacity: 1;
}
/* forwarddetail 从下往上进report 往上出 */
.step4-slide-up-enter-from {
opacity: 0.01;
transform: translateY(100vh);
}
.step4-slide-up-leave-to {
opacity: 0.01;
transform: translateY(-100vh);
}
/* backreport 从上往下进detail 往下出(反向) */
.step4-slide-down-enter-from {
opacity: 0.01;
transform: translateY(-100vh);
}
.step4-slide-down-leave-to {
opacity: 0.01;
transform: translateY(100vh);
}
</style>