|
|
@@ -0,0 +1,283 @@
|
|
|
+<template>
|
|
|
+ <view class="screen-container">
|
|
|
+ <view class="screen-header">
|
|
|
+ <text class="screen-title">心理状态自评</text>
|
|
|
+ <text class="screen-subtitle">定期评估,了解自己的心理状态</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section" v-if="!currentScreen">
|
|
|
+ <view class="scale-card" @click="startScreen('PHQ9')">
|
|
|
+ <view class="scale-icon-wrap" style="background:#FFF0F5">
|
|
|
+ <text class="scale-icon">🧠</text>
|
|
|
+ </view>
|
|
|
+ <view class="scale-info">
|
|
|
+ <text class="scale-name">PHQ-9 抑郁筛查</text>
|
|
|
+ <text class="scale-desc">过去两周,您是否被以下问题困扰?</text>
|
|
|
+ </view>
|
|
|
+ <text class="scale-arrow">></text>
|
|
|
+ </view>
|
|
|
+ <view class="scale-card" @click="startScreen('GAD7')">
|
|
|
+ <view class="scale-icon-wrap" style="background:#F0F4FF">
|
|
|
+ <text class="scale-icon">💨</text>
|
|
|
+ </view>
|
|
|
+ <view class="scale-info">
|
|
|
+ <text class="scale-name">GAD-7 焦虑筛查</text>
|
|
|
+ <text class="scale-desc">过去两周,您是否被以下问题困扰?</text>
|
|
|
+ </view>
|
|
|
+ <text class="scale-arrow">></text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section" v-if="currentScreen">
|
|
|
+ <view class="quiz-header">
|
|
|
+ <text class="quiz-title">{{ currentScreen === 'PHQ9' ? 'PHQ-9 抑郁筛查' : 'GAD-7 焦虑筛查' }}</text>
|
|
|
+ <text class="quiz-progress">{{ currentStep + 1 }}/{{ questions.length }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="progress-track">
|
|
|
+ <view class="progress-fill" :style="{ width: ((currentStep + 1) / questions.length * 100) + '%' }"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="question-card">
|
|
|
+ <text class="question-num">Q{{ currentStep + 1 }}</text>
|
|
|
+ <text class="question-text">{{ questions[currentStep] }}</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="options-list">
|
|
|
+ <view
|
|
|
+ v-for="(opt, oi) in answerOptions"
|
|
|
+ :key="oi"
|
|
|
+ :class="['option-btn', answers[currentStep] === oi ? 'option-active' : '']"
|
|
|
+ @click="selectAnswer(oi)">
|
|
|
+ <view :class="['option-radio', answers[currentStep] === oi ? 'radio-checked' : '']">
|
|
|
+ <view v-if="answers[currentStep] === oi" class="radio-dot"></view>
|
|
|
+ </view>
|
|
|
+ <text class="option-text">{{ opt }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="quiz-nav">
|
|
|
+ <button class="nav-btn prev-btn" v-if="currentStep > 0" @click="prevStep">上一题</button>
|
|
|
+ <button class="nav-btn next-btn" v-if="currentStep < questions.length - 1" @click="nextStep">下一题</button>
|
|
|
+ <button class="nav-btn submit-btn" v-if="currentStep === questions.length - 1" @click="submitScreen">提交问卷</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section" v-if="result">
|
|
|
+ <view class="result-header">
|
|
|
+ <text class="result-type">{{ currentScreen === 'PHQ9' ? 'PHQ-9 抑郁筛查' : 'GAD-7 焦虑筛查' }}</text>
|
|
|
+ <view :class="['result-score-circle', severityClass]">
|
|
|
+ <text class="result-score">{{ result.totalScore }}</text>
|
|
|
+ <text class="result-score-label">分</text>
|
|
|
+ </view>
|
|
|
+ <text :class="['result-severity', severityClass]">{{ severityLabel }}</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="suggestion-card">
|
|
|
+ <text class="suggestion-title">评估建议</text>
|
|
|
+ <text class="suggestion-text">{{ result.suggestions }}</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="risk-section" v-if="result.riskFlags && result.riskFlags.length > 0">
|
|
|
+ <view class="risk-item" v-for="flag in result.riskFlags" :key="flag">
|
|
|
+ <text class="risk-icon">⚠️</text>
|
|
|
+ <text class="risk-text">{{ riskFlagLabel(flag) }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="crisis-banner" v-if="showCrisisBanner">
|
|
|
+ <text class="crisis-title">🚨 需要帮助?</text>
|
|
|
+ <text class="crisis-phone">全国心理危机干预热线</text>
|
|
|
+ <text class="crisis-number">400-161-9995</text>
|
|
|
+ <text class="crisis-hint">24小时 · 免费 · 专业</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="result-actions">
|
|
|
+ <button class="action-btn primary-btn" @click="goTrend">查看情绪趋势</button>
|
|
|
+ <button class="action-btn secondary-btn" @click="resetScreen">再测一次</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="loading-mask" v-if="submitting">
|
|
|
+ <view class="loading-box">
|
|
|
+ <text class="loading-text">提交中...</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import config from '../../config'
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ currentScreen: null,
|
|
|
+ currentStep: 0,
|
|
|
+ answers: [],
|
|
|
+ submitting: false,
|
|
|
+ result: null,
|
|
|
+ phq9Questions: [
|
|
|
+ '\u505A\u4E8B\u65F6\u63D0\u4E0D\u8D77\u52B2\u6216\u6CA1\u6709\u5174\u8DA3',
|
|
|
+ '\u611F\u5230\u5FC3\u60C5\u4F4E\u843D\u3001\u6CAE\u4E27\u6216\u7EDD\u671B',
|
|
|
+ '\u5165\u7761\u56F0\u96BE\u3001\u7761\u4E0D\u5B89\u7A33\u6216\u7761\u7720\u8FC7\u591A',
|
|
|
+ '\u611F\u89C9\u75B2\u4E4F\u6216\u6CA1\u6709\u6D3B\u529B',
|
|
|
+ '\u98DF\u6B32\u4E0D\u632F\u6216\u5403\u592A\u591A',
|
|
|
+ '\u89C9\u5F97\u81EA\u5DF1\u5F88\u7CDF\u2014\u2014\u6216\u89C9\u5F97\u81EA\u5DF1\u5F88\u5931\u8D25',
|
|
|
+ '\u5BF9\u4E8B\u7269\u4E13\u6CE8\u6709\u56F0\u96BE',
|
|
|
+ '\u884C\u52A8\u6216\u8BF4\u8BDD\u901F\u5EA6\u7F13\u6162',
|
|
|
+ '\u6709\u4E0D\u5982\u6B7B\u6389\u6216\u4F24\u5BB3\u81EA\u5DF1\u7684\u5FF5\u5934'
|
|
|
+ ],
|
|
|
+ gad7Questions: [
|
|
|
+ '\u611F\u5230\u7D27\u5F20\u3001\u7126\u8651\u6216\u70E6\u8E81',
|
|
|
+ '\u65E0\u6CD5\u505C\u6B62\u6216\u63A7\u5236\u62C5\u5FE7',
|
|
|
+ '\u5BF9\u5404\u79CD\u5404\u6837\u7684\u4E8B\u60C5\u62C5\u5FE7\u8FC7\u591A',
|
|
|
+ '\u5F88\u96BE\u653E\u677E\u4E0B\u6765',
|
|
|
+ '\u7531\u4E8E\u4E0D\u5B89\u800C\u65E0\u6CD5\u9759\u5750',
|
|
|
+ '\u53D8\u5F97\u5BB9\u6613\u70E6\u607C\u6216\u6025\u8E81',
|
|
|
+ '\u611F\u5230\u5BB3\u6015\uFF0C\u597D\u50CF\u53EF\u80FD\u53D1\u751F\u53EF\u6015\u7684\u4E8B\u60C5'
|
|
|
+ ],
|
|
|
+ answerOptions: ['\u5B8C\u5168\u4E0D\u4F1A', '\u597D\u51E0\u5929', '\u4E00\u534A\u4EE5\u4E0A\u7684\u5929\u6570', '\u51E0\u4E4E\u6BCF\u5929'],
|
|
|
+ riskFlagLabels: {
|
|
|
+ 'suicide_ideation': '存在自杀/自伤相关念头,请立即寻求帮助',
|
|
|
+ 'core_depression_symptoms': '核心抑郁症状明显,建议关注',
|
|
|
+ 'core_anxiety_symptoms': '核心焦虑症状明显,建议关注'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ computed: {
|
|
|
+ questions() {
|
|
|
+ if (this.currentScreen === 'PHQ9') return this.phq9Questions
|
|
|
+ if (this.currentScreen === 'GAD7') return this.gad7Questions
|
|
|
+ return []
|
|
|
+ },
|
|
|
+ severityLabel() {
|
|
|
+ if (!this.result) return ''
|
|
|
+ var map = { 'none': '状态良好', 'mild': '轻度', 'moderate': '中度', 'moderately_severe': '中重度', 'severe': '重度' }
|
|
|
+ return map[this.result.severityLevel] || this.result.severityLevel
|
|
|
+ },
|
|
|
+ severityClass() {
|
|
|
+ if (!this.result) return ''
|
|
|
+ var map = { 'none': 'severity-good', 'mild': 'severity-mild', 'moderate': 'severity-moderate', 'moderately_severe': 'severity-moderate', 'severe': 'severity-severe' }
|
|
|
+ return map[this.result.severityLevel] || ''
|
|
|
+ },
|
|
|
+ showCrisisBanner() {
|
|
|
+ return this.result && this.result.riskFlags && this.result.riskFlags.indexOf('suicide_ideation') !== -1
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ startScreen(type) {
|
|
|
+ this.currentScreen = type
|
|
|
+ this.currentStep = 0
|
|
|
+ this.answers = []
|
|
|
+ this.result = null
|
|
|
+ var count = type === 'PHQ9' ? 9 : 7
|
|
|
+ for (var i = 0; i < count; i++) { this.answers.push(-1) }
|
|
|
+ },
|
|
|
+ selectAnswer(oi) {
|
|
|
+ var newAnswers = this.answers.slice()
|
|
|
+ newAnswers[this.currentStep] = oi
|
|
|
+ this.answers = newAnswers
|
|
|
+ },
|
|
|
+ nextStep() {
|
|
|
+ if (this.answers[this.currentStep] === -1) { uni.showToast({ title: '请先选择一项', icon: 'none' }); return }
|
|
|
+ this.currentStep++
|
|
|
+ },
|
|
|
+ prevStep() {
|
|
|
+ if (this.currentStep > 0) this.currentStep--
|
|
|
+ },
|
|
|
+ submitScreen() {
|
|
|
+ for (var i = 0; i < this.answers.length; i++) {
|
|
|
+ if (this.answers[i] === -1) { uni.showToast({ title: '请回答所有问题', icon: 'none' }); this.currentStep = i; return }
|
|
|
+ }
|
|
|
+ this.submitting = true
|
|
|
+ const app = getApp()
|
|
|
+ const childId = app.globalData.currentChildId
|
|
|
+ uni.request({
|
|
|
+ url: config.API_BASE_URL + '/api/mind/screening/submit',
|
|
|
+ method: 'POST',
|
|
|
+ data: { childId, screenType: this.currentScreen, answers: this.answers },
|
|
|
+ success: (res) => {
|
|
|
+ this.submitting = false
|
|
|
+ if (res.data && res.data.code === 200) { this.result = res.data.data }
|
|
|
+ else { uni.showToast({ title: (res.data && res.data.message) || '提交失败', icon: 'none' }) }
|
|
|
+ },
|
|
|
+ fail: () => { this.submitting = false; uni.showToast({ title: '网络错误', icon: 'none' }) }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ resetScreen() { this.currentScreen = null; this.currentStep = 0; this.answers = []; this.result = null },
|
|
|
+ goTrend() { uni.navigateTo({ url: '/pages/mind-detail/emotion-trend' }) },
|
|
|
+ riskFlagLabel(flag) { return this.riskFlagLabels[flag] || flag }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.screen-container { min-height: 100vh; background: linear-gradient(180deg, #F0F4FF 0%, #FFFFFF 100%); padding-bottom: 40rpx; }
|
|
|
+.screen-header { padding: 40rpx 32rpx 20rpx; }
|
|
|
+.screen-title { font-size: 36rpx; font-weight: 700; color: #333; display: block; }
|
|
|
+.screen-subtitle { font-size: 26rpx; color: #999; margin-top: 8rpx; display: block; }
|
|
|
+.section { margin: 20rpx 32rpx; background: #fff; border-radius: 20rpx; padding: 28rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04); }
|
|
|
+.scale-card { display: flex; align-items: center; padding: 24rpx; background: #FAFAFA; border-radius: 16rpx; margin-bottom: 16rpx; gap: 20rpx; }
|
|
|
+.scale-icon-wrap { width: 72rpx; height: 72rpx; border-radius: 36rpx; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
|
|
+.scale-icon { font-size: 36rpx; }
|
|
|
+.scale-info { flex: 1; }
|
|
|
+.scale-name { font-size: 28rpx; font-weight: 600; color: #333; display: block; }
|
|
|
+.scale-desc { font-size: 22rpx; color: #999; margin-top: 4rpx; display: block; }
|
|
|
+.scale-arrow { font-size: 28rpx; color: #ccc; }
|
|
|
+.quiz-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16rpx; }
|
|
|
+.quiz-title { font-size: 28rpx; font-weight: 600; color: #333; }
|
|
|
+.quiz-progress { font-size: 24rpx; color: #999; }
|
|
|
+.progress-track { height: 6rpx; background: #F0F0F0; border-radius: 3rpx; margin-bottom: 24rpx; overflow: hidden; }
|
|
|
+.progress-fill { height: 100%; background: linear-gradient(90deg, #6366F1, #8B5CF6); border-radius: 3rpx; transition: width 0.3s; }
|
|
|
+.question-card { background: #F8F6FF; border-radius: 16rpx; padding: 24rpx; margin-bottom: 24rpx; }
|
|
|
+.question-num { font-size: 22rpx; color: #8B5CF6; font-weight: 600; display: block; margin-bottom: 8rpx; }
|
|
|
+.question-text { font-size: 30rpx; color: #333; line-height: 1.5; }
|
|
|
+.options-list { display: flex; flex-direction: column; gap: 12rpx; }
|
|
|
+.option-btn { display: flex; align-items: center; padding: 20rpx 24rpx; border-radius: 14rpx; border: 2rpx solid #F0F0F0; gap: 16rpx; }
|
|
|
+.option-active { border-color: #8B5CF6; background: #F8F6FF; }
|
|
|
+.option-radio { width: 40rpx; height: 40rpx; border-radius: 20rpx; border: 3rpx solid #D0D0D0; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
|
|
+.radio-checked { border-color: #8B5CF6; }
|
|
|
+.radio-dot { width: 22rpx; height: 22rpx; border-radius: 11rpx; background: #8B5CF6; }
|
|
|
+.option-text { font-size: 28rpx; color: #444; }
|
|
|
+.option-active .option-text { color: #333; font-weight: 500; }
|
|
|
+.quiz-nav { display: flex; gap: 16rpx; margin-top: 32rpx; }
|
|
|
+.nav-btn { flex: 1; height: 80rpx; line-height: 80rpx; border-radius: 40rpx; font-size: 28rpx; text-align: center; }
|
|
|
+.prev-btn { background: #F0F0F0; color: #666; }
|
|
|
+.next-btn { background: #6366F1; color: #fff; }
|
|
|
+.submit-btn { background: linear-gradient(135deg, #6366F1, #8B5CF6); color: #fff; }
|
|
|
+.result-header { display: flex; flex-direction: column; align-items: center; padding: 20rpx 0; }
|
|
|
+.result-type { font-size: 24rpx; color: #999; margin-bottom: 16rpx; }
|
|
|
+.result-score-circle { width: 120rpx; height: 120rpx; border-radius: 60rpx; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 12rpx; }
|
|
|
+.result-score { font-size: 48rpx; font-weight: 700; color: #fff; line-height: 1; }
|
|
|
+.result-score-label { font-size: 20rpx; color: rgba(255,255,255,0.8); margin-top: 2rpx; }
|
|
|
+.result-severity { font-size: 30rpx; font-weight: 600; }
|
|
|
+.severity-good { background: #10B981; color: #10B981; }
|
|
|
+.severity-mild { background: #F59E0B; color: #F59E0B; }
|
|
|
+.severity-moderate { background: #FF8C42; color: #FF8C42; }
|
|
|
+.severity-severe { background: #EF4444; color: #EF4444; }
|
|
|
+.result-score-circle.severity-good { background: #10B981; }
|
|
|
+.result-score-circle.severity-mild { background: #F59E0B; }
|
|
|
+.result-score-circle.severity-moderate { background: #FF8C42; }
|
|
|
+.result-score-circle.severity-severe { background: #EF4444; }
|
|
|
+.suggestion-card { background: #F0FFF4; border-radius: 14rpx; padding: 20rpx; margin-top: 16rpx; }
|
|
|
+.suggestion-title { font-size: 24rpx; color: #10B981; font-weight: 600; display: block; margin-bottom: 8rpx; }
|
|
|
+.suggestion-text { font-size: 26rpx; color: #555; line-height: 1.6; }
|
|
|
+.risk-section { margin-top: 16rpx; }
|
|
|
+.risk-item { display: flex; align-items: flex-start; gap: 8rpx; padding: 12rpx 16rpx; background: #FFF5F5; border-radius: 12rpx; margin-bottom: 8rpx; }
|
|
|
+.risk-icon { font-size: 24rpx; flex-shrink: 0; }
|
|
|
+.risk-text { font-size: 24rpx; color: #E53E3E; line-height: 1.5; }
|
|
|
+.crisis-banner { margin-top: 16rpx; padding: 24rpx; background: linear-gradient(135deg, #FF6B6B, #E53E3E); border-radius: 16rpx; text-align: center; }
|
|
|
+.crisis-title { font-size: 28rpx; color: #fff; font-weight: 700; display: block; }
|
|
|
+.crisis-phone { font-size: 22rpx; color: rgba(255,255,255,0.8); margin-top: 12rpx; display: block; }
|
|
|
+.crisis-number { font-size: 40rpx; color: #fff; font-weight: 700; margin-top: 4rpx; display: block; letter-spacing: 2rpx; }
|
|
|
+.crisis-hint { font-size: 20rpx; color: rgba(255,255,255,0.7); margin-top: 4rpx; display: block; }
|
|
|
+.result-actions { display: flex; gap: 16rpx; margin-top: 28rpx; }
|
|
|
+.action-btn { flex: 1; height: 76rpx; line-height: 76rpx; border-radius: 38rpx; font-size: 26rpx; text-align: center; }
|
|
|
+.primary-btn { background: #FF6B9D; color: #fff; }
|
|
|
+.secondary-btn { background: #F0F0F0; color: #666; }
|
|
|
+.loading-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.3); display: flex; align-items: center; justify-content: center; z-index: 999; }
|
|
|
+.loading-box { background: #fff; padding: 40rpx 60rpx; border-radius: 20rpx; }
|
|
|
+.loading-text { font-size: 28rpx; color: #666; }
|
|
|
+</style>
|