const echarts = require('../../../components/ec-canvas/echarts.js') Page({ data: { fold1: true, fold2: true, // 用户信息 pharmacistName: '', pharmacistAvatar: '', pharmacyName: '', // 项目列表 projectList: [] as Array<{ projectId: number; projectName: string; projectDescription: string }>, currentProjectId: 0, currentProjectName: '', projectIndex: 0, // 待处理患者数 pendingCount: 0, jumpPendingCount: 0, enrollPendingCount: 0, // 累计统计数据 invitePatientCount: 0, jumpPatientCount: 0, enrollPatientCount: 0, // 累计适应症统计 indicationStats: [] as Array<{ indicationId: number indicationName: string invitePatientCount: number jumpPatientCount: number enrollPatientCount: number }>, // 日/月度统计数据 dailyInvitePatientCount: 0, dailyJumpPatientCount: 0, dailyEnrollPatientCount: 0, // 日/月度适应症统计 dailyIndicationStats: [] as Array<{ indicationId: number indicationName: string invitePatientCount: number jumpPatientCount: number enrollPatientCount: number }>, // 图表数据 chartData: [] as Array<{ date: string invitePatientCount: number jumpPatientCount: number enrollPatientCount: number }>, // 日期范围 - 邀约患者统计卡片(单日) startDate: '', today: '', // 统计卡片显示用的月份(YYYY-MM) startMonth: '', // 日期范围 - 图表(日期范围) chartStartDate: '', chartEndDate: '', // 图表显示用的月份(YYYY-MM) chartStartMonth: '', chartEndMonth: '', // 统计类型: day-日统计, month-月统计 statType: 'day', }, ecDataTrendComponent1_1: null as any, async onLoad() { const app = getApp() // 药店端页面,仅允许药店人员(4)访问 app.waitLogin({ types: [4] }).then(() => { this.getUserInfo() this.getProjectList() }) // 初始化日期 const today = this.formatDate(new Date()) const currentMonth = this.formatMonth(new Date()) const defaultStartDate = this.formatDate(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)) const defaultStartMonth = this.formatMonth(new Date(Date.now() - 365 * 24 * 60 * 60 * 1000)) this.setData({ today, // 邀约患者统计卡片(单日)- 默认为今天 startDate: today, startMonth: currentMonth, // 图表(日期范围)- 默认为最近30天 chartStartDate: defaultStartDate, chartEndDate: today, // 图表月份显示 - 默认为最近12个月 chartStartMonth: defaultStartMonth, chartEndMonth: currentMonth, }) }, // 格式化日期 formatDate(date: Date): string { const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') return `${year}-${month}-${day}` }, // 格式化月份(YYYY-MM) formatMonth(date: Date): string { const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') return `${year}-${month}` }, // 获取用户信息 getUserInfo() { wx.ajax({ method: 'GET', url: '/app/pharmacist/pharmacist/profile', }).then((res: any) => { this.setData({ pharmacistName: res.name, pharmacistAvatar: res.avatar, pharmacyName: res.pharmacyName, }) }) }, // 获取项目列表 getProjectList() { wx.ajax({ method: 'GET', url: '/app/pharmacist/pharmacist/project-list', }).then((res: any) => { const projectList = res.list || [] const currentProjectId = res.currentProjectId || projectList[0]?.projectId || 0 const currentProject = projectList.find((item: any) => item.projectId === currentProjectId) || projectList[0] const projectIndex = projectList.findIndex((item: any) => item.projectId === currentProjectId) this.setData({ projectList, currentProjectId, currentProjectName: currentProject?.projectName || '', projectIndex: projectIndex >= 0 ? projectIndex : 0, }) // 获取其他数据 this.getPendingCount() this.getTotalStatistics() this.getDailyStatistics() this.getPatientChart() }) }, // 切换项目 onProjectChange(e: WechatMiniprogram.CustomEvent) { const index = e.detail.value const project = this.data.projectList[index] if (project && project.projectId !== this.data.currentProjectId) { // 先调用切换项目接口 wx.ajax({ method: 'POST', url: '/app/pharmacist/pharmacist/switch-project', data: { projectId: project.projectId, }, }) .then(() => { // 切换成功后更新页面数据 this.setData({ currentProjectId: project.projectId, currentProjectName: project.projectName, projectIndex: index, }) // 重新加载数据 this.getPendingCount() this.getTotalStatistics() this.getDailyStatistics() this.getPatientChart() wx.showToast({ title: '切换成功', icon: 'success', }) }) .catch(() => { wx.showToast({ title: '切换失败', icon: 'none', }) }) } }, // 获取待处理患者数 getPendingCount() { wx.ajax({ method: 'GET', url: '/app/pharmacist/pharmacist/pending-count', }) .then((res: any) => { this.setData({ pendingCount: res.totalPendingCount || 0, jumpPendingCount: res.jumpPendingCount || 0, enrollPendingCount: res.enrollPendingCount || 0, }) }) .catch(() => { // 接口失败时使用默认值 this.setData({ pendingCount: 0, jumpPendingCount: 0, enrollPendingCount: 0, }) }) }, // 获取累计统计数据看板 getTotalStatistics() { wx.ajax({ method: 'GET', url: '/app/pharmacist/pharmacist/statistics', }).then((res: any) => { this.setData({ invitePatientCount: res.invitePatientCount || 0, jumpPatientCount: res.jumpPatientCount || 0, enrollPatientCount: res.enrollPatientCount || 0, indicationStats: res.indicationStats || [], }) }) }, // 获取日/月度统计数据看板 getDailyStatistics() { // 根据统计类型格式化日期 const statDate = this.data.statType === 'month' ? this.data.startMonth // YYYY-MM : this.data.startDate // YYYY-MM-DD wx.ajax({ method: 'GET', url: '/app/pharmacist/pharmacist/patient-statistics', data: { statDate, type: this.data.statType, }, }).then((res: any) => { this.setData({ dailyInvitePatientCount: res.invitePatientCount || 0, dailyJumpPatientCount: res.jumpPatientCount || 0, dailyEnrollPatientCount: res.enrollPatientCount || 0, dailyIndicationStats: res.indicationStats || [], }) }) }, // 获取邀约患者统计图表(使用 chart 的日期范围) getPatientChart() { // 根据统计类型格式化日期 const startDate = this.data.statType === 'month' ? this.data.chartStartMonth // YYYY-MM : this.data.chartStartDate // YYYY-MM-DD const endDate = this.data.statType === 'month' ? this.data.chartEndMonth // YYYY-MM : this.data.chartEndDate // YYYY-MM-DD wx.ajax({ method: 'GET', url: '/app/pharmacist/pharmacist/patient-chart', data: { type: this.data.statType, startDate, endDate, }, }).then((res: any) => { const list = res || [] // 转换为图表需要的格式 const chartData = list.map((item: any) => ({ date: item.statDate, invitePatientCount: item.invitePatientCount || 0, jumpPatientCount: item.jumpPatientCount || 0, enrollPatientCount: item.enrollPatientCount || 0, })) this.setData({ chartData, }) this.initChartBar(chartData) }) }, // 切换统计类型 switchStatType(e: WechatMiniprogram.CustomEvent) { const type = e.currentTarget.dataset.type const isMonth = type === 'month' // 根据统计类型重置日期范围 let startDate = this.data.startDate let startMonth = this.data.startMonth let chartStartDate = this.data.chartStartDate let chartEndDate = this.data.chartEndDate let chartStartMonth = this.data.chartStartMonth let chartEndMonth = this.data.chartEndMonth if (isMonth) { // 切换到月统计,设置默认月份 startMonth = this.formatMonth(new Date()) startDate = `${startMonth}-01` // 图表月份范围为最近12个月 chartEndMonth = this.formatMonth(new Date()) chartStartMonth = this.formatMonth(new Date(Date.now() - 365 * 24 * 60 * 60 * 1000)) chartEndDate = `${chartEndMonth}-01` chartStartDate = `${chartStartMonth}-01` } else { // 切换到日统计,设置默认日期为今天 startDate = this.formatDate(new Date()) startMonth = startDate.substring(0, 7) // 图表日期范围为最近30天 chartEndDate = this.formatDate(new Date()) chartStartDate = this.formatDate(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)) chartEndMonth = chartEndDate.substring(0, 7) chartStartMonth = chartStartDate.substring(0, 7) } this.setData({ statType: type, startDate, startMonth, chartStartDate, chartEndDate, chartStartMonth, chartEndMonth, }) this.getDailyStatistics() this.getPatientChart() }, // 日期选择变化 onDateChange(e: WechatMiniprogram.CustomEvent) { const value = e.detail.value // YYYY-MM-DD 或 YYYY-MM // 月统计时,value 是 YYYY-MM 格式,需要补全为 YYYY-MM-DD const isMonth = value.length === 7 const fullDate = isMonth ? `${value}-01` : value const monthValue = isMonth ? value : value.substring(0, 7) this.setData({ startDate: fullDate, startMonth: monthValue, }) // 重新加载日/月度统计数据 this.getDailyStatistics() }, // 切换到上一天/上月 prevDate() { const isMonth = this.data.statType === 'month' let newDate: Date let startDate: string let startMonth: string if (isMonth) { // 月统计:切换到上个月 const currentDate = new Date(this.data.startDate) newDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1) startDate = this.formatDate(newDate) startMonth = this.formatMonth(newDate) } else { // 日统计:切换到上一天 const currentDate = new Date(this.data.startDate) newDate = new Date(currentDate.getTime() - 24 * 60 * 60 * 1000) startDate = this.formatDate(newDate) startMonth = startDate.substring(0, 7) } this.setData({ startDate, startMonth }) // 重新加载日/月度统计数据 this.getDailyStatistics() }, // 切换到下一天/下月 nextDate() { const isMonth = this.data.statType === 'month' const today = new Date() let newDate: Date let startDate: string let startMonth: string if (isMonth) { // 月统计:切换到下个月 const currentDate = new Date(this.data.startDate) newDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1) // 最大月份不能大于当前月份 const currentMonth = new Date(today.getFullYear(), today.getMonth(), 1) if (newDate > currentMonth) { wx.showToast({ title: '不能选择未来月份', icon: 'none', }) return } startDate = this.formatDate(newDate) startMonth = this.formatMonth(newDate) } else { // 日统计:切换到下一天 const currentDate = new Date(this.data.startDate) newDate = new Date(currentDate.getTime() + 24 * 60 * 60 * 1000) // 最大日期不能大于当前日期 if (newDate > today) { wx.showToast({ title: '不能选择未来日期', icon: 'none', }) return } startDate = this.formatDate(newDate) startMonth = startDate.substring(0, 7) } this.setData({ startDate, startMonth }) // 重新加载日/月度统计数据 this.getDailyStatistics() }, // 图表日期选择变化(开始日期) onChartStartDateChange(e: WechatMiniprogram.CustomEvent) { const value = e.detail.value // YYYY-MM-DD 或 YYYY-MM const chartEndDate = this.data.chartEndDate // 月统计时,value 是 YYYY-MM 格式,需要补全为 YYYY-MM-DD const isMonth = value.length === 7 const fullDate = isMonth ? `${value}-01` : value const monthValue = isMonth ? value : value.substring(0, 7) // 验证日期范围 if (chartEndDate && fullDate > chartEndDate) { wx.showToast({ title: '开始时间不能大于结束时间', icon: 'none', }) return } this.setData({ chartStartDate: fullDate, chartStartMonth: monthValue, }) this.getPatientChart() }, // 图表日期选择变化(结束日期) onChartEndDateChange(e: WechatMiniprogram.CustomEvent) { const value = e.detail.value // YYYY-MM-DD 或 YYYY-MM const chartStartDate = this.data.chartStartDate // 月统计时,value 是 YYYY-MM 格式,需要补全为 YYYY-MM-DD const isMonth = value.length === 7 const fullDate = isMonth ? `${value}-01` : value const monthValue = isMonth ? value : value.substring(0, 7) // 验证日期范围 if (chartStartDate && fullDate < chartStartDate) { wx.showToast({ title: '结束时间不能小于开始时间', icon: 'none', }) return } this.setData({ chartEndDate: fullDate, chartEndMonth: monthValue, }) this.getPatientChart() }, initChartBar(list: any[]) { return new Promise((reslove) => { this.ecDataTrendComponent1_1 = this.selectComponent('#chart1_1') this.ecDataTrendComponent1_1.init((canvas, width, height, dpr) => { const chart = echarts.init(canvas, null, { width, height, devicePixelRatio: dpr, }) canvas.setChart(chart) const x: string[] = [] const y1: number[] = [] const y2: number[] = [] const y3: number[] = [] list.forEach((item) => { x.push(item.date) y1.push(item.enrollPatientCount) y2.push(item.jumpPatientCount) y3.push(item.invitePatientCount) }) const option = { tooltip: { trigger: 'axis', axisPointer: { type: 'shadow', }, formatter (params) { let result = `${params[0].axisValue }\n` params.forEach((item, index) => { result += `${item.marker } ${ item.seriesName }: ${ item.value }` if (index < params.length - 1) { result += '\n' } }) return result }, }, legend: { top: 0, right: 0, itemWidth: 8, itemHeight: 8, icon: 'rect', lineStyle: { width: '0', }, textStyle: { color: '#B5B8BB', fontSize: '12', }, }, grid: { top: '10%', left: '3%', right: '4%', bottom: '0', containLabel: true, }, xAxis: [ { type: 'category', axisTick: { show: false, }, axisLabel: { fontSize: 10, color: '#B5B8BB', }, axisLine: { show: false, }, data: x, }, ], yAxis: [ { type: 'value', minInterval: 1, splitLine: { lineStyle: { type: 'dashed', }, }, axisLabel: { fontSize: 10, color: '#B5B8BB', formatter(value) { return Math.abs(value) }, }, }, ], series: [ { name: '入组患者数', type: 'bar', stack: 'a', color: '#FF5722', barWidth: 12, data: y1, }, { name: '跳转患者数', type: 'bar', stack: 'a', color: '#FF8A4C', barWidth: 12, data: y2, }, { name: '邀约患者数', type: 'bar', stack: 'a', width: 4, color: '#FFA64D', barWidth: 12, data: y3, }, ], dataZoom: { type: 'inside', startValue: x.length - 6, endValue: x.length - 1, filterMode: 'none', }, } chart.setOption(option) reslove(chart) return chart }) }) }, handleInvite() { wx.navigateTo({ url: '/doctor/pages/invite/index', }) }, handleStat() { const { chartStartDate, chartEndDate, statType } = this.data wx.navigateTo({ url: `/doctor/pages/stat/index?startDate=${chartStartDate}&endDate=${chartEndDate}&type=${statType}`, }) }, handleFold(e) { const { key } = e.currentTarget.dataset this.setData({ [key]: !this.data[key], }) }, })