Browse Source

联调完成

dev
kola-web 4 hours ago
parent
commit
7e78bde327
  1. 2
      src/components/popup/index.wxml
  2. 2
      src/components/toast/index.wxml
  3. 71
      src/pages/d_interactiveDoctor/index.scss
  4. 33
      src/pages/d_interactiveDoctor/index.ts
  5. 80
      src/pages/d_interactiveDoctor/index.wxml
  6. 4
      src/patient/pages/follow/index.json
  7. 46
      src/patient/pages/follow/index.scss
  8. 120
      src/patient/pages/follow/index.ts
  9. 27
      src/patient/pages/follow/index.wxml
  10. 214
      src/patient/pages/followForm/index.ts
  11. 51
      src/patient/pages/followForm/index.wxml
  12. 17
      src/patient/pages/index/index.scss
  13. 142
      src/patient/pages/index/index.ts
  14. 28
      src/patient/pages/index/index.wxml
  15. 66
      src/patient/pages/interactivePatient/index.scss
  16. 190
      src/patient/pages/interactivePatient/index.ts
  17. 69
      src/patient/pages/interactivePatient/index.wxml
  18. 4
      src/patient/pages/my/index.wxml
  19. 766
      接口文档.md

2
src/components/popup/index.wxml

@ -252,7 +252,7 @@
</view> </view>
</view> </view>
<view class="popup19" wx:if="{{type==='popup19'}}"> <view class="popup19" wx:if="{{type==='popup19'}}">
<image class="badge" src="/images/icon173.png"></image> <image class="badge" src="{{imageUrl}}icon173.png?t={{Timestamp}}"></image>
<view class="popup-container"> <view class="popup-container">
<view class="title">档案已保存</view> <view class="title">档案已保存</view>
<view class="content">下次就医时可出示该卡给医生</view> <view class="content">下次就医时可出示该卡给医生</view>

2
src/components/toast/index.wxml

@ -854,7 +854,7 @@
</view> </view>
</view> </view>
<view class="popup-follow-guide" wx:if="{{type==='followGuide'}}"> <view class="popup-follow-guide" wx:if="{{type==='followGuide'}}">
<image class="badge" src="/images/icon174.png"></image> <image class="badge" src="{{imageUrl}}icon174.png?t={{Timestamp}}"></image>
<view class="popup-container" bind:tap="handleCancel"> <view class="popup-container" bind:tap="handleCancel">
<view class="title"> <view class="title">
记录复诊信息 记录复诊信息

71
src/pages/d_interactiveDoctor/index.scss

@ -186,6 +186,49 @@ page {
} }
} }
} }
.follow-result-reason {
margin-bottom: 32rpx;
padding: 32rpx;
border-radius: 32rpx;
background-color: #fff;
.title {
font-size: 32rpx;
color: rgba(33, 29, 46, 1);
}
.info {
margin-top: 20rpx;
padding: 24rpx;
background-color: rgba(246, 248, 249, 1);
border-radius: 16rpx;
.info-item {
font-size: 32rpx;
padding-left: 50rpx;
color: rgba(33, 29, 46, 1);
.label {
display: inline;
font-weight: bold;
}
.value {
display: inline;
}
&::before {
margin-left: -30rpx;
margin-right: 20rpx;
margin-top: 20rpx;
display: inline-block;
flex-shrink: 0;
content: '';
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #7d7d82;
}
&:not(:first-of-type) {
margin-top: 24rpx;
}
}
}
}
.follow-result { .follow-result {
margin-bottom: 32rpx; margin-bottom: 32rpx;
padding: 32rpx; padding: 32rpx;
@ -522,14 +565,22 @@ page {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
&.disabled {
color: rgba(105, 104, 110, 1);
border-color: rgba(105, 104, 110, 1);
}
} }
.btn2 { .btn2 {
padding: 0; padding: 0;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%); background: linear-gradient(180deg, #ffbcf9 0%, #b982ff 100%);
color: #ffffff; color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
&.disabled {
background: rgba(246, 248, 249, 1);
color: rgba(105, 104, 110, 1);
}
} }
} }
} }
@ -572,8 +623,12 @@ page {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: linear-gradient(180deg, #e98ff8 0%, #b073ff 100%); background: linear-gradient(180deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 64rpx 64rpx 64rpx 64rpx; border-radius: 64rpx 64rpx 64rpx 64rpx;
&.disabled {
background: rgba(246, 248, 249, 1);
color: rgba(105, 104, 110, 1);
}
} }
} }
.follow-reset { .follow-reset {
@ -593,8 +648,12 @@ page {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: linear-gradient(180deg, #e98ff8 0%, #b073ff 100%); background: linear-gradient(180deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 64rpx 64rpx 64rpx 64rpx; border-radius: 64rpx 64rpx 64rpx 64rpx;
&.disabled {
background: rgba(246, 248, 249, 1);
color: rgba(105, 104, 110, 1);
}
} }
} }
.follow-next { .follow-next {
@ -614,8 +673,12 @@ page {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: linear-gradient(180deg, #e98ff8 0%, #b073ff 100%); background: linear-gradient(180deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 64rpx 64rpx 64rpx 64rpx; border-radius: 64rpx 64rpx 64rpx 64rpx;
&.disabled {
background: rgba(246, 248, 249, 1);
color: rgba(105, 104, 110, 1);
}
} }
} }
} }

33
src/pages/d_interactiveDoctor/index.ts

@ -4,7 +4,7 @@ const app = getApp<IAppOption>()
interface IMessageItem { interface IMessageItem {
msgId: string msgId: string
msgContentType: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | '13' | '14' | '15' // 1:文本 2: 出诊时间 3: adl卡片 4: 语音 5: 欢迎语 6:补充真实姓名 7: 提醒完善信息 8: 复诊卡片 9:患者恢复复诊消息 12:复诊提醒 13:复诊提醒-快速问答 14:复诊提醒-未复诊鼓励 15:复诊提醒-已复诊结果 msgContentType: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | '13' | '14' | '15' | '16' | '17' // 1:文本 2: 出诊时间 3: adl卡片 4: 语音 5: 欢迎语 6:补充真实姓名 7: 提醒完善信息 8: 复诊卡片 9:患者恢复复诊消息 12:复诊提醒 13:复诊提醒-快速问答 14:未复诊原因 15:未复诊原因回复 16:未复诊鼓励 17:下一步
msgContent: any msgContent: any
msgVisitTime: string msgVisitTime: string
msgVisitTimeType?: string msgVisitTimeType?: string
@ -13,7 +13,13 @@ interface IMessageItem {
msgCreateTime: string // 消息创建时间 msgCreateTime: string // 消息创建时间
msgCreateTimeName?: string // 消息创建时间 msgCreateTimeName?: string // 消息创建时间
showTime?: boolean showTime?: boolean
ReVisitInfo?: any
msgCustomSendStatus?: number | string msgCustomSendStatus?: number | string
msgTipsInfo?: string
followUpStatus?: number // 复诊状态,>0 表示已回复
replyMsgId?: number // 回复消息ID,>0 表示已回复
followUpTitle?: string // 复诊原因标题
followUpTitleChoice?: string // 复诊原因多选提示
} }
interface Item { interface Item {
@ -136,6 +142,31 @@ Page({
item.ReVisitInfo = JSON.parse(item.ReVisitInfo) item.ReVisitInfo = JSON.parse(item.ReVisitInfo)
item.ReVisitInfo.visitDateName = dayjs(item.ReVisitInfo.visitDate).format('YYYY年M月DD日') item.ReVisitInfo.visitDateName = dayjs(item.ReVisitInfo.visitDate).format('YYYY年M月DD日')
} }
if (item.msgContentType === '13') {
const rawInfo = JSON.parse(item.ReVisitInfo)
// 解析结构:{title, lastVisitTitle, visitDate, mySolutionTitle, reVisitSolution}
item.ReVisitInfo = rawInfo
}
if (item.msgContentType === '14') {
const rawInfo = JSON.parse(item.ReVisitInfo)
// 解析结构:{title, titleChoice, missionReasonList, reasonList}
const missionReasonList = rawInfo.missionReasonList || {}
const reasonList = rawInfo.reasonList || []
item.ReVisitInfo = Object.keys(missionReasonList).map(key => ({
key,
label: missionReasonList[key],
isSelected: reasonList.includes(key),
}))
item.followUpTitle = rawInfo.title || '请问您没能按时复诊的主要原因是?'
item.followUpTitleChoice = rawInfo.titleChoice || '(多选)'
}
if (item.msgContentType === '15') {
const rawInfo = JSON.parse(item.ReVisitInfo)
// 解析结构:{title, reasonInfoList}
const reasonInfoList = rawInfo.reasonInfoList || {}
item.followUpTitle = rawInfo.title || '没能按时复诊的主要原因是?'
item.ReVisitInfo = Object.keys(reasonInfoList).map(key => reasonInfoList[key])
}
return item return item
}) })

