Browse Source

feat(ground): 添加项目切换功能并优化统计页面

- 在药师页面添加项目切换功能
- 重构统计页面数据获取逻辑,分离累计数据和日期筛选数据
- 为不同图表添加独立的日期范围控制
- 优化页面数据展示逻辑,添加空状态处理
- 修复分页组件显示条件
master
kola-web 1 week ago
parent
commit
14b9ee4fc0
  1. 2
      src/doctor/pages/articleList/index.wxml
  2. 3
      src/doctor/pages/home/index.json
  3. 4
      src/doctor/pages/home/index.scss
  4. 3
      src/doctor/pages/home/index.wxml
  5. 2
      src/doctor/pages/loginForm/index.wxml
  6. 2
      src/doctor/pages/patientList/index.ts
  7. 2
      src/doctor/pages/patientList/index.wxml
  8. 8
      src/doctor/pages/stat/index.wxml
  9. 3
      src/ground/pages/home/index.json
  10. 254
      src/ground/pages/home/index.ts
  11. 42
      src/ground/pages/home/index.wxml
  12. 1
      src/ground/pages/invite/index.wxml
  13. 72
      src/ground/pages/pharmacist/index.ts
  14. 14
      src/ground/pages/pharmacist/index.wxml
  15. 132
      src/ground/pages/stat/index.ts
  16. 9
      src/ground/pages/stat/index.wxml

2
src/doctor/pages/articleList/index.wxml

@ -41,7 +41,7 @@ @@ -41,7 +41,7 @@
</view>
</view>
<!-- 分页组件 -->
<pagination pagination="{{pagination}}" wx:if="{{!loading || articleList.length > 0}}"></pagination>
<pagination pagination="{{pagination}}"></pagination>
</view>
<doctor-tab-bar active="{{ 2 }}"></doctor-tab-bar>

3
src/doctor/pages/home/index.json

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
"usingComponents": {
"navbar": "../../../components/navbar/index",
"doctor-tab-bar": "/doctor/components/doctor-tab-bar/index",
"ec-canvas": "/components/ec-canvas/ec-canvas"
"ec-canvas": "/components/ec-canvas/ec-canvas",
"van-empty": "@vant/weapp/empty/index"
}
}

4
src/doctor/pages/home/index.scss

