|
|
@@ -147,23 +147,46 @@
|
|
|
|
|
|
<!-- 健康指标(舌诊时隐藏,使用上方舌象指标卡片) -->
|
|
|
<view class="card" v-if="payload.type !== 'tongue' && payload.indicators && payload.indicators.length">
|
|
|
- <view class="card-title">健康指标 ({{ payload.indicators.length }})</view>
|
|
|
- <view class="indicator-item" v-for="(ind, idx) in payload.indicators" :key="idx">
|
|
|
- <view class="ind-header">
|
|
|
- <input class="ind-name" v-model="payload.indicators[idx].name" />
|
|
|
- <input class="ind-value" v-model="payload.indicators[idx].value" />
|
|
|
+ <view class="card-title">
|
|
|
+ <text>健康指标 ({{ payload.indicators.length }})</text>
|
|
|
+ <view class="card-title-actions">
|
|
|
+ <text class="expand-all-btn" @click="toggleAllGroups(true)">全部展开</text>
|
|
|
+ <text class="expand-all-btn" @click="toggleAllGroups(false)">全部折叠</text>
|
|
|
</view>
|
|
|
- <view class="ind-detail" v-if="payload.indicators[idx].unit || payload.indicators[idx].referenceRange">
|
|
|
- <text class="ind-ref" v-if="payload.indicators[idx].referenceRange">参考: {{ payload.indicators[idx].referenceRange }}</text>
|
|
|
- <text class="ind-unit" v-if="payload.indicators[idx].unit">{{ payload.indicators[idx].unit }}</text>
|
|
|
- </view>
|
|
|
- <view class="ind-symptoms" v-if="payload.indicators[idx].symptoms">
|
|
|
- <text class="ind-symptom-label">症状:</text>
|
|
|
- <input class="ind-symptom-input" v-model="payload.indicators[idx].symptoms" />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 按指标类型分组折叠 -->
|
|
|
+ <view class="indicator-group" v-for="(group, gIdx) in indicatorGroups" :key="gIdx">
|
|
|
+ <view class="indicator-group-header" @click="toggleGroup(gIdx)">
|
|
|
+ <view class="indicator-group-header-left">
|
|
|
+ <text class="indicator-group-arrow" :class="{ 'arrow-open': groupExpandList[gIdx] }">›</text>
|
|
|
+ <text class="indicator-group-name">{{ group.category }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="indicator-group-header-right">
|
|
|
+ <text class="indicator-group-need" v-if="group.needCount > 0">{{ group.needCount }} 项需处理</text>
|
|
|
+ <text class="indicator-group-count">{{ group.items.length }} 项</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <view class="ind-status-row">
|
|
|
- <view class="status-tag" :class="'status-' + (payload.indicators[idx].status || 'normal')">
|
|
|
- {{ statusText(payload.indicators[idx].status) }}
|
|
|
+
|
|
|
+ <view class="indicator-group-body" v-if="groupExpandList[gIdx]">
|
|
|
+ <view class="indicator-item" v-for="(ind, idx) in group.items" :key="idx">
|
|
|
+ <view class="ind-header">
|
|
|
+ <input class="ind-name" v-model="ind.indicatorName" />
|
|
|
+ <input class="ind-value" v-model="ind.indicatorValue" />
|
|
|
+ </view>
|
|
|
+ <view class="ind-detail" v-if="ind.unit || ind.refRange">
|
|
|
+ <text class="ind-ref" v-if="ind.refRange">参考: {{ ind.refRange }}</text>
|
|
|
+ <text class="ind-unit" v-if="ind.unit">{{ ind.unit }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="ind-symptoms" v-if="ind.symptoms">
|
|
|
+ <text class="ind-symptom-label">症状:</text>
|
|
|
+ <input class="ind-symptom-input" v-model="ind.symptoms" />
|
|
|
+ </view>
|
|
|
+ <view class="ind-status-row">
|
|
|
+ <view class="status-tag" :class="'status-' + (ind.status || 'normal')">
|
|
|
+ {{ statusText(ind.status) }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
@@ -256,7 +279,9 @@ export default {
|
|
|
age: ''
|
|
|
},
|
|
|
creatingMember: false,
|
|
|
- createdMemberId: null
|
|
|
+ createdMemberId: null,
|
|
|
+ // 指标分组折叠状态(按分组下标,默认全部折叠)
|
|
|
+ groupExpandList: []
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -286,6 +311,27 @@ export default {
|
|
|
if (this.matchLabel === 'profile_match') return '根据档案信息推测匹配,请手动确认'
|
|
|
if (this.matchLabel === 'no_match') return '无法匹配到现有家庭成员,可新建成员'
|
|
|
return ''
|
|
|
+ },
|
|
|
+ // 指标按类型(category)分组,保持解析顺序,统计需处理(非正常)数量
|
|
|
+ indicatorGroups() {
|
|
|
+ var groups = []
|
|
|
+ var orderMap = {}
|
|
|
+ var list = (this.payload && this.payload.indicators) || []
|
|
|
+ for (var i = 0; i < list.length; i++) {
|
|
|
+ var ind = list[i]
|
|
|
+ var cat = ind.category || '其他指标'
|
|
|
+ if (!orderMap[cat]) {
|
|
|
+ orderMap[cat] = groups.length
|
|
|
+ groups.push({ category: cat, items: [], needCount: 0 })
|
|
|
+ }
|
|
|
+ var group = groups[orderMap[cat]]
|
|
|
+ group.items.push(ind)
|
|
|
+ var st = ind.status || 'normal'
|
|
|
+ if (st === 'high' || st === 'low' || st === 'abnormal') {
|
|
|
+ group.needCount++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return groups
|
|
|
}
|
|
|
},
|
|
|
onLoad: function(options) {
|
|
|
@@ -418,6 +464,16 @@ export default {
|
|
|
self.creatingMember = false
|
|
|
})
|
|
|
},
|
|
|
+ toggleGroup(gIdx) {
|
|
|
+ this.$set(this.groupExpandList, gIdx, !this.groupExpandList[gIdx])
|
|
|
+ },
|
|
|
+ toggleAllGroups(expand) {
|
|
|
+ var arr = []
|
|
|
+ for (var i = 0; i < this.indicatorGroups.length; i++) {
|
|
|
+ arr.push(expand)
|
|
|
+ }
|
|
|
+ this.groupExpandList = arr
|
|
|
+ },
|
|
|
statusText(status) {
|
|
|
if (status === 'high') return '偏高'
|
|
|
if (status === 'low') return '偏低'
|
|
|
@@ -566,6 +622,91 @@ export default {
|
|
|
margin-bottom: 20rpx;
|
|
|
padding-bottom: 12rpx;
|
|
|
border-bottom: 2rpx solid #F0F0F0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+.card-title-actions {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+.expand-all-btn {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #5B9BD5;
|
|
|
+ padding: 4rpx 12rpx;
|
|
|
+ border: 2rpx solid #5B9BD5;
|
|
|
+ border-radius: 20rpx;
|
|
|
+}
|
|
|
+.expand-all-btn:active { opacity: 0.7; }
|
|
|
+
|
|
|
+/* ===== 指标分组折叠 ===== */
|
|
|
+.indicator-group {
|
|
|
+ border: 2rpx solid #E8EDF2;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.indicator-group-header {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 20rpx 16rpx;
|
|
|
+ background: #F1F5F9;
|
|
|
+}
|
|
|
+.indicator-group-header:active { opacity: 0.8; }
|
|
|
+.indicator-group-header-left {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+.indicator-group-arrow {
|
|
|
+ font-size: 30rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+ margin-right: 12rpx;
|
|
|
+ transform: rotate(0deg);
|
|
|
+ transition: transform 0.2s ease;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.indicator-group-arrow.arrow-open {
|
|
|
+ transform: rotate(90deg);
|
|
|
+}
|
|
|
+.indicator-group-name {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333;
|
|
|
+ font-weight: 600;
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+.indicator-group-header-right {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-left: 12rpx;
|
|
|
+}
|
|
|
+.indicator-group-need {
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: #E65100;
|
|
|
+ background: #FFF3E0;
|
|
|
+ padding: 4rpx 12rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+.indicator-group-count {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+}
|
|
|
+.indicator-group-body {
|
|
|
+ padding: 16rpx;
|
|
|
}
|
|
|
|
|
|
.field-row {
|