80
src/pages/d_interactiveDoctor/index.wxml

@ -69,20 +69,24 @@
<view class="item" wx:if="{{message.ReVisitInfo.other==1}}">9.其他</view> <view class="item" wx:if="{{message.ReVisitInfo.other==1}}">9.其他</view>
</view> </view>
</view> </view>
<view class="follow-result" wx:if="{{message.msgContentType==='15'}}"> <view class="follow-result-reason" wx:if="{{message.msgContentType==='13'}}">
<view class="title">医生您好,我刚刚完成了复诊记录:</view> <view class="title">{{message.ReVisitInfo.title}}</view>
<view class="list"> <view class="info">
<view class="list-item"> <view class="info-item">
<view class="li-content"> <view class="label">{{message.ReVisitInfo.lastVisitTitle}}</view>
<text class="blob">我最近一次复诊时间是:</text> <view class="value">{{message.ReVisitInfo.visitDate}}</view>
2025年6月11日 </view>
<view class="info-item">
<view class="label">{{message.ReVisitInfo.mySolutionTitle}}</view>
<view class="value" wx:for="{{message.ReVisitInfo.reVisitSolution}}" wx:key="index">{{item}}</view>
</view> </view>
</view> </view>
<view class="list-item">
<view class="li-content">
<text class="blob">我的方案是:</text>
生物制剂IGF-1R抗体(替妥尤单抗)第2次使用替妥尤单抗
</view> </view>
<view class="follow-result" wx:if="{{message.msgContentType==='15'}}">
<view class="title">{{message.followUpTitle}}</view>
<view class="list">
<view class="list-item" wx:for="{{message.ReVisitInfo}}" wx:key="index">
<view class="li-content">{{item}}</view>
</view> </view>
</view> </view>
</view> </view>
@ -151,13 +155,13 @@
<view class="content">{{message.msgContent}}</view> <view class="content">{{message.msgContent}}</view>
<view class="btn">完善个人信息</view> <view class="btn">完善个人信息</view>
</view> </view>
<view class="referral" wx:elif="{{message.msgContentType==='8'}}"> <view class="follow" wx:elif="{{message.msgContentType==='8'}}">
<view class="r-header"> <view class="content">
<view class="title">您最近有按照医生的 提醒,定期复诊吗?</view> 您好!出院后的康复需要我们双方共同努力,请问您最近有按照医生的提醒,定期到院复诊吗?
<image class="icon" src="{{imageUrl}}za-images5/hostipal.png?t={{Timestamp}}"></image>
</view> </view>
<view class="r-footer"> <view class="f-footer">
<view class="btn">已复诊</view> <view class="btn1">已复诊</view>
<view class="btn2">未复诊</view>
</view> </view>
</view> </view>
<view class="follow" wx:elif="{{message.msgContentType==='12'}}"> <view class="follow" wx:elif="{{message.msgContentType==='12'}}">
@ -171,22 +175,48 @@
</view> </view>
<view class="follow-form" wx:elif="{{message.msgContentType==='13'}}"> <view class="follow-form" wx:elif="{{message.msgContentType==='13'}}">
<view class="content"> <view class="content">
请问您没能按时复诊的主要原因是? {{message.followUpTitle}}
<text class="sub">(多选)</text> <text class="sub">{{message.followUpTitleChoice}}</text>
</view> </view>
<view class="list"> <view class="list">
<view class="list-item">症状感觉好转,觉得不用去了</view> <view
class="list-item {{item.isSelected ? 'active' : ''}}"
wx:for="{{message.ReVisitInfo}}"
wx:key="key"
>{{item.label}}</view>
</view> </view>
<view class="btn">提交</view> <view class="btn">提交</view>
</view> </view>
<view class="follow-reset" wx:elif="{{message.msgContentType==='14'}}"> <view class="follow-form" wx:elif="{{message.msgContentType==='14'}}">
<view class="content">规范治疗可获得更好的疗效,减少复发。</view> <view class="content">
<view class="btn">提交</view> {{message.followUpTitle}}
<text class="sub">{{message.followUpTitleChoice}}</text>
</view>
<view class="list">
<view
class="list-item {{item.isSelected ? 'active' : ''}}"
wx:for="{{message.ReVisitInfo}}"
wx:key="key"
>{{item.label}}</view>
</view> </view>
<view class="follow-next" wx:elif="{{message.msgContentType==='15'}}">
<view class="content">坚持规范治疗,继续加油,愿身体稳步向好!</view>
<view class="btn">提交</view> <view class="btn">提交</view>
</view> </view>
<view class="follow-reset" wx:elif="{{message.msgContentType==='15'}}">
<view class="title">{{message.followUpTitle}}</view>
<view class="list">
<view class="list-item" wx:for="{{message.ReVisitInfo}}" wx:key="index">
<view class="li-content">{{item}}</view>
</view>
</view>
</view>
<view class="follow-reset" wx:elif="{{message.msgContentType==='16'}}">
<view class="content">{{message.msgContent}}</view>
<view class="btn">重新预约复诊</view>
</view>
<view class="follow-next" wx:elif="{{message.msgContentType==='17'}}">
<view class="content">{{message.msgContent}}</view>
<view class="btn">设置下一次复诊提醒</view>
</view>
</view> </view>
<view class="avatar"> <view class="avatar">
<image class="a-img" mode="aspectFill" src="{{doctor.Img}}"></image> <image class="a-img" mode="aspectFill" src="{{doctor.Img}}"></image>

4
src/patient/pages/follow/index.json

@ -1,5 +1,7 @@
{ {
"navigationStyle": "default", "navigationStyle": "default",
"navigationBarTitleText": "复诊记录", "navigationBarTitleText": "复诊记录",
"usingComponents": {} "usingComponents": {
"popup": "/components/popup/index"
}
} }

46
src/patient/pages/follow/index.scss

