diff --git a/pages/message/detail.vue b/pages/message/detail.vue
index 06f3290..7b9f838 100644
--- a/pages/message/detail.vue
+++ b/pages/message/detail.vue
@@ -20,6 +20,8 @@
{{ auditApprovedText }}
您于 {{ formatDate(msg.create_time) }} 提交的个人资料经审核未通过。
您的样品已经寄回,请注意查收。
+ 您的送检信息修改申请已审核通过,请前往送检信息页面重新提交。
+ 您的送检信息修改申请未通过。
请根据以下原因修改后重新提交。
@@ -41,8 +43,8 @@
-
- 驳回原因:
+
+ {{ msg.type === 4 ? '审核原因:' : '驳回原因:' }}
{{ msg.reason }}
@@ -61,6 +63,9 @@
+
+
+
@@ -79,19 +84,27 @@ const tagText = computed(() => {
if (!msg.value) return ''
if (msg.value.type === 1) return '已通过'
if (msg.value.type === 3) return '已寄回'
+ if (msg.value.type === 4) return msg.value.reason ? '未通过' : '已通过'
return '已驳回'
})
-const headerTitle = computed(() => (msg.value && msg.value.type === 3) ? '回寄信息' : '审核通知')
+const headerTitle = computed(() => {
+ if (!msg.value) return ''
+ if (msg.value.type === 3) return '回寄信息'
+ if (msg.value.type === 4) return '送检信息通知'
+ return '审核通知'
+})
const tagClass = computed(() => {
if (!msg.value) return ''
if (msg.value.type === 1) return 'tag-success'
if (msg.value.type === 3) return 'tag-return'
+ if (msg.value.type === 4) return msg.value.reason ? 'tag-fail' : 'tag-success'
return 'tag-fail'
})
const mainTitle = computed(() => {
if (!msg.value) return ''
if (msg.value.type === 1) return '资料已审核通过'
if (msg.value.type === 3) return '样品已经寄回'
+ if (msg.value.type === 4) return msg.value.reason ? '送检修改申请未通过' : '送检修改申请已通过'
return '您提交的资料未通过审核'
})
@@ -115,6 +128,10 @@ const goMyInfo = () => {
uni.navigateTo({ url: '/pages/myinfo/myinfo' })
}
+const goSampleInfo = () => {
+ uni.navigateTo({ url: '/pages/sample-info/sample-info' })
+}
+
const copySampleReceiverInfo = () => {
const info = sampleReceiverInfo.value
const text = [
diff --git a/pages/message/message.vue b/pages/message/message.vue
index be35880..0f30c64 100644
--- a/pages/message/message.vue
+++ b/pages/message/message.vue
@@ -76,18 +76,21 @@ const loadMessages = async () => {
const getMsgClass = (item) => {
if (item.type === 1) return 'success'
if (item.type === 3) return 'return'
+ if (item.type === 4) return item.reason ? 'fail' : 'sample'
return 'fail'
}
const getMsgIcon = (item) => {
if (item.type === 1) return 'checkmark-circle-fill'
if (item.type === 3) return 'order'
+ if (item.type === 4) return item.reason ? 'close-circle-fill' : 'checkmark-circle-fill'
return 'close-circle-fill'
}
const getMsgColor = (item) => {
if (item.type === 1) return '#52c41a'
if (item.type === 3) return '#0e63e3'
+ if (item.type === 4) return item.reason ? '#f5222d' : '#52c41a'
return '#f5222d'
}
@@ -137,6 +140,10 @@ const goDetail = (id) => {
&.return {
background: #f0f5ff;
}
+
+ &.sample {
+ background: #f6ffed;
+ }
}
.msg-body {
diff --git a/pages/sample-info/sample-info.vue b/pages/sample-info/sample-info.vue
index f5f6d0a..028e80b 100644
--- a/pages/sample-info/sample-info.vue
+++ b/pages/sample-info/sample-info.vue
@@ -61,6 +61,10 @@
回寄时间:{{ returnTime }}
复制单号
+
+ 修改申请未通过
+ 原因:{{ sampleEditRejectReason }}
+
送检样本类型{{ sampleRequired ? '' : '(选填)' }}
@@ -131,9 +135,24 @@
请阅读并同意
《患者告知书》
-
+
+
+
+
+
+
+
@@ -163,19 +182,33 @@ const submitting = ref(false)
const agreed = ref(false)
const sampleTypeList = ref([])
const sampleRequired = ref(false)
-const sampleReceiverInfo = ref({ address: '', receiver: '', phone: '' })
+const sampleReceiverInfo = ref({ address: '', receiver: '', phone: '', contact_phone: '' })
const sampleInfoStatus = ref(0)
const returnTrackingNo = ref('')
const returnTime = ref('')
+const sampleEditReason = ref('')
+const sampleEditRejectReason = ref('')
+const sampleEditApplyTime = ref('')
+const applyEditVisible = ref(false)
+const applyEditReason = ref('')
+const applyEditSubmitting = ref(false)
+const sampleEditAuditTmplId = ref('')
const isSampleReturned = computed(() => sampleInfoStatus.value === 2)
-const isSampleInfoLocked = computed(() => sampleInfoStatus.value === 1 || sampleInfoStatus.value === 2)
+const isSampleEditApplying = computed(() => sampleInfoStatus.value === 3)
+const isSampleInfoLocked = computed(() => sampleInfoStatus.value === 1 || sampleInfoStatus.value === 2 || sampleInfoStatus.value === 3)
+const canApplySampleEdit = computed(() => sampleInfoStatus.value === 1)
const sampleInfoStatusText = computed(() => {
+ if (sampleInfoStatus.value === 3) return '申请审核中'
if (sampleInfoStatus.value === 2) return '已寄回'
if (sampleInfoStatus.value === 1) return '已生效'
return ''
})
-const sampleInfoStatusClass = computed(() => sampleInfoStatus.value === 2 ? 'returned' : 'effective')
+const sampleInfoStatusClass = computed(() => {
+ if (sampleInfoStatus.value === 3) return 'applying'
+ return sampleInfoStatus.value === 2 ? 'returned' : 'effective'
+})
const submitButtonText = computed(() => {
+ if (sampleInfoStatus.value === 3) return '修改申请审核中'
if (sampleInfoStatus.value === 2) return '样品已寄回'
if (sampleInfoStatus.value === 1) return '送检信息已生效'
return '提交送检信息'
@@ -280,8 +313,34 @@ onLoad(async () => {
await loadRegions()
await loadPatientInfo()
await loadSampleTypes()
+ await loadSubscribeConfig()
})
+const loadSubscribeConfig = async () => {
+ try {
+ const res = await get('/api/mp/subscribeConfig')
+ if (res.data && res.data.sample_edit_audit) {
+ sampleEditAuditTmplId.value = res.data.sample_edit_audit
+ }
+ } catch (e) {}
+}
+
+const requestSampleEditSubscribe = () => {
+ return new Promise((resolve) => {
+ if (!sampleEditAuditTmplId.value) return resolve(false)
+ // #ifdef MP-WEIXIN
+ wx.requestSubscribeMessage({
+ tmplIds: [sampleEditAuditTmplId.value],
+ success: () => resolve(true),
+ fail: () => resolve(false)
+ })
+ // #endif
+ // #ifndef MP-WEIXIN
+ resolve(false)
+ // #endif
+ })
+}
+
const loadPatientInfo = async () => {
try {
const res = await get('/api/mp/sampleInfo')
@@ -302,8 +361,11 @@ const loadPatientInfo = async () => {
sampleInfoStatus.value = Number(res.data.sample_info_status) || 0
returnTrackingNo.value = res.data.return_tracking_no || ''
returnTime.value = res.data.return_time || ''
- sampleReceiverInfo.value = res.data.sample_receiver_info || { address: '', receiver: '', phone: '' }
- if (sampleInfoStatus.value === 1) {
+ sampleEditReason.value = res.data.sample_edit_reason || ''
+ sampleEditRejectReason.value = res.data.sample_edit_reject_reason || ''
+ sampleEditApplyTime.value = res.data.sample_edit_apply_time || ''
+ sampleReceiverInfo.value = res.data.sample_receiver_info || { address: '', receiver: '', phone: '', contact_phone: '' }
+ if ((sampleInfoStatus.value === 1 && !sampleEditRejectReason.value) || sampleInfoStatus.value === 3) {
setTimeout(() => showLockedTip(), 300)
}
}
@@ -406,9 +468,18 @@ const contactPlatform = () => {
}
const showLockedTip = () => {
+ if (isSampleEditApplying.value) {
+ uni.showModal({
+ title: '温馨提示',
+ content: '送检信息修改申请正在审核中,请等待平台处理。',
+ showCancel: false,
+ confirmText: '知道了'
+ })
+ return
+ }
if (isSampleReturned.value) {
uni.showModal({
- title: '提示',
+ title: '温馨提示',
content: `样品已经寄回,回寄物流单号:${returnTrackingNo.value || '—'}。`,
cancelText: '知道了',
confirmText: '复制单号',
@@ -419,26 +490,46 @@ const showLockedTip = () => {
return
}
const phone = getContactPhone()
- if (!phone) {
- uni.showModal({
- title: '提示',
- content: '送检信息已生效,如需修改请联系平台重置修改权限。',
- showCancel: false,
- confirmText: '知道了'
- })
- return
- }
+ let content = '送检信息已生效,如需修改请点击页面的【申请修改送检信息】按钮申请,通过后可重新提交送检信息。'
+ if (phone) content += `详情咨询${phone}。`
uni.showModal({
- title: '提示',
- content: `送检信息已生效,如需修改请联系平台【${phone}】重置修改权限。`,
- cancelText: '知道了',
- confirmText: '联系平台',
- success: (res) => {
- if (res.confirm) contactPlatform()
- }
+ title: '温馨提示',
+ content,
+ showCancel: false,
+ confirmText: '知道了'
})
}
+const showApplyEditDialog = () => {
+ if (!canApplySampleEdit.value) return showLockedTip()
+ applyEditReason.value = ''
+ applyEditVisible.value = true
+}
+
+const submitApplyEdit = async () => {
+ if (!applyEditReason.value.trim()) {
+ return uni.showToast({ title: '请填写申请原因', icon: 'none' })
+ }
+ applyEditSubmitting.value = true
+ try {
+ await requestSampleEditSubscribe()
+ const params = { reason: applyEditReason.value.trim() }
+ // #ifdef MP-WEIXIN
+ params.mp_env_version = uni.getAccountInfoSync().miniProgram.envVersion || 'release'
+ // #endif
+ await post('/api/mp/applySampleInfoEdit', params)
+ sampleInfoStatus.value = 3
+ sampleEditReason.value = applyEditReason.value.trim()
+ sampleEditApplyTime.value = ''
+ applyEditVisible.value = false
+ uni.showToast({ title: '申请已提交', icon: 'success' })
+ } catch (e) {
+ if (e && e.msg) uni.showToast({ title: e.msg, icon: 'none' })
+ } finally {
+ applyEditSubmitting.value = false
+ }
+}
+
const copyReturnTrackingNo = () => {
if (!returnTrackingNo.value) return uni.showToast({ title: '暂无单号', icon: 'none' })
uni.setClipboardData({
@@ -494,10 +585,12 @@ const handleSubmit = async () => {
uni.showToast({ title: '提交成功', icon: 'success' })
setTimeout(() => uni.navigateBack(), 1500)
} catch (e) {
- if (e && e.data && [1, 2].includes(Number(e.data.sample_info_status))) {
+ if (e && e.data && [1, 2, 3].includes(Number(e.data.sample_info_status))) {
sampleInfoStatus.value = Number(e.data.sample_info_status)
returnTrackingNo.value = e.data.return_tracking_no || returnTrackingNo.value
returnTime.value = e.data.return_time || returnTime.value
+ sampleEditReason.value = e.data.sample_edit_reason || sampleEditReason.value
+ sampleEditApplyTime.value = e.data.sample_edit_apply_time || sampleEditApplyTime.value
if (e.data.sample_receiver_info) sampleReceiverInfo.value = e.data.sample_receiver_info
return showLockedTip()
}
@@ -512,7 +605,7 @@ const handleSubmit = async () => {
.page { min-height: 100vh; background: #f4f4f5; padding: 24rpx; padding-bottom: 260rpx; }
.section { background: #fff; border-radius: 10rpx; padding: 32rpx; margin-bottom: 24rpx; border: 1rpx solid #ebeef5; }
.section-title { display: flex; align-items: center; gap: 12rpx; font-size: 32rpx; font-weight: 600; color: #333; margin-bottom: 28rpx; }
-.status-pill { margin-left: auto; font-size: 22rpx; font-weight: 500; padding: 4rpx 14rpx; border-radius: 6rpx; &.effective { color: #52c41a; background: #f6ffed; border: 1rpx solid #b7eb8f; } &.returned { color: #0e63e3; background: #f0f5ff; border: 1rpx solid #adc6ff; } }
+.status-pill { margin-left: auto; font-size: 22rpx; font-weight: 500; padding: 4rpx 14rpx; border-radius: 6rpx; &.effective { color: #52c41a; background: #f6ffed; border: 1rpx solid #b7eb8f; } &.returned { color: #0e63e3; background: #f0f5ff; border: 1rpx solid #adc6ff; } &.applying { color: #d46b08; background: #fff7e6; border: 1rpx solid #ffd591; } }
.info-compact { padding-bottom: 8rpx; }
.info-compact-row { display: flex; gap: 32rpx; margin-bottom: 12rpx; &:last-child { margin-bottom: 0; } }
.info-compact-item { font-size: 26rpx; color: #666; }
@@ -521,6 +614,9 @@ const handleSubmit = async () => {
.return-text { display: block; font-size: 28rpx; color: #0e63e3; font-weight: 600; line-height: 1.5; }
.return-time { display: block; font-size: 24rpx; color: #909399; margin-top: 8rpx; }
.copy-return-no { display: block; text-align: right; font-size: 26rpx; color: #0e63e3; margin-top: 12rpx; }
+.reject-info { background: #fff2f0; border-left: 6rpx solid #ff4d4f; border-radius: 8rpx; padding: 24rpx; margin-bottom: 20rpx; }
+.reject-title { display: block; font-size: 28rpx; font-weight: 600; color: #a8071a; margin-bottom: 10rpx; }
+.reject-text { display: block; font-size: 26rpx; color: #606266; line-height: 1.6; }
.receiver-info { padding-bottom: 8rpx; }
.receiver-row { display: flex; gap: 20rpx; margin-bottom: 14rpx; &:last-child { margin-bottom: 0; } }
.receiver-label { width: 120rpx; flex-shrink: 0; font-size: 26rpx; color: #909399; }
@@ -543,4 +639,9 @@ const handleSubmit = async () => {
.agree-row { display: flex; align-items: center; margin-bottom: 16rpx; padding-left: 4rpx; }
.agree-text { font-size: 24rpx; color: #666; margin-left: 8rpx; }
.agree-link { font-size: 24rpx; color: #0e63e3; }
+.apply-popup { width: 620rpx; background: #fff; border-radius: 16rpx; padding: 32rpx; }
+.apply-title { font-size: 32rpx; font-weight: 600; color: #303133; margin-bottom: 12rpx; }
+.apply-desc { font-size: 26rpx; color: #606266; line-height: 1.6; margin-bottom: 20rpx; }
+.apply-textarea { width: 100%; height: 180rpx; box-sizing: border-box; border: 1rpx solid #dcdfe6; border-radius: 8rpx; padding: 20rpx; font-size: 28rpx; color: #303133; background: #fff; }
+.apply-actions { display: flex; gap: 20rpx; margin-top: 24rpx; }