import dayjs from 'dayjs' const app = getApp() let echarts: any = null const MEDICATIONS_MAP: Record = { 1: '没有使用激素', 2: '激素', 3: '免疫抑制剂', 4: '靶向CD19生物制剂', 5: '靶向CD20生物制剂', 99: '其他', } const IMMUNOSUPPRESSANT_MAP: Record = { 1: '吗替麦考酚酯', 2: '替唑嘌呤', 3: '环磷酰胺', 4: '来氟米特', 5: '甲氨蝶呤', 6: '环孢素A', 7: '他克莫司', 8: '艾拉莫德', 99: '其他', } 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: '新农合', }, ], 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年以上', }, // 图表筛选 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[], // 病历报告 caseReportList: [ { icon: 'icon142.png', name: '门诊病历及处方', content: '医生手写或电脑打印的病历、处方', 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', }, ], // Tab 切换 currentTab: 0, // 就诊记录列表 recordList: [] as any[], recordPagination: { count: 0, page: 1, pages: 1 }, // 导出PPT pptGenerating: false, }, ecDataTrendComponent: null as any, async onLoad(option) { this.setData({ id: option.id, }) echarts = await require.async('../../../resource/components/echart/echarts.js') this.ecDataTrendComponent = this.selectComponent('#chart1') app.waitLogin().then(async (_res) => { this.getDoctorDetail() await this.getDetail() this.getIndicatorHistory() this.getRecordList(true) }) }, // ========== 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' }, }, data: list.map((item: any) => dayjs(item.visitDate).format('MM-DD')), }, ], yAxis: [ { type: 'value', minInterval: 1, axisLabel: { color: 'rgba(34, 34, 34, 0.40)' }, splitLine: { lineStyle: { color: 'rgba(34, 34, 34, 0.20)', type: 'dashed' }, }, }, ], series: [ { name: 'IgG4', data: list.length ? list.map((item: any) => item.value) : [0], barWidth: '16', label: { show: true, position: 'top', color, }, type: 'line', symbol: 'circle', symbolSize: 8, showSymbol: list.length >= 1, connectNulls: true, z: 10, itemStyle: { color, }, markLine: { symbol: ['none', 'none'], data: [ { name: '135 安全区', yAxis: 135, label: { formatter: '{b}', position: 'insideMiddle', color, fontSize: '10', }, lineStyle: { cap: '', color, type: 'dashed', }, }, ], }, markArea: { itemStyle: { color: 'rgba(22, 121, 203, 0.16)', }, data: [[{ yAxis: 0 }, { yAxis: 135 }]], }, }, ], dataZoom: { type: 'inside', startValue: 0, endValue: 4, filterMode: 'none', }, } chart.setOption(option) return chart }) }, getIndicatorHistory() { const data: Record = { 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)) } 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 || [], }) this.initChart(res.list || []) }) }, // ========== 就诊记录列表 ========== 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, }, }) }) }, // ========== 患者详情 ========== getDoctorDetail() { wx.ajax({ method: 'GET', url: '?r=igg4/doctor/account/info', 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', url: '?r=igg4/doctor/patient/info', 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(' ', '') } 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) q.AnswerTextStr = q.AnswerTextArr.join('、') + (q.OtherText ? `(${q.OtherText})` : '') } else { q.AnswerTextStr = q.AnswerText || '' if (q.AnswerTextStr && q.OtherText) { q.AnswerTextStr += `(${q.OtherText})` } } }) } this.setData({ detail: { ...res, hideName: res.Name.length <= 2 ? res.Name.charAt(0) + '*' : res.Name.charAt(0) + '*' + res.Name.charAt(res.Name.length - 1), hideTelephone: res.Telephone ? res.Telephone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : '', }, }) }) }, handleRemark() { 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: '请输入备注', }) return } wx.ajax({ method: 'POST', url: '?r=igg4/doctor/patient/remark', 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', url: '?r=igg4/doctor/patient/update', data: { PatientId: detail.PatientId, AntibodyType: detail.AntibodyType, ThyroidAbnormal: detail.ThyroidAbnormal, PreviousConvulsion: detail.PreviousConvulsion, TraditionalImmunosuppressant: detail.TraditionalImmunosuppressant, MedicalInsuranceType: detail.MedicalInsuranceType, }, }).then(() => { wx.showToast({ icon: 'none', title: '更新成功', }) this.getDetail() }) }, handleSend() { wx.navigateTo({ url: `/doctor/pages/d_interactiveDoctor/index?patientId=${this.data.detail.PatientId}`, }) }, handleToggleTel() { this.setData({ showTel: !this.data.showTel, }) }, handleToastOk() { this.setData({ toastShow: false, }) }, handleToastCancel() { wx.navigateBack() }, // ========== 病历报告导航 ========== 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() } }, })