@ -3,7 +3,7 @@ page {
} }
.page { .page {
padding: 48rpx 32rpx; padding: 48rpx 32rpx 200rpx;
.card { .card {
display: flex; display: flex;
gap: 14rpx; gap: 14rpx;
@ -45,6 +45,8 @@ page {
} }
} }
.container { .container {
flex: 1;
padding-bottom: 48rpx;
.date { .date {
font-size: 36rpx; font-size: 36rpx;
color: rgba(33, 29, 46, 1); color: rgba(33, 29, 46, 1);
@ -105,6 +107,48 @@ page {
color: rgba(248, 166, 26, 1); color: rgba(248, 166, 26, 1);
} }
} }
.actions {
margin-top: 24rpx;
display: flex;
justify-content: flex-end;
gap: 24rpx;
.action-btn {
padding: 10rpx 32rpx;
font-size: 28rpx;
border-radius: 32rpx;
}
.edit {
color: rgba(185, 130, 255, 1);
border: 1px solid rgba(185, 130, 255, 1);
}
.delete {
color: rgba(173, 172, 178, 1);
border: 1px solid rgba(173, 172, 178, 1);
}
}
}
&:first-child {
.aside {
.line-top {
opacity: 0;
}
}
}
&:last-of-type {
.container {
padding-bottom: 0;
}
}
}
.add-btn {
position: fixed;
bottom: 140rpx;
left: 50%;
transform: translateX(-50%);
.icon {
display: block;
width: 136rpx;
height: 136rpx;
} }
} }
} }

120
src/patient/pages/follow/index.ts

@ -1,8 +1,120 @@
const _app = getApp<IAppOption>(); const app = getApp<IAppOption>()
Page({ Page({
data: {}, data: {
onLoad() {}, list: [] as any[],
}); planMap: {} as Record<string, string>,
pagination: {
page: 1,
pages: 1,
count: 0,
},
popupShow: false,
popupType: 'popup15',
popupParams: {} as any,
deleteId: '',
},
onShow() {
app.waitLogin({ type: [1] }).then(() => {
this.getEnum().then(() => {
this.getList()
})
})
},
getEnum() {
return wx.ajax({
method: 'GET',
url: '?r=xd/follow-up-reminder/enum',
}).then((res: any) => {
const tp = res.treatmentPlan || {}
const planMap: Record<string, string> = {}
Object.keys(tp).forEach((key) => {
planMap[key] = tp[key]
})
this.setData({ planMap })
})
},
getList(newPage = 1) {
wx.ajax({
method: 'GET',
url: '?r=xd/follow-up-reminder/list',
data: { page: newPage },
loading: true,
}).then((res: any) => {
const rawList = res.list || res || []
const planMap = this.data.planMap
const list = (newPage === 1 ? [] : [...this.data.list]).concat(
rawList.map((item: any) => {
const planKeys = item.treatmentPlan ? item.treatmentPlan.split(',') : []
const planList = planKeys.map((key: string) => {
const label = planMap[key] || key
if (key === '5' && item.usageCount) {
return `${label}${item.usageCount}次使用`
}
return label
})
return { ...item, planList }
}),
)
this.setData({
list,
pagination: {
page: res.page || newPage,
pages: res.pages || 1,
count: res.count || list.length,
},
})
})
},
onReachBottom() {
const { page, pages } = this.data.pagination
if (pages > page) {
this.getList(page + 1)
}
},
handleAdd() {
wx.navigateTo({
url: '/patient/pages/followForm/index',
})
},
handleEdit(e: any) {
const id = e.currentTarget.dataset.id
wx.navigateTo({
url: `/patient/pages/followForm/index?id=${id}`,
})
},
handleDelete(e: any) {
const id = e.currentTarget.dataset.id
this.setData({
deleteId: id,
popupShow: true,
popupType: 'popup15',
})
},
handlePopupOk() {
this.setData({ popupShow: false })
wx.ajax({
method: 'POST',
url: '?r=xd/follow-up-reminder/delete',
data: { id: this.data.deleteId },
loading: true,
}).then(() => {
wx.showToast({ title: '删除成功', icon: 'none' })
this.getList()
})
},
handlePopupCancel() {
this.setData({ popupShow: false })
},
})
export {} export {}

27
src/patient/pages/follow/index.wxml

@ -1,22 +1,37 @@
<view class="page"> <view class="page">
<view class="card"> <view class="card" wx:for="{{list}}" wx:key="id" bind:tap="handleEdit" data-id="{{item.id}}">
<view class="aside"> <view class="aside">
<view class="line-top"></view> <view class="line-top"></view>
<view class="circle"></view> <view class="circle"></view>
<view class="line-bottom"></view> <view class="line-bottom"></view>
</view> </view>
<view class="container"> <view class="container">
<view class="date">复诊时间:2025-06-11</view> <view class="date">复诊时间:{{item.visitTime}}</view>
<view class="wrap"> <view class="wrap">
<view class="title">复诊方案</view> <view class="title">复诊方案</view>
<view class="list"> <view class="list">
<view class="list-item">生物制剂IGF-1R抗体(替妥尤单抗) 第2次使用</view> <view class="list-item" wx:for="{{item.planList}}" wx:for-item="plan" wx:key="index">{{plan}}</view>
<view class="list-item">传统免疫抑制剂(如:吗替麦考酚酯、环孢素等、甲氨蝶呤)</view>
</view> </view>
<view class="next-date"> <view class="next-date">
<image class="icon" src="/images/icon172.png"></image> <image class="icon" src="{{imageUrl}}icon172.png?t={{Timestamp}}"></image>
下次复诊时间:2025-06-11</view> 下次复诊时间:{{item.nextVisitTime}}
</view> </view>
</view> </view>
</view> </view>
</view>
<pagination pagination="{{pagination}}"></pagination>
<view class="add-btn" bind:tap="handleAdd">
<image class="icon" src="{{imageUrl}}icon177.png?t={{Timestamp}}"></image>
</view>
</view> </view>
<popup
id="popup"
show="{{popupShow}}"
type="{{popupType}}"
params="{{popupParams}}"
bind:ok="handlePopupOk"
bind:cancel="handlePopupCancel"
/>

214
src/patient/pages/followForm/index.ts

