|
|
@@ -0,0 +1,1942 @@
|
|
|
+<template>
|
|
|
+ <div class="weekly-report no-scrollbar">
|
|
|
+ <div class="report-header">
|
|
|
+ <div class="report-title">
|
|
|
+ <img class="title-icon" src="@/assets/images/watchApi/title-icon.png" />
|
|
|
+ <span>周报</span>
|
|
|
+ </div>
|
|
|
+ <div class="date-selector">
|
|
|
+ <el-date-picker
|
|
|
+ :picker-options="{ firstDayOfWeek: 1 }"
|
|
|
+ v-model="selectedDate"
|
|
|
+ type="week"
|
|
|
+ format="yyyy 第 WW 周"
|
|
|
+ placeholder="选择周"
|
|
|
+ @change="handleDateChange"
|
|
|
+ ></el-date-picker>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-card class="report-card">
|
|
|
+ <div class="progress-section">
|
|
|
+ <div class="progress-container">
|
|
|
+ <el-progress type="circle" :percentage="healthIndex" :width="120" color="#FF9F43"></el-progress>
|
|
|
+ <div class="progress-info">
|
|
|
+ <div class="progress-label">健康指数</div>
|
|
|
+ </div>
|
|
|
+ <div class="health-status">{{ healthStatus }}</div>
|
|
|
+ <div class="health-description">{{ healthDesc }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="health-metrics-container">
|
|
|
+ <div class="health-metrics-row">
|
|
|
+ <div class="metric-item">
|
|
|
+ <div class="metric-data">
|
|
|
+ <div class="metric-value">{{ height }}<span class="metric-unit">cm</span></div>
|
|
|
+ <div class="metric-label">身高</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-icon orange">
|
|
|
+ <i class="el-icon-sort"></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-item">
|
|
|
+ <div class="metric-data">
|
|
|
+ <div class="metric-value">{{ weight }}<span class="metric-unit">kg</span></div>
|
|
|
+ <div class="metric-label">体重</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-icon green">
|
|
|
+ <i class="el-icon-top"></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="health-metrics-row">
|
|
|
+ <div class="metric-item">
|
|
|
+ <div class="metric-data">
|
|
|
+ <div class="metric-value">{{ bmiStatus }}</div>
|
|
|
+ <div class="metric-label">BMI</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-icon blue">
|
|
|
+ <i class="el-icon-plus"></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-item">
|
|
|
+ <div class="metric-data">
|
|
|
+ <div class="metric-value">{{ caloriesData.value }}<span class="metric-unit">{{ caloriesData.unit }}</span></div>
|
|
|
+ <div class="metric-label">{{ caloriesData.label }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-icon red">
|
|
|
+ <i class="el-icon-hot-water"></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="health-metrics-row">
|
|
|
+ <div class="metric-item">
|
|
|
+ <div class="metric-data">
|
|
|
+ <div class="metric-value">{{ stepsData.value }}<span class="metric-unit">{{ stepsData.unit }}</span></div>
|
|
|
+ <div class="metric-label">{{ stepsData.label }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-icon orange">
|
|
|
+ <i class="el-icon-s-promotion"></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-item">
|
|
|
+ <div class="metric-data">
|
|
|
+ <div class="metric-value">{{ sleepCardData.status }}</div>
|
|
|
+ <div class="metric-label">{{ sleepCardData.label }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="metric-icon purple">
|
|
|
+ <i class="el-icon-moon"></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 健康数据 (Health Data) Section -->
|
|
|
+ <div class="health-data-section">
|
|
|
+ <div class="section-title">健康数据</div>
|
|
|
+
|
|
|
+ <!-- 血糖趋势 (Blood Sugar Trend) -->
|
|
|
+ <div class="trend-chart">
|
|
|
+ <div class="trend-title">血糖趋势</div>
|
|
|
+ <div class="trend-subtitle">单位: mmol/L</div>
|
|
|
+ <div class="line-chart-container" ref="bloodSugarChart"></div>
|
|
|
+ <div class="trend-advice">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 尿酸趋势 (Uric Acid Trend) -->
|
|
|
+ <div class="trend-chart">
|
|
|
+ <div class="trend-title">尿酸趋势</div>
|
|
|
+ <div class="trend-subtitle">单位: μmol/L</div>
|
|
|
+ <div class="bar-chart-container" ref="uricAcidChart"></div>
|
|
|
+ <div class="legend">
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #4CD964;"></span>
|
|
|
+ <span>150~416μmol/L</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #FFCC00;"></span>
|
|
|
+ <span><150μmol/L</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #FF6B6B;"></span>
|
|
|
+ <span>>416μmol/L</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="trend-chart">
|
|
|
+ <div class="trend-title">血压趋势</div>
|
|
|
+ <div class="trend-subtitle">单位: mmgh</div>
|
|
|
+ <div class="line-chart-container" ref="bloodPressureChart"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="trend-chart">
|
|
|
+ <div class="trend-title">心率趋势</div>
|
|
|
+ <div class="trend-subtitle">单位: 次/分</div>
|
|
|
+ <div class="line-chart-container" ref="heartRateChart"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="trend-chart">
|
|
|
+ <div class="trend-title">血氧趋势</div>
|
|
|
+ <div class="trend-subtitle"></div>
|
|
|
+ <div class="line-chart-container" ref="bloodOxygenChart"></div>
|
|
|
+ <div class="legend">
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #4CD964;"></span>
|
|
|
+ <span><90%</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #FFCC00;"></span>
|
|
|
+ <span><95%</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #FF6B6B;"></span>
|
|
|
+ <span>其他</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="trend-chart">
|
|
|
+ <div class="trend-title">睡眠趋势</div>
|
|
|
+ <div class="trend-subtitle"></div>
|
|
|
+ <div class="line-chart-container" ref="sleepChart"></div>
|
|
|
+ <div class="legend">
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #8C37E6;"></span>
|
|
|
+ <span>深睡</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #D138CF;"></span>
|
|
|
+ <span>浅睡</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #F88082;"></span>
|
|
|
+ <span>快速眼动</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="legend-color" style="background-color: #FDBD27;"></span>
|
|
|
+ <span>清醒</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ <div class="health-archive-section">
|
|
|
+ <div class="section-title">健康档案</div>
|
|
|
+ <div class="archive-items">
|
|
|
+ <!-- 健康预测 -->
|
|
|
+ <div class="archive-item">
|
|
|
+ <div class="archive-icon warning">
|
|
|
+ <i class="el-icon-warning-outline"></i>
|
|
|
+ </div>
|
|
|
+ <div class="archive-content">
|
|
|
+ <div class="archive-title">健康预测</div>
|
|
|
+ <div class="archive-text" v-for="(item, idx) in healthArchive" :key="'prediction' + idx">
|
|
|
+ {{ item.prediction }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 解析 -->
|
|
|
+ <div class="archive-item">
|
|
|
+ <div class="archive-icon analysis">
|
|
|
+ <i class="el-icon-data-analysis"></i>
|
|
|
+ </div>
|
|
|
+ <div class="archive-content">
|
|
|
+ <div class="archive-title">解析</div>
|
|
|
+ <div class="archive-text" v-for="(item, idx) in healthArchive" :key="'analysis' + idx">
|
|
|
+ {{ item.analysis }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 治疗建议 -->
|
|
|
+ <div class="archive-item">
|
|
|
+ <div class="archive-icon suggestion">
|
|
|
+ <i class="el-icon-first-aid-kit"></i>
|
|
|
+ </div>
|
|
|
+ <div class="archive-content">
|
|
|
+ <div class="archive-title">治疗建议</div>
|
|
|
+ <div class="archive-text" v-for="(item, idx) in healthArchive" :key="'suggestion' + idx">
|
|
|
+ {{ item.suggestion }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 注意事项 -->
|
|
|
+ <div class="archive-item">
|
|
|
+ <div class="archive-icon attention">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ </div>
|
|
|
+ <div class="archive-content">
|
|
|
+ <div class="archive-title">注意事项</div>
|
|
|
+ <div class="archive-text" v-for="(item, idx) in healthArchive" :key="'precautions' + idx">
|
|
|
+ {{ item.precautions }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- AI舌诊 (AI Tongue Diagnosis) Section -->
|
|
|
+ <div class="ai-diagnosis-section">
|
|
|
+ <div class="section-title">AI舌诊</div>
|
|
|
+ <div class="date-selector-tabs">
|
|
|
+ <div
|
|
|
+ v-for="date in weekDates"
|
|
|
+ :key="date"
|
|
|
+ :class="['date-tab', selectedDiagnosisDate === date ? 'active' : '']"
|
|
|
+ @click="selectedDiagnosisDate = date"
|
|
|
+ >
|
|
|
+ {{ date }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="diagnosis-content" v-if="tongueData">
|
|
|
+ <div class="diagnosis-time">检测时间 {{ tongueData.createTime || '未知时间' }}</div>
|
|
|
+
|
|
|
+ <div class="diagnosis-result">
|
|
|
+ <div class="diagnosis-label">您属于</div>
|
|
|
+ <div class="diagnosis-type">{{ tongueData.typeName || '未知体质' }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="diagnosis-section">
|
|
|
+ <div class="diagnosis-section-title">舌苔特征</div>
|
|
|
+ <div class="diagnosis-feature">
|
|
|
+ <div class="feature-dot"></div>
|
|
|
+ <div class="feature-title">{{ tongueData.taiseName || '未知' }}</div>
|
|
|
+ <div class="feature-description">{{ tongueData.taiseDesc || '未知' }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="diagnosis-feature">
|
|
|
+ <div class="feature-dot"></div>
|
|
|
+ <div class="feature-title">{{ tongueData.shemianName || '未知' }}</div>
|
|
|
+ <div class="feature-description">{{ tongueData.shemianDesc || '未知' }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="diagnosis-section">
|
|
|
+ <!-- <div class="diagnosis-section-title">体质解析</div> -->
|
|
|
+ <div
|
|
|
+ class="diagnosis-analysis"
|
|
|
+ v-for="(item, index) in tongueData.typeJsonObj"
|
|
|
+ :key="index"
|
|
|
+ >
|
|
|
+ <div class="diagnosis-section-title">{{ item.name }}</div>
|
|
|
+ <div class="analysis-content">{{ item.value }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="diagnosis-content" v-else>
|
|
|
+ <div class="no-data">暂无舌诊数据</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <script>
|
|
|
+ import * as echarts from 'echarts';
|
|
|
+ import {getUserHealthInfoByDeviceId,queryHealthReport,queryGlucoseList,queryUaList,queryPressureList,queryHrList,querySpo2List,querySleepList,queryTongueList} from "@/api/watch/deviceInfo";
|
|
|
+ export default {
|
|
|
+ props: {
|
|
|
+ // detailsType: {
|
|
|
+ // type: Boolean,
|
|
|
+ // default: false
|
|
|
+ // },
|
|
|
+ userInfo: {
|
|
|
+ type: Object,
|
|
|
+ default: () => ({})
|
|
|
+ },
|
|
|
+ deviceId: {
|
|
|
+ type: String || Number,
|
|
|
+ default: "",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ name: 'WeeklyReport',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ sleepDefaultInfo: {
|
|
|
+ 4: { name: "浅睡", color: "#D138CF", yValue: 7 },
|
|
|
+ 3: { name: "深睡", color: "#8C37E6", yValue: 3 },
|
|
|
+ 6: { name: "清醒", color: "#FDBD27", yValue: 9 },
|
|
|
+ 7: { name: "快速眼动", color: "#F88082", yValue: 12 },
|
|
|
+ },
|
|
|
+ startTime: null,
|
|
|
+ endTime: null,
|
|
|
+ // 基础数据
|
|
|
+ height: '--',
|
|
|
+ weight: '--',
|
|
|
+ bmi: 0,
|
|
|
+ bmiStatus: '--',
|
|
|
+ healthIndex: 0,
|
|
|
+ healthStatus: '--',
|
|
|
+ healthDesc:"",
|
|
|
+ // 健康指标数据
|
|
|
+ caloriesData: {
|
|
|
+ value: '--',
|
|
|
+ unit: 'kcal',
|
|
|
+ label: '卡路里'
|
|
|
+ },
|
|
|
+ stepsData: {
|
|
|
+ value: '--',
|
|
|
+ unit: '步',
|
|
|
+ label: '步数'
|
|
|
+ },
|
|
|
+ sleepCardData: {
|
|
|
+ status: '--',
|
|
|
+ label: '睡眠'
|
|
|
+ },
|
|
|
+ selectedDate: new Date(),
|
|
|
+ // 健康档案
|
|
|
+ healthArchive: [],
|
|
|
+ selectedDiagnosisDate: '12/27',
|
|
|
+ bloodSugarChart: null,
|
|
|
+ uricAcidChart: null,
|
|
|
+ bloodPressureChart:null,
|
|
|
+ heartRateChart:null,
|
|
|
+ bloodOxygenChart:null,
|
|
|
+ sleepChart:null,
|
|
|
+ bloodSugarData: {
|
|
|
+ values: []
|
|
|
+ },
|
|
|
+
|
|
|
+ uricAcidData: {
|
|
|
+ values: [
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ bloodPressureData:{},
|
|
|
+ heartRateData:{},
|
|
|
+ bloodOxygenData:{values: []},
|
|
|
+ sleepData:[],
|
|
|
+ tongueData:null
|
|
|
+ };
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.initBloodSugarChart();
|
|
|
+ this.initBloodPressureChart();
|
|
|
+ this.initUricAcidChart();
|
|
|
+ this.initHeartRateChart();
|
|
|
+ this.initBloodOxygenChart();
|
|
|
+ this.initSleepChart();
|
|
|
+ this.setInitialDiagnosisDate();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ weekDates() {
|
|
|
+ const dates = [];
|
|
|
+ const startOfWeek = new Date(this.selectedDate);
|
|
|
+ startOfWeek.setDate(this.selectedDate.getDate() - (this.selectedDate.getDay() || 7) + 1); // Set to Monday
|
|
|
+ for (let i = 0; i < 7; i++) {
|
|
|
+ const date = new Date(startOfWeek);
|
|
|
+ date.setDate(startOfWeek.getDate() + i);
|
|
|
+ dates.push(this.formatDate(date));
|
|
|
+ }
|
|
|
+ return dates;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ userInfo: {
|
|
|
+ handler(newVal) {
|
|
|
+ if (newVal) {
|
|
|
+ this.updateUserInfo();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ deep: true
|
|
|
+ },
|
|
|
+ selectedDate() {
|
|
|
+ this.setInitialDiagnosisDate();
|
|
|
+ },
|
|
|
+ selectedDiagnosisDate(newVal) {
|
|
|
+ if (newVal) {
|
|
|
+ this.getTongueDate();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ formatDate(date) {
|
|
|
+ return `${date.getMonth() + 1}/${date.getDate()}`;
|
|
|
+ },
|
|
|
+ setInitialDiagnosisDate() {
|
|
|
+ this.selectedDiagnosisDate = this.weekDates[0] || null;
|
|
|
+ },
|
|
|
+ getWeekDates(date) {
|
|
|
+ const startOfWeek = new Date(date);
|
|
|
+ const endOfWeek = new Date(date);
|
|
|
+ startOfWeek.setDate(date.getDate() - (date.getDay() || 7) + 1); // 如果是周日,getDay() 返回 0,需要加 7
|
|
|
+ // 将日期设置为周一,时间为00:00:00
|
|
|
+ // startOfWeek.setDate(date.getDate() - date.getDay());
|
|
|
+ startOfWeek.setHours(0, 0, 0, 0);
|
|
|
+
|
|
|
+ // 将日期设置为周日,时间为23:59:59
|
|
|
+ endOfWeek.setDate(date.getDate() - (date.getDay() || 7) + 7); // 如果是周日,getDay() 返回 0,需要加 7
|
|
|
+ // endOfWeek.setDate(date.getDate() - date.getDay() + 6);
|
|
|
+ endOfWeek.setHours(23, 59, 59, 999);
|
|
|
+
|
|
|
+ this.startTime= startOfWeek,
|
|
|
+ this.endTime= endOfWeek
|
|
|
+ },
|
|
|
+ // 更新基本信息
|
|
|
+ updateUserInfo() {
|
|
|
+ if (this.userInfo) {
|
|
|
+ // 设置身高体重
|
|
|
+ this.height = this.userInfo.height || '--';
|
|
|
+ this.weight = this.userInfo.weight || '--';
|
|
|
+
|
|
|
+ // 计算BMI
|
|
|
+ this.calculateBMI();}
|
|
|
+ },
|
|
|
+ // 计算BMI
|
|
|
+ calculateBMI() {
|
|
|
+ if (this.height && this.weight && this.height !== '--' && this.weight !== '--') {
|
|
|
+ // BMI = 体重(kg) / 身高(m)²
|
|
|
+ const heightInMeters = parseFloat(this.height) / 100;
|
|
|
+ const weightInKg = parseFloat(this.weight);
|
|
|
+
|
|
|
+ if (!isNaN(heightInMeters) && !isNaN(weightInKg) && heightInMeters > 0) {
|
|
|
+ this.bmi = (weightInKg / (heightInMeters * heightInMeters)).toFixed(1);
|
|
|
+
|
|
|
+ // 设置BMI状态
|
|
|
+ if (this.bmi < 18.5) {
|
|
|
+ this.bmiStatus = '偏瘦';
|
|
|
+ } else if (this.bmi >= 18.5 && this.bmi < 24) {
|
|
|
+ this.bmiStatus = '正常';
|
|
|
+ } else if (this.bmi >= 24 && this.bmi < 28) {
|
|
|
+ this.bmiStatus = '超重';
|
|
|
+ } else {
|
|
|
+ this.bmiStatus = '肥胖';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async getSportData() {
|
|
|
+ try{
|
|
|
+ const params = {
|
|
|
+ deviceId: this.deviceId,
|
|
|
+ startTime: this.parseTime(this.startTime),
|
|
|
+ endTime: this.parseTime(this.endTime),
|
|
|
+ };
|
|
|
+ const response = await getUserHealthInfoByDeviceId(params);
|
|
|
+ if(response.data){
|
|
|
+ this.caloriesData.value = response.data.calorie;
|
|
|
+ this.stepsData.value = response.data.step;
|
|
|
+ this.sleepData.status = response.data.sleepStatus;
|
|
|
+ }
|
|
|
+ }catch(error){
|
|
|
+ console.error("获取步数,卡路里,睡眠等信息数据失败:", error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async getHealthArchive() {
|
|
|
+ try{
|
|
|
+ const params = {
|
|
|
+ deviceId: this.deviceId,
|
|
|
+ startTime: this.parseTime(this.startTime),
|
|
|
+ endTime: this.parseTime(this.endTime),
|
|
|
+ };
|
|
|
+ const response = await queryHealthReport(params);
|
|
|
+ if(response.data){
|
|
|
+ this.healthArchive = response.data.list;
|
|
|
+ this.healthIndex = response.data.score;
|
|
|
+ this.healthStatus = response.data.title;
|
|
|
+ this.healthDesc = response.data.desc;
|
|
|
+
|
|
|
+ }
|
|
|
+ }catch(error){
|
|
|
+ console.error("获取步数,卡路里,睡眠等信息数据失败:", error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async getGlucoseDate() {
|
|
|
+ try{
|
|
|
+ const params = {
|
|
|
+ deviceId: this.deviceId,
|
|
|
+ startTime: this.parseTime(this.startTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ endTime: this.parseTime(this.endTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ };
|
|
|
+ const response = await queryGlucoseList(params);
|
|
|
+ if(response.data && response.data.length > 0){
|
|
|
+ const values = response.data.map(item => {
|
|
|
+ const timestamp = new Date(item.createTime).getTime();
|
|
|
+ return [timestamp, item.bloodGlucose, item.createTime];
|
|
|
+ });
|
|
|
+ this.bloodSugarData = {
|
|
|
+ values: values
|
|
|
+ };
|
|
|
+
|
|
|
+ } else {
|
|
|
+ this.bloodSugarData = {
|
|
|
+ values: []
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }catch(error){
|
|
|
+ console.error("获取血糖数据失败:", error);
|
|
|
+ this.bloodSugarData = {
|
|
|
+ values: []
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async getUaDate() {
|
|
|
+ try{
|
|
|
+ const params = {
|
|
|
+ deviceId: this.deviceId,
|
|
|
+ startTime: this.parseTime(this.startTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ endTime: this.parseTime(this.endTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ };
|
|
|
+ const response = await queryUaList(params);
|
|
|
+ if(response.data && response.data.length > 0){
|
|
|
+ const values = response.data.map(item => {
|
|
|
+ const timestamp = new Date(item.createTime).getTime();
|
|
|
+ const val = item.val/10;
|
|
|
+ let color;
|
|
|
+ if (val < 150) {
|
|
|
+ color = '#FFCC00';
|
|
|
+ } else if (val < 416) {
|
|
|
+ color = '#4CD964';
|
|
|
+ } else {
|
|
|
+ color = '#FF6B6B';
|
|
|
+ }
|
|
|
+ return [timestamp, val, item.createTime,color];
|
|
|
+ });
|
|
|
+ this.uricAcidData.values = values;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ this.uricAcidChart.values = [];
|
|
|
+ }
|
|
|
+ }catch(error){
|
|
|
+ console.error("获取尿酸数据失败:", error);
|
|
|
+ this.uricAcidChart.values = [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async getSleepDate() {
|
|
|
+ try{
|
|
|
+ const params = {
|
|
|
+ deviceId: this.deviceId,
|
|
|
+ startTime: this.parseTime(this.startTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ endTime: this.parseTime(this.endTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ };
|
|
|
+ const response = await querySleepList(params);
|
|
|
+ if(response.data.sleepSection && response.data.sleepSection.length > 0){
|
|
|
+ this.sleepData = response.data.sleepSection;
|
|
|
+ }
|
|
|
+ }catch(error){
|
|
|
+ console.error("获取睡眠数据失败:", error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async querySpo2Data() {
|
|
|
+ try{
|
|
|
+ const params = {
|
|
|
+ deviceId: this.deviceId,
|
|
|
+ startTime: this.parseTime(this.startTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ endTime: this.parseTime(this.endTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ };
|
|
|
+ const response = await querySpo2List(params);
|
|
|
+ if(response.data.list && response.data.list.length > 0){
|
|
|
+ const values = response.data.list.map(item => {
|
|
|
+ const timestamp = new Date(item.createTime).getTime();
|
|
|
+ const val = item.avgBoxy;
|
|
|
+ let color;
|
|
|
+ if (val < 150) {
|
|
|
+ color = '#FFCC00';
|
|
|
+ } else if (val < 416) {
|
|
|
+ color = '#4CD964';
|
|
|
+ } else {
|
|
|
+ color = '#FF6B6B';
|
|
|
+ }
|
|
|
+ return [timestamp, val, item.createTime,color];
|
|
|
+ });
|
|
|
+ this.bloodOxygenData.values = values;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ this.bloodOxygenData.values = [];
|
|
|
+ }
|
|
|
+ }catch(error){
|
|
|
+ console.error("获取尿酸数据失败:", error);
|
|
|
+ this.bloodOxygenData.values = [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async getHrDate() {
|
|
|
+ try{
|
|
|
+ const params = {
|
|
|
+ deviceId: this.deviceId,
|
|
|
+ startTime: this.parseTime(this.startTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ endTime: this.parseTime(this.endTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ };
|
|
|
+ const response = await queryHrList(params);
|
|
|
+ if(response.data.list && response.data.list.length > 0){
|
|
|
+ const values = response.data.list.map(item => {
|
|
|
+ const timestamp = new Date(item.createTime).getTime();
|
|
|
+ return [timestamp, (item.maxBpm + item.minBpm)/2, item.createTime];
|
|
|
+ });
|
|
|
+ this.heartRateData = {
|
|
|
+ values: values
|
|
|
+ };
|
|
|
+
|
|
|
+ } else {
|
|
|
+ this.heartRateData = {
|
|
|
+ values: []
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }catch(error){
|
|
|
+ console.error("获取心率数据失败:", error);
|
|
|
+ this.bloodSugarData = {
|
|
|
+ values: []
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ async queryPressureData() {
|
|
|
+ try{
|
|
|
+ const params = {
|
|
|
+ deviceId: this.deviceId,
|
|
|
+ startTime: this.parseTime(this.startTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ endTime: this.parseTime(this.endTime,'{y}/{m}/{d} {h}:{i}:{s}'),
|
|
|
+ };
|
|
|
+ const response = await queryPressureList(params);
|
|
|
+ if(response.data && response.data.length > 0){
|
|
|
+
|
|
|
+
|
|
|
+ const sbp = response.data.map((item) => ({
|
|
|
+ value: [
|
|
|
+ new Date(item.createTime).getTime(),
|
|
|
+ item.sbp,
|
|
|
+ ]
|
|
|
+ }));
|
|
|
+ const dbp = response.data.map((item) => ({
|
|
|
+ value: [
|
|
|
+ new Date(item.createTime).getTime(),
|
|
|
+ item.dbp,
|
|
|
+ ]
|
|
|
+ }));
|
|
|
+ const hr = response.data.map((item) => ({
|
|
|
+ value: [
|
|
|
+ new Date(item.createTime).getTime(),
|
|
|
+ item.hr,
|
|
|
+ ]
|
|
|
+ }));
|
|
|
+ const createTime = response.data.map((item) => ({
|
|
|
+ value: [
|
|
|
+ item.createTime
|
|
|
+ ]
|
|
|
+ }));
|
|
|
+ this.bloodPressureData = {
|
|
|
+ sbp : sbp,
|
|
|
+ dbp : dbp,
|
|
|
+ hr : hr,
|
|
|
+ createTime:createTime,
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ this.bloodPressureData = {
|
|
|
+ sbp : [],
|
|
|
+ dbp : [],
|
|
|
+ hr : [],
|
|
|
+ createTime:[]
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }catch(error){
|
|
|
+ console.error("获取血压数据失败:", error);
|
|
|
+ this.bloodPressureData = {
|
|
|
+ sbp : [],
|
|
|
+ dbp : [],
|
|
|
+ hr : [],
|
|
|
+ createTime:[]
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ formatCreateDay(dateStr) {
|
|
|
+ const [month, day] = dateStr.split('/').map(Number);
|
|
|
+ const year = this.selectedDate.getFullYear();
|
|
|
+ const date = new Date(year, month - 1, day);
|
|
|
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
|
|
+ },
|
|
|
+
|
|
|
+ async getTongueDate(){
|
|
|
+ if(this.userInfo && this.userInfo.userId){
|
|
|
+ const params = {
|
|
|
+ userId: this.userInfo.userId,
|
|
|
+ createDay: this.formatCreateDay(this.selectedDiagnosisDate),
|
|
|
+ };
|
|
|
+
|
|
|
+ const response = await queryTongueList(params);
|
|
|
+ if(response && response.rows.length > 0){
|
|
|
+ this.tongueData = response.rows[0]
|
|
|
+ this.tongueData.typeJsonObj = JSON.parse(this.tongueData.typeJson || '[]')
|
|
|
+ console.log(this.tongueData)
|
|
|
+ } else {
|
|
|
+ this.tongueData = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取周报详情数据
|
|
|
+ async getDetailsData() {
|
|
|
+ try {
|
|
|
+ this.getWeekDates(this.selectedDate);
|
|
|
+ // 获取健康周报-步数,卡路里,睡眠等信息
|
|
|
+ await this.getSportData();
|
|
|
+ await this.getHealthArchive();
|
|
|
+ await this.getGlucoseDate();
|
|
|
+ await this.getUaDate();
|
|
|
+ await this.queryPressureData();
|
|
|
+ await this.getHrDate();
|
|
|
+ await this.querySpo2Data();
|
|
|
+ await this.getSleepDate();
|
|
|
+ await this.getTongueDate();
|
|
|
+ this.updateCharts();
|
|
|
+ } catch (error) {
|
|
|
+ console.error("获取周报数据失败:", error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ handleDateChange(date) {
|
|
|
+ this.selectedDate = date || this.parseTime(new Date(), "{y}-{m}-{d}");
|
|
|
+ this.getDetailsData();
|
|
|
+ },
|
|
|
+
|
|
|
+ initBloodSugarChart() {
|
|
|
+ const chartDom = this.$refs.bloodSugarChart;
|
|
|
+ this.bloodSugarChart = echarts.init(chartDom);
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: function(params) {
|
|
|
+ if (!params.data || params.data.length < 3) {
|
|
|
+ return '无数据';
|
|
|
+ }
|
|
|
+ const value = params.data[1];
|
|
|
+ const createTime = params.data[2];
|
|
|
+ return `时间: ${createTime}<br/>血糖: ${value} mmol/L`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ top: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'time',
|
|
|
+ boundaryGap: false,
|
|
|
+ splitNumber: 7,
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ axisLabel: {
|
|
|
+ color: "#999999",
|
|
|
+ margin: 20,
|
|
|
+ // fontSize: 14,
|
|
|
+ fontWeight: "bold",
|
|
|
+ formatter: (value) => {
|
|
|
+ return this.parseTime(value, "{m}/{d}");
|
|
|
+ },
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ min: 0,
|
|
|
+ max: 12,
|
|
|
+ interval: 2,
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '血糖',
|
|
|
+ data: this.bloodSugarData.values,
|
|
|
+ type: 'line',
|
|
|
+ smooth: true,
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 7,
|
|
|
+ itemStyle: {
|
|
|
+ color: '#FF9F43'
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: '#FF9F43'
|
|
|
+ },
|
|
|
+ areaStyle: {
|
|
|
+ color: {
|
|
|
+ type: 'linear',
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ x2: 0,
|
|
|
+ y2: 1,
|
|
|
+ colorStops: [
|
|
|
+ {
|
|
|
+ offset: 0,
|
|
|
+ color: 'rgba(255, 159, 67, 0.3)'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ offset: 1,
|
|
|
+ color: 'rgba(255, 159, 67, 0.1)'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ this.bloodSugarChart.setOption(option);
|
|
|
+
|
|
|
+ // 响应式调整
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ this.bloodSugarChart.resize();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ initBloodPressureChart() {
|
|
|
+ const chartDom = this.$refs.bloodPressureChart;
|
|
|
+ this.bloodPressureChart = echarts.init(chartDom);
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ formatter: function(params) {
|
|
|
+ if (!params) {
|
|
|
+ return '无数据';
|
|
|
+ }
|
|
|
+ const sbp = params[0].data.value;
|
|
|
+ const dbp = params[1].data.value;
|
|
|
+ const hr = params[2].data.value;
|
|
|
+ const createTime = new Date(sbp[0]).toLocaleString();
|
|
|
+ return `时间: ${createTime}<br/>sbp: ${sbp[1]} mmgh<br/>bdp: ${dbp[1]} mmgh<br/>hr: ${hr[1]} 次/分`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ legend: {},
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ top: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "time",
|
|
|
+ boundaryGap: false,
|
|
|
+ splitNumber: 7,
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime(),
|
|
|
+ axisLabel: {
|
|
|
+ color: "#999999",
|
|
|
+ margin: 20,
|
|
|
+ fontWeight: "bold",
|
|
|
+ formatter: (value) => {
|
|
|
+ return this.parseTime(value, "{m}/{d}");
|
|
|
+ },
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ min: 0,
|
|
|
+ max: 180,
|
|
|
+ interval: 30,
|
|
|
+ axisLabel: {
|
|
|
+ formatter: '{value}'
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: 'sbp(mmgh)',
|
|
|
+ type: "line",
|
|
|
+ symbol: "none",
|
|
|
+ data: this.bloodPressureData.sbp
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'dbp(mmgh)',
|
|
|
+ type: "line",
|
|
|
+ symbol: "none",
|
|
|
+ data: this.bloodPressureData.dbp
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'hr(次/分)',
|
|
|
+ type: "line",
|
|
|
+ symbol: "none",
|
|
|
+ data: this.bloodPressureData.hr
|
|
|
+ }
|
|
|
+ ]
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ this.bloodPressureChart.setOption(option);
|
|
|
+
|
|
|
+ // 响应式调整
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ this.bloodPressureChart.resize();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ initUricAcidChart() {
|
|
|
+ const chartDom = this.$refs.uricAcidChart;
|
|
|
+ this.uricAcidChart = echarts.init(chartDom);
|
|
|
+
|
|
|
+ const data = this.uricAcidData.values.map((item, index) => {
|
|
|
+ return {
|
|
|
+ value: [item[0],item[1]],
|
|
|
+ itemStyle: {
|
|
|
+ color: item[3]
|
|
|
+ },
|
|
|
+ time:item[2]
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: function(params) {
|
|
|
+ if (!params.data || params.data.length < 4) {
|
|
|
+ return '无数据';
|
|
|
+ }
|
|
|
+ const value = params.data.value[1];
|
|
|
+ const createTime = params.data.time;
|
|
|
+ return `时间: ${createTime}<br/>尿酸: ${value} μmol/L`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ top: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'time',
|
|
|
+ splitNumber: 7,
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ axisLabel: {
|
|
|
+ color: "#999999",
|
|
|
+ margin: 20,
|
|
|
+ fontWeight: "bold",
|
|
|
+ formatter: (value) => {
|
|
|
+ return this.parseTime(value, "{m}/{d}");
|
|
|
+ },
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ min: 0,
|
|
|
+ max: 600,
|
|
|
+ interval: 100,
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '尿酸',
|
|
|
+ type: 'bar',
|
|
|
+ data: data,
|
|
|
+ // barWidth: '40%'
|
|
|
+ barWidth: 10, // 设置柱子的宽度为 20 像素
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ this.uricAcidChart.setOption(option);
|
|
|
+
|
|
|
+ // 响应式调整
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ if (this.uricAcidChart) {
|
|
|
+ this.uricAcidChart.resize();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ initHeartRateChart(){
|
|
|
+ const chartDom = this.$refs.heartRateChart;
|
|
|
+ this.heartRateChart = echarts.init(chartDom);
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: function(params) {
|
|
|
+ if (!params.data || params.data.length < 3) {
|
|
|
+ return '无数据';
|
|
|
+ }
|
|
|
+ const value = params.data[1];
|
|
|
+ const createTime = params.data[2];
|
|
|
+ return `时间: ${createTime}<br/>心率: ${value} 次/分`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ top: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'time',
|
|
|
+ boundaryGap: false,
|
|
|
+ splitNumber: 7,
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ axisLabel: {
|
|
|
+ color: "#999999",
|
|
|
+ margin: 20,
|
|
|
+ // fontSize: 14,
|
|
|
+ fontWeight: "bold",
|
|
|
+ formatter: (value) => {
|
|
|
+ return this.parseTime(value, "{m}/{d}");
|
|
|
+ },
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '心率',
|
|
|
+ data: this.heartRateData.values,
|
|
|
+ type: 'line',
|
|
|
+ smooth: true,
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 7,
|
|
|
+ itemStyle: {
|
|
|
+ color: '#FF9F43'
|
|
|
+ },
|
|
|
+ lineStyle: {
|
|
|
+ color: '#FF9F43'
|
|
|
+ },
|
|
|
+ areaStyle: {
|
|
|
+ color: {
|
|
|
+ type: 'linear',
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ x2: 0,
|
|
|
+ y2: 1,
|
|
|
+ colorStops: [
|
|
|
+ {
|
|
|
+ offset: 0,
|
|
|
+ color: 'rgba(255, 159, 67, 0.3)'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ offset: 1,
|
|
|
+ color: 'rgba(255, 159, 67, 0.1)'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ this.heartRateChart.setOption(option);
|
|
|
+
|
|
|
+ // 响应式调整
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ this.heartRateChart.resize();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ initBloodOxygenChart(){
|
|
|
+ const chartDom = this.$refs.bloodOxygenChart;
|
|
|
+ this.bloodOxygenChart = echarts.init(chartDom);
|
|
|
+
|
|
|
+ const data = this.bloodOxygenData.values.map((item, index) => {
|
|
|
+ return {
|
|
|
+ value: [item[0],item[1]],
|
|
|
+ itemStyle: {
|
|
|
+ color: item[3]
|
|
|
+ },
|
|
|
+ time:item[2]
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: function(params) {
|
|
|
+ if (!params.data || params.data.length < 4) {
|
|
|
+ return '无数据';
|
|
|
+ }
|
|
|
+ const value = params.data.value[1];
|
|
|
+ const createTime = params.data.time;
|
|
|
+ return `时间: ${createTime}<br/>血氧: ${value} %`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ top: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'time',
|
|
|
+ splitNumber: 7,
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ axisLabel: {
|
|
|
+ color: "#999999",
|
|
|
+ margin: 20,
|
|
|
+ fontWeight: "bold",
|
|
|
+ formatter: (value) => {
|
|
|
+ return this.parseTime(value, "{m}/{d}");
|
|
|
+ },
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '血氧',
|
|
|
+ type: 'bar',
|
|
|
+ data: data,
|
|
|
+ // barWidth: '40%'
|
|
|
+ barWidth: 10, // 设置柱子的宽度为 20 像素
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ this.bloodOxygenChart.setOption(option);
|
|
|
+
|
|
|
+ // 响应式调整
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ if (this.bloodOxygenChart) {
|
|
|
+ this.bloodOxygenChart.resize();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ initSleepChart(){
|
|
|
+ const chartDom = this.$refs.sleepChart;
|
|
|
+ this.sleepChart = echarts.init(chartDom);
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ show: true,
|
|
|
+ formatter: (params) => {
|
|
|
+ const start = params.value[3]
|
|
|
+ const end = params.value[4]
|
|
|
+ return `${start}到${end}<br/>${params.name}`;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: '3%',
|
|
|
+ right: '4%',
|
|
|
+ bottom: '3%',
|
|
|
+ top: '3%',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'time',
|
|
|
+ boundaryGap: false,
|
|
|
+ splitNumber: 7,
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ axisLabel: {
|
|
|
+ color: "#999999",
|
|
|
+ margin: 20,
|
|
|
+ // fontSize: 14,
|
|
|
+ fontWeight: "bold",
|
|
|
+ formatter: (value) => {
|
|
|
+ return this.parseTime(value, "{m}/{d}");
|
|
|
+ },
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ max: 14,
|
|
|
+ show: false,
|
|
|
+ axisTick: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ show: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ type: "custom",
|
|
|
+ renderItem: (params, api) => {
|
|
|
+ let yValue = api.value(2);
|
|
|
+ let start = api.coord([api.value(0), yValue]);
|
|
|
+ let size = api.size([api.value(1) - api.value(0), yValue]);
|
|
|
+ let style = api.style();
|
|
|
+ return {
|
|
|
+ type: "rect",
|
|
|
+ shape: {
|
|
|
+ x: start[0],
|
|
|
+ y: start[1],
|
|
|
+ width: size[0],
|
|
|
+ height: size[1],
|
|
|
+ },
|
|
|
+ style: style,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ data: [],
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ this.sleepChart.setOption(option);
|
|
|
+
|
|
|
+ // 响应式调整
|
|
|
+ window.addEventListener('resize', () => {
|
|
|
+ this.sleepChart.resize();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ updateCharts() {
|
|
|
+ if (this.bloodSugarChart) {
|
|
|
+ // 更新血糖图表数据
|
|
|
+ this.bloodSugarChart.setOption({
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: this.bloodSugarData.values
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ xAxis: {
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.bloodPressureChart) {
|
|
|
+ this.bloodPressureChart.setOption({
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: 'sbp(mmgh)',
|
|
|
+ type: "line",
|
|
|
+ symbol: "none",
|
|
|
+ data: this.bloodPressureData.sbp
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'dbp(mmgh)',
|
|
|
+ type: "line",
|
|
|
+ symbol: "none",
|
|
|
+ data: this.bloodPressureData.dbp
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'hr(次/分)',
|
|
|
+ type: "line",
|
|
|
+ symbol: "none",
|
|
|
+ data: this.bloodPressureData.hr
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ xAxis: {
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.uricAcidChart) {
|
|
|
+ // 更新尿酸图表数据
|
|
|
+ const data = this.uricAcidData.values.map((item, index) => {
|
|
|
+ return {
|
|
|
+ value: [item[0],item[1]],
|
|
|
+ itemStyle: {
|
|
|
+ color: item[3]
|
|
|
+ },
|
|
|
+ time:item[2]
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ this.uricAcidChart.setOption({
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ // type: 'bar',
|
|
|
+ data: data
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ xAxis: {
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (this.heartRateChart) {
|
|
|
+ this.heartRateChart.setOption({
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: this.heartRateData.values
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ xAxis: {
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (this.bloodOxygenChart) {
|
|
|
+ const data = this.bloodOxygenData.values.map((item, index) => {
|
|
|
+ return {
|
|
|
+ value: [item[0],item[1]],
|
|
|
+ itemStyle: {
|
|
|
+ color: item[3]
|
|
|
+ },
|
|
|
+ time:item[2]
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ this.bloodOxygenChart.setOption({
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ // type: 'bar',
|
|
|
+ data: data
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ xAxis: {
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.sleepChart) {
|
|
|
+ const chartData = this.sleepData.map((item, index) => {
|
|
|
+ return {
|
|
|
+ name: this.sleepDefaultInfo[item.type] && this.sleepDefaultInfo[item.type].name,
|
|
|
+ value: [
|
|
|
+ new Date(item.start).getTime(),
|
|
|
+ new Date(item.end).getTime(),
|
|
|
+ this.sleepDefaultInfo[item.type] && this.sleepDefaultInfo[item.type].yValue,
|
|
|
+ item.start,
|
|
|
+ item.end
|
|
|
+ ],
|
|
|
+ itemStyle: {
|
|
|
+ color: this.sleepDefaultInfo[item.type] && this.sleepDefaultInfo[item.type].color,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ });
|
|
|
+ this.sleepChart.setOption({
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: chartData
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ xAxis: {
|
|
|
+ min:new Date(this.startTime).getTime(),
|
|
|
+ max:new Date(this.endTime).getTime() + 1,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ // 清除事件监听
|
|
|
+ window.removeEventListener('resize', this.resizeHandler);
|
|
|
+
|
|
|
+ // 销毁图表实例
|
|
|
+ if (this.bloodSugarChart) {
|
|
|
+ this.bloodSugarChart.dispose();
|
|
|
+ this.bloodSugarChart = null;
|
|
|
+ }
|
|
|
+ if (this.bloodPressureChart) {
|
|
|
+ this.bloodPressureChart.dispose();
|
|
|
+ this.bloodPressureChart = null;
|
|
|
+ }
|
|
|
+ if (this.uricAcidChart) {
|
|
|
+ this.uricAcidChart.dispose();
|
|
|
+ this.uricAcidChart = null;
|
|
|
+ }
|
|
|
+ if (this.heartRateChart) {
|
|
|
+ this.heartRateChart.dispose();
|
|
|
+ this.heartRateChart = null;
|
|
|
+ }
|
|
|
+ if (this.bloodOxygenChart) {
|
|
|
+ this.bloodOxygenChart.dispose();
|
|
|
+ this.bloodOxygenChart = null;
|
|
|
+ }
|
|
|
+ if (this.sleepChart) {
|
|
|
+ this.sleepChart.dispose();
|
|
|
+ this.sleepChart = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <style scoped lang="scss">
|
|
|
+
|
|
|
+ /* 确保内容不会因为隐藏滚动条而被截断 */
|
|
|
+ .weekly-report {
|
|
|
+ padding: 20px;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ min-height: 100%;
|
|
|
+ overflow-y: auto;
|
|
|
+ overflow-x: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .report-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .report-title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #2284ff;
|
|
|
+
|
|
|
+ .title-icon {
|
|
|
+ width: 13px;
|
|
|
+ height: 20px;
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .report-card {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
+ overflow: hidden; /* 确保内容不会溢出卡片 */
|
|
|
+ }
|
|
|
+
|
|
|
+ .progress-section {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding: 20px 0;
|
|
|
+
|
|
|
+ @media (min-width: 768px) {
|
|
|
+ flex-direction: row;
|
|
|
+ justify-content: space-around;
|
|
|
+ align-items: flex-start;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .progress-container {
|
|
|
+ position: relative;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ @media (min-width: 768px) {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .progress-info {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ text-align: center;
|
|
|
+
|
|
|
+ .progress-value {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #FF9F43;
|
|
|
+
|
|
|
+ .progress-unit {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .progress-label {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .health-status {
|
|
|
+ margin-top: 10px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #FF9F43;
|
|
|
+ }
|
|
|
+ .health-description {
|
|
|
+ margin-top: 8px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ text-align: center;
|
|
|
+ max-width: 240px;
|
|
|
+ line-height: 1.5;
|
|
|
+ padding: 0 10px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+ .health-metrics-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ @media (min-width: 768px) {
|
|
|
+ width: 60%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .health-metrics-row {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .metric-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 10px 15px;
|
|
|
+ width: 48%;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
|
+
|
|
|
+ .metric-data {
|
|
|
+ .metric-value {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+
|
|
|
+ .metric-unit {
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: normal;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .metric-label {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .metric-icon {
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ i {
|
|
|
+ font-size: 16px;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.green {
|
|
|
+ background-color: #4CD964;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.blue {
|
|
|
+ background-color: #2284FF;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.orange {
|
|
|
+ background-color: #FF9F43;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.red {
|
|
|
+ background-color: #FF6B6B;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.purple {
|
|
|
+ background-color: #8A70D6;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .section-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin: 20px 0 15px;
|
|
|
+ color: #303133;
|
|
|
+ padding-left: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 健康数据部分 */
|
|
|
+ .health-data-section {
|
|
|
+ padding: 0 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .trend-chart {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 15px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
|
+ }
|
|
|
+
|
|
|
+ .trend-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+
|
|
|
+ .trend-subtitle {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .line-chart-container,
|
|
|
+ .bar-chart-container {
|
|
|
+ height: 250px;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .trend-advice {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ margin-top: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .legend {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ margin-top: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .legend-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 15px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ }
|
|
|
+
|
|
|
+ .legend-color {
|
|
|
+ display: inline-block;
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ margin-right: 5px;
|
|
|
+ border-radius: 2px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .health-tabs {
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 健康档案部分 */
|
|
|
+ .health-archive-section {
|
|
|
+ padding: 0 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .archive-items {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .archive-item {
|
|
|
+ display: flex;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 15px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
|
+ }
|
|
|
+
|
|
|
+ .archive-icon {
|
|
|
+ width: 36px;
|
|
|
+ height: 36px;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 15px;
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ i {
|
|
|
+ font-size: 18px;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.warning {
|
|
|
+ background-color: #FF6B6B;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.analysis {
|
|
|
+ background-color: #4CD964;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.suggestion {
|
|
|
+ background-color: #2284FF;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.attention {
|
|
|
+ background-color: #FF9F43;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .archive-content {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .archive-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .archive-text {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* AI舌诊部分 */
|
|
|
+ .ai-diagnosis-section {
|
|
|
+ padding: 0 10px 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .date-selector-tabs {
|
|
|
+ display: flex;
|
|
|
+ overflow-x: auto;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .date-tab {
|
|
|
+ padding: 8px 15px;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ border-radius: 4px;
|
|
|
+ margin-right: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ white-space: nowrap;
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ background-color: #FF9F43;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-content {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 15px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-time {
|
|
|
+ text-align: center;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #909399;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-result {
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-type {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #FF6B6B;
|
|
|
+ margin-top: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-section {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-section-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #FF9F43;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ position: relative;
|
|
|
+ padding-left: 10px;
|
|
|
+
|
|
|
+ &:before {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ width: 4px;
|
|
|
+ height: 16px;
|
|
|
+ background-color: #FF9F43;
|
|
|
+ border-radius: 2px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-feature {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .feature-dot {
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ background-color: #FF9F43;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 8px;
|
|
|
+ margin-top: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .feature-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .feature-description {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-analysis {
|
|
|
+ margin-bottom: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .analysis-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .analysis-content {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ .diagnosis-characteristics {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .characteristics-title {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+ margin-bottom: 3px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .characteristics-content {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
+ </style>
|