654 lines
17 KiB
Vue
654 lines
17 KiB
Vue
<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: '120–139 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;
|
||
}
|
||
|
||
/* forward:detail 从下往上进,report 往上出 */
|
||
.step4-slide-up-enter-from {
|
||
opacity: 0.01;
|
||
transform: translateY(100vh);
|
||
}
|
||
|
||
.step4-slide-up-leave-to {
|
||
opacity: 0.01;
|
||
transform: translateY(-100vh);
|
||
}
|
||
|
||
/* back:report 从上往下进,detail 往下出(反向) */
|
||
.step4-slide-down-enter-from {
|
||
opacity: 0.01;
|
||
transform: translateY(-100vh);
|
||
}
|
||
|
||
.step4-slide-down-leave-to {
|
||
opacity: 0.01;
|
||
transform: translateY(100vh);
|
||
}
|
||
</style>
|