@ -1,23 +1,221 @@
const _app = getApp<IAppOption>(); const app = getApp<IAppOption>()
Page({ Page({
data: { data: {
id: '',
isEdit: false,
visitTime: '',
treatmentPlan: [] as string[],
planOptions: [] as any[],
teprotumumabCount: 1,
showUsageCount: false,
nextVisitTime: '',
nextVisitPreset: '',
intervalOptions: [] as any[],
popupShow: false, popupShow: false,
popupType: 'popup19', popupType: 'popup16',
popupParams: {}, popupParams: {} as any,
hasChange: false,
},
onLoad(options: any) {
app.waitLogin({ type: [1] }).then(() => {
this.getEnum().then(() => {
if (options.id) {
this.setData({
id: options.id,
isEdit: true,
})
this.getDetail()
}
})
})
},
getEnum() {
return wx.ajax({
method: 'GET',
url: '?r=xd/follow-up-reminder/enum',
}).then((res: any) => {
const tp = res.treatmentPlan || {}
const planOptions = Object.keys(tp).map(key => ({
value: key,
label: tp[key],
isSelected: false,
}))
const nvi = res.nextVisitInterval || {}
const intervalOptions = Object.keys(nvi).map(key => ({
value: key,
label: nvi[key],
}))
this.setData({ planOptions, intervalOptions })
})
},
updatePlanOptions(treatmentPlan: string[]) {
const planOptions = this.data.planOptions.map((opt: any) => ({
...opt,
isSelected: treatmentPlan.includes(opt.value),
}))
const showUsageCount = treatmentPlan.includes('5')
this.setData({ planOptions, showUsageCount })
},
getDetail() {
wx.ajax({
method: 'GET',
url: '?r=xd/follow-up-reminder/detail',
data: { id: this.data.id },
loading: true,
}).then((res: any) => {
const treatmentPlan = res.treatmentPlan ? res.treatmentPlan.split(',') : []
this.setData({
visitTime: res.visitTime || '',
treatmentPlan,
teprotumumabCount: res.teprotumumabCount || 1,
nextVisitTime: res.nextVisitTime || '',
hasChange: false,
})
this.updatePlanOptions(treatmentPlan)
})
},
onVisitDateChange(e: any) {
this.setData({ visitTime: e.detail.value, hasChange: true })
},
onNextDateChange(e: any) {
this.setData({ nextVisitTime: e.detail.value, nextVisitPreset: '', hasChange: true })
},
togglePlan(e: any) {
const value = e.currentTarget.dataset.value
const treatmentPlan = [...this.data.treatmentPlan]
const index = treatmentPlan.indexOf(value)
if (index > -1) {
treatmentPlan.splice(index, 1)
}
else {
treatmentPlan.push(value)
}
this.setData({ treatmentPlan, hasChange: true })
this.updatePlanOptions(treatmentPlan)
},
onStepperChange(e: any) {
this.setData({ teprotumumabCount: e.detail, hasChange: true })
},
onNextPresetChange(e: any) {
const preset = e.currentTarget.dataset.value
const { visitTime } = this.data
if (!visitTime) {
wx.showToast({ title: '请先选择复诊时间', icon: 'none' })
return
}
const date = new Date(visitTime)
if (preset === '21') {
date.setDate(date.getDate() + 21)
}
else if (preset === '30') {
date.setMonth(date.getMonth() + 1)
}
else if (preset === '60') {
date.setMonth(date.getMonth() + 2)
}
const nextVisitTime = this.formatDate(date)
this.setData({ nextVisitPreset: preset, nextVisitTime, hasChange: true })
},
formatDate(date: Date) {
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
const d = String(date.getDate()).padStart(2, '0')
return `${y}-${m}-${d}`
},
handleSubmit() {
const { visitTime, treatmentPlan, teprotumumabCount, nextVisitTime, id, isEdit } = this.data
if (!visitTime) {
wx.showToast({ title: '请选择复诊时间', icon: 'none' })
return
}
if (!treatmentPlan.length) {
wx.showToast({ title: '请选择复诊方案', icon: 'none' })
return
}
if (!nextVisitTime) {
wx.showToast({ title: '请选择下次复诊时间', icon: 'none' })
return
}
const data = {
visitTime,
treatmentPlan: treatmentPlan.join(','),
teprotumumabCount,
nextVisitTime,
}
if (isEdit) {
wx.ajax({
method: 'POST',
url: '?r=xd/follow-up-reminder/update',
data: { id, ...data },
loading: true,
}).then(() => {
wx.showToast({ title: '更新成功', icon: 'none' })
setTimeout(() => wx.navigateBack(), 1500)
})
}
else {
wx.ajax({
method: 'POST',
url: '?r=xd/follow-up-reminder/create',
data,
loading: true,
}).then(() => {
wx.showToast({ title: '创建成功', icon: 'none' })
setTimeout(() => wx.navigateBack(), 1500)
})
}
},
handleCancel() {
if (this.data.hasChange) {
this.setData({ popupShow: true, popupType: 'popup16' })
}
else {
wx.navigateBack()
}
},
handleDelete() {
this.setData({ popupShow: true, popupType: 'popup15' })
}, },
onLoad() {},
// popup 确认(继续退出)
handlePopupOk() { handlePopupOk() {
const { popupType } = this.data
this.setData({ popupShow: false }) this.setData({ popupShow: false })
wx.navigateBack() if (popupType === 'popup15') {
// 删除确认
wx.ajax({
method: 'POST',
url: '?r=xd/follow-up-reminder/delete',
data: { id: this.data.id },
loading: true,
}).then(() => {
wx.showToast({ title: '删除成功', icon: 'none' })
setTimeout(() => wx.navigateBack(), 1500)
})
}
else {
// 保存记录
this.handleSubmit()
}
}, },
// popup 取消
handlePopupCancel() { handlePopupCancel() {
this.setData({ popupShow: false }) this.setData({ popupShow: false })
wx.navigateBack()
}, },
}); })
export {} export {}

51
src/patient/pages/followForm/index.wxml

@ -1,26 +1,33 @@
<view class="page"> <view class="page">
<view class="card"> <view class="card">
<view class="c-title">您的复诊时间</view> <view class="c-title">您的复诊时间</view>
<picker mode="date"> <picker mode="date" value="{{visitTime}}" bind:change="onVisitDateChange">
<view class="date active"> <view class="date {{visitTime ? 'active' : ''}}">
<view class="content">年 / 月 / 日</view> <view class="content">{{visitTime || '年 / 月 / 日'}}</view>
<van-icon name="arrow-down" /> <van-icon name="arrow-down" />
</view> </view>
</picker> </picker>
</view> </view>
<view class="card"> <view class="card">
<view class="c-title">您复诊后的方案是?(多选)</view> <view class="c-title">您复诊后的方案是?(多选)</view>
<view class="check-item">1、激素静脉冲击治疗</view> <view
<view class="check-item active">2、生物制剂IGF-1R 抗体(替妥尤单抗)</view> class="check-item {{item.isSelected ? 'active' : ''}}"
wx:for="{{planOptions}}"
wx:key="value"
bind:tap="togglePlan"
data-value="{{item.value}}"
>{{item.label}}</view>
</view> </view>
<view class="card">
<view class="card" wx:if="{{showUsageCount}}">
<view class="c-title1">您是第几次使用替妥尤单抗?</view> <view class="c-title1">您是第几次使用替妥尤单抗?</view>
<view class="step"> <view class="step">
<van-stepper <van-stepper
value="{{ 1 }}" value="{{ teprotumumabCount }}"
min="{{1}}" min="{{1}}"
max="{{99}}" max="{{99}}"
bind:change="onChange" bind:change="onStepperChange"
custom-class="stepper" custom-class="stepper"
plus-class="pm" plus-class="pm"
minus-class="pm" minus-class="pm"
@ -36,26 +43,38 @@
</view> </view>
<view class="tip">注:替妥尤单抗常规疗程共 8 次注射(每3周1次)</view> <view class="tip">注:替妥尤单抗常规疗程共 8 次注射(每3周1次)</view>
</view> </view>
<view class="card"> <view class="card">
<view class="c-title"> <view class="c-title">
您的下次复诊时间 您的下次复诊时间
<view class="sub">配合就医建议周期</view> <view class="sub">配合就医建议周期</view>
</view> </view>
<picker mode="date"> <picker mode="date" value="{{nextVisitTime}}" bind:change="onNextDateChange">
<view class="date active"> <view class="date {{nextVisitTime ? 'active' : ''}}">
<view class="content">年 / 月 / 日</view> <view class="content">{{nextVisitTime || '年 / 月 / 日'}}</view>
<van-icon name="arrow-down" /> <van-icon name="arrow-down" />
</view> </view>
</picker> </picker>
<view class="radio-wrap"> <view class="radio-wrap">
<view class="radio active">21天后</view> <view
<view class="radio">1个月后</view> class="radio {{nextVisitPreset === item.value ? 'active' : ''}}"
<view class="radio">2个月后</view> wx:for="{{intervalOptions}}"
wx:key="value"
bind:tap="onNextPresetChange"
data-value="{{item.value}}"
>{{item.label}}</view>
</view> </view>
</view> </view>
<view class="page-footer"> <view class="page-footer">
<view class="cancel">取消</view> <block wx:if="{{isEdit}}">
<view class="submit">提交</view> <view class="cancel" bind:tap="handleDelete">删除</view>
<view class="submit" bind:tap="handleSubmit">提交</view>
</block>
<block wx:else>
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="submit" bind:tap="handleSubmit">提交</view>
</block>
</view> </view>
</view> </view>

