| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- <template>
- <view class="qd-container">
- <!-- Loading -->
- <view class="qd-loading" v-if="loading">
- <text class="loading-text">加载中...</text>
- </view>
- <template v-else>
- <!-- Step 1: 选择维度 -->
- <view v-if="step === 1" class="qd-step">
- <view class="qd-header">
- <text class="qd-title">选择健康维度</text>
- <text class="qd-desc">请选择一个维度进行评估</text>
- </view>
- <view class="qd-dim-list">
- <view
- class="qd-dim-item"
- :class="{ active: selectedDimension === dim.code }"
- v-for="dim in dimensions"
- :key="dim.code"
- @click="selectedDimension = dim.code"
- >
- <text class="qd-dim-icon">{{ dim.icon }}</text>
- <text class="qd-dim-label">{{ dim.label }}</text>
- <text class="qd-dim-check" v-if="selectedDimension === dim.code">✓</text>
- </view>
- </view>
- <view class="qd-footer">
- <button class="qd-btn" :disabled="!selectedDimension" @click="startQuestions">开始答题</button>
- </view>
- </view>
- <!-- Step 2: 回答问题 -->
- <view v-if="step === 2" class="qd-step">
- <view class="qd-header">
- <text class="qd-title">{{ currentDimLabel }}</text>
- <text class="qd-progress">{{ currentQIndex + 1 }} / {{ currentQuestions.length }}</text>
- </view>
- <view class="qd-progress-bar">
- <view class="qd-progress-fill" :style="{ width: ((currentQIndex + 1) / currentQuestions.length * 100) + '%' }"></view>
- </view>
- <view class="qd-question-card">
- <text class="qd-q-text">{{ currentQuestion.question }}</text>
- <view class="qd-options">
- <view
- class="qd-option"
- :class="{ selected: currentAnswer === opt.value }"
- v-for="opt in currentQuestion.options"
- :key="opt.value"
- @click="currentAnswer = opt.value"
- >
- <text class="qd-opt-label">{{ opt.label }}</text>
- <text class="qd-opt-check" v-if="currentAnswer === opt.value">✓</text>
- </view>
- </view>
- </view>
- <view class="qd-footer">
- <button class="qd-btn qd-btn-prev" @click="prevQuestion" v-if="currentQIndex > 0">上一题</button>
- <button class="qd-btn" @click="nextQuestion" :disabled="!currentAnswer">
- {{ currentQIndex < currentQuestions.length - 1 ? '下一题' : '提交评估' }}
- </button>
- </view>
- </view>
- <!-- Step 3: 提交结果 -->
- <view v-if="step === 3" class="qd-step">
- <view class="qd-result" v-if="result">
- <text class="qd-result-icon">{{ resultIcon }}</text>
- <text class="qd-result-title">评估完成!</text>
- <text class="qd-result-score">{{ currentDimLabel }}:{{ result.score }}分</text>
- <view class="qd-result-level" :class="'level-' + (result.level || 'fair')">
- {{ levelText(result.level) }}
- </view>
- <text class="qd-result-tip" v-if="result.suggestion">{{ result.suggestion }}</text>
- </view>
- <view class="qd-footer">
- <button class="qd-btn" @click="goToDimensions">查看维度全景</button>
- <button class="qd-btn qd-btn-outline" @click="resetQuestionnaire">继续评估其他维度</button>
- </view>
- </view>
- </template>
- </view>
- </template>
- <script>
- import { submitDimensionQuestionnaire } from '@/utils/api'
- export default {
- data() {
- return {
- loading: false,
- step: 1,
- dimensions: [
- { code: 'growth', label: '生长发育', icon: '📈' },
- { code: 'sleep', label: '睡眠质量', icon: '🛌' },
- { code: 'vision', label: '视力健康', icon: '👁️' },
- { code: 'immunity', label: '免疫力', icon: '🛡️' },
- { code: 'nutrition', label: '营养均衡', icon: '🥗' },
- { code: 'gut', label: '肠胃健康', icon: '🌿' },
- { code: 'exercise', label: '运动活力', icon: '💪' }
- ],
- selectedDimension: '',
- questions: {
- growth: [
- { question: '孩子的身高体重在同龄人中属于?', options: [
- { label: '偏高/偏壮', value: 'tall' },
- { label: '正常范围', value: 'normal' },
- { label: '偏矮/偏瘦', value: 'short' },
- { label: '不清楚', value: 'unknown' }
- ]},
- { question: '过去半年身高增长情况?', options: [
- { label: '持续增长,速度正常', value: 'steady' },
- { label: '增长缓慢', value: 'slow' },
- { label: '没有明显变化', value: 'none' },
- { label: '没留意', value: 'unknown' }
- ]}
- ],
- sleep: [
- { question: '孩子平均每天睡眠时长?', options: [
- { label: '不足6小时', value: 'lt6' },
- { label: '6-8小时', value: '6to8' },
- { label: '8-10小时', value: '8to10' },
- { label: '超过10小时', value: 'gt10' }
- ]},
- { question: '孩子睡眠质量如何?', options: [
- { label: '很好,倒头就睡', value: 'good' },
- { label: '一般,偶尔翻来覆去', value: 'fair' },
- { label: '较差,频繁夜醒/难入睡', value: 'poor' }
- ]},
- { question: '孩子是否有规律的作息时间?', options: [
- { label: '作息很规律', value: 'regular' },
- { label: '基本规律', value: 'mostly' },
- { label: '不太规律', value: 'irregular' }
- ]}
- ],
- vision: [
- { question: '孩子目前是否佩戴眼镜?', options: [
- { label: '不戴眼镜', value: 'no' },
- { label: '已戴眼镜', value: 'yes' }
- ]},
- { question: '孩子每天的屏幕使用时间(手机/平板/电视)?', options: [
- { label: '少于1小时', value: 'lt1' },
- { label: '1-2小时', value: '1to2' },
- { label: '2-4小时', value: '2to4' },
- { label: '超过4小时', value: 'gt4' }
- ]}
- ],
- immunity: [
- { question: '过去半年孩子生病次数?', options: [
- { label: '0次,基本不生病', value: 'zero' },
- { label: '1-2次,偶尔感冒', value: 'few' },
- { label: '3-5次,经常生病', value: 'some' },
- { label: '6次以上,频繁生病', value: 'many' }
- ]},
- { question: '生病严重程度如何?', options: [
- { label: '从未住院,吃药就好', value: 'mild' },
- { label: '偶尔需要输液/雾化', value: 'moderate' },
- { label: '曾住院治疗', value: 'severe' }
- ]},
- { question: '孩子是否有过敏史?', options: [
- { label: '没有过敏', value: 'none' },
- { label: '有轻微过敏(花粉/尘螨等)', value: 'mild' },
- { label: '有食物/药物过敏', value: 'severe' }
- ]}
- ],
- nutrition: [
- { question: '孩子挑食/偏食程度?', options: [
- { label: '不挑食,什么都吃', value: 'none' },
- { label: '挑几样特定的食物', value: 'mild' },
- { label: '严重挑食,种类很少', value: 'severe' }
- ]},
- { question: '每周大概吃多少种不同食材?', options: [
- { label: '超过20种,饮食多样', value: 'diverse' },
- { label: '10-20种,比较丰富', value: 'moderate' },
- { label: '少于10种,比较单一', value: 'limited' }
- ]},
- { question: '孩子是否在使用营养补充剂?', options: [
- { label: '按医嘱使用多种补充剂', value: 'multiple' },
- { label: '使用维生素D/钙等基础补充剂', value: 'basic' },
- { label: '不使用任何补充剂', value: 'none' }
- ]}
- ],
- gut: [
- { question: '孩子最近消化舒适度如何?', options: [
- { label: '很好,消化顺畅', value: 'good' },
- { label: '一般,偶尔肚子不舒服', value: 'fair' },
- { label: '较差,经常腹痛/腹胀/腹泻', value: 'poor' }
- ]},
- { question: '孩子排便频率?', options: [
- { label: '每天1-2次,规律', value: 'regular' },
- { label: '隔天一次,基本规律', value: 'mostly' },
- { label: '不规律,经常便秘或腹泻', value: 'irregular' }
- ]},
- { question: '孩子是否有肠胃相关诊断?', options: [
- { label: '没有肠胃问题', value: 'none' },
- { label: '有偶发性消化不良', value: 'mild' },
- { label: '有确诊肠胃问题', value: 'diagnosed' }
- ]}
- ],
- exercise: [
- { question: '孩子每周运动频率?', options: [
- { label: '每天运动', value: 'daily' },
- { label: '每周3-5次', value: 'often' },
- { label: '每周1-2次', value: 'sometimes' },
- { label: '基本不运动', value: 'rarely' }
- ]},
- { question: '孩子每次运动时长?', options: [
- { label: '超过1小时', value: 'gt1h' },
- { label: '30分钟到1小时', value: '30to1h' },
- { label: '少于30分钟', value: 'lt30m' }
- ]},
- { question: '孩子喜欢的运动类型?', options: [
- { label: '球类/田径等竞技运动', value: 'competitive' },
- { label: '游泳/骑行等有氧运动', value: 'aerobic' },
- { label: '跳绳/体操等灵活性运动', value: 'flexibility' },
- { label: '不太喜欢运动', value: 'sedentary' }
- ]}
- ]
- },
- currentQIndex: 0,
- answers: {},
- currentAnswer: '',
- result: null
- }
- },
- computed: {
- currentDimLabel: function() {
- var dim = this.dimensions.find(function(d) { return d.code === this.selectedDimension }.bind(this))
- return dim ? dim.label : ''
- },
- currentQuestions: function() {
- return this.questions[this.selectedDimension] || []
- },
- currentQuestion: function() {
- return this.currentQuestions[this.currentQIndex] || {}
- },
- resultIcon: function() {
- if (!this.result) return '✅'
- var level = this.result.level
- if (level === 'excellent') return '🌟'
- if (level === 'good') return '👍'
- if (level === 'fair') return '💪'
- return '📋'
- }
- },
- methods: {
- startQuestions: function() {
- if (!this.selectedDimension) return
- this.currentQIndex = 0
- this.answers = {}
- this.currentAnswer = ''
- this.step = 2
- },
- nextQuestion: function() {
- if (!this.currentAnswer) return
- var key = 'q' + this.currentQIndex
- this.answers[key] = this.currentAnswer
- if (this.currentQIndex < this.currentQuestions.length - 1) {
- this.currentQIndex++
- this.currentAnswer = this.answers['q' + this.currentQIndex] || ''
- } else {
- this.submitAnswers()
- }
- },
- prevQuestion: function() {
- if (this.currentQIndex > 0) {
- var key = 'q' + this.currentQIndex
- this.answers[key] = this.currentAnswer
- this.currentQIndex--
- this.currentAnswer = this.answers['q' + this.currentQIndex] || ''
- }
- },
- submitAnswers: function() {
- var _this = this
- var answersList = []
- for (var i = 0; i < this.currentQuestions.length; i++) {
- var ansKey = 'q' + i
- answersList.push({
- question: this.currentQuestions[i].question,
- answer: _this.answers[ansKey] || ''
- })
- }
- var data = {
- memberId: this.activeChildId,
- dimension: this.selectedDimension,
- answers: answersList
- }
- _this.loading = true
- submitDimensionQuestionnaire(data).then(function(res) {
- _this.loading = false
- if (res.code === 200) {
- _this.result = {
- score: res.data && res.data.score ? res.data.score : 75,
- level: res.data && res.data.level ? res.data.level : 'good',
- suggestion: res.data && res.data.suggestion ? res.data.suggestion : ''
- }
- _this.step = 3
- } else {
- // Fallback: compute estimated score locally
- _this.result = {
- score: 70,
- level: 'good',
- suggestion: '可根据评估结果关注相关健康维度。'
- }
- _this.step = 3
- }
- }).catch(function() {
- _this.loading = false
- _this.result = { score: 70, level: 'good', suggestion: '提交成功,可根据评估结果关注相关健康维度。' }
- _this.step = 3
- })
- },
- levelText: function(level) {
- var map = { excellent: '优秀', good: '良好', fair: '一般', poor: '较差' }
- return map[level] || '一般'
- },
- goToDimensions: function() {
- uni.navigateTo({ url: '/pages/body/health-dimensions?childId=' + this.activeChildId })
- },
- resetQuestionnaire: function() {
- this.step = 1
- this.selectedDimension = ''
- this.currentQIndex = 0
- this.answers = {}
- this.currentAnswer = ''
- this.result = null
- }
- },
- onLoad: function(options) {
- this.activeChildId = options.childId || ''
- }
- }
- </script>
- <style scoped>
- .qd-container {
- min-height: 100vh;
- background: #F5FAFE;
- padding: 20rpx 30rpx 100rpx;
- }
- .qd-loading {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 60vh;
- }
- .loading-text {
- font-size: 28rpx;
- color: #999;
- }
- .qd-step {
- animation: fadeIn 0.3s ease;
- }
- @keyframes fadeIn {
- from { opacity: 0; transform: translateY(10rpx); }
- to { opacity: 1; transform: translateY(0); }
- }
- .qd-header {
- text-align: center;
- padding: 30rpx 0;
- }
- .qd-title {
- font-size: 36rpx;
- font-weight: 600;
- color: #333;
- }
- .qd-desc {
- font-size: 26rpx;
- color: #888;
- margin-top: 10rpx;
- }
- .qd-dim-list {
- display: flex;
- flex-wrap: wrap;
- gap: 20rpx;
- margin: 20rpx 0;
- }
- .qd-dim-item {
- width: 45%;
- background: #fff;
- border-radius: 16rpx;
- padding: 30rpx 20rpx;
- display: flex;
- flex-direction: column;
- align-items: center;
- border: 2rpx solid #eee;
- position: relative;
- box-sizing: border-box;
- }
- .qd-dim-item.active {
- border-color: #4A9BD7;
- background: #F0F8FF;
- }
- .qd-dim-icon {
- font-size: 48rpx;
- margin-bottom: 10rpx;
- }
- .qd-dim-label {
- font-size: 28rpx;
- color: #333;
- font-weight: 500;
- }
- .qd-dim-check {
- position: absolute;
- top: 10rpx;
- right: 10rpx;
- width: 36rpx;
- height: 36rpx;
- background: #4A9BD7;
- color: #fff;
- border-radius: 50%;
- text-align: center;
- line-height: 36rpx;
- font-size: 22rpx;
- }
- .qd-progress {
- font-size: 26rpx;
- color: #4A9BD7;
- margin-top: 10rpx;
- }
- .qd-progress-bar {
- height: 6rpx;
- background: #E8E8E8;
- border-radius: 3rpx;
- margin: 20rpx 0;
- }
- .qd-progress-fill {
- height: 100%;
- background: linear-gradient(90deg, #4A9BD7, #63B3ED);
- border-radius: 3rpx;
- transition: width 0.3s ease;
- }
- .qd-question-card {
- background: #fff;
- border-radius: 20rpx;
- padding: 40rpx 30rpx;
- margin: 20rpx 0;
- box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
- }
- .qd-q-text {
- font-size: 32rpx;
- font-weight: 500;
- color: #333;
- line-height: 1.5;
- }
- .qd-options {
- margin-top: 30rpx;
- }
- .qd-option {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 24rpx 20rpx;
- border: 2rpx solid #eee;
- border-radius: 12rpx;
- margin-bottom: 16rpx;
- transition: all 0.2s;
- }
- .qd-option.selected {
- border-color: #4A9BD7;
- background: #F0F8FF;
- }
- .qd-opt-label {
- font-size: 28rpx;
- color: #333;
- flex: 1;
- }
- .qd-opt-check {
- width: 36rpx;
- height: 36rpx;
- background: #4A9BD7;
- color: #fff;
- border-radius: 50%;
- text-align: center;
- line-height: 36rpx;
- font-size: 22rpx;
- }
- .qd-footer {
- display: flex;
- gap: 20rpx;
- margin-top: 40rpx;
- justify-content: center;
- }
- .qd-btn {
- flex: 1;
- height: 88rpx;
- line-height: 88rpx;
- background: linear-gradient(135deg, #4A9BD7, #63B3ED);
- color: #fff;
- font-size: 32rpx;
- border-radius: 44rpx;
- border: none;
- text-align: center;
- }
- .qd-btn[disabled] {
- opacity: 0.5;
- }
- .qd-btn-prev {
- flex: 0.4;
- background: #f0f0f0;
- color: #666;
- }
- .qd-btn-outline {
- background: #fff;
- color: #4A9BD7;
- border: 2rpx solid #4A9BD7;
- }
- .qd-result {
- text-align: center;
- padding: 60rpx 0;
- }
- .qd-result-icon {
- font-size: 80rpx;
- }
- .qd-result-title {
- font-size: 40rpx;
- font-weight: 600;
- color: #333;
- margin: 20rpx 0;
- }
- .qd-result-score {
- font-size: 32rpx;
- color: #666;
- margin-bottom: 20rpx;
- }
- .qd-result-level {
- font-size: 28rpx;
- padding: 8rpx 24rpx;
- border-radius: 20rpx;
- display: inline-block;
- margin-bottom: 20rpx;
- }
- .qd-result-level.level-excellent { background: #E8F5E9; color: #2E7D32; }
- .qd-result-level.level-good { background: #E3F2FD; color: #1565C0; }
- .qd-result-level.level-fair { background: #FFF8E1; color: #F57F17; }
- .qd-result-level.level-poor { background: #FFEBEE; color: #C62828; }
- .qd-result-tip {
- font-size: 28rpx;
- color: #888;
- margin-top: 20rpx;
- line-height: 1.6;
- padding: 0 30rpx;
- }
- </style>
|