|
|
@@ -171,8 +171,8 @@
|
|
|
<view class="back-link" @click="step = 3">← 返回健康问卷</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 成功 -->
|
|
|
- <view v-if="taskSubmitted" class="success-overlay">
|
|
|
+ <!-- 成功(非查看模式) -->
|
|
|
+ <view v-if="taskSubmitted && !viewMode" class="success-overlay">
|
|
|
<view class="success-card">
|
|
|
<text class="success-icon">✅</text>
|
|
|
<text class="success-title">方案已确认</text>
|
|
|
@@ -180,6 +180,26 @@
|
|
|
<button class="btn-done" @click="goBack">完成</button>
|
|
|
</view>
|
|
|
</view>
|
|
|
+
|
|
|
+ <!-- 查看已有方案(有 planId 时显示) -->
|
|
|
+ <view class="section plan-view-section" v-if="viewMode && planDetail">
|
|
|
+ <view class="section-header">
|
|
|
+ <text class="section-title">📋 健康方案</text>
|
|
|
+ </view>
|
|
|
+ <view class="plan-meta">
|
|
|
+ <text class="plan-meta-item">目标:{{ planDetail.goal || '—' }}</text>
|
|
|
+ <text class="plan-meta-item" v-if="planDetail.memberName">成员:{{ planDetail.memberName }}</text>
|
|
|
+ <text class="plan-meta-item" v-if="planDetail.createdAt">制定于 {{ formatTime(planDetail.createdAt) }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="plan-preview" v-if="planDetail.planContent">
|
|
|
+ <view class="plan-preview-label">方案详情</view>
|
|
|
+ <text class="plan-preview-text">{{ planDetail.planContent }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="plan-actions">
|
|
|
+ <button class="btn-edit" @click="reCreate">重新制定方案</button>
|
|
|
+ <button class="btn-done plan-done-btn" @click="goBack">返回</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
@@ -203,7 +223,12 @@ export default {
|
|
|
taskSubmittedCount: 0,
|
|
|
healthStatus: null,
|
|
|
dietPrefs: null,
|
|
|
- autoExecute: false
|
|
|
+ autoExecute: false,
|
|
|
+ // 查看模式
|
|
|
+ planId: null,
|
|
|
+ planDetail: null,
|
|
|
+ isPaidAnnualFamily: false,
|
|
|
+ recreateUsed: false
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -213,6 +238,17 @@ export default {
|
|
|
canConfirmTasks: function() {
|
|
|
return this.parsedTasks.length > 0 && this.parsedTasks.every(function(t) { return t.executorId })
|
|
|
},
|
|
|
+ /** 是否处于查看模式(有 planId 参数) */
|
|
|
+ viewMode: function() {
|
|
|
+ return !!this.planId
|
|
|
+ },
|
|
|
+ /** 是否付费年度家庭会员(不受重做次数限制) */
|
|
|
+ canRecreate: function() {
|
|
|
+ if (this.isPaidAnnualFamily) return true
|
|
|
+ // 非付费会员:仅可重新制定一次(通过 localStorage 记录)
|
|
|
+ var key = 'health_plan_recreate_used_' + (this.planDetail && this.planDetail.familyId ? this.planDetail.familyId : '')
|
|
|
+ return !uni.getStorageSync(key)
|
|
|
+ },
|
|
|
healthStatusSummary: function() {
|
|
|
var d = this.healthStatus || {}
|
|
|
var list = []
|
|
|
@@ -237,8 +273,14 @@ export default {
|
|
|
}
|
|
|
this.subjectId = options.subjectId || ''
|
|
|
this.autoExecute = options.autoExecute === '1'
|
|
|
+ this.planId = options.planId ? parseInt(options.planId) : null
|
|
|
this.loadExecutors()
|
|
|
this.loadHealthContext()
|
|
|
+ // 查看已有方案模式
|
|
|
+ if (this.planId) {
|
|
|
+ this.loadPlanDetail()
|
|
|
+ this.loadMembership()
|
|
|
+ }
|
|
|
// 自动出方案模式:等待异步加载完成后执行
|
|
|
if (this.autoExecute) {
|
|
|
var self = this
|
|
|
@@ -249,6 +291,8 @@ export default {
|
|
|
},
|
|
|
onShow: function() {
|
|
|
this.loadHealthContext()
|
|
|
+ // 每次显示时刷新会员状态(可能刚续费)
|
|
|
+ if (this.planId) this.loadMembership()
|
|
|
},
|
|
|
methods: {
|
|
|
getMemberKey: function(m, idx) { return m.memberId || idx },
|
|
|
@@ -278,6 +322,63 @@ export default {
|
|
|
}
|
|
|
}).catch(function() { self.dietPrefs = null })
|
|
|
},
|
|
|
+ /** 查看模式:加载已有方案详情 */
|
|
|
+ loadPlanDetail: function() {
|
|
|
+ var self = this
|
|
|
+ var api = require('../../utils/api.js')
|
|
|
+ api.getHealthPlanDetail({ planId: this.planId }).then(function(res) {
|
|
|
+ if (res && res.code === 200 && res.data) {
|
|
|
+ self.planDetail = res.data
|
|
|
+ // 还原目标
|
|
|
+ self.userGoal = res.data.goal || ''
|
|
|
+ // 还原执行成员
|
|
|
+ if (res.data.memberIds) {
|
|
|
+ self.selectedMemberIds = res.data.memberIds.split(',').filter(function(id) { return id })
|
|
|
+ }
|
|
|
+ // 解析方案内容为任务(只读展示)
|
|
|
+ self.parseTasksFromPlan(res.data.planContent)
|
|
|
+ self.planContent = res.data.planContent
|
|
|
+ }
|
|
|
+ }).catch(function() {
|
|
|
+ uni.showToast({ title: '方案加载失败', icon: 'none' })
|
|
|
+ setTimeout(function() { uni.navigateBack() }, 1500)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /** 加载会员信息判断是否付费年度家庭会员 */
|
|
|
+ loadMembership: function() {
|
|
|
+ var self = this
|
|
|
+ var api = require('../../utils/api.js')
|
|
|
+ api.getMyMembership().then(function(res) {
|
|
|
+ if (res && res.code === 200 && res.data && res.data.membership) {
|
|
|
+ var m = res.data.membership
|
|
|
+ self.isPaidAnnualFamily = !!(m.isActive && (m.levelCode === 'ANNUAL_FAMILY' || m.levelCode === 'ANNUAL'))
|
|
|
+ }
|
|
|
+ }).catch(function() {})
|
|
|
+ },
|
|
|
+ /** 重新制定:检查会员限制后进入新建流程 */
|
|
|
+ reCreate: function() {
|
|
|
+ if (!this.canRecreate) {
|
|
|
+ uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '非付费会员每月仅限重新制定一次,升级年度家庭会员可无限次重做',
|
|
|
+ showCancel: false,
|
|
|
+ confirmText: '知道了'
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 标记已使用一次(非付费会员)
|
|
|
+ if (!this.isPaidAnnualFamily) {
|
|
|
+ var key = 'health_plan_recreate_used_' + (this.planDetail && this.planDetail.familyId ? this.planDetail.familyId : '')
|
|
|
+ if (key) uni.setStorageSync(key, true)
|
|
|
+ }
|
|
|
+ // 重置为新建模式
|
|
|
+ this.step = 1
|
|
|
+ this.planId = null
|
|
|
+ this.planDetail = null
|
|
|
+ this.taskSubmitted = false
|
|
|
+ this.parsedTasks = []
|
|
|
+ this.planContent = ''
|
|
|
+ },
|
|
|
toggleMember: function(memberId) {
|
|
|
var idx = this.selectedMemberIds.indexOf(memberId)
|
|
|
if (idx >= 0) this.selectedMemberIds.splice(idx, 1)
|
|
|
@@ -927,4 +1028,36 @@ export default {
|
|
|
.btn-step-next {
|
|
|
width: 100%;
|
|
|
}
|
|
|
+
|
|
|
+/* ===== 方案查看模式 ===== */
|
|
|
+.plan-view-section { margin-top: 0; }
|
|
|
+.plan-meta {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 6rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ padding: 16rpx 20rpx;
|
|
|
+ background: #FFF7ED;
|
|
|
+ border-radius: 12rpx;
|
|
|
+}
|
|
|
+.plan-meta-item {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #92400E;
|
|
|
+}
|
|
|
+.plan-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 16rpx;
|
|
|
+ margin-top: 24rpx;
|
|
|
+}
|
|
|
+.plan-done-btn {
|
|
|
+ flex: 1;
|
|
|
+ height: 80rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ background: #F97316;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 28rpx;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ border: none;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
</style>
|