17
src/patient/pages/index/index.scss

@ -121,12 +121,20 @@ page {
} }
} }
.f-container { .f-container {
position: relative;
padding: 16rpx 20rpx 16rpx 40rpx; padding: 16rpx 20rpx 16rpx 40rpx;
background: linear-gradient(70deg, #e98ff8 0%, #b073ff 100%); background: linear-gradient(70deg, #e98ff8 0%, #b073ff 100%);
border-radius: 24rpx; border-radius: 26rpx;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 42rpx; gap: 42rpx;
.pos {
position: absolute;
top: 0;
right: 0;
width: 212rpx;
height: 76rpx;
}
.aside { .aside {
padding-top: 70rpx; padding-top: 70rpx;
width: 150rpx; width: 150rpx;
@ -143,6 +151,13 @@ page {
color: rgba(185, 130, 255, 1); color: rgba(185, 130, 255, 1);
font-weight: bold; font-weight: bold;
} }
.a-name {
padding-top: 16rpx;
font-size: 40rpx;
font-weight: bold;
color: rgba(105, 104, 110, 0.83);
letter-spacing: 10rpx;
}
} }
.wrap { .wrap {
padding-top: 30rpx; padding-top: 30rpx;

142
src/patient/pages/index/index.ts

@ -50,6 +50,8 @@ Page({
unreadCount: 0, unreadCount: 0,
followLatest: null as any,
options: {} as any, options: {} as any,
}, },
onLoad(options) { onLoad(options) {
@ -105,6 +107,7 @@ Page({
this.getPopup() this.getPopup()
this.getConfig(zdUserInfo) this.getConfig(zdUserInfo)
this.getSystemConfig() this.getSystemConfig()
this.getFollowLatest()
if (zdUserInfo.ExclusiveDoctorId > 0) { if (zdUserInfo.ExclusiveDoctorId > 0) {
this.getUnreadCount() this.getUnreadCount()
} }
@ -113,7 +116,39 @@ Page({
}, },
async getPopup() { async getPopup() {
// https://fa0ci3qr2z.feishu.cn/wiki/EBX6woN7xiaartkYkBpcfbYQnfn // https://fa0ci3qr2z.feishu.cn/wiki/EBX6woN7xiaartkYkBpcfbYQnfn
if (this.data.toastShow) return if (this.data.toastShow)
return
const data4 = await wx.ajax({
method: 'GET',
url: '?r=zd/popup/get-need-popup',
data: {
type: 1,
},
})
if (data4.showAlert) {
this.setData({
toastShow: data4.showAlert,
toastType: 'guideEnterInfo',
toastParams: {},
})
return
}
const data5 = await wx.ajax({
method: 'GET',
url: '?r=zd/popup/get-popup',
data: {
type: 4,
},
})
if (data5.showAlert) {
this.setData({
toastShow: data5.showAlert,
toastType: 'followGuide',
toastParams: { close: true },
})
}
const noteGuideShown = wx.getStorageSync('noteGuideShown') const noteGuideShown = wx.getStorageSync('noteGuideShown')
if (!noteGuideShown) { if (!noteGuideShown) {
@ -156,21 +191,6 @@ Page({
toastParams: { close: true }, toastParams: { close: true },
}) })
} }
const data4 = await wx.ajax({
method: 'GET',
url: '?r=zd/popup/get-need-popup',
data: {
type: 1,
},
})
if (data4.showAlert) {
this.setData({
toastShow: data4.showAlert,
toastType: 'guideEnterInfo',
toastParams: {},
})
}
}, },
getUnreadCount() { getUnreadCount() {
wx.ajax({ wx.ajax({
@ -183,6 +203,34 @@ Page({
}) })
}) })
}, },
getFollowLatest() {
wx.ajax({
method: 'GET',
url: '?r=xd/follow-up-reminder/latest',
data: {},
}).then((res: any) => {
if (res && res.nextVisitTime) {
const date = dayjs(res.nextVisitTime)
const year = date.format('YYYY')
this.setData({
followLatest: {
...res,
year,
yearPrefix: year.slice(0, 2),
yearSuffix: year.slice(2),
month: date.format('MM'),
day: date.format('DD'),
week: date.format('dddd'),
},
})
}
else {
this.setData({ followLatest: null })
}
}).catch(() => {
this.setData({ followLatest: null })
})
},
getSystemConfig() { getSystemConfig() {
wx.ajax({ wx.ajax({
method: 'GET', method: 'GET',
@ -228,11 +276,13 @@ Page({
// 设置显示状态 // 设置显示状态
if (code === 'medicalInsurance' && showStatus == 1) { if (code === 'medicalInsurance' && showStatus == 1) {
statusMap.medicalInsuranceShow = true statusMap.medicalInsuranceShow = true
if (openStatus == 1) statusMap.medicalInsuranceJump = true if (openStatus == 1)
statusMap.medicalInsuranceJump = true
} }
if (code === 'hospitalMap' && showStatus == 1) { if (code === 'hospitalMap' && showStatus == 1) {
statusMap.hospitalMapShow = true statusMap.hospitalMapShow = true
if (openStatus == 1) statusMap.hospitalMapJump = true if (openStatus == 1)
statusMap.hospitalMapJump = true
} }
if (code === 'adl' && showStatus == 1) { if (code === 'adl' && showStatus == 1) {
statusMap.qolShow = true statusMap.qolShow = true
@ -352,7 +402,8 @@ Page({
}) })
return return
} }
if (!url) return if (!url)
return
if (code === 'doctor') { if (code === 'doctor') {
app.mpBehavior({ PageName: 'BTN_PatientHomeDoctorCard' }) app.mpBehavior({ PageName: 'BTN_PatientHomeDoctorCard' })
} }
@ -386,8 +437,8 @@ Page({
}, },
handleAddQol() { handleAddQol() {
const { qolDetail } = this.data const { qolDetail } = this.data
const url = const url
qolDetail.Id && qolDetail.isTodayRecord = qolDetail.Id && qolDetail.isTodayRecord
? `/patient/pages/qolAdd/index?id=${qolDetail.Id}&edit=1` ? `/patient/pages/qolAdd/index?id=${qolDetail.Id}&edit=1`
: `/patient/pages/qol/index` : `/patient/pages/qol/index`
wx.navigateTo({ wx.navigateTo({
@ -408,7 +459,8 @@ Page({
wx.navigateTo({ wx.navigateTo({
url: `/patient/pages/hormones/index?id=${hormoneDetail.recordId}`, url: `/patient/pages/hormones/index?id=${hormoneDetail.recordId}`,
}) })
} else { }
else {
wx.navigateTo({ wx.navigateTo({
url: '/patient/pages/hormonesStart/index', url: '/patient/pages/hormonesStart/index',
}) })
@ -424,12 +476,14 @@ Page({
url: '/patient/pages/adl/index?nrdl=1', url: '/patient/pages/adl/index?nrdl=1',
}) })
this.handleToastCancel() this.handleToastCancel()
} else if (toastType === 'doubleStandards') { }
else if (toastType === 'doubleStandards') {
wx.navigateTo({ wx.navigateTo({
url: '/patient/pages/adl/index', url: '/patient/pages/adl/index',
}) })
this.handleToastCancel() this.handleToastCancel()
} else if (toastType === 'dedicatedDoctor') { }
else if (toastType === 'dedicatedDoctor') {
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '?r=zd/popup/close-popup', url: '?r=zd/popup/close-popup',
@ -442,7 +496,8 @@ Page({
}) })
}) })
this.handleToastCancel(null, false) this.handleToastCancel(null, false)
} else if (toastType === 'medical-guide') { }
else if (toastType === 'medical-guide') {
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '?r=zd/popup/add-record', url: '?r=zd/popup/add-record',
@ -453,7 +508,8 @@ Page({
}) })
}) })
this.handleToastCancel(null, false) this.handleToastCancel(null, false)
} else if (toastType === 'guideEnterInfo') { }
else if (toastType === 'guideEnterInfo') {
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '?r=zd/popup/close-need-popup', url: '?r=zd/popup/close-need-popup',
@ -464,12 +520,25 @@ Page({
}) })
this.handleToastCancel(null, false) this.handleToastCancel(null, false)
}) })
} else if (toastType === 'guideEnterInfoJump') { }
else if (toastType === 'guideEnterInfoJump') {
wx.navigateTo({ wx.navigateTo({
url: '/patient/pages/personalInformation/index', url: '/patient/pages/personalInformation/index',
}) })
this.handleToastCancel(null, false) this.handleToastCancel(null, false)
} }
else if (toastType === 'followGuide') {
wx.ajax({
method: 'POST',
url: '?r=zd/popup/add-record',
data: { type: 4 },
}).then(() => {
wx.navigateTo({
url: '/patient/pages/followForm/index',
})
})
this.handleToastCancel(null, false)
}
}, },
handleToastCancel(_e = null, sure = true) { handleToastCancel(_e = null, sure = true) {
const { toastType } = this.data const { toastType } = this.data
@ -481,7 +550,8 @@ Page({
Type: 5, Type: 5,
}, },
}) })
} else if (toastType === 'dedicatedDoctor' && sure) { }
else if (toastType === 'dedicatedDoctor' && sure) {
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '?r=zd/popup/close-popup', url: '?r=zd/popup/close-popup',
@ -489,19 +559,28 @@ Page({
Type: 6, Type: 6,
}, },
}) })
} else if (toastType === 'medical-guide' && sure) { }
else if (toastType === 'medical-guide' && sure) {
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '?r=zd/popup/add-record', url: '?r=zd/popup/add-record',
data: { type: 3 }, data: { type: 3 },
}) })
} else if (toastType === 'guideEnterInfo' && sure) { }
else if (toastType === 'guideEnterInfo' && sure) {
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '?r=zd/popup/close-need-popup', url: '?r=zd/popup/close-need-popup',
data: { type: 1 }, data: { type: 1 },
}) })
} }
else if (toastType === 'followGuide' && sure) {
wx.ajax({
method: 'POST',
url: '?r=zd/popup/add-record',
data: { type: 4 },
})
}
this.setData({ this.setData({
toastShow: false, toastShow: false,
@ -538,7 +617,8 @@ Page({
infoList: list, infoList: list,
}) })
}) })
} else { }
else {
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '?r=zd/pic-text/collection', url: '?r=zd/pic-text/collection',

28
src/patient/pages/index/index.wxml

@ -36,33 +36,37 @@
<image class="more" src="{{imageUrl}}icon118.png?t={{Timestamp}}"></image> <image class="more" src="{{imageUrl}}icon118.png?t={{Timestamp}}"></image>
</view> </view>
<view class="follow"> <view class="follow">
<view class="empty" wx:if="{{true}}" bind:tap="handleFollowEmpty"> <view class="empty" wx:if="{{!followLatest}}" bind:tap="handleFollowEmpty">
<image class="icon" src="/images/icon170.png"></image> <image class="icon" src="{{imageUrl}}icon170.png?t={{Timestamp}}"></image>
<view class="content">设置复诊提醒</view> <view class="content">设置复诊提醒</view>
</view> </view>
<view class="f-container" wx:if="{{false}}" bind:tap="handleFollow"> <view class="f-container" wx:if="{{followLatest}}" bind:tap="handleFollow">
<view class="aside" style="background: url('/images/bg60.png') no-repeat top center/100%"> <image class="pos" wx:if="{{followLatest.remainingDays < 0}}" src="{{imageUrl}}bg61.png?t={{Timestamp}}"></image>
<view class="a-num">10</view> <view class="aside" style="background: url('{{imageUrl}}bg60.png?t={{Timestamp}}') no-repeat top center/100%">
<text wx:if="{{nextVisitDays !== 0}}">天</text> <block wx:if="{{followLatest.remainingDays >= 0}}">
<view class="a-num">{{followLatest.remainingDays}}</view>
<text>天</text>
</block>
<view class="a-name" wx:else>-天</view>
</view> </view>
<view class="wrap"> <view class="wrap">
<view class="title"> <view class="title">
<image class="icon" src="/images/icon171.png"></image> <image class="icon" src="{{imageUrl}}icon171.png?t={{Timestamp}}"></image>
复诊时间 复诊时间
</view> </view>
<view class="content"> <view class="content">
<view class="year"> <view class="year">
20 {{followLatest.yearPrefix}}
<view></view> <view></view>
26 {{followLatest.yearSuffix}}
</view> </view>
<view class="yd"> <view class="yd">
<view class="yd-num">06</view> <view class="yd-num">{{followLatest.month}}</view>
<view class="sub">月</view> <view class="sub">月</view>
<view class="yd-num">10</view> <view class="yd-num">{{followLatest.day}}</view>
<view class="sub">日</view> <view class="sub">日</view>
</view> </view>
<view class="week">星期三</view> <view class="week">{{followLatest.week}}</view>
</view> </view>
</view> </view>
</view> </view>

66
src/patient/pages/interactivePatient/index.scss

@ -368,6 +368,18 @@ page {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.tip {
margin-top: 30rpx;
width: 100%;
height: 76rpx;
font-size: 32rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 64rpx 64rpx 64rpx 64rpx;
background: rgba(246, 248, 249, 1);
color: rgba(105, 104, 110, 1);
}
} }
} }
.follow-form { .follow-form {
@ -407,6 +419,10 @@ page {
justify-content: center; justify-content: center;
background: linear-gradient(180deg, #e98ff8 0%, #b073ff 100%); background: linear-gradient(180deg, #e98ff8 0%, #b073ff 100%);
border-radius: 64rpx 64rpx 64rpx 64rpx; border-radius: 64rpx 64rpx 64rpx 64rpx;
&.disabled {
background: rgba(246, 248, 249, 1);
color: rgba(105, 104, 110, 1);
}
} }
} }
.follow-reset { .follow-reset {
@ -581,7 +597,7 @@ page {
} }
} }
} }
.follow-result { .follow-result-reason {
margin-bottom: 32rpx; margin-bottom: 32rpx;
padding: 32rpx; padding: 32rpx;
border-radius: 32rpx; border-radius: 32rpx;
@ -590,14 +606,56 @@ page {
font-size: 32rpx; font-size: 32rpx;
color: rgba(33, 29, 46, 1); color: rgba(33, 29, 46, 1);
} }
.list { .info {
margin-top: 20rpx; margin-top: 20rpx;
padding: 24rpx; padding: 24rpx;
background-color: rgba(246, 248, 249, 1); background-color: rgba(246, 248, 249, 1);
border-radius: 16rpx; border-radius: 16rpx;
.list-item { .info-item {
font-size: 32rpx; font-size: 32rpx;
padding-left: 50rpx;
color: rgba(33, 29, 46, 1); color: rgba(33, 29, 46, 1);
.label {
display: inline;
font-weight: bold;
}
.value {
display: inline;
}
&::before {
margin-left: -30rpx;
margin-right: 20rpx;
margin-top: 20rpx;
display: inline-block;
flex-shrink: 0;
content: '';
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #7d7d82;
}
&:not(:first-of-type) {
margin-top: 24rpx;
}
}
}
}
.follow-result {
margin-bottom: 32rpx;
padding: 32rpx;
border-radius: 32rpx;
background-color: rgba(185, 130, 255, 1);
.title {
font-size: 32rpx;
color: #fff;
}
.list {
margin-top: 20rpx;
padding: 24rpx;
border-radius: 16rpx;
.list-item {
font-size: 32rpx;
color: #fff;
display: flex; display: flex;
.blob { .blob {
font-weight: bold; font-weight: bold;
@ -611,7 +669,7 @@ page {
width: 10rpx; width: 10rpx;
height: 10rpx; height: 10rpx;
border-radius: 50%; border-radius: 50%;
background-color: #7d7d82; background-color: #fff;
} }
&:not(:first-of-type) { &:not(:first-of-type) {
margin-top: 24rpx; margin-top: 24rpx;

190
src/patient/pages/interactivePatient/index.ts

@ -4,7 +4,24 @@ const app = getApp<IAppOption>()
interface IMessageItem { interface IMessageItem {
msgId: string msgId: string
msgContentType: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' // 1:文本 2: 出诊时间 3: adl卡片 4: 语音 5: 欢迎语 6:补充真实姓名 7: 提醒完善信息 8: 复诊卡片 9:患者恢复复诊消息 msgContentType:
| '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
| '8'
| '9'
| '10'
| '11'
| '12'
| '13'
| '14'
| '15'
| '16'
| '17' // 1:文本 2: 出诊时间 3: adl卡片 4: 语音 5: 欢迎语 6:补充真实姓名 7: 提醒完善信息 8: 复诊卡片 9:患者恢复复诊消息 13: 患者复诊回复 14: 未复诊原因 15: 患者未复诊原因回复 16: 其他输入 17: 下一步
msgContent: any msgContent: any
msgVisitTime: string msgVisitTime: string
msgFromType: '1' | '2' // 1: 患者 2: 医生 msgFromType: '1' | '2' // 1: 患者 2: 医生
@ -18,6 +35,12 @@ interface IMessageItem {
ReVisitInfo?: any ReVisitInfo?: any
msgCustomSendStatus?: number | string msgCustomSendStatus?: number | string
msgTipsInfo?: string msgTipsInfo?: string
followUpStatus?: number // 复诊状态,>0 表示已回复
replyMsgId?: number // 回复消息ID,>0 表示已回复
followUpTitle?: string // 复诊原因标题
followUpTitleChoice?: string // 复诊原因多选提示
selectedReasons?: string[] // 选中的未复诊原因
otherReason?: string // 其他原因文本
} }
interface Item { interface Item {
@ -153,6 +176,34 @@ Page({
item.ReVisitInfo = JSON.parse(item.ReVisitInfo) item.ReVisitInfo = JSON.parse(item.ReVisitInfo)
item.ReVisitInfo.visitDateName = dayjs(item.ReVisitInfo.visitDate).format('YYYY年M月DD日') item.ReVisitInfo.visitDateName = dayjs(item.ReVisitInfo.visitDate).format('YYYY年M月DD日')
} }
if (item.msgContentType === '14') {
const rawInfo = JSON.parse(item.ReVisitInfo)
// 解析结构:{title, titleChoice, missionReasonList, reasonList}
const missionReasonList = rawInfo.missionReasonList || {}
const reasonList = rawInfo.reasonList || []
// 将对象转换为数组 {key, label, isSelected} 格式
item.ReVisitInfo = Object.keys(missionReasonList).map(key => ({
key,
label: missionReasonList[key],
isSelected: reasonList.includes(key),
}))
item.followUpTitle = rawInfo.title || '请问您没能按时复诊的主要原因是?'
item.followUpTitleChoice = rawInfo.titleChoice || '(多选)'
item.selectedReasons = [...reasonList]
}
if (item.msgContentType === '13') {
const rawInfo = JSON.parse(item.ReVisitInfo)
// 解析结构:{title, lastVisitTitle, visitDate, mySolutionTitle, reVisitSolution}
item.ReVisitInfo = rawInfo
}
if (item.msgContentType === '15') {
const rawInfo = JSON.parse(item.ReVisitInfo)
// 解析结构:{title, reasonInfoList}
const reasonInfoList = rawInfo.reasonInfoList || {}
item.followUpTitle = rawInfo.title || '没能按时复诊的主要原因是?'
// 将 reasonInfoList 对象转换为数组
item.ReVisitInfo = Object.keys(reasonInfoList).map(key => reasonInfoList[key])
}
return item return item
}) })
@ -483,4 +534,141 @@ Page({
}, },
}) })
}, },
// 复诊消息回复 - 已复诊/未复诊
handleFollowUpReply(e: any) {
const { status, mindex } = e.currentTarget.dataset
const { messageList } = this.data
const message = messageList[mindex]
if (Number(message.followUpStatus) > 0)
return
wx.ajax({
method: 'POST',
url: '?r=zd/message-interact/send-reply-followup-message',
data: {
msgId: message.msgId,
followUpStatus: status, // 1-未复诊, 2-已复诊
},
loading: true,
}).then((res: any) => {
// 刷新消息列表
setTimeout(() => {
this.refreshMessageList()
}, 500)
})
},
// 未复诊原因选择
handleReasonToggle(e: any) {
const { key, mindex } = e.currentTarget.dataset
const { messageList } = this.data
const message = messageList[mindex]
const selectedReasons = message.selectedReasons || []
const index = selectedReasons.indexOf(key)
if (index > -1) {
selectedReasons.splice(index, 1)
}
else {
selectedReasons.push(key)
}
messageList[mindex].selectedReasons = [...selectedReasons]
// 更新每个选项的选中状态
messageList[mindex].ReVisitInfo = messageList[mindex].ReVisitInfo.map((item: any) => ({
...item,
isSelected: selectedReasons.includes(item.key),
}))
this.setData({ messageList })
},
// 提交未复诊原因
handleReasonSubmit(e: any) {
const { mindex } = e.currentTarget.dataset
const { messageList } = this.data
const message = messageList[mindex]
const selectedReasons = message.selectedReasons || []
if (selectedReasons.length === 0) {
wx.showToast({ title: '请选择至少一个原因', icon: 'none' })
return
}
// 构建 reasonList 参数
const data: any = { msgId: message.msgId, reasonList: [] }
selectedReasons.forEach((reason, index) => {
data.reasonList.push(reason)
})
wx.ajax({
method: 'POST',
url: '?r=zd/message-interact/send-reply-followup-reason',
data,
loading: true,
}).then(() => {
// 刷新消息列表
setTimeout(() => {
this.refreshMessageList()
}, 500)
})
},
// 其他原因输入
handleOtherReasonInput(e: any) {
const { mindex } = e.currentTarget.dataset
const { messageList } = this.data
messageList[mindex].otherReason = e.detail.value
this.setData({ messageList })
},
// 提交其他原因 (msgContentType 16)
handleOtherReasonSubmit(e: any) {
const { mindex } = e.currentTarget.dataset
const { messageList } = this.data
const message = messageList[mindex]
const otherReason = message.otherReason || ''
if (!otherReason.trim()) {
wx.showToast({ title: '请输入原因', icon: 'none' })
return
}
// TODO: 需要确认 16 类型的提交接口
wx.ajax({
method: 'POST',
url: '?r=zd/message-interact/send-reply-followup-reason',
data: {
'msgId': message.msgId,
'reasonList[0]': 'other',
'otherReason': otherReason.trim(),
},
loading: true,
}).then(() => {
setTimeout(() => {
this.refreshMessageList()
}, 500)
})
},
// 刷新消息列表
refreshMessageList() {
this.setData({
messageList: [],
nextMsgId: '',
isFinish: false,
})
this.getMessageList()
},
handleResetFollowUp() {
wx.navigateTo({
url: '/patient/pages/follow/index',
})
},
handleNextFollowUp() {
wx.navigateTo({
url: '/patient/pages/follow/index',
})
},
}) })

