|
|
@@ -58,20 +58,22 @@
|
|
|
|
|
|
<!-- 报告列表 -->
|
|
|
<view class="report-list" v-else-if="reports.length > 0">
|
|
|
- <view class="swipe-row" v-for="item in reports" :key="getReportKey(item)">
|
|
|
+ <view class="swipe-row" v-for="item in reports" :key="item._uk">
|
|
|
<!-- 右侧操作按钮(左滑后露出:删除 + 调整归属);DAN 报告不可左右滑动删除 -->
|
|
|
<view class="swipe-actions" v-if="item.reportType !== 'dan'">
|
|
|
- <view class="swipe-delete" @click.stop="confirmDelete(item.id)">删除</view>
|
|
|
- <view class="swipe-adjust" @click.stop="adjustBinding(item.id, item.subjectId)">调整归属</view>
|
|
|
+ <view class="swipe-delete" :data-id="item.id" @click.stop="confirmDelete">删除</view>
|
|
|
+ <view class="swipe-adjust" :data-id="item.id" :data-subject-id="item.subjectId" @click.stop="adjustBinding">调整归属</view>
|
|
|
</view>
|
|
|
<!-- 卡片内容(可左滑) -->
|
|
|
<view class="swipe-content"
|
|
|
:class="{ 'swipe-moving': curId === item.id }"
|
|
|
:style="'transform: translateX(' + (curId === item.id ? moveOffset : (openMap[item.id] ? -160 : 0)) + 'px)'"
|
|
|
- @touchstart="onTouchStart($event, item.id, item.reportType)"
|
|
|
+ :data-id="item.id"
|
|
|
+ :data-report-type="item.reportType"
|
|
|
+ @touchstart="onTouchStart"
|
|
|
@touchmove="onTouchMove"
|
|
|
@touchend="onTouchEnd"
|
|
|
- @click="onRowClick(item.id, item.reportType)">
|
|
|
+ @click="onRowClick">
|
|
|
<view class="report-card">
|
|
|
<view class="report-card-left">
|
|
|
<view class="report-type-badge" :class="'badge-' + (item.reportType === 'gut_flora' ? 'gut' : item.reportType === 'tongue' ? 'tongue' : item.reportType === 'dan' ? 'dan' : 'exam')">
|
|
|
@@ -98,52 +100,19 @@
|
|
|
<view class="empty-btn" @click="goToUpload">上传报告</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 成员调整面板 -->
|
|
|
- <view class="adjust-panel" v-if="showAdjustPanel">
|
|
|
- <view class="panel-header">
|
|
|
- <text class="panel-title">调整报告归属</text>
|
|
|
- <view class="panel-close" @click="closeAdjustPanel">×</view>
|
|
|
- </view>
|
|
|
- <view class="panel-content">
|
|
|
- <!-- 取消归属选项 -->
|
|
|
- <view class="cancel-bind-option" @click="cancelBinding" v-if="adjustCurrentMemberId">
|
|
|
- <text class="cancel-bind-text">取消归属</text>
|
|
|
- <text class="cancel-bind-arrow">×</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="member-filter">
|
|
|
- <scroll-view class="filter-scroll" scroll-x="true" :show-scrollbar="false">
|
|
|
- <view class="filter-chips">
|
|
|
- <view class="chip" :class="{ 'chip-active': !selectedAdjustMemberId }" @click="selectAllAdjustMembers">
|
|
|
- <text class="chip-text">全部</text>
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="chip"
|
|
|
- v-for="member in adjustMembers"
|
|
|
- :key="member.id"
|
|
|
- :class="{ 'chip-active': selectedAdjustMemberId === member._filterId }"
|
|
|
- @click="selectMemberAdjust(member.id)"
|
|
|
- >
|
|
|
- <text class="chip-text">{{ member.nickname || '成员' }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 家庭成员列表 -->
|
|
|
- <view class="member-list" v-if="adjustMembers.length > 0">
|
|
|
- <view
|
|
|
- class="member-item"
|
|
|
- v-for="(member, mIdx) in adjustMembers"
|
|
|
- :key="mIdx"
|
|
|
- @click="selectMemberAdjust(member.id)"
|
|
|
- >
|
|
|
- <text class="member-avatar">{{ (member.nickname || '?').substring(0, 1) }}</text>
|
|
|
- <text class="member-name">{{ member.nickname || '未知' }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
+ <!-- 成员调整面板(统一控件 MemberPickerPopup,蓝本:首页能量沙盘切换成员弹出页) -->
|
|
|
+ <MemberPickerPopup
|
|
|
+ :visible="showAdjustPanel"
|
|
|
+ title="调整报告归属"
|
|
|
+ :options="adjustOptions"
|
|
|
+ :active-key="adjustCurrentMemberId != null ? String(adjustCurrentMemberId) : ''"
|
|
|
+ :show-cancel="adjustCurrentMemberId != null"
|
|
|
+ cancel-text="取消归属"
|
|
|
+ empty-text="暂无家庭成员"
|
|
|
+ @close="closeAdjustPanel"
|
|
|
+ @cancel-bind="cancelBinding"
|
|
|
+ @select="selectAdjustMember"
|
|
|
+ />
|
|
|
|
|
|
<!-- 底部占位 -->
|
|
|
<view class="bottom-spacer"></view>
|
|
|
@@ -154,13 +123,14 @@
|
|
|
import { BrandColors } from '../../utils/brand-colors.js'
|
|
|
import { parseDate } from '../../utils/format.js'
|
|
|
import MemberSelector from '@/components/MemberSelector.vue'
|
|
|
+import MemberPickerPopup from '@/components/MemberPickerPopup.vue'
|
|
|
import { normalizeMembers, memberIdOf, resolveMemberId } from '@/utils/memberNormalize.js'
|
|
|
import { getReportList, deleteReport, getFamilyMemberList, getCollectingReports, reassignReport, getReportTransferList, approveReportTransfer, denyReportTransfer } from '../../utils/api.js'
|
|
|
import fontScaleMixin from '@/mixins/font-scale.js'
|
|
|
|
|
|
export default {
|
|
|
mixins: [fontScaleMixin],
|
|
|
- components: { MemberSelector },
|
|
|
+ components: { MemberSelector, MemberPickerPopup },
|
|
|
data() {
|
|
|
return {
|
|
|
reports: [],
|
|
|
@@ -179,13 +149,12 @@ export default {
|
|
|
startY: 0,
|
|
|
touchDidMove: false,
|
|
|
baseOffset: 0,
|
|
|
- // 调整归属面板状态
|
|
|
+ // 调整归属面板状态(统一控件 MemberPickerPopup)
|
|
|
showAdjustPanel: false,
|
|
|
adjustReportId: null,
|
|
|
adjustCurrentMemberId: null,
|
|
|
// 调整面板成员数据
|
|
|
- adjustMembers: [],
|
|
|
- selectedAdjustMemberId: null,
|
|
|
+ adjustOptions: [],
|
|
|
candidates: [],
|
|
|
showAutoCreateForm: false,
|
|
|
newMemberName: '',
|
|
|
@@ -229,19 +198,36 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
- getReportKey(item) {
|
|
|
- return item.reportType + '-' + item.id
|
|
|
+ ensureReportKeys() {
|
|
|
+ var list = this.reports || []
|
|
|
+ for (var i = 0; i < list.length; i++) {
|
|
|
+ if (list[i] && list[i]._uk == null) {
|
|
|
+ list[i]._uk = list[i].reportType + '-' + list[i].id
|
|
|
+ }
|
|
|
+ }
|
|
|
},
|
|
|
- adjustBinding(id, subjectId) {
|
|
|
+ adjustBinding(e) {
|
|
|
+ var id = e && e.currentTarget ? e.currentTarget.dataset.id : undefined
|
|
|
+ var subjectId = e && e.currentTarget ? e.currentTarget.dataset.subjectId : undefined
|
|
|
+ if (id != null && typeof id === 'string' && /^-?\d+$/.test(id)) id = parseInt(id, 10)
|
|
|
+ if (subjectId != null && typeof subjectId === 'string' && /^-?\d+$/.test(subjectId)) subjectId = parseInt(subjectId, 10)
|
|
|
var self = this
|
|
|
- // 显示成员选择面板
|
|
|
- self.showAdjustPanel = true
|
|
|
+ // 记录目标报告与当前归属成员ID(用于显示"取消归属"及高亮当前归属)
|
|
|
self.adjustReportId = id
|
|
|
- // 记录当前归属成员ID(用于判断是否显示"取消归属"选项)
|
|
|
self.adjustCurrentMemberId = subjectId
|
|
|
- // 使用已加载的成员列表
|
|
|
- self.adjustMembers = self.members
|
|
|
- self.selectedAdjustMemberId = null
|
|
|
+ // 使用已加载的成员列表构建统一控件选项(active 由 active-key 预计算)
|
|
|
+ self.adjustOptions = (self.members || []).map(function(member) {
|
|
|
+ var mid = memberIdOf(member)
|
|
|
+ return {
|
|
|
+ // key 用纯 id 字符串:与 active-key(subjectId)同口径,组件内 String(key)===String(activeKey) 命中高亮
|
|
|
+ key: String(mid),
|
|
|
+ label: member.nickname || member.name || '未知',
|
|
|
+ memberId: mid,
|
|
|
+ member: member
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // 打开面板
|
|
|
+ self.showAdjustPanel = true
|
|
|
},
|
|
|
cancelBinding() {
|
|
|
var self = this
|
|
|
@@ -262,11 +248,14 @@ export default {
|
|
|
closeAdjustPanel() {
|
|
|
this.showAdjustPanel = false
|
|
|
},
|
|
|
- selectAdjustMember(member) {
|
|
|
+ selectAdjustMember(option) {
|
|
|
var self = this
|
|
|
+ var member = option && option.member ? option.member : null
|
|
|
+ // 与原实现一致:优先用成员行 id 调后端(高亮比较用 canonical memberId,落库用行 id)
|
|
|
+ var memberId = member && member.id != null ? member.id : (option ? option.memberId : null)
|
|
|
self.showAdjustPanel = false
|
|
|
// 调用后端接口修改归属
|
|
|
- reassignReport(self.adjustReportId, member.id).then(function(res) {
|
|
|
+ reassignReport(self.adjustReportId, memberId).then(function(res) {
|
|
|
if (res.code === 200) {
|
|
|
uni.showToast({ title: '归属修改成功', icon: 'success' })
|
|
|
self.loadData()
|
|
|
@@ -334,37 +323,18 @@ export default {
|
|
|
this.selectedMemberId = null
|
|
|
this.loadData()
|
|
|
},
|
|
|
- selectAllAdjustMembers() {
|
|
|
- if (this.selectedAdjustMemberId === null) return
|
|
|
- this.selectedAdjustMemberId = null
|
|
|
- },
|
|
|
selectMember(item) {
|
|
|
var filterId = item._filterId != null ? item._filterId : memberIdOf(item)
|
|
|
if (this.selectedMemberId === filterId) return
|
|
|
this.selectedMemberId = filterId
|
|
|
this.loadData()
|
|
|
},
|
|
|
- selectMemberAdjust(memberId) {
|
|
|
- var self = this
|
|
|
- self.showAdjustPanel = false
|
|
|
- // 调用后端接口修改归属
|
|
|
- reassignReport(self.adjustReportId, memberId).then(function(res) {
|
|
|
- if (res.code === 200) {
|
|
|
- uni.showToast({ title: '归属修改成功', icon: 'success' })
|
|
|
- self.loadData()
|
|
|
- } else {
|
|
|
- uni.showToast({ title: res.message || '修改失败', icon: 'none' })
|
|
|
- }
|
|
|
- }).catch(function(e) {
|
|
|
- console.log('修改归属失败', e)
|
|
|
- uni.showToast({ title: '修改失败', icon: 'none' })
|
|
|
- })
|
|
|
- },
|
|
|
loadData() {
|
|
|
var self = this
|
|
|
self.loading = true
|
|
|
getReportList(self.selectedMemberId).then(function(res) {
|
|
|
self.reports = res.data || []
|
|
|
+ self.ensureReportKeys()
|
|
|
}).catch(function(e) {
|
|
|
console.log('获取报告列表失败', e)
|
|
|
uni.showToast({ title: '加载失败', icon: 'none' })
|
|
|
@@ -458,20 +428,28 @@ export default {
|
|
|
}
|
|
|
uni.navigateTo({ url: url })
|
|
|
},
|
|
|
- onRowClick(id, reportType) {
|
|
|
+ onRowClick(e) {
|
|
|
+ var dataset = (e && e.currentTarget ? e.currentTarget.dataset : (e && e.target ? e.target.dataset : {})) || {}
|
|
|
+ var id = dataset.id
|
|
|
+ var reportType = dataset.reportType
|
|
|
+ if (id != null && typeof id === 'string' && /^-?\d+$/.test(id)) id = parseInt(id, 10)
|
|
|
// 刚滑动过,忽略本次点击
|
|
|
if (this.touchDidMove) {
|
|
|
this.touchDidMove = false
|
|
|
return
|
|
|
}
|
|
|
// 行处于打开态,点击先收起
|
|
|
- if (this.openMap[id]) {
|
|
|
+ if (id != null && this.openMap[id]) {
|
|
|
this.$set(this.openMap, id, false)
|
|
|
return
|
|
|
}
|
|
|
this.goToDetail(id, reportType)
|
|
|
},
|
|
|
- onTouchStart(e, id, reportType) {
|
|
|
+ onTouchStart(e) {
|
|
|
+ var dataset = (e && e.currentTarget ? e.currentTarget.dataset : {}) || {}
|
|
|
+ var id = dataset.id
|
|
|
+ var reportType = dataset.reportType
|
|
|
+ if (id != null && typeof id === 'string' && /^-?\d+$/.test(id)) id = parseInt(id, 10)
|
|
|
// DAN 报告无删除/调整归属能力,禁止左滑
|
|
|
if (id != null && reportType === 'dan') {
|
|
|
this.curId = null
|
|
|
@@ -482,7 +460,7 @@ export default {
|
|
|
if (this.curId !== null && this.curId !== id && this.openMap[this.curId]) {
|
|
|
this.$set(this.openMap, this.curId, false)
|
|
|
}
|
|
|
- var touch = e.touches[0]
|
|
|
+ var touch = (e && e.touches ? e.touches[0] : null) || (e && e.changedTouches ? e.changedTouches[0] : {})
|
|
|
this.curId = id
|
|
|
this.startX = touch.clientX
|
|
|
this.startY = touch.clientY
|
|
|
@@ -515,7 +493,9 @@ export default {
|
|
|
goToUpload() {
|
|
|
uni.navigateTo({ url: '/pages/health/report-upload' })
|
|
|
},
|
|
|
- confirmDelete(id) {
|
|
|
+ confirmDelete(e) {
|
|
|
+ var id = e && e.currentTarget ? e.currentTarget.dataset.id : undefined
|
|
|
+ if (id != null && typeof id === 'string' && /^-?\d+$/.test(id)) id = parseInt(id, 10)
|
|
|
var self = this
|
|
|
uni.showModal({
|
|
|
title: '删除报告',
|
|
|
@@ -567,39 +547,6 @@ export default {
|
|
|
background: $app-bg;
|
|
|
}
|
|
|
|
|
|
-/* ===== 成员过滤 ===== */
|
|
|
-.member-filter {
|
|
|
- background: $app-bg;
|
|
|
- padding: 20rpx $uni-space-page 4rpx;
|
|
|
-}
|
|
|
-.filter-scroll {
|
|
|
- width: 100%;
|
|
|
- white-space: nowrap;
|
|
|
-}
|
|
|
-.filter-chips {
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
-}
|
|
|
-.chip {
|
|
|
- flex-shrink: 0;
|
|
|
- background: $app-surface;
|
|
|
- border: 1rpx solid $uni-border-color-light;
|
|
|
- border-radius: 24rpx;
|
|
|
- padding: 10rpx $uni-space-page;
|
|
|
- margin-right: 16rpx;
|
|
|
-}
|
|
|
-.chip-active {
|
|
|
- background: $brand-primary;
|
|
|
- border-color: $brand-primary;
|
|
|
-}
|
|
|
-.chip-text {
|
|
|
- font-size: calc(26rpx * var(--font-scale, 1));
|
|
|
- color: $uni-text-color-secondary;
|
|
|
-}
|
|
|
-.chip-active .chip-text {
|
|
|
- color: $app-surface;
|
|
|
-}
|
|
|
-
|
|
|
/* ===== 跨家庭报告转移申请 ===== */
|
|
|
.transfer-wrap {
|
|
|
margin: 20rpx $uni-space-lg 0;
|
|
|
@@ -908,88 +855,4 @@ export default {
|
|
|
.bottom-spacer {
|
|
|
height: 60rpx;
|
|
|
}
|
|
|
-
|
|
|
-/* ===== 调整归属面板 ===== */
|
|
|
-.adjust-panel {
|
|
|
- position: fixed;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- bottom: 0;
|
|
|
- background: rgba(0, 0, 0, 0.5);
|
|
|
- z-index: 999;
|
|
|
- display: flex;
|
|
|
- align-items: flex-end;
|
|
|
-}
|
|
|
-.adjust-panel .panel-content {
|
|
|
- background: $app-surface;
|
|
|
- border-radius: 24rpx 24rpx 0 0;
|
|
|
- padding: 32rpx $uni-space-page;
|
|
|
- max-height: 70vh;
|
|
|
- overflow-y: auto;
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-.adjust-panel .panel-header {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- margin-bottom: 24rpx;
|
|
|
-}
|
|
|
-.adjust-panel .panel-title {
|
|
|
- font-size: calc(32rpx * var(--font-scale, 1));
|
|
|
- font-weight: 600;
|
|
|
- color: $facade-text-strong;
|
|
|
-}
|
|
|
-.adjust-panel .panel-close {
|
|
|
- font-size: calc(48rpx * var(--font-scale, 1));
|
|
|
- color: $facade-text-muted;
|
|
|
- line-height: 1;
|
|
|
- padding: 0 8rpx;
|
|
|
-}
|
|
|
-.adjust-panel .cancel-bind-option {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- padding: 24rpx 0;
|
|
|
- border-bottom: 1rpx solid $facade-fill;
|
|
|
- margin-bottom: 16rpx;
|
|
|
-}
|
|
|
-.adjust-panel .cancel-bind-text {
|
|
|
- font-size: calc(28rpx * var(--font-scale, 1));
|
|
|
- color: $el-danger;
|
|
|
-}
|
|
|
-.adjust-panel .cancel-bind-arrow {
|
|
|
- font-size: calc(32rpx * var(--font-scale, 1));
|
|
|
- color: $facade-text-ghost;
|
|
|
-}
|
|
|
-.adjust-panel .member-list {
|
|
|
- margin-top: 16rpx;
|
|
|
-}
|
|
|
-.adjust-panel .member-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 20rpx 0;
|
|
|
- border-bottom: 1rpx solid $facade-fill-2;
|
|
|
-}
|
|
|
-.adjust-panel .member-item:last-child {
|
|
|
- border-bottom: none;
|
|
|
-}
|
|
|
-.adjust-panel .member-avatar {
|
|
|
- width: 64rpx;
|
|
|
- height: 64rpx;
|
|
|
- border-radius: 50%;
|
|
|
- background: $brand-primary;
|
|
|
- color: $app-surface;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- font-size: calc(28rpx * var(--font-scale, 1));
|
|
|
- font-weight: 500;
|
|
|
- margin-right: 20rpx;
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-.adjust-panel .member-name {
|
|
|
- font-size: calc(28rpx * var(--font-scale, 1));
|
|
|
- color: $facade-text-strong;
|
|
|
-}
|
|
|
</style>
|