You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

648 lines
16 KiB

3 months ago
import dayjs from 'dayjs'
const app = getApp<IAppOption>()
2 weeks ago
let echarts: any = null
2 weeks ago
const MEDICATIONS_MAP: Record<number, string> = {
1: '没有使用激素',
2: '激素',
3: '免疫抑制剂',
4: '靶向CD19生物制剂',
5: '靶向CD20生物制剂',
99: '其他',
}
const IMMUNOSUPPRESSANT_MAP: Record<number, string> = {
1: '吗替麦考酚酯',
2: '替唑嘌呤',
3: '环磷酰胺',
4: '来氟米特',
5: '甲氨蝶呤',
6: '环孢素A',
7: '他克莫司',
8: '艾拉莫德',
99: '其他',
}
3 months ago
Page({
data: {
toastShow: false,
toastType: 'patientDetailSafeDoctor',
toastParams: {} as any,
showTel: false,
doctor: {},
hospital: {},
id: '',
remark: '',
detail: {} as any,
popupRemarkShow: false,
remarkFocus: false,
popupEditShow: false,
antibodyTypeRangeList: [
{
id: '1',
value: 'AchR',
},
{
id: '2',
value: 'MuSK',
},
{
id: '3',
value: 'LRP4',
},
{
id: '4',
value: 'RyR',
},
],
thyroidAbnormalRangeList: [
{
id: '1',
value: '是',
},
{
id: '2',
value: '否',
},
],
previousConvulsionRangeList: [
{
id: '1',
value: '是',
},
{
id: '2',
value: '否',
},
],
traditionalImmunosuppressantRangeList: [
{
id: '1',
value: '他克莫司',
},
{
id: '2',
value: '硫唑嘌呤',
},
{
id: '3',
value: '吗替麦考酚酯',
},
{
id: '4',
value: '其它',
},
],
medicalInsuranceTypeRangeList: [
{
id: '1',
value: '城市职工',
},
{
id: '2',
value: '城市居民',
},
{
id: '3',
value: '新农合',
},
],
2 months ago
ageRangeMap: {
1: '<40岁',
2: '40-49岁',
3: '50-59岁',
4: '60-69岁',
5: '70-79岁',
6: '80岁以上',
},
diagnosisTimeRangeMap: {
1: '6个月以内',
2: '6个月-3年',
3: '3年以上',
},
2 weeks ago
2 weeks ago
// 图表筛选
yearOptions: [
{ label: '按年', value: 1 },
{ label: '按次', value: 2 },
] as { label: string; value: number }[],
selected: 1,
selectedLabel: '按年',
BeginMonth: dayjs().subtract(1, 'year').add(1, 'month').format('YYYY-MM'),
EndMonth: dayjs().format('YYYY-MM'),
chartUnit: '',
chartList: [] as any[],
// 病历报告
2 weeks ago
caseReportList: [
{
icon: 'icon142.png',
name: '门诊病历及处方',
content: '医生手写或电脑打印的病历、处方',
2 weeks ago
imageField: 'outpatientRecord',
},
{ icon: 'icon127.png', name: '检验报告', content: '抽血检测的IgG4、IgG、ESR等', imageField: 'labReport' },
{
icon: 'icon128.png',
name: '影像学检查',
content: '超声/CT/MRI的描述结论、电子胶片',
imageField: 'imagingExam',
},
{
icon: 'icon129.png',
name: '病理诊断及活检',
content: '受累组织穿刺或切除免疫组化报告',
imageField: 'pathology',
},
{
icon: 'icon130.png',
name: '外周血免疫功能评估',
content: '免疫细胞亚群、淋巴细胞比例测定',
imageField: 'immuneFunction',
2 weeks ago
},
],
2 weeks ago
// Tab 切换
currentTab: 0,
// 就诊记录列表
recordList: [] as any[],
recordPagination: { count: 0, page: 1, pages: 1 },
// 导出PPT
pptGenerating: false,
3 months ago
},
2 weeks ago
ecDataTrendComponent: null as any,
async onLoad(option) {
3 months ago
this.setData({
id: option.id,
})
2 weeks ago
echarts = await require.async('../../../resource/components/echart/echarts.js')
this.ecDataTrendComponent = this.selectComponent('#chart1')
3 months ago
app.waitLogin().then(async (_res) => {
2 weeks ago
app.mpBehavior({ doctor: true, PageName: 'PG_DoctorPatientDetail', detailId: this.data.id })
3 months ago
this.getDoctorDetail()
await this.getDetail()
2 weeks ago
this.getIndicatorHistory()
this.getRecordList(true)
3 months ago
})
},
2 weeks ago
2 weeks ago
// ========== Tab 切换 ==========
handleTabChange(e: any) {
const { index } = e.currentTarget.dataset
const tab = Number(index)
if (tab === this.data.currentTab) return
this.setData({ currentTab: tab })
wx.pageScrollTo({ scrollTop: 0, duration: 200 })
// 切换到就诊记录时如果列表为空则请求
if (tab === 1 && !this.data.recordList.length) {
this.getRecordList(true)
}
// 切换到基本信息时重新获取图表组件并渲染
if (tab === 0 && this.data.chartList.length) {
setTimeout(() => {
this.ecDataTrendComponent = this.selectComponent('#chart1')
this.initChart(this.data.chartList)
}, 100)
}
},
// ========== 图表筛选 ==========
handleChange(e: any) {
const idx = Number(e.detail.value)
const selected = this.data.yearOptions[idx]
if (!selected) return
const isByYear = selected.value === 1
this.setData({
selected: selected.value,
selectedLabel: selected.label,
BeginMonth: isByYear ? dayjs().subtract(1, 'year').add(1, 'month').format('YYYY-MM') : '',
EndMonth: isByYear ? dayjs().format('YYYY-MM') : '',
})
this.getIndicatorHistory()
},
handleBeginDateChange(e: any) {
const BeginMonth = e.detail.value
this.setData({ BeginMonth })
if (this.data.EndMonth) {
this.getIndicatorHistory()
}
},
handleEndDateChange(e: any) {
const EndMonth = e.detail.value
this.setData({ EndMonth })
if (this.data.BeginMonth) {
this.getIndicatorHistory()
}
},
// ========== 指标趋势图表 ==========
initChart(defaultList: any[] = []) {
if (!defaultList.length) return
if (!echarts || !this.ecDataTrendComponent) {
this.ecDataTrendComponent = this.selectComponent('#chart1')
if (!echarts || !this.ecDataTrendComponent) return
}
const list = defaultList
this.ecDataTrendComponent.init((canvas: any, width: number, height: number, dpr: number) => {
const chart = echarts.init(canvas, null, {
width,
height,
devicePixelRatio: dpr,
})
canvas.setChart(chart)
const color = 'rgba(22, 121, 203, 1)'
const option: any = {
tooltip: {
show: false,
trigger: 'axis',
axisPointer: { type: 'shadow' },
confine: true,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
textStyle: { color: '#fff', fontSize: 10 },
order: 'seriesDesc',
},
grid: {
top: '30',
left: '0',
right: '0',
bottom: '10',
containLabel: true,
},
xAxis: [
{
type: 'category',
axisTick: { alignWithLabel: true },
axisLine: {
lineStyle: { color: 'rgba(34, 34, 34, 0.20)', type: 'dashed' },
2 weeks ago
},
2 weeks ago
data: list.map((item: any) => dayjs(item.visitDate).format('MM-DD')),
2 weeks ago
},
2 weeks ago
],
yAxis: [
{
type: 'value',
minInterval: 1,
axisLabel: { color: 'rgba(34, 34, 34, 0.40)' },
splitLine: {
lineStyle: { color: 'rgba(34, 34, 34, 0.20)', type: 'dashed' },
},
2 weeks ago
},
2 weeks ago
],
series: [
{
name: 'IgG4',
data: list.length ? list.map((item: any) => item.value) : [0],
barWidth: '16',
label: {
show: true,
position: 'top',
color,
2 weeks ago
},
2 weeks ago
type: 'line',
symbol: 'circle',
symbolSize: 8,
showSymbol: list.length >= 1,
connectNulls: true,
z: 10,
itemStyle: {
color,
2 weeks ago
},
2 weeks ago
markLine: {
symbol: ['none', 'none'],
data: [
{
name: '135 安全区',
yAxis: 135,
label: {
formatter: '{b}',
position: 'insideMiddle',
color,
fontSize: '10',
},
lineStyle: {
cap: '',
color,
type: 'dashed',
2 weeks ago
},
},
2 weeks ago
],
},
markArea: {
itemStyle: {
color: 'rgba(22, 121, 203, 0.16)',
2 weeks ago
},
2 weeks ago
data: [[{ yAxis: 0 }, { yAxis: 135 }]],
2 weeks ago
},
},
2 weeks ago
],
dataZoom: {
type: 'inside',
startValue: 0,
endValue: 4,
filterMode: 'none',
},
}
chart.setOption(option)
return chart
})
},
getIndicatorHistory() {
const data: Record<string, any> = {
patientId: this.data.id,
indicatorField: 'igG4',
}
const { BeginMonth, EndMonth, selected } = this.data
if (BeginMonth && EndMonth && selected === 1) {
data.yearStart = Number(BeginMonth.substring(0, 4))
data.yearEnd = Number(EndMonth.substring(0, 4))
}
2 weeks ago
2 weeks ago
wx.ajax({
method: 'GET',
url: '?r=igg4/doctor/medical-visit/indicator-history',
data,
}).then((res: any) => {
if (!res) return
this.setData({
chartUnit: res.unit || 'mg/dL',
chartList: res.list || [],
2 weeks ago
})
2 weeks ago
this.initChart(res.list || [])
2 weeks ago
})
},
2 weeks ago
// ========== 就诊记录列表 ==========
getRecordList(reset = false) {
const page = reset ? 1 : this.data.recordPagination.page
wx.ajax({
method: 'GET',
url: '?r=igg4/doctor/medical-visit/list',
data: {
patientId: this.data.id,
page,
pageSize: 10,
},
}).then((res: any) => {
if (!res) return
const list = (res.list || []).map((item: any) => ({
...item,
medicationLabels: (item.medicationsUsed || []).map((id: number) => MEDICATIONS_MAP[id]).filter(Boolean),
immunosuppressantLabels: (item.immunosuppressantName || [])
.map((id: number) => IMMUNOSUPPRESSANT_MAP[id])
.filter(Boolean),
}))
this.setData({
recordList: reset ? list : [...this.data.recordList, ...list],
recordPagination: {
count: res.totalCount || 0,
page: res.page || 1,
pages: res.pages || 1,
},
})
})
},
// ========== 患者详情 ==========
3 months ago
getDoctorDetail() {
wx.ajax({
method: 'GET',
2 months ago
url: '?r=igg4/doctor/account/info',
3 months ago
data: {},
}).then((res) => {
this.setData({
doctor: res.doctor,
hospital: res.hospital,
toastShow: true,
toastType: 'patientDetailSafeDoctor',
toastParams: {
Name: res.doctor.Name,
HospitalName: res.hospital.Name,
},
})
})
},
getDetail() {
return wx
.ajax({
method: 'GET',
2 months ago
url: '?r=igg4/doctor/patient/info',
3 months ago
data: { patientId: this.data.id },
})
.then((res) => {
if (res.LastAdlTime) {
res.LastAdlTimeName = dayjs(res.LastAdlTime).from(dayjs().format('YYYY-MM-DD')).replace(' ', '')
}
if (res.LastUseDrugsTime) {
res.LastUseDrugsTimeName =
dayjs().format('YYYY-MM-DD') === res.LastUseDrugsTime
? ''
: dayjs(res.LastUseDrugsTime).from(dayjs().format('YYYY-MM-DD')).replace(' ', '')
}
2 months ago
res.AgeRangeName = this.data.ageRangeMap[res.AgeRange] || ''
res.DiagnosisTimeRangeName = this.data.diagnosisTimeRangeMap[res.DiagnosisTimeRange] || ''
if (res.HealthQA && res.HealthQA.hasSubmitted && res.HealthQA.questions) {
res.HealthQA.questions.forEach((q: any) => {
q.isAnswerArray = Array.isArray(q.AnswerText)
if (q.isAnswerArray) {
q.AnswerTextArr = q.AnswerText.filter((a: any) => a !== null && a !== undefined && a !== '其他')
q.AnswerTextStr = q.AnswerTextArr.join('、') + (q.OtherText ? `${q.OtherText}` : '')
2 months ago
} else {
q.AnswerTextStr = q.AnswerText || ''
if (q.AnswerTextStr && q.OtherText) {
q.AnswerTextStr += `${q.OtherText}`
}
2 months ago
}
})
}
wx.setNavigationBarTitle({
title: res.Name ? `${res.Name}的患者详情` : '患者详情',
})
3 months ago
this.setData({
detail: {
...res,
hideTelephone: res.Telephone ? res.Telephone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : '',
3 months ago
},
})
})
},
handleRemark() {
3 months ago
this.setData({
popupRemarkShow: true,
remark: this.data.detail.DoctorRemark,
})
setTimeout(() => {
this.setData({
remarkFocus: true,
})
}, 300)
},
handleRemarkClose() {
this.setData({
popupRemarkShow: false,
remarkFocus: false,
remark: '',
})
},
handleRemarkSubmit() {
if (!this.data.remark) {
wx.showToast({
icon: 'none',
title: '请输入备注',
})
2 months ago
return
3 months ago
}
wx.ajax({
method: 'POST',
2 months ago
url: '?r=igg4/doctor/patient/remark',
3 months ago
data: {
PatientId: this.data.id,
DoctorRemark: this.data.remark,
},
}).then((_res) => {
this.handleRemarkClose()
this.getDetail()
})
},
handleEditUser() {
this.setData({
popupEditShow: true,
})
},
handleUserCancel() {
this.setData({
popupEditShow: false,
})
},
handleUserSubmit() {
this.handleUserCancel()
this.handlePatientUpdate()
},
handleRadio(e) {
const { id, key } = e.currentTarget.dataset
this.setData({
[`detail.${key}`]: id,
})
},
handlePatientUpdate() {
const { detail } = this.data
wx.ajax({
method: 'POST',
2 months ago
url: '?r=igg4/doctor/patient/update',
3 months ago
data: {
PatientId: detail.PatientId,
AntibodyType: detail.AntibodyType,
ThyroidAbnormal: detail.ThyroidAbnormal,
PreviousConvulsion: detail.PreviousConvulsion,
TraditionalImmunosuppressant: detail.TraditionalImmunosuppressant,
MedicalInsuranceType: detail.MedicalInsuranceType,
3 months ago
},
}).then(() => {
wx.showToast({
icon: 'none',
title: '更新成功',
})
this.getDetail()
})
},
handleSend() {
wx.navigateTo({
url: `/doctor/pages/d_interactiveDoctor/index?patientId=${this.data.detail.PatientId}`,
})
},
handleToggleTel() {
3 months ago
this.setData({
showTel: !this.data.showTel,
3 months ago
})
},
handleToastOk() {
this.setData({
toastShow: false,
})
},
handleToastCancel() {
wx.navigateBack()
},
2 weeks ago
// ========== 病历报告导航 ==========
handleDetail(e: any) {
const { name, imagefield } = e.currentTarget.dataset
wx.navigateTo({
url: `/doctor/pages/d_caseReport/index?name=${name}&imageField=${imagefield}&patientId=${this.data.id}`,
})
},
// ========== 导出PPT ==========
handleGeneratePdf() {
if (this.data.pptGenerating) return
this.setData({ pptGenerating: true })
const patientId = this.data.id
const downloadUrl = `${app.globalData.url}?r=igg4/doctor/medical-visit/export-ppt&loginState=${app.globalData.loginState}&patientId=${patientId}`
wx.downloadFile({
url: downloadUrl,
success: (res) => {
if (res.statusCode === 200) {
wx.shareFileMessage({
filePath: res.tempFilePath,
fileName: 'medical-visit.pptx',
success: () => {
wx.showToast({ title: '分享成功', icon: 'success' })
this.setData({ pptGenerating: false })
},
fail: () => {
wx.showToast({ title: '分享失败', icon: 'none' })
this.setData({ pptGenerating: false })
},
})
} else {
wx.showToast({ title: '下载失败', icon: 'none' })
this.setData({ pptGenerating: false })
}
},
fail: () => {
wx.showToast({ title: '下载失败', icon: 'none' })
this.setData({ pptGenerating: false })
},
})
},
// ========== 分页加载 ==========
onReachBottom() {
const { page, pages } = this.data.recordPagination
if (page < pages) {
this.setData({ 'recordPagination.page': page + 1 })
this.getRecordList()
}
},
3 months ago
})