69
src/patient/pages/interactivePatient/index.wxml

@ -105,33 +105,46 @@
<view class="btn" bind:tap="handleFillUserInfo">完善个人信息</view> <view class="btn" bind:tap="handleFillUserInfo">完善个人信息</view>
</view> </view>
<!-- 复诊提醒 --> <!-- 复诊提醒 -->
<view class="follow" wx:elif="{{message.msgContentType==='12'}}"> <view class="follow" wx:elif="{{message.msgContentType==='8'}}">
<view class="content"> <view class="content">
您好!出院后的康复需要我们双方共同努力,请问您最近有按照医生的提醒,定期到院复诊吗? 您好!出院后的康复需要我们双方共同努力,请问您最近有按照医生的提醒,定期到院复诊吗?
</view> </view>
<view class="f-footer"> <view class="f-footer" wx:if="{{message.followUpStatus == 0}}">
<view class="btn1">已复诊</view> <view class="btn1" bind:tap="handleFollowUpReply" data-status="2" data-mindex="{{mIndex}}">已复诊</view>
<view class="btn2">未复诊</view> <view class="btn2" bind:tap="handleFollowUpReply" data-status="1" data-mindex="{{mIndex}}">未复诊</view>
</view>
<view class="f-footer replied" wx:else>
<view class="tip">已回复</view>
</view> </view>
</view> </view>
<!-- 复诊提醒-快速问答 --> <!-- 复诊提醒-快速问答 -->
<view class="follow-form" wx:elif="{{message.msgContentType==='13'}}"> <view class="follow-form" wx:elif="{{message.msgContentType==='14'}}">
<view class="content"> <view class="content">
请问您没能按时复诊的主要原因是? {{message.followUpTitle}}
<text class="sub">(多选)</text> <text class="sub">{{message.followUpTitleChoice}}</text>
</view> </view>
<view class="list"> <view class="list">
<view class="list-item">症状感觉好转,觉得不用去了</view> <view
class="list-item {{item.isSelected ? 'active' : ''}}"
wx:for="{{message.ReVisitInfo}}"
wx:key="key"
bind:tap="handleReasonToggle"
data-key="{{item.key}}"
data-mindex="{{mIndex}}"
>
{{item.label}}
</view>
</view> </view>
<view class="btn">提交</view> <view class="btn" wx:if="{{message.replyMsgId == 0}}" bind:tap="handleReasonSubmit" data-mindex="{{mIndex}}">提交</view>
<view class="btn disabled" wx:else>已提交</view>
</view> </view>
<view class="follow-reset" wx:elif="{{message.msgContentType==='14'}}"> <view class="follow-reset" wx:elif="{{message.msgContentType==='16'}}">
<view class="content">规范治疗可获得更好的疗效,减少复发。</view> <view class="content">{{message.msgContent}}</view>
<view class="btn">提交</view> <view class="btn" bind:tap="handleResetFollowUp">重新预约复诊</view>
</view> </view>
<view class="follow-next" wx:elif="{{message.msgContentType==='15'}}"> <view class="follow-next" wx:elif="{{message.msgContentType==='17'}}">
<view class="content">坚持规范治疗,继续加油,愿身体稳步向好!</view> <view class="content">{{message.msgContent}}</view>
<view class="btn">提交</view> <view class="btn" bind:tap="handleNextFollowUp">设置下一次复诊提醒</view>
</view> </view>
</view> </view>
</view> </view>
@ -170,21 +183,25 @@
<view class="item" wx:if="{{message.ReVisitInfo.other==1}}">9.其他</view> <view class="item" wx:if="{{message.ReVisitInfo.other==1}}">9.其他</view>
</view> </view>
</view> </view>
<view class="follow-result" wx:if="{{message.msgContentType==='15'}}"> <view class="follow-result-reason" wx:if="{{message.msgContentType==='13'}}">
<view class="title">医生您好,我刚刚完成了复诊记录:</view> <view class="title">{{message.ReVisitInfo.title}}</view>
<view class="list"> <view class="info">
<view class="list-item"> <view class="info-item">
<view class="li-content"> <view class="label">{{message.ReVisitInfo.lastVisitTitle}}</view>
<text class="blob">我最近一次复诊时间是:</text> <view class="value">{{message.ReVisitInfo.visitDate}}</view>
2025年6月11日
</view> </view>
<view class="info-item">
<view class="label">{{message.ReVisitInfo.mySolutionTitle}}</view>
<view class="value" wx:for="{{message.ReVisitInfo.reVisitSolution}}" wx:key="index">{{item}}</view>
</view> </view>
<view class="list-item">
<view class="li-content">
<text class="blob">我的方案是:</text>
生物制剂IGF-1R抗体(替妥尤单抗)第2次使用替妥尤单抗
</view> </view>
</view> </view>
<view class="follow-result" wx:if="{{message.msgContentType==='15'}}">
<view class="title">{{message.followUpTitle}}</view>
<view class="list">
<view class="list-item" wx:for="{{message.ReVisitInfo}}" wx:key="index">
<view class="li-content">{{item}}</view>
</view>
</view> </view>
</view> </view>
</view> </view>

4
src/patient/pages/my/index.wxml

@ -26,11 +26,11 @@
</view> </view>
<view class="kkd"> <view class="kkd">
<view class="kkd-item" bind:tap="routerTo" data-url="/patient/pages/qolReport/index"> <view class="kkd-item" bind:tap="routerTo" data-url="/patient/pages/qolReport/index">
<image class="icon" src="/images/icon175.png"></image> <image class="icon" src="{{imageUrl}}icon175.png?t={{Timestamp}}"></image>
健康档案 健康档案
</view> </view>
<view class="kkd-item" bind:tap="routerTo" data-url="/patient/pages/follow/index"> <view class="kkd-item" bind:tap="routerTo" data-url="/patient/pages/follow/index">
<image class="icon" src="/images/icon175.png"></image> <image class="icon" src="{{imageUrl}}icon175.png?t={{Timestamp}}"></image>
复诊记录 复诊记录
</view> </view>
</view> </view>

766
接口文档.md

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save