@ -412,6 +412,10 @@ page { @@ -412,6 +412,10 @@ page {
width: 100%;
height: 546rpx;
box-sizing: border-box;
.hide {
display: none;
}
}
.more {
padding: 20rpx 0 0;

3
src/doctor/pages/home/index.wxml

@ -172,7 +172,8 @@ @@ -172,7 +172,8 @@
</picker>
</view>
<view class="chart-container">
<ec-canvas id="chart1_1" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>
<ec-canvas class="{{chartData.length === 0 ? 'hide' : ''}}" id="chart1_1" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>
<van-empty class="{{chartData.length > 0 ? 'hide' : ''}}" description="暂无数据" />
</view>
<view class="more" bind:tap="handleStat">
查看明细

2
src/doctor/pages/loginForm/index.wxml

@ -75,7 +75,7 @@ @@ -75,7 +75,7 @@
<view class="name">{{item.name}}</view>
<view class="site">{{item.provinceName}}{{item.cityName}}{{item.districtName}}{{item.address}}</view>
</view>
<pagination pagination="{{pagination}}" wx:if="{{pharmacyList.length > 0}}" />
<pagination pagination="{{pagination}}" />
</scroll-view>
</view>
</van-popup>

2
src/doctor/pages/patientList/index.ts

@ -267,7 +267,7 @@ Page({ @@ -267,7 +267,7 @@ Page({
})
},
// 弹窗确认
handlePopupOk(e: WechatMiniprogram.CustomEvent) {
handlePopupOk() {
this.setData({
popupShow: false,
})

2
src/doctor/pages/patientList/index.wxml

@ -139,7 +139,7 @@ @@ -139,7 +139,7 @@
</view>
</view>
<!-- 分页组件 -->
<pagination pagination="{{pagination}}" wx:if="{{!loading || patientList.length > 0}}"></pagination>
<pagination pagination="{{pagination}}"></pagination>
</view>
</view>

8
src/doctor/pages/stat/index.wxml

@ -8,16 +8,16 @@ @@ -8,16 +8,16 @@
<view class="page" style="padding-top: {{pageTop}}px;">
<view class="page-header" style="top:{{pageTop}}px">
<view class="chart-range">
<picker class="picker" mode="date" end="{{end}}">
<picker class="picker" mode="date" value="{{startDate}}" end="{{endDate}}" bindchange="handleStartDateChange">
<view class="p-content">
<view class="content">2025/02/26</view>
<view class="content">{{startDate}}</view>
<image class="icon" src="{{imageUrl}}icon13.png?t={{Timestamp}}"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" start="{{satrt}}">
<picker class="picker" mode="date" value="{{endDate}}" start="{{startDate}}" bindchange="handleEndDateChange">
<view class="p-content">
<view class="content">2025/02/26</view>
<view class="content">{{endDate}}</view>
<image class="icon" src="{{imageUrl}}icon13.png?t={{Timestamp}}"></image>
</view>
</picker>

3
src/ground/pages/home/index.json

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
"usingComponents": {
"navbar": "../../../components/navbar/index",
"ground-tab-bar": "/ground/components/ground-tab-bar/index",
"ec-canvas": "/components/ec-canvas/ec-canvas"
"ec-canvas": "/components/ec-canvas/ec-canvas",
"van-empty": "@vant/weapp/empty/index"
}
}

254
src/ground/pages/home/index.ts

@ -10,9 +10,21 @@ Page({ @@ -10,9 +10,21 @@ Page({
promoterAvatar: '',
label: '邀约专员',
// 统计数据
invitePharmacyCount: 0,
invitePharmacistCount: 0,
// 累计统计数据(来自 getStatistics)
totalInvitePharmacyCount: 0,
totalInvitePharmacistCount: 0,
totalInvitePatientCount: 0,
totalJumpPatientCount: 0,
totalEnrollPatientCount: 0,
totalIndicationStats: [] as Array<{
indicationId: number
indicationName: string
invitePatientCount: number
jumpPatientCount: number
enrollPatientCount: number
}>,
// 日期筛选统计数据(来自 getPatientStatistics)
invitePatientCount: 0,
jumpPatientCount: 0,
enrollPatientCount: 0,
@ -29,11 +41,22 @@ Page({ @@ -29,11 +41,22 @@ Page({
pharmacistChartData: [] as Array<{ date: string, count: number }>,
pharmacyChartData: [] as Array<{ date: string, count: number }>,
// 日期范围
// 日期范围 - 邀约患者统计卡片(单日)
startDate: '',
endDate: '',
today: '',
// 日期范围 - 图表1(邀约患者统计)
chart1StartDate: '',
chart1EndDate: '',
// 日期范围 - 图表2(邀约药师统计)
chart2StartDate: '',
chart2EndDate: '',
// 日期范围 - 图表3(邀约药店统计)
chart3StartDate: '',
chart3EndDate: '',
// 统计类型: day-日统计, month-月统计
statType: 'day',
@ -56,14 +79,20 @@ Page({ @@ -56,14 +79,20 @@ Page({
this.getProjectList()
})
// 初始化日期范围为最近30天
// 初始化日期
const today = this.formatDate(new Date())
const endDate = today
const startDate = this.formatDate(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000))
const defaultStartDate = this.formatDate(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000))
this.setData({
today,
startDate,
endDate,
// 邀约患者统计卡片(单日)- 默认为今天
startDate: today,
// 图表1-3(日期范围)- 默认为最近30天
chart1StartDate: defaultStartDate,
chart1EndDate: today,
chart2StartDate: defaultStartDate,
chart2EndDate: today,
chart3StartDate: defaultStartDate,
chart3EndDate: today,
})
},
@ -108,6 +137,7 @@ Page({ @@ -108,6 +137,7 @@ Page({
// 获取统计数据
this.getStatistics()
this.getPatientStatistics()
this.getPatientChart()
this.getPharmacistChart()
this.getPharmacyChart()
@ -119,33 +149,68 @@ Page({ @@ -119,33 +149,68 @@ Page({
const index = e.detail.value
const project = this.data.projectList[index]
if (project && project.projectId !== this.data.currentProjectId) {
this.setData({
currentProjectId: project.projectId,
currentProjectName: project.projectName,
projectIndex: index,
// 先调用切换项目接口
wx.ajax({
method: 'POST',
url: '/app/promoter/promoter/switch-project',
data: {
projectId: project.projectId,
},
}).then(() => {
// 切换成功后更新页面数据
this.setData({
currentProjectId: project.projectId,
currentProjectName: project.projectName,
projectIndex: index,
})
// 重新加载数据
this.getStatistics()
this.getPatientStatistics()
this.getPatientChart()
this.getPharmacistChart()
this.getPharmacyChart()
wx.showToast({
title: '切换成功',
icon: 'success',
})
}).catch(() => {
wx.showToast({
title: '切换失败',
icon: 'none',
})
})
// 重新加载数据
this.getStatistics()
this.getPatientChart()
this.getPharmacistChart()
this.getPharmacyChart()
}
},
// 获取统计数据看板
// 获取统计数据看板(累计数据)
getStatistics() {
const data: any = {}
if (this.data.currentProjectId) {
data.projectId = this.data.currentProjectId
}
wx.ajax({
method: 'GET',
url: '/app/promoter/promoter/statistics',
data,
}).then((res: any) => {
this.setData({
invitePharmacyCount: res.invitePharmacyCount || 0,
invitePharmacistCount: res.invitePharmacistCount || 0,
// 累计数据
totalInvitePharmacyCount: res.invitePharmacyCount || 0,
totalInvitePharmacistCount: res.invitePharmacistCount || 0,
totalInvitePatientCount: res.invitePatientCount || 0,
totalJumpPatientCount: res.jumpPatientCount || 0,
totalEnrollPatientCount: res.enrollPatientCount || 0,
totalIndicationStats: res.indicationStats || [],
})
})
},
// 获取日/月度邀约患者统计数据(按日期筛选)
getPatientStatistics() {
wx.ajax({
method: 'GET',
url: '/app/promoter/promoter/patient-statistics',
data: {
statDate: this.data.startDate,
type: this.data.statType,
},
}).then((res: any) => {
this.setData({
invitePatientCount: res.invitePatientCount || 0,
jumpPatientCount: res.jumpPatientCount || 0,
enrollPatientCount: res.enrollPatientCount || 0,
@ -154,34 +219,38 @@ Page({ @@ -154,34 +219,38 @@ Page({
})
},
// 获取邀约患者统计图表
// 获取邀约患者统计图表(使用 chart1 的日期)
getPatientChart() {
const data: any = {
type: this.data.statType,
startDate: this.data.startDate,
endDate: this.data.endDate,
}
if (this.data.currentProjectId) {
data.projectId = this.data.currentProjectId
}
wx.ajax({
method: 'GET',
url: '/app/promoter/promoter/patient-chart',
data,
data: {
type: this.data.statType,
startDate: this.data.chart1StartDate,
endDate: this.data.chart1EndDate,
},
}).then((list: any) => {
// 新接口返回的数据格式包含 invitePatientCount, jumpPatientCount, enrollPatientCount, indicationStats
// 转换为图表需要的格式
const chartData = (list || []).map((item: any) => ({
date: item.statDate,
inviteCount: item.invitePatientCount || 0,
jumpCount: item.jumpPatientCount || 0,
enrollCount: item.enrollPatientCount || 0,
}))
this.setData({
chartData: list || [],
chartData,
})
this.initChartBar(list || [])
this.initChartBar(chartData)
})
},
// 获取邀约药师统计图表
// 获取邀约药师统计图表(使用 chart2 的日期)
getPharmacistChart() {
const data: any = {
type: this.data.statType,
startDate: this.data.startDate,
endDate: this.data.endDate,
startDate: this.data.chart2StartDate,
endDate: this.data.chart2EndDate,
}
if (this.data.currentProjectId) {
data.projectId = this.data.currentProjectId
@ -198,12 +267,12 @@ Page({ @@ -198,12 +267,12 @@ Page({
})
},
// 获取邀约药店统计图表
// 获取邀约药店统计图表(使用 chart3 的日期)
getPharmacyChart() {
const data: any = {
type: this.data.statType,
startDate: this.data.startDate,
endDate: this.data.endDate,
startDate: this.data.chart3StartDate,
endDate: this.data.chart3EndDate,
}
if (this.data.currentProjectId) {
data.projectId = this.data.currentProjectId
@ -226,25 +295,39 @@ Page({ @@ -226,25 +295,39 @@ Page({
this.setData({
statType: type,
})
this.getPatientStatistics()
this.getPatientChart()
this.getPharmacistChart()
this.getPharmacyChart()
},
// 日期选择变化
// 日期选择变化(邀约患者统计卡片 - 单日选择)
onDateChange(e: WechatMiniprogram.CustomEvent) {
const value = e.detail.value
this.setData({
startDate: value,
})
// 重新加载统计数据
this.getPatientStatistics()
},
// 图表1日期选择变化
onChart1DateChange(e: WechatMiniprogram.CustomEvent) {
const { field } = e.currentTarget.dataset
const value = e.detail.value
const startDate = this.data.chart1StartDate
const endDate = this.data.chart1EndDate
// 验证日期范围
if (field === 'startDate' && this.data.endDate && value > this.data.endDate) {
if (field === 'startDate' && endDate && value > endDate) {
wx.showToast({
title: '开始时间不能大于结束时间',
icon: 'none',
})
return
}
if (field === 'endDate' && this.data.startDate && value < this.data.startDate) {
if (field === 'endDate' && startDate && value < startDate) {
wx.showToast({
title: '结束时间不能小于开始时间',
icon: 'none',
@ -253,28 +336,81 @@ Page({ @@ -253,28 +336,81 @@ Page({
}
this.setData({
[field]: value,
[field === 'startDate' ? 'chart1StartDate' : 'chart1EndDate']: value,
})
// 重新加载图表数据
this.getPatientChart()
},
// 图表2日期选择变化
onChart2DateChange(e: WechatMiniprogram.CustomEvent) {
const { field } = e.currentTarget.dataset
const value = e.detail.value
const startDate = this.data.chart2StartDate
const endDate = this.data.chart2EndDate
// 验证日期范围
if (field === 'startDate' && endDate && value > endDate) {
wx.showToast({
title: '开始时间不能大于结束时间',
icon: 'none',
})
return
}
if (field === 'endDate' && startDate && value < startDate) {
wx.showToast({
title: '结束时间不能小于开始时间',
icon: 'none',
})
return
}
this.setData({
[field === 'startDate' ? 'chart2StartDate' : 'chart2EndDate']: value,
})
this.getPharmacistChart()
},
// 图表3日期选择变化
onChart3DateChange(e: WechatMiniprogram.CustomEvent) {
const { field } = e.currentTarget.dataset
const value = e.detail.value
const startDate = this.data.chart3StartDate
const endDate = this.data.chart3EndDate
// 验证日期范围
if (field === 'startDate' && endDate && value > endDate) {
wx.showToast({
title: '开始时间不能大于结束时间',
icon: 'none',
})
return
}
if (field === 'endDate' && startDate && value < startDate) {
wx.showToast({
title: '结束时间不能小于开始时间',
icon: 'none',
})
return
}
this.setData({
[field === 'startDate' ? 'chart3StartDate' : 'chart3EndDate']: value,
})
this.getPharmacyChart()
},
// 切换到上一天
// 切换到上一天(只更新邀约患者统计卡片)
prevDate() {
const currentDate = new Date(this.data.startDate)
const newDate = new Date(currentDate.getTime() - 24 * 60 * 60 * 1000)
const startDate = this.formatDate(newDate)
this.setData({ startDate })
// 重新加载图表数据
this.getPatientChart()
this.getPharmacistChart()
this.getPharmacyChart()
// 只重新加载统计数据
this.getPatientStatistics()
},
// 切换到下一天
// 切换到下一天(只更新邀约患者统计卡片)
nextDate() {
const currentDate = new Date(this.data.startDate)
const newDate = new Date(currentDate.getTime() + 24 * 60 * 60 * 1000)
@ -291,10 +427,8 @@ Page({ @@ -291,10 +427,8 @@ Page({
const startDate = this.formatDate(newDate)
this.setData({ startDate })
// 重新加载图表数据
this.getPatientChart()
this.getPharmacistChart()
this.getPharmacyChart()
// 只重新加载统计数据
this.getPatientStatistics()
},
initChartBar(list: any[]) {

42
src/ground/pages/home/index.wxml

@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
<view class="s-header">
<view class="title" bind:tap="handleFold" data-key="fold1">
累计邀约
<view class="fold {{fold1&&'active'}}">
<view class="fold {{fold1&&'active'}}" wx:if="{{totalIndicationStats.length > 0}}">
{{fold1?'展开':'收起'}}
<van-icon class="icon" name="arrow-down" />
</view>
@ -34,33 +34,33 @@ @@ -34,33 +34,33 @@
<view class="row1">
<view class="col">
<view class="name">药店数</view>
<view class="num">{{invitePharmacyCount}}</view>
<view class="num">{{totalInvitePharmacyCount}}</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">药师数</view>
<view class="num">{{invitePharmacistCount}}</view>
<view class="num">{{totalInvitePharmacistCount}}</view>
</view>
</view>
<view class="card">
<view class="row2">
<view class="col">
<view class="name">邀约患者数</view>
<view class="num">{{invitePatientCount}}</view>
<view class="num">{{totalInvitePatientCount}}</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">跳转患者数</view>
<view class="num">{{jumpPatientCount}}</view>
<view class="num">{{totalJumpPatientCount}}</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">入组患者数</view>
<view class="num">{{enrollPatientCount}}</view>
<view class="num">{{totalEnrollPatientCount}}</view>
</view>
</view>
<view class="card-container {{fold1&&'fold'}}">
<view wx:for="{{indicationStats}}" wx:key="indicationId" class="row3">
<view wx:for="{{totalIndicationStats}}" wx:key="indicationId" class="row3">
<view class="col">
<view class="name">{{item.indicationName}}</view>
<view class="num">{{item.invitePatientCount}}</view>
@ -90,12 +90,12 @@ @@ -90,12 +90,12 @@
<view class="c-options">
<view class="name" bind:tap="handleFold" data-key="fold2">
邀约患者统计
<view class="fold {{fold2&&'active'}}">
<view class="fold {{fold2&&'active'}}" wx:if="{{indicationStats.length > 0}}">
{{fold2?'展开':'收起'}}
<van-icon class="icon" name="arrow-down" />
</view>
</view>
<picker class="picker" mode="date" value="{{startDate}}" end="{{today}}" bindchange="onDateChange" data-field="startDate">
<picker class="picker" mode="date" value="{{startDate}}" end="{{today}}" bindchange="onDateChange">
<view class="p-content">
<van-icon class="icon" name="arrow-left" catchtap="prevDate" />
<view class="content">{{startDate}}</view>
@ -140,16 +140,16 @@ @@ -140,16 +140,16 @@
</view>
</view>
<view class="chart-range">
<picker class="picker" mode="date" value="{{startDate}}" end="{{endDate}}" bindchange="onDateChange" data-field="startDate">
<picker class="picker" mode="date" value="{{chart1StartDate}}" end="{{chart1EndDate}}" bindchange="onChart1DateChange" data-field="startDate">
<view class="p-content">
<view class="content">{{startDate}}</view>
<view class="content">{{chart1StartDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" value="{{endDate}}" start="{{startDate}}" bindchange="onDateChange" data-field="endDate">
<picker class="picker" mode="date" value="{{chart1EndDate}}" start="{{chart1StartDate}}" bindchange="onChart1DateChange" data-field="endDate">
<view class="p-content">
<view class="content">{{endDate}}</view>
<view class="content">{{chart1EndDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view>
</picker>
@ -168,16 +168,16 @@ @@ -168,16 +168,16 @@
<view class="title">邀约药师数统计</view>
</view>
<view class="chart-range">
<picker class="picker" mode="date" value="{{startDate}}" end="{{endDate}}" bindchange="onDateChange" data-field="startDate">
<picker class="picker" mode="date" value="{{chart2StartDate}}" end="{{chart2EndDate}}" bindchange="onChart2DateChange" data-field="startDate">
<view class="p-content">
<view class="content">{{startDate}}</view>
<view class="content">{{chart2StartDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" value="{{endDate}}" start="{{startDate}}" bindchange="onDateChange" data-field="endDate">
<picker class="picker" mode="date" value="{{chart2EndDate}}" start="{{chart2StartDate}}" bindchange="onChart2DateChange" data-field="endDate">
<view class="p-content">
<view class="content">{{endDate}}</view>
<view class="content">{{chart2EndDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view>
</picker>
@ -192,16 +192,16 @@ @@ -192,16 +192,16 @@
<view class="title">邀约药店统计</view>
</view>
<view class="chart-range">
<picker class="picker" mode="date" value="{{startDate}}" end="{{endDate}}" bindchange="onDateChange" data-field="startDate">
<picker class="picker" mode="date" value="{{chart3StartDate}}" end="{{chart3EndDate}}" bindchange="onChart3DateChange" data-field="startDate">
<view class="p-content">
<view class="content">{{startDate}}</view>
<view class="content">{{chart3StartDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" value="{{endDate}}" start="{{startDate}}" bindchange="onDateChange" data-field="endDate">
<picker class="picker" mode="date" value="{{chart3EndDate}}" start="{{chart3StartDate}}" bindchange="onChart3DateChange" data-field="endDate">
<view class="p-content">
<view class="content">{{endDate}}</view>
<view class="content">{{chart3EndDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view>
</picker>

1
src/ground/pages/invite/index.wxml

@ -40,6 +40,5 @@ @@ -40,6 +40,5 @@
扫码立即加入
<view class="dot"></view>
</view>
<view class="save-tip" wx:if="{{qrCodeUrl}}">点击二维码保存到相册</view>
</view>
</view>

72
src/ground/pages/pharmacist/index.ts

@ -8,6 +8,12 @@ Page({ @@ -8,6 +8,12 @@ Page({
startDate: '',
endDate: '',
// 项目列表
projectList: [] as Array<{ projectId: number; projectName: string; projectDescription: string }>,
currentProjectId: 0,
currentProjectName: '',
projectIndex: 0,
// 药师列表
pharmacistList: [] as any[],
totalCount: 0,
@ -26,9 +32,75 @@ Page({ @@ -26,9 +32,75 @@ Page({
onLoad() {
// 地推端药师页面,仅允许地推人员访问
app.waitLogin({ types: [3] }).then(() => {
this.getProjectList()
})
},
// 获取项目列表
getProjectList() {
wx.ajax({
method: 'GET',
url: '/app/promoter/promoter/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.getPharmacistList()
})
},
// 切换项目
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/promoter/promoter/switch-project',
data: {
projectId: project.projectId,
},
}).then(() => {
// 切换成功后更新页面数据
this.setData({
currentProjectId: project.projectId,
currentProjectName: project.projectName,
projectIndex: index,
// 重置列表数据
page: 1,
pharmacistList: [],
hasMore: true,
pagination: {
count: 0,
page: 0,
pages: 0,
},
})
// 重新加载数据
this.getPharmacistList()
wx.showToast({
title: '切换成功',
icon: 'success',
})
}).catch(() => {
wx.showToast({
title: '切换失败',
icon: 'none',
})
})
}
},
// 获取药师列表
getPharmacistList() {
if (this.data.loading || !this.data.hasMore) return

14
src/ground/pages/pharmacist/index.wxml

@ -1,9 +1,9 @@ @@ -1,9 +1,9 @@
<navbar fixed custom-style="background: #fff;">
<view class="page-switch" slot="left">
特诺雅
<picker class="page-switch" slot="left" mode="selector" range="{{projectList}}" range-key="projectName" value="{{projectIndex}}" bindchange="onProjectChange">
{{currentProjectName}}
<text style="font-size: 0.5em; vertical-align: super">®</text>
<van-icon class="arrow" name="arrow-down" />
</view>
</picker>
</navbar>
<view class="page" style="padding-top:{{pageTop}}px">
@ -22,11 +22,11 @@ @@ -22,11 +22,11 @@
<view class="range">
<view class="label">时间筛选:</view>
<view class="r-wrap">
<picker class="picker" mode="date" bindchange="handleStartDateChange" end="{{endDate || ''}}">
<picker class="picker" mode="date" value="{{startDate}}" bindchange="handleStartDateChange" end="{{endDate || ''}}">
<view class="date">{{startDate || '开始时间'}}</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" bindchange="handleEndDateChange" start="{{startDate || ''}}">
<picker class="picker" mode="date" value="{{endDate}}" bindchange="handleEndDateChange" start="{{startDate || ''}}">
<view class="date">{{endDate || '结束时间'}}</view>
</picker>
<image class="icon" src="{{imageUrl}}icon2.png?t={{Timestamp}}"></image>
@ -43,7 +43,7 @@ @@ -43,7 +43,7 @@
<view class="pharmacist-card" wx:for="{{pharmacistList}}" wx:key="id" data-id="{{item.id}}" bind:tap="handleInfo">
<!-- 药师基本信息 -->
<view class="user">
<image class="avatar" src="{{imageUrl}}cache/a2.png?t={{Timestamp}}"></image>
<image class="avatar" src="{{item.avatar}}"></image>
<view class="wrap">
<view class="pharmacist-info">
<text class="pharmacist-name">{{item.name}}</text>
@ -84,7 +84,7 @@ @@ -84,7 +84,7 @@
<view class="detail-btn">数据详情</view>
</view>
</view>
<pagination pagination="{{pagination}}" wx:if="{{pharmacistList.length > 0}}" />
<pagination pagination="{{pagination}}" />
</view>
</view>

132
src/ground/pages/stat/index.ts

@ -2,53 +2,36 @@ const app = getApp<IAppOption>() @@ -2,53 +2,36 @@ const app = getApp<IAppOption>()
Page({
data: {
// 药师ID
pharmacistId: '',
// 时间筛选
startDate: '',
endDate: '',
type: 'day', // day-按日,month-按月
// 统计数据
// 统计数据(从 summary 获取)
invitePatientCount: 0,
jumpPatientCount: 0,
enrollPatientCount: 0,
indicationStats: [] as any[],
// 图表数据
chartList: [] as any[],
// 加载状态
loading: false,
// 列表数据
list: [] as any[],
// 分页信息
page: 1,
pageSize: 20,
pagination: {
count: 0,
page: 1,
pages: 1,
page: 0,
pages: 0,
},
},
onLoad(option: { id?: string }) {
onLoad() {
// 地推端统计页面,仅允许地推人员访问
app.waitLogin({ types: [3] }).then(() => {
// 获取药师ID
const pharmacistId = option.id || ''
if (!pharmacistId) {
wx.showToast({
title: '缺少药师ID',
icon: 'none',
})
return
}
this.setData({ pharmacistId })
// 设置默认时间范围(最近30天)
// 设置默认时间范围(2026年3月至今)
this.setDefaultDateRange()
// 获取统计数据
this.getStatistics()
this.getChartData()
// 获取列表数据(包含顶部统计数据)
this.getList(true)
})
},
// 设置默认时间范围(2026年3月至今)
@ -68,57 +51,78 @@ Page({ @@ -68,57 +51,78 @@ Page({
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
// 获取统计数据
getStatistics() {
const { pharmacistId } = this.data
if (!pharmacistId) return
// 获取列表数据(包含顶部统计数据)
getList(reset = false) {
const { startDate, endDate, type, page, pageSize, pagination } = this.data
wx.ajax({
method: 'GET',
url: '/app/promoter/promoter/pharmacist-statistics',
data: {
pharmacistId,
},
}).then((res: any) => {
// 如果是重置(如筛选条件变化),先重置状态
if (reset) {
if (pagination.page > 0 && pagination.page < pagination.pages) return // 如果正在加载,不重复请求
this.setData({
invitePatientCount: res.invitePatientCount || 0,
jumpPatientCount: res.jumpPatientCount || 0,
enrollPatientCount: res.enrollPatientCount || 0,
indicationStats: res.indicationStats || [],
page: 1,
list: [],
pagination: { count: 0, page: 0, pages: 0 },
})
})
},
// 获取图表数据
getChartData() {
const { pharmacistId, startDate, endDate, type } = this.data
if (!pharmacistId || !startDate || !endDate) return
} else {
// 非重置情况下,如果正在加载或已加载完,不再请求
if (pagination.page > 0 && (pagination.page >= pagination.pages)) return
}
this.setData({ loading: true })
const currentPage = reset ? 1 : page
wx.ajax({
method: 'GET',
url: '/app/promoter/promoter/pharmacist-chart',
url: '/app/promoter/promoter/patient-statistics-list',
data: {
pharmacistId,
startDate,
endDate,
type,
page: currentPage,
pageSize,
},
}).then((data: any) => {
const chartList = data || []
}).then((res: any) => {
const newList = res.list || []
const total = res.total || 0
const summary = res.summary || {}
// 转换数据格式
const formattedList = newList.map((item: any) => ({
date: item.statDate,
inviteCount: item.invitePatientCount || 0,
jumpCount: item.jumpPatientCount || 0,
enrollCount: item.enrollPatientCount || 0,
indicationStats: (item.indicationStats || []).map((ind: any) => ({
indicationName: ind.indicationName,
inviteCount: ind.invitePatientCount || 0,
jumpCount: ind.jumpPatientCount || 0,
enrollCount: ind.enrollPatientCount || 0,
})),
}))
const list = reset ? formattedList : [...this.data.list, ...formattedList]
const pages = Math.ceil(total / pageSize)
this.setData({
chartList,
loading: false,
// 顶部统计数据从 summary 获取
invitePatientCount: summary.invitePatientCount || 0,
jumpPatientCount: summary.jumpPatientCount || 0,
enrollPatientCount: summary.enrollPatientCount || 0,
// 列表数据
list,
page: currentPage + 1,
pagination: {
count: chartList.length,
page: 1,
pages: 1,
count: total,
page: currentPage,
pages,
},
})
}).catch(() => {
this.setData({ loading: false })
})
},
// 加载更多
onReachBottom() {
this.getList()
},
// 开始时间选择
handleStartDateChange(e: WechatMiniprogram.CustomEvent) {
const startDate = e.detail.value
@ -134,7 +138,7 @@ Page({ @@ -134,7 +138,7 @@ Page({
}
this.setData({ startDate })
this.getChartData()
this.getList(true)
},
// 结束时间选择
handleEndDateChange(e: WechatMiniprogram.CustomEvent) {
@ -151,13 +155,13 @@ Page({ @@ -151,13 +155,13 @@ Page({
}
this.setData({ endDate })
this.getChartData()
this.getList(true)
},
// 切换统计类型
handleTypeChange(e: WechatMiniprogram.CustomEvent) {
const type = e.currentTarget.dataset.type
this.setData({ type })
this.getChartData()
this.getList(true)
},
handleBack() {
wx.navigateBack()

9
src/ground/pages/stat/index.wxml

@ -8,14 +8,14 @@ @@ -8,14 +8,14 @@
<view class="page" style="padding-top: {{pageTop}}px;">
<view class="page-header" style="top:{{pageTop}}px">
<view class="chart-range">
<picker class="picker" mode="date" end="{{endDate}}" bindchange="handleStartDateChange">
<picker class="picker" mode="date" value="{{startDate}}" end="{{endDate}}" bindchange="handleStartDateChange">
<view class="p-content">
<view class="content">{{startDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" start="{{startDate}}" bindchange="handleEndDateChange">
<picker class="picker" mode="date" value="{{endDate}}" start="{{startDate}}" bindchange="handleEndDateChange">
<view class="p-content">
<view class="content">{{endDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
@ -47,8 +47,7 @@ @@ -47,8 +47,7 @@
</view>
</view>
<view class="stat-list">
<view class="loading" wx:if="{{loading}}">加载中...</view>
<view class="module" wx:for="{{chartList}}" wx:key="date">
<view class="module" wx:for="{{list}}" wx:key="date">
<view class="aside">
<view class="line-top"></view>
<view class="dot"></view>
@ -93,6 +92,6 @@ @@ -93,6 +92,6 @@
</view>
</view>
</view>
<view class="empty" wx:if="{{!loading && chartList.length === 0}}">暂无数据</view>
<pagination pagination="{{pagination}}" />
</view>
</view>

Loading…
Cancel
Save