|
|
|
|
@ -4,6 +4,27 @@ const app = getApp<IAppOption>()
@@ -4,6 +4,27 @@ const app = getApp<IAppOption>()
|
|
|
|
|
|
|
|
|
|
let echarts: any = null |
|
|
|
|
|
|
|
|
|
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: '其他', |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Page({ |
|
|
|
|
data: { |
|
|
|
|
toastShow: false, |
|
|
|
|
@ -109,17 +130,56 @@ Page({
@@ -109,17 +130,56 @@ Page({
|
|
|
|
|
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', |
|
|
|
|
}, |
|
|
|
|
{ icon: 'icon127.png', name: '检验报告', content: '抽血检测的IgG4、IgG、ESR等' }, |
|
|
|
|
{ icon: 'icon128.png', name: '影像学检查', content: '超声/CT/MRI的描述结论、电子胶片' }, |
|
|
|
|
{ icon: 'icon129.png', name: '病理诊断及活检', content: '受累组织穿刺或切除免疫组化报告' }, |
|
|
|
|
{ icon: 'icon130.png', name: '外周血免疫功能评估', content: '免疫细胞亚群、淋巴细胞比例测定' }, |
|
|
|
|
], |
|
|
|
|
|
|
|
|
|
// Tab 切换
|
|
|
|
|
currentTab: 0, |
|
|
|
|
|
|
|
|
|
// 就诊记录列表
|
|
|
|
|
recordList: [] as any[], |
|
|
|
|
recordPagination: { count: 0, page: 1, pages: 1 }, |
|
|
|
|
|
|
|
|
|
// 导出PPT
|
|
|
|
|
pptGenerating: false, |
|
|
|
|
}, |
|
|
|
|
ecDataTrendComponent: null as any, |
|
|
|
|
async onLoad(option) { |
|
|
|
|
@ -128,41 +188,96 @@ Page({
@@ -128,41 +188,96 @@ Page({
|
|
|
|
|
}) |
|
|
|
|
echarts = await require.async('../../../resource/components/echart/echarts.js') |
|
|
|
|
this.ecDataTrendComponent = this.selectComponent('#chart1') |
|
|
|
|
this.initChart() |
|
|
|
|
app.waitLogin().then(async (_res) => { |
|
|
|
|
this.getDoctorDetail() |
|
|
|
|
await this.getDetail() |
|
|
|
|
this.getIndicatorHistory() |
|
|
|
|
this.getRecordList(true) |
|
|
|
|
}) |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
initChart(defaultList = []) { |
|
|
|
|
const list: any = [ |
|
|
|
|
...defaultList, |
|
|
|
|
{ Date: '2026-7-7', TotalScore: 100, InjectionBottles: false }, |
|
|
|
|
{ Date: '2026-7-8', TotalScore: 1000, InjectionBottles: false }, |
|
|
|
|
] |
|
|
|
|
return new Promise((reslove) => { |
|
|
|
|
this.ecDataTrendComponent.init((canvas, width, height, dpr) => { |
|
|
|
|
// ========== 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, // new
|
|
|
|
|
devicePixelRatio: dpr, |
|
|
|
|
}) |
|
|
|
|
canvas.setChart(chart) |
|
|
|
|
|
|
|
|
|
const color = 'rgba(22, 121, 203, 1)' |
|
|
|
|
|
|
|
|
|
const option: any = { |
|
|
|
|
tooltip: { |
|
|
|
|
show: false, |
|
|
|
|
trigger: 'axis', |
|
|
|
|
axisPointer: { |
|
|
|
|
type: 'shadow', |
|
|
|
|
}, |
|
|
|
|
axisPointer: { type: 'shadow' }, |
|
|
|
|
confine: true, |
|
|
|
|
backgroundColor: 'rgba(0, 0, 0, 0.5)', |
|
|
|
|
textStyle: { |
|
|
|
|
color: '#fff', |
|
|
|
|
fontSize: 10, |
|
|
|
|
}, |
|
|
|
|
textStyle: { color: '#fff', fontSize: 10 }, |
|
|
|
|
order: 'seriesDesc', |
|
|
|
|
}, |
|
|
|
|
grid: { |
|
|
|
|
@ -175,42 +290,32 @@ Page({
@@ -175,42 +290,32 @@ Page({
|
|
|
|
|
xAxis: [ |
|
|
|
|
{ |
|
|
|
|
type: 'category', |
|
|
|
|
axisTick: { |
|
|
|
|
alignWithLabel: true, |
|
|
|
|
}, |
|
|
|
|
axisTick: { alignWithLabel: true }, |
|
|
|
|
axisLine: { |
|
|
|
|
lineStyle: { |
|
|
|
|
color: 'rgba(34, 34, 34, 0.20)', |
|
|
|
|
type: 'dashed', |
|
|
|
|
lineStyle: { color: 'rgba(34, 34, 34, 0.20)', type: 'dashed' }, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
data: list.map((item) => dayjs(item.Date).format('MM-DD')), |
|
|
|
|
data: list.map((item: any) => dayjs(item.visitDate).format('MM-DD')), |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
yAxis: [ |
|
|
|
|
{ |
|
|
|
|
type: 'value', |
|
|
|
|
minInterval: 1, |
|
|
|
|
axisLabel: { |
|
|
|
|
color: 'rgba(34, 34, 34, 0.40)', |
|
|
|
|
}, |
|
|
|
|
axisLabel: { color: 'rgba(34, 34, 34, 0.40)' }, |
|
|
|
|
splitLine: { |
|
|
|
|
lineStyle: { |
|
|
|
|
color: 'rgba(34, 34, 34, 0.20)', |
|
|
|
|
type: 'dashed', |
|
|
|
|
}, |
|
|
|
|
lineStyle: { color: 'rgba(34, 34, 34, 0.20)', type: 'dashed' }, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
series: [ |
|
|
|
|
{ |
|
|
|
|
name: '总分', |
|
|
|
|
data: list.length ? list.map((item) => item.TotalScore) : [25], |
|
|
|
|
name: 'IgG4', |
|
|
|
|
data: list.length ? list.map((item: any) => item.value) : [0], |
|
|
|
|
barWidth: '16', |
|
|
|
|
label: { |
|
|
|
|
show: true, |
|
|
|
|
position: 'top', |
|
|
|
|
color: 'rgba(22, 121, 203, 1)', |
|
|
|
|
color, |
|
|
|
|
}, |
|
|
|
|
type: 'line', |
|
|
|
|
symbol: 'circle', |
|
|
|
|
@ -219,7 +324,7 @@ Page({
@@ -219,7 +324,7 @@ Page({
|
|
|
|
|
connectNulls: true, |
|
|
|
|
z: 10, |
|
|
|
|
itemStyle: { |
|
|
|
|
color: 'rgba(22, 121, 203, 1)', |
|
|
|
|
color, |
|
|
|
|
}, |
|
|
|
|
markLine: { |
|
|
|
|
symbol: ['none', 'none'], |
|
|
|
|
@ -230,12 +335,12 @@ Page({
@@ -230,12 +335,12 @@ Page({
|
|
|
|
|
label: { |
|
|
|
|
formatter: '{b}', |
|
|
|
|
position: 'insideMiddle', |
|
|
|
|
color: 'rgba(22, 121, 203, 1)', |
|
|
|
|
color, |
|
|
|
|
fontSize: '10', |
|
|
|
|
}, |
|
|
|
|
lineStyle: { |
|
|
|
|
cap: '', |
|
|
|
|
color: 'rgba(22, 121, 203, 1)', |
|
|
|
|
color, |
|
|
|
|
type: 'dashed', |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
@ -245,21 +350,12 @@ Page({
@@ -245,21 +350,12 @@ Page({
|
|
|
|
|
itemStyle: { |
|
|
|
|
color: 'rgba(22, 121, 203, 0.16)', |
|
|
|
|
}, |
|
|
|
|
data: [ |
|
|
|
|
[ |
|
|
|
|
{ |
|
|
|
|
yAxis: 0, |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
yAxis: 135, |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
], |
|
|
|
|
data: [[{ yAxis: 0 }, { yAxis: 135 }]], |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
dataZoom: { |
|
|
|
|
type: 'inside', // 有type这个属性,滚动条在最下面,也可以不行,写y:36,这表示距离顶端36px,一般就是在图上面。
|
|
|
|
|
type: 'inside', |
|
|
|
|
startValue: 0, |
|
|
|
|
endValue: 4, |
|
|
|
|
filterMode: 'none', |
|
|
|
|
@ -267,11 +363,71 @@ Page({
@@ -267,11 +363,71 @@ Page({
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
chart.setOption(option) |
|
|
|
|
reslove(chart) |
|
|
|
|
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)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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', |
|
|
|
|
@ -434,4 +590,58 @@ Page({
@@ -434,4 +590,58 @@ Page({
|
|
|
|
|
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() |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
|