Browse Source

feat: 优化图片加载模式为aspectFill并修复相关页面问题

refactor: 重构项目选择器逻辑和用户信息处理

fix: 修正登录注册流程和状态管理

style: 统一日期选择器样式和字段显示

perf: 优化头像上传和用户信息更新逻辑

docs: 更新注释和移除模拟数据代码

test: 添加项目列表和邀约人信息接口测试
master
kola-web 1 week ago
parent
commit
d355e7c804
  1. 10
      src/app.ts
  2. 2
      src/components/popupDoctor/index.wxml
  3. 21
      src/doctor/pages/article/index.ts
  4. 63
      src/doctor/pages/articleList/index.ts
  5. 1
      src/doctor/pages/articleList/index.wxml
  6. 27
      src/doctor/pages/changeNickname/index.ts
  7. 83
      src/doctor/pages/changeTel/index.ts
  8. 332
      src/doctor/pages/home/index.ts
  9. 24
      src/doctor/pages/home/index.wxml
  10. 29
      src/doctor/pages/invite/index.ts
  11. 7
      src/doctor/pages/invite/index.wxml
  12. 38
      src/doctor/pages/login/index.ts
  13. 54
      src/doctor/pages/loginForm/index.ts
  14. 125
      src/doctor/pages/my/index.ts
  15. 6
      src/doctor/pages/my/index.wxml
  16. 154
      src/doctor/pages/stat/index.ts
  17. 2
      src/ground/pages/changeNickname/index.wxml
  18. 235
      src/ground/pages/home/index.ts
  19. 30
      src/ground/pages/home/index.wxml
  20. 24
      src/ground/pages/login/index.ts
  21. 6
      src/ground/pages/my/index.ts
  22. 2
      src/ground/pages/my/index.wxml
  23. 2
      src/ground/pages/pharmacist/index.wxml
  24. 3
      src/pages/index/index.scss
  25. 93
      src/pages/index/index.ts
  26. 9
      src/pages/index/index.wxml
  27. 42
      src/pages/start/index.ts
  28. 2
      src/pages/start/index.wxml
  29. 20
      src/pages/tourists/index.ts
  30. 4
      src/pages/tourists/index.wxml
  31. 2
      src/pages/work/index.ts
  32. 2
      typings/index.d.ts

10
src/app.ts

@ -105,15 +105,11 @@ App<IAppOption>({
return true return true
} }
if (loginIdentity && types.includes(loginIdentity) && loginIdentity === 1) {
return true
}
if (!isLogin) { if (!isLogin) {
const typeRegPageUrl = { const typeRegPageUrl = {
2: '/pages/register/index', 2: '/pages/tourists/index',
3: '/ground/pages/register/index', 3: '/ground/pages/login/index',
4: '/doctor/pages/register/index', 4: '/doctor/pages/login/index',
}[loginIdentity as 2 | 3 | 4] }[loginIdentity as 2 | 3 | 4]
wx.reLaunch({ wx.reLaunch({
url: typeRegPageUrl || '/pages/statr/index', url: typeRegPageUrl || '/pages/statr/index',

2
src/components/popupDoctor/index.wxml

@ -14,7 +14,7 @@
<view class="container"> <view class="container">
<view class="title">医生介绍</view> <view class="title">医生介绍</view>
<view class="user"> <view class="user">
<image class="avatar" src="{{doctorInfo.doctorAvatar}}"></image> <image class="avatar" mode="aspectFill" src="{{doctorInfo.doctorAvatar}}"></image>
<view class="wrap"> <view class="wrap">
<view class="name">{{doctorInfo.doctorName}}</view> <view class="name">{{doctorInfo.doctorName}}</view>
</view> </view>

21
src/doctor/pages/article/index.ts

@ -5,18 +5,8 @@ Page({
// 文章ID // 文章ID
articleId: 0, articleId: 0,
// 文章详情(模拟数据,接口上线后删除) // 文章详情
articleDetail: { articleDetail: {} as any,
id: 1,
title: '银屑病日常护理指南',
content:
'<p>银屑病是一种慢性、复发性、炎症性皮肤病,需要长期的管理和护理。</p><h3>一、日常护理要点</h3><p>1. 保持皮肤湿润,每天使用保湿霜</p><p>2. 避免过度清洁,使用温和的洗浴产品</p><p>3. 穿着宽松、透气的棉质衣物</p><h3>二、饮食建议</h3><p>1. 多吃新鲜蔬菜水果</p><p>2. 避免辛辣刺激食物</p><p>3. 适量补充优质蛋白</p><h3>三、心理调节</h3><p>保持良好的心态,积极配合治疗,定期复诊。</p>',
imageUrl: '',
viewCount: 100,
likeCount: 10,
isLiked: false,
updateTime: 1700000000,
},
// 是否已点赞 // 是否已点赞
isLiked: false, isLiked: false,
@ -27,10 +17,9 @@ Page({
const articleId = option.id ? Number.parseInt(option.id) : 0 const articleId = option.id ? Number.parseInt(option.id) : 0
this.setData({ articleId }) this.setData({ articleId })
// TODO: 接口上线后取消注释 if (articleId) {
// if (articleId) { this.getArticleDetail(articleId)
// this.getArticleDetail(articleId) }
// }
}) })
}, },
// 获取文章详情 // 获取文章详情

63
src/doctor/pages/articleList/index.ts

@ -2,48 +2,15 @@ const app = getApp<IAppOption>()
Page({ Page({
data: { data: {
// 分类列表(模拟数据,接口上线后删除) // 分类列表
categoryList: [ categoryList: [] as any[],
{ id: 1, name: '学习专栏', images: [] }, currentCategoryId: 0,
{ id: 2, name: '社区热帖', images: [] },
{ id: 3, name: '行业热点', images: [] },
{ id: 4, name: '中国药店', images: [] },
] as any[],
currentCategoryId: 1,
// Banner列表 // Banner列表
bannerList: [] as any[], bannerList: [] as any[],
// 文章列表(模拟数据,接口上线后删除) // 文章列表
articleList: [ articleList: [] as any[],
{
id: 1,
title: '银屑病日常护理指南',
imageUrl: '',
viewCount: 100,
likeCount: 10,
updateTime: 1700000000,
updateTimeFormatted: '2023-11-14',
},
{
id: 2,
title: '从强降糖到防事件,那些糖尿病指南走过的路',
imageUrl: '',
viewCount: 256,
likeCount: 32,
updateTime: 1700086400,
updateTimeFormatted: '2023-11-15',
},
{
id: 3,
title: '特诺雅患者援助项目介绍',
imageUrl: '',
viewCount: 89,
likeCount: 15,
updateTime: 1700172800,
updateTimeFormatted: '2023-11-16',
},
] as any[],
// 分页 // 分页
page: 1, page: 1,
@ -51,7 +18,7 @@ Page({
loading: false, loading: false,
hasMore: true, hasMore: true,
pagination: { pagination: {
count: 3, count: 0,
page: 1, page: 1,
pages: 1, pages: 1,
}, },
@ -59,8 +26,7 @@ Page({
onLoad() { onLoad() {
// 药店端教育页面,仅允许药店人员访问 // 药店端教育页面,仅允许药店人员访问
app.waitLogin({ types: [4] }).then(() => { app.waitLogin({ types: [4] }).then(() => {
// TODO: 接口上线后取消注释 this.getCategoryList()
// this.getCategoryList()
}) })
}, },
// 获取教育分类列表 // 获取教育分类列表
@ -110,10 +76,10 @@ Page({
page: this.data.page, page: this.data.page,
pageSize: this.data.pageSize, pageSize: this.data.pageSize,
}, },
}).then((res: any) => { })
.then((res: any) => {
const list = (res.list || []).map((item: any) => ({ const list = (res.list || []).map((item: any) => ({
...item, ...item,
updateTimeFormatted: item.updateTime ? this.formatDate(item.updateTime) : '',
})) }))
const total = res.total || 0 const total = res.total || 0
const currentPage = this.data.page const currentPage = this.data.page
@ -129,18 +95,11 @@ Page({
pages: Math.ceil(total / this.data.pageSize) || 1, pages: Math.ceil(total / this.data.pageSize) || 1,
}, },
}) })
}).catch(() => { })
.catch(() => {
this.setData({ loading: false }) this.setData({ loading: false })
}) })
}, },
// 格式化日期
formatDate(timestamp: number): string {
const date = new Date(timestamp * 1000)
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}`
},
// 切换分类 // 切换分类
handleTabChange(e: WechatMiniprogram.CustomEvent) { handleTabChange(e: WechatMiniprogram.CustomEvent) {
const categoryId = e.currentTarget.dataset.id const categoryId = e.currentTarget.dataset.id

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

@ -36,7 +36,6 @@
<text class="num">{{item.likeCount || 0}}</text> <text class="num">{{item.likeCount || 0}}</text>
</view> </view>
</view> </view>
<view class="time" wx:if="{{item.updateTimeFormatted}}">{{item.updateTimeFormatted}}</view>
</view> </view>
</view> </view>
</view> </view>

27
src/doctor/pages/changeNickname/index.ts

@ -2,13 +2,25 @@ const app = getApp<IAppOption>()
Page({ Page({
data: { data: {
// 新姓名
name: '', name: '',
loading: false,
}, },
onLoad() { onLoad() {
// 药店端修改昵称页面,仅允许药店人员访问 // 药店端修改昵称页面,仅允许药店人员访问
app.waitLogin({ types: [4] }).then(() => { app.waitLogin({ types: [4] }).then(() => {
// 页面加载完成 // 获取当前姓名
this.getCurrentName()
})
},
// 获取当前姓名
getCurrentName() {
wx.ajax({
method: 'GET',
url: '/app/pharmacist/pharmacist/profile',
}).then((res: any) => {
this.setData({
name: res.name || '',
})
}) })
}, },
// 输入姓名 // 输入姓名
@ -28,7 +40,8 @@ Page({
return return
} }
wx.showLoading({ title: '提交中...' }) if (this.data.loading) return
this.setData({ loading: true })
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
@ -37,11 +50,7 @@ Page({
name: name.trim(), name: name.trim(),
}, },
}).then(() => { }).then(() => {
wx.hideLoading() this.setData({ loading: false })
// 更新全局数据
if (app.globalData.initLoginInfo?.pharmacistInfo) {
app.globalData.initLoginInfo.pharmacistInfo.name = name.trim()
}
wx.showToast({ wx.showToast({
title: '修改成功', title: '修改成功',
icon: 'success', icon: 'success',
@ -50,7 +59,7 @@ Page({
wx.navigateBack() wx.navigateBack()
}, 1500) }, 1500)
}).catch(() => { }).catch(() => {
wx.hideLoading() this.setData({ loading: false })
wx.showToast({ wx.showToast({
title: '修改失败', title: '修改失败',
icon: 'none', icon: 'none',

83
src/doctor/pages/changeTel/index.ts

@ -1,14 +1,14 @@
const app = getApp<IAppOption>() const app = getApp<IAppOption>()
let timer = null as null | number
Page({ Page({
data: { data: {
mobile: '', mobile: '',
code: '', code: '',
codeText: '发送验证码', codeText: '发送验证码',
counting: false, loading: false,
countdown: 60,
}, },
timer: null as any,
onLoad() { onLoad() {
// 药店端修改手机号页面,仅允许药店人员访问 // 药店端修改手机号页面,仅允许药店人员访问
app.waitLogin({ types: [4] }).then(() => { app.waitLogin({ types: [4] }).then(() => {
@ -16,23 +16,25 @@ Page({
}) })
}, },
onUnload() { onUnload() {
// 清除定时器 // 页面卸载时清除定时器
if (this.timer) { if (timer) {
clearInterval(this.timer) clearInterval(timer)
timer = null
} }
}, },
// 获取验证码 // 获取验证码
getCode() { getCode() {
if (this.data.counting) return if (timer) return
const { mobile } = this.data const mobile = this.data.mobile
if (!mobile) { if (!mobile) {
wx.showToast({ wx.showToast({
title: '请输入手机号', title: '手机号不能为空',
icon: 'none', icon: 'none',
}) })
return return
} }
// 验证手机号
if (!/^1[3-9]\d{9}$/.test(mobile)) { if (!/^1[3-9]\d{9}$/.test(mobile)) {
wx.showToast({ wx.showToast({
title: '手机号格式不正确', title: '手机号格式不正确',
@ -46,85 +48,60 @@ Page({
url: '/app/common/common/send-code', url: '/app/common/common/send-code',
data: { data: {
phone: mobile, phone: mobile,
type: 2, // 2-绑定手机号 type: 3, // 3-修改手机号
}, },
}).then(() => { }).then(() => {
wx.showToast({ wx.showToast({
title: '验证码已发送',
icon: 'success',
})
this.startCountdown()
}).catch(() => {
wx.showToast({
title: '发送失败',
icon: 'none', icon: 'none',
title: '验证码已发送~',
}) })
}) let time = 60
}, timer = setInterval(() => {
// 开始倒计时 time--
startCountdown() {
this.setData({ this.setData({
counting: true, codeText: `${time}s后重新发送`,
countdown: 60,
codeText: '60s',
}) })
if (time <= 0) {
this.timer = setInterval(() => { clearInterval(timer as number)
const countdown = this.data.countdown - 1 timer = null
if (countdown <= 0) {
clearInterval(this.timer)
this.setData({ this.setData({
counting: false,
codeText: '发送验证码', codeText: '发送验证码',
}) })
} else {
this.setData({
countdown,
codeText: `${countdown}s`,
})
} }
}, 1000) }, 1000)
})
}, },
// 确认修改 // 提交修改
handleSubmit() { handleSubmit() {
const { mobile, code } = this.data const { mobile, code } = this.data
if (!mobile) { if (!mobile) {
wx.showToast({ wx.showToast({
title: '请输入手机号',
icon: 'none',
})
return
}
if (!/^1[3-9]\d{9}$/.test(mobile)) {
wx.showToast({
title: '手机号格式不正确',
icon: 'none', icon: 'none',
title: '请输入手机号',
}) })
return return
} }
if (!code) { if (!code) {
wx.showToast({ wx.showToast({
title: '请输入验证码',
icon: 'none', icon: 'none',
title: '请输入验证码',
}) })
return return
} }
wx.showLoading({ title: '提交中...' }) if (this.data.loading) return
this.setData({ loading: true })
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '/app/pharmacist/pharmacist/update-phone', url: '/app/pharmacist/pharmacist/update-phone',
data: { data: {
phone: mobile, phone: mobile,
code: code, code,
}, },
}).then(() => { }).then(() => {
wx.hideLoading() this.setData({ loading: false })
// 更新全局数据
if (app.globalData.initLoginInfo?.pharmacistInfo) {
app.globalData.initLoginInfo.pharmacistInfo.phone = mobile
}
wx.showToast({ wx.showToast({
title: '修改成功', title: '修改成功',
icon: 'success', icon: 'success',
@ -133,7 +110,7 @@ Page({
wx.navigateBack() wx.navigateBack()
}, 1500) }, 1500)
}).catch(() => { }).catch(() => {
wx.hideLoading() this.setData({ loading: false })
wx.showToast({ wx.showToast({
title: '修改失败', title: '修改失败',
icon: 'none', icon: 'none',

332
src/doctor/pages/home/index.ts

@ -10,6 +10,12 @@ Page({
pharmacistAvatar: '', pharmacistAvatar: '',
pharmacyName: '', pharmacyName: '',
// 项目列表
projectList: [] as Array<{ projectId: number; projectName: string; projectDescription: string }>,
currentProjectId: 0,
currentProjectName: '特诺雅',
projectIndex: 0,
// 待处理患者数 // 待处理患者数
pendingCount: 0, pendingCount: 0,
@ -28,11 +34,20 @@ Page({
}>, }>,
// 图表数据 // 图表数据
chartData: [] as Array<{ date: string, count: number }>, chartData: [] as Array<{ date: string; count: number }>,
// 日期范围 // 日期范围 - 邀约患者统计卡片(单日)
startDate: '', startDate: '',
endDate: '', today: '',
// 统计卡片显示用的月份(YYYY-MM)
startMonth: '',
// 日期范围 - 图表(日期范围)
chartStartDate: '',
chartEndDate: '',
// 图表显示用的月份(YYYY-MM)
chartStartMonth: '',
chartEndMonth: '',
// 统计类型: day-日统计, month-月统计 // 统计类型: day-日统计, month-月统计
statType: 'day', statType: 'day',
@ -45,17 +60,25 @@ Page({
// 药店端页面,仅允许药店人员(4)访问 // 药店端页面,仅允许药店人员(4)访问
app.waitLogin({ types: [4] }).then(() => { app.waitLogin({ types: [4] }).then(() => {
this.getUserInfo() this.getUserInfo()
this.getPendingCount() this.getProjectList()
this.getStatistics()
this.getPatientChart()
}) })
// 初始化日期范围为最近30天 // 初始化日期
const endDate = this.formatDate(new Date()) const today = this.formatDate(new Date())
const startDate = this.formatDate(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)) 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({ this.setData({
startDate, today,
endDate, // 邀约患者统计卡片(单日)- 默认为今天
startDate: today,
startMonth: currentMonth,
// 图表(日期范围)- 默认为最近30天
chartStartDate: defaultStartDate,
chartEndDate: today,
// 图表月份显示 - 默认为最近12个月
chartStartMonth: defaultStartMonth,
chartEndMonth: currentMonth,
}) })
}, },
@ -67,6 +90,13 @@ Page({
return `${year}-${month}-${day}` 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() { getUserInfo() {
wx.ajax({ wx.ajax({
@ -78,14 +108,70 @@ Page({
pharmacistAvatar: res.avatar, pharmacistAvatar: res.avatar,
pharmacyName: res.pharmacyName, pharmacyName: res.pharmacyName,
}) })
}).catch(() => { })
// 接口失败时使用模拟数据 },
// 获取项目列表
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({ this.setData({
pharmacistName: '李药师', projectList,
pharmacistAvatar: '', currentProjectId,
pharmacyName: '康泰大药房(人民路店)', currentProjectName: currentProject?.projectName || '特诺雅',
projectIndex: projectIndex >= 0 ? projectIndex : 0,
})
// 获取其他数据
this.getPendingCount()
this.getStatistics()
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.getStatistics()
this.getPatientChart()
wx.showToast({
title: '切换成功',
icon: 'success',
}) })
}) })
.catch(() => {
wx.showToast({
title: '切换失败',
icon: 'none',
})
})
}
}, },
// 获取待处理患者数 // 获取待处理患者数
@ -93,11 +179,13 @@ Page({
wx.ajax({ wx.ajax({
method: 'GET', method: 'GET',
url: '/app/pharmacist/pharmacist/pending-count', url: '/app/pharmacist/pharmacist/pending-count',
}).then((res: any) => { })
.then((res: any) => {
this.setData({ this.setData({
pendingCount: res.count || 0, pendingCount: res.count || 0,
}) })
}).catch(() => { })
.catch(() => {
// 接口失败时使用模拟数据 // 接口失败时使用模拟数据
this.setData({ this.setData({
pendingCount: 12, pendingCount: 12,
@ -117,44 +205,40 @@ Page({
enrollPatientCount: res.enrollPatientCount || 0, enrollPatientCount: res.enrollPatientCount || 0,
indicationStats: res.indicationStats || [], indicationStats: res.indicationStats || [],
}) })
}).catch(() => {
// 接口失败时使用模拟数据
this.setData({
invitePatientCount: 156,
jumpPatientCount: 128,
enrollPatientCount: 89,
indicationStats: [
{ indicationId: 1, indicationName: '斑块状银屑病', invitePatientCount: 80, jumpPatientCount: 65, enrollPatientCount: 45 },
{ indicationId: 2, indicationName: '溃疡性结肠炎', invitePatientCount: 45, jumpPatientCount: 38, enrollPatientCount: 28 },
{ indicationId: 3, indicationName: '克罗恩病', invitePatientCount: 31, jumpPatientCount: 25, enrollPatientCount: 16 },
],
})
}) })
}, },
// 获取邀约患者统计图表 // 获取邀约患者统计图表(使用 chart 的日期范围)
getPatientChart() { getPatientChart() {
// 根据统计类型格式化日期
const startDate =
this.data.statType === 'month'
? this.data.chartStartDate.substring(0, 7) // YYYY-MM
: this.data.chartStartDate // YYYY-MM-DD
const endDate =
this.data.statType === 'month'
? this.data.chartEndDate.substring(0, 7) // YYYY-MM
: this.data.chartEndDate // YYYY-MM-DD
wx.ajax({ wx.ajax({
method: 'GET', method: 'GET',
url: '/app/pharmacist/pharmacist/patient-chart', url: '/app/pharmacist/pharmacist/patient-chart',
data: { data: {
type: this.data.statType, type: this.data.statType,
startDate: this.data.startDate, startDate,
endDate: this.data.endDate, endDate,
}, },
}).then((res: any) => { }).then((res: any) => {
const list = res.list || [] const list = res.list || []
// 转换为图表需要的格式
const chartData = list.map((item: any) => ({
date: item.statDate || item.date,
count: item.invitePatientCount || item.count || 0,
}))
this.setData({ this.setData({
chartData: list, chartData,
})
this.initChartBar(list)
}).catch(() => {
// 接口失败时使用模拟数据
const mockData = this.generateMockChartData()
this.setData({
chartData: mockData,
}) })
this.initChartBar(mockData) this.initChartBar(chartData)
}) })
}, },
// 生成模拟图表数据 // 生成模拟图表数据
@ -183,26 +267,178 @@ Page({
// 切换统计类型 // 切换统计类型
switchStatType(e: WechatMiniprogram.CustomEvent) { switchStatType(e: WechatMiniprogram.CustomEvent) {
const type = e.currentTarget.dataset.type 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({ this.setData({
statType: type, statType: type,
startDate,
startMonth,
chartStartDate,
chartEndDate,
chartStartMonth,
chartEndMonth,
}) })
this.getStatistics()
this.getPatientChart() this.getPatientChart()
}, },
// 日期选择变化 // 日期选择变化
onDateChange(e: WechatMiniprogram.CustomEvent) { onDateChange(e: WechatMiniprogram.CustomEvent) {
const { field } = e.currentTarget.dataset const value = e.detail.value // YYYY-MM-DD 或 YYYY-MM
const value = e.detail.value
// 月统计时,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.getStatistics()
},
// 切换到上一天/上月
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.getStatistics()
},
// 切换到下一天/下月
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.getStatistics()
},
// 图表日期选择变化(开始日期)
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 (field === 'startDate' && this.data.endDate && value > this.data.endDate) { if (chartEndDate && fullDate > chartEndDate) {
wx.showToast({ wx.showToast({
title: '开始时间不能大于结束时间', title: '开始时间不能大于结束时间',
icon: 'none', icon: 'none',
}) })
return return
} }
if (field === 'endDate' && this.data.startDate && value < this.data.startDate) {
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({ wx.showToast({
title: '结束时间不能小于开始时间', title: '结束时间不能小于开始时间',
icon: 'none', icon: 'none',
@ -211,9 +447,9 @@ Page({
} }
this.setData({ this.setData({
[field]: value, chartEndDate: fullDate,
chartEndMonth: monthValue,
}) })
// 重新加载图表数据
this.getPatientChart() this.getPatientChart()
}, },

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

@ -1,9 +1,9 @@
<navbar fixed custom-style="background: {{background}};"> <navbar fixed custom-style="background: {{background}};">
<view class="page-switch" slot="left" style="color: {{background=='transparent'?'#fff':'#FF8A4C'}};"> <picker class="page-switch" slot="left" mode="selector" range="{{projectList}}" range-key="projectName" value="{{projectIndex}}" bindchange="onProjectChange" style="color: {{background=='transparent'?'#fff':'#FF8A4C'}};">
特诺雅 {{currentProjectName}}
<text style="font-size: 0.5em; vertical-align: super">®</text> <text style="font-size: 0.5em; vertical-align: super">®</text>
<van-icon class="arrow" name="arrow-down" /> <van-icon class="arrow" name="arrow-down" />
</view> </picker>
</navbar> </navbar>
<view <view
@ -11,7 +11,7 @@
style="background:url('{{imageUrl}}bg7.png?t={{Timestamp}}') no-repeat top center/100% 602rpx; padding-top: {{pageTop+20}}px" style="background:url('{{imageUrl}}bg7.png?t={{Timestamp}}') no-repeat top center/100% 602rpx; padding-top: {{pageTop+20}}px"
> >
<view class="user"> <view class="user">
<image class="avatar" src="{{pharmacistAvatar || imageUrl + 'cache/a1.png'}}?t={{Timestamp}}"></image> <image class="avatar" mode="aspectFill" src="{{pharmacistAvatar}}"></image>
<view class="wrap"> <view class="wrap">
<view class="name"> <view class="name">
{{pharmacistName || '药师'}} {{pharmacistName || '药师'}}
@ -112,11 +112,11 @@
<van-icon class="icon" name="arrow-down" /> <van-icon class="icon" name="arrow-down" />
</view> </view>
</view> </view>
<picker class="picker" mode="date" value="{{startDate}}" bindchange="onDateChange" data-field="startDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{startDate}}" end="{{today}}" bindchange="onDateChange">
<view class="p-content"> <view class="p-content">
<van-icon class="icon" name="arrow-left" /> <van-icon class="icon" name="arrow-left" catchtap="prevDate" />
<view class="content">{{startDate}}</view> <view class="content">{{statType === 'month' ? startMonth : startDate}}</view>
<van-icon class="icon" name="arrow" /> <van-icon class="icon" name="arrow" catchtap="nextDate" />
</view> </view>
</picker> </picker>
</view> </view>
@ -157,16 +157,16 @@
</view> </view>
</view> </view>
<view class="chart-range"> <view class="chart-range">
<picker class="picker" mode="date" value="{{startDate}}" end="{{endDate}}" bindchange="onDateChange" data-field="startDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{chartStartDate}}" end="{{chartEndDate}}" bindchange="onChartStartDateChange">
<view class="p-content"> <view class="p-content">
<view class="content">{{startDate}}</view> <view class="content">{{statType === 'month' ? chartStartMonth : chartStartDate}}</view>
<image class="icon" src="{{imageUrl}}icon13.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon13.png?t={{Timestamp}}"></image>
</view> </view>
</picker> </picker>
<view class="line"></view> <view class="line"></view>
<picker class="picker" mode="date" value="{{endDate}}" start="{{startDate}}" bindchange="onDateChange" data-field="endDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{chartEndDate}}" start="{{chartStartDate}}" bindchange="onChartEndDateChange">
<view class="p-content"> <view class="p-content">
<view class="content">{{endDate}}</view> <view class="content">{{statType === 'month' ? chartEndMonth : chartEndDate}}</view>
<image class="icon" src="{{imageUrl}}icon13.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon13.png?t={{Timestamp}}"></image>
</view> </view>
</picker> </picker>

29
src/doctor/pages/invite/index.ts

@ -17,41 +17,16 @@ Page({
onLoad() { onLoad() {
// 药店端邀约页面,仅允许药店人员访问 // 药店端邀约页面,仅允许药店人员访问
app.waitLogin({ types: [4] }).then(() => { app.waitLogin({ types: [4] }).then(() => {
this.getUserInfo() // 生成小程序码(接口会返回所有需要的信息)
})
},
// 获取药店人员信息
getUserInfo() {
wx.ajax({
method: 'GET',
url: '/app/pharmacist/pharmacist/profile',
}).then((res: any) => {
this.setData({
pharmacistName: res.name || '',
pharmacistAvatar: res.avatar || '',
pharmacistId: res.id || '',
})
// 获取小程序码
this.generateQrCode() this.generateQrCode()
}) })
}, },
// 生成药店邀约小程序码 // 生成药店邀约小程序码
generateQrCode() { generateQrCode() {
const { projectId } = this.data
if (!projectId) {
wx.showToast({
title: '获取项目信息失败',
icon: 'none',
})
return
}
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '/app/pharmacist/pharmacist/generate-code', url: '/app/pharmacist/pharmacist/generate-code',
data: { data: {},
projectId: parseInt(projectId),
},
}).then((res: any) => { }).then((res: any) => {
this.setData({ this.setData({
qrCodeUrl: res.imageUrl || '', qrCodeUrl: res.imageUrl || '',

7
src/doctor/pages/invite/index.wxml

@ -14,11 +14,7 @@
style="background: url('{{imageUrl}}bg9.png?t={{Timestamp}}') no-repeat top center/100% 964rpx" style="background: url('{{imageUrl}}bg9.png?t={{Timestamp}}') no-repeat top center/100% 964rpx"
> >
<view class="user"> <view class="user">
<image <image class="avatar" src="{{pharmacistAvatar}}" mode="aspectFill"></image>
class="avatar"
src="{{pharmacistAvatar || imageUrl + 'cache/a1.png'}}?t={{Timestamp}}"
mode="aspectFill"
></image>
<view class="wrap"> <view class="wrap">
<view class="nickname">{{pharmacistName || '药师'}}</view> <view class="nickname">{{pharmacistName || '药师'}}</view>
<view class="label">药师</view> <view class="label">药师</view>
@ -40,6 +36,5 @@
扫码立即加入 扫码立即加入
<view class="dot"></view> <view class="dot"></view>
</view> </view>
<view class="save-tip" wx:if="{{qrCodeUrl}}">点击二维码保存到相册</view>
</view> </view>
</view> </view>

38
src/doctor/pages/login/index.ts

@ -91,15 +91,13 @@ Page({
data: { data: {
phone: this.data.mobile, phone: this.data.mobile,
code: this.data.code, code: this.data.code,
promoterId: app.globalData.promoterId || '',
projectId: app.globalData.projectId || '',
}, },
}).then((res: any) => { }).then((res: any) => {
app.globalData.initLoginInfo = { app.startLogin(() => {
...app.globalData.initLoginInfo, this.submitCallback(res)
isLogin: 1, })
loginIdentity: 4,
userId: res.userId,
}
this.submitCallback()
}) })
}, },
handleWxSubmit(e: WechatMiniprogram.CustomEvent) { handleWxSubmit(e: WechatMiniprogram.CustomEvent) {
@ -121,23 +119,31 @@ Page({
sessionKey, sessionKey,
encryptedData, encryptedData,
iv, iv,
promoterId: app.globalData.promoterId || '',
projectId: app.globalData.projectId || '',
}, },
}).then((res: any) => { }).then((res: any) => {
// 更新登录信息 app.startLogin(() => {
app.globalData.initLoginInfo = { this.submitCallback(res)
...app.globalData.initLoginInfo, })
isLogin: 1,
loginIdentity: 4,
userId: res.userId,
}
this.submitCallback()
}) })
} }
}, },
submitCallback() { submitCallback(res: any) {
// 根据 isRegister 判断是否已注册
// isRegister: 0-未注册,1-已注册
if (res.isRegister === 1) {
// 已注册,设置isLogin并跳转到首页
app.globalData.initLoginInfo.isLogin = 1
wx.reLaunch({
url: '/doctor/pages/home/index',
})
} else {
// 未注册,跳转到注册页面(isLogin仍为0)
wx.reLaunch({ wx.reLaunch({
url: '/doctor/pages/loginForm/index', url: '/doctor/pages/loginForm/index',
}) })
}
}, },
handlePatient() { handlePatient() {
wx.redirectTo({ wx.redirectTo({

54
src/doctor/pages/loginForm/index.ts

@ -2,10 +2,6 @@ const app = getApp<IAppOption>()
Page({ Page({
data: { data: {
// 扫码参数
promoterId: '',
projectId: '',
// 表单数据 // 表单数据
name: '', name: '',
pharmacyId: '', pharmacyId: '',
@ -39,29 +35,8 @@ Page({
pages: 0, pages: 0,
}, },
}, },
onLoad(options) { onLoad() {
// 解析扫码参数 // 页面加载
const promoterId = app.globalData.promoterId || ''
const projectId = app.globalData.projectId || ''
this.setData({
promoterId,
projectId,
})
},
// 解析 scene 参数
parseScene(scene: string): { promoterId?: string; projectId?: string } {
const params: { promoterId?: string; projectId?: string } = {}
const pairs = scene.split('&')
pairs.forEach((pair) => {
const [key, value] = pair.split('=')
if (key === 'promoterId') {
params.promoterId = value
} else if (key === 'projectId') {
params.projectId = value
}
})
return params
}, },
// 输入姓名 // 输入姓名
handleNameInput(e: WechatMiniprogram.CustomEvent) { handleNameInput(e: WechatMiniprogram.CustomEvent) {
@ -113,8 +88,13 @@ Page({
const currentPage = this.data.page const currentPage = this.data.page
const total = res.total || 0 const total = res.total || 0
const pages = Math.ceil(total / this.data.pageSize) const pages = Math.ceil(total / this.data.pageSize)
const otherPharmacy = {
id: '-1',
name: '其他药店',
address: '没有找到所在药店',
}
this.setData({ this.setData({
pharmacyList: [...this.data.pharmacyList, ...list], pharmacyList: [...this.data.pharmacyList, ...list, otherPharmacy],
total, total,
page: currentPage + 1, page: currentPage + 1,
hasMore: currentPage < pages, hasMore: currentPage < pages,
@ -179,9 +159,9 @@ Page({
show: false, show: false,
}) })
}, },
// 提交绑定 // 提交注册
handleSubmit() { handleSubmit() {
const { promoterId, projectId, name, pharmacyId } = this.data const { name, pharmacyId } = this.data
if (!name.trim()) { if (!name.trim()) {
wx.showToast({ wx.showToast({
@ -203,10 +183,8 @@ Page({
wx.ajax({ wx.ajax({
method: 'POST', method: 'POST',
url: '/app/pharmacist/pharmacist/bind-promoter', url: '/app/pharmacist/pharmacist/register',
data: { data: {
promoterId,
projectId,
name: name.trim(), name: name.trim(),
pharmacyId, pharmacyId,
}, },
@ -215,13 +193,13 @@ Page({
wx.hideLoading() wx.hideLoading()
// 保存登录信息 // 保存登录信息
app.globalData.initLoginInfo = { app.globalData.initLoginInfo = {
loginType: 4, ...app.globalData.initLoginInfo,
isLogin: 1, isLogin: 1,
isReg: 1, loginIdentity: 4,
...res, loginIdentityId: res.pharmacistId,
} }
wx.showToast({ wx.showToast({
title: '绑定成功', title: '注册成功',
icon: 'success', icon: 'success',
}) })
// 跳转到药店端首页 // 跳转到药店端首页
@ -234,7 +212,7 @@ Page({
.catch(() => { .catch(() => {
wx.hideLoading() wx.hideLoading()
wx.showToast({ wx.showToast({
title: '绑定失败', title: '注册失败',
icon: 'none', icon: 'none',
}) })
}) })

125
src/doctor/pages/my/index.ts

@ -11,11 +11,12 @@ Page({
pharmacyName: '', pharmacyName: '',
}, },
// 邀约人信息 // 邀约人列表
inviterInfo: { inviterList: [] as Array<{
promoterName: '', promoterName: string
promoterPhone: '', promoterPhone: string
}, projectName: string
}>,
}, },
onLoad() { onLoad() {
// 药店端我的页面,仅允许药店人员访问 // 药店端我的页面,仅允许药店人员访问
@ -24,14 +25,6 @@ Page({
this.getInviterInfo() this.getInviterInfo()
}) })
}, },
onShow() {
// 页面显示时刷新用户信息
if (app.globalData.initLoginInfo?.pharmacistInfo) {
this.setData({
pharmacistInfo: app.globalData.initLoginInfo.pharmacistInfo,
})
}
},
// 获取药店人员信息 // 获取药店人员信息
getProfile() { getProfile() {
wx.ajax({ wx.ajax({
@ -47,10 +40,6 @@ Page({
pharmacyName: res.pharmacyName || '', pharmacyName: res.pharmacyName || '',
}, },
}) })
// 更新全局数据
if (app.globalData.initLoginInfo) {
app.globalData.initLoginInfo.pharmacistInfo = this.data.pharmacistInfo
}
}) })
}, },
// 获取邀约人信息 // 获取邀约人信息
@ -59,12 +48,13 @@ Page({
method: 'GET', method: 'GET',
url: '/app/pharmacist/pharmacist/inviter-info', url: '/app/pharmacist/pharmacist/inviter-info',
}).then((res: any) => { }).then((res: any) => {
this.setData({ const list = res.list || res || []
inviterInfo: { const inviterList = list.map((item: any) => ({
promoterName: res.promoterName || '', promoterName: item.promoterName || '',
promoterPhone: res.promoterPhone || '', promoterPhone: item.promoterPhone || '',
}, projectName: item.projectName || '',
}) }))
this.setData({ inviterList })
}) })
}, },
// 修改头像 // 修改头像
@ -72,63 +62,41 @@ Page({
wx.chooseMedia({ wx.chooseMedia({
count: 1, count: 1,
mediaType: ['image'], mediaType: ['image'],
sizeType: ['compressed'],
sourceType: ['album', 'camera'], sourceType: ['album', 'camera'],
}).then((res: any) => { })
.then((res) => {
const tempFilePath = res.tempFiles[0].tempFilePath const tempFilePath = res.tempFiles[0].tempFilePath
// 上传图片
this.uploadAvatar(tempFilePath)
})
.catch(() => {
// 用户取消选择
})
},
// 上传头像
uploadAvatar(filePath: string) {
wx.showLoading({ title: '上传中...' }) wx.showLoading({ title: '上传中...' })
wx.uploadFile({ wx.uploadFile({
url: `${app.globalData.url }/app/common/common/upload`, url: `${app.globalData.url}/app/common/common/upload`,
filePath: tempFilePath, filePath,
name: 'file', name: 'file',
header: { header: {
loginState: app.globalData.loginState, loginState: app.globalData.loginState || '',
}, },
success: (uploadRes: any) => { success: (res) => {
try {
const data = JSON.parse(uploadRes.data)
if (data.code === 200) {
const avatarUrl = data.data.url
// 更新头像
wx.ajax({
method: 'POST',
url: '/app/pharmacist/pharmacist/update-avatar',
data: { avatar: avatarUrl },
}).then(() => {
wx.hideLoading()
this.setData({
'pharmacistInfo.avatar': avatarUrl,
})
// 更新全局数据
if (app.globalData.initLoginInfo?.pharmacistInfo) {
app.globalData.initLoginInfo.pharmacistInfo.avatar = avatarUrl
}
wx.showToast({
title: '头像更新成功',
icon: 'success',
})
}).catch(() => {
wx.hideLoading() wx.hideLoading()
wx.showToast({ const data = JSON.parse(res.data)
title: '头像更新失败', if (data.code === 0) {
icon: 'none', const avatarUrl = data.data?.url || data.data
}) // 更新头像
}) this.updateAvatar(avatarUrl)
} else { } else {
wx.hideLoading()
wx.showToast({ wx.showToast({
title: data.msg || '上传失败', title: data.msg || '上传失败',
icon: 'none', icon: 'none',
}) })
} }
} catch (e) {
wx.hideLoading()
wx.showToast({
title: '上传失败',
icon: 'none',
})
}
}, },
fail: () => { fail: () => {
wx.hideLoading() wx.hideLoading()
@ -138,6 +106,29 @@ Page({
}) })
}, },
}) })
},
// 更新头像
updateAvatar(avatarUrl: string) {
wx.ajax({
method: 'POST',
url: '/app/pharmacist/pharmacist/update-avatar',
data: {
avatar: avatarUrl,
},
})
.then(() => {
wx.showToast({
title: '头像修改成功',
icon: 'success',
})
// 刷新用户信息
this.getProfile()
})
.catch(() => {
wx.showToast({
title: '头像修改失败',
icon: 'none',
})
}) })
}, },
handleNickname() { handleNickname() {
@ -166,12 +157,12 @@ Page({
method: 'POST', method: 'POST',
url: '/app/pharmacist/pharmacist/logout', url: '/app/pharmacist/pharmacist/logout',
}).finally(() => { }).finally(() => {
// 清除登录信息 app.startLogin(() => {
app.globalData.initLoginInfo = {}
wx.reLaunch({ wx.reLaunch({
url: '/pages/work/index', url: '/pages/work/index',
}) })
}) })
})
} }
}, },
}) })

6
src/doctor/pages/my/index.wxml

@ -6,7 +6,7 @@
> >
<view class="user"> <view class="user">
<view class="avatar" bind:tap="handleAvatar"> <view class="avatar" bind:tap="handleAvatar">
<image class="a-img" src="{{pharmacistInfo.avatar || imageUrl + 'cache/a1.png'}}?t={{Timestamp}}" mode="aspectFill"></image> <image class="a-img" mode="aspectFill" src="{{pharmacistInfo.avatar}}"></image>
<view class="edit"> <view class="edit">
<image class="icon" src="{{imageUrl}}icon3.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon3.png?t={{Timestamp}}"></image>
</view> </view>
@ -30,9 +30,9 @@
<view class="title">我的邀约码</view> <view class="title">我的邀约码</view>
<van-icon class="arrow" name="arrow" /> <van-icon class="arrow" name="arrow" />
</view> </view>
<view class="list-item" wx:if="{{inviterInfo.promoterName}}"> <view class="list-item" wx:for="{{inviterList}}" wx:key="index">
<image class="icon" src="{{imageUrl}}icon17.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon17.png?t={{Timestamp}}"></image>
<view class="title">我的邀约人 <text class="content">({{inviterInfo.promoterName}} {{inviterInfo.promoterPhone}})</text></view> <view class="title">我的邀约人 <text class="content">({{item.promoterName}} {{item.promoterPhone}})</text></view>
</view> </view>
</view> </view>
<view class="exit" bind:tap="handleExit">退出登录</view> <view class="exit" bind:tap="handleExit">退出登录</view>

154
src/doctor/pages/stat/index.ts

@ -1,13 +1,163 @@
const app = getApp<IAppOption>() const app = getApp<IAppOption>()
Page({ Page({
data: {}, data: {
imageUrl: '',
Timestamp: Date.now(),
// 日期范围
startDate: '',
endDate: '',
today: '',
// 统计类型 day-按日 month-按月
statType: 'day',
// 汇总数据
summary: {
invitePatientCount: 0,
jumpPatientCount: 0,
enrollPatientCount: 0,
},
// 统计列表
statList: [] as any[],
// 分页
page: 1,
pageSize: 20,
total: 0,
loading: false,
hasMore: true,
},
onLoad() { onLoad() {
// 药店端统计页面,仅允许药店人员访问 // 药店端统计页面,仅允许药店人员访问
app.waitLogin({ types: [4] }).then(() => { app.waitLogin({ types: [4] }).then(() => {
// 页面加载完成 this.initDate()
this.getStatisticsList()
})
},
// 初始化日期
initDate() {
const today = this.formatDate(new Date())
const startDate = this.formatDate(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000))
this.setData({
startDate,
endDate: today,
today,
}) })
}, },
// 格式化日期
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}`
},
// 获取统计列表
getStatisticsList() {
if (this.data.loading || !this.data.hasMore) return
this.setData({ loading: true })
wx.ajax({
method: 'GET',
url: '/app/pharmacist/pharmacist/patient-statistics-list',
data: {
startDate: this.data.startDate,
endDate: this.data.endDate,
type: this.data.statType,
page: this.data.page,
pageSize: this.data.pageSize,
},
}).then((res: any) => {
const list = res.list || []
const summary = res.summary || {
invitePatientCount: 0,
jumpPatientCount: 0,
enrollPatientCount: 0,
}
this.setData({
summary,
statList: this.data.page === 1 ? list : [...this.data.statList, ...list],
total: res.total || 0,
page: this.data.page + 1,
hasMore: list.length >= this.data.pageSize,
loading: false,
})
}).catch(() => {
this.setData({ loading: false })
})
},
// 切换统计类型
switchStatType(e: WechatMiniprogram.CustomEvent) {
const type = e.currentTarget.dataset.type
if (type === this.data.statType) return
this.setData({
statType: type,
page: 1,
hasMore: true,
statList: [],
})
this.getStatisticsList()
},
// 开始日期变化
handleStartDateChange(e: WechatMiniprogram.CustomEvent) {
const startDate = e.detail.value
if (startDate > this.data.endDate) {
wx.showToast({
title: '开始日期不能大于结束日期',
icon: 'none',
})
return
}
this.setData({
startDate,
page: 1,
hasMore: true,
statList: [],
})
this.getStatisticsList()
},
// 结束日期变化
handleEndDateChange(e: WechatMiniprogram.CustomEvent) {
const endDate = e.detail.value
if (endDate < this.data.startDate) {
wx.showToast({
title: '结束日期不能小于开始日期',
icon: 'none',
})
return
}
this.setData({
endDate,
page: 1,
hasMore: true,
statList: [],
})
this.getStatisticsList()
},
// 页面上拉触底事件
onReachBottom() {
if (this.data.loading || !this.data.hasMore) {
return
}
this.getStatisticsList()
},
handleBack() { handleBack() {
wx.navigateBack() wx.navigateBack()
}, },

2
src/ground/pages/changeNickname/index.wxml

@ -1,7 +1,7 @@
<navbar fixed custom-style="background:#fff"> <navbar fixed custom-style="background:#fff">
<view slot="left" class="page-title"> <view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" /> <van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
资料姓名 修改姓名
</view> </view>
</navbar> </navbar>

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

@ -44,18 +44,29 @@ Page({
// 日期范围 - 邀约患者统计卡片(单日) // 日期范围 - 邀约患者统计卡片(单日)
startDate: '', startDate: '',
today: '', today: '',
// 统计卡片显示用的月份(YYYY-MM)
startMonth: '',
// 日期范围 - 图表1(邀约患者统计) // 日期范围 - 图表1(邀约患者统计)
chart1StartDate: '', chart1StartDate: '',
chart1EndDate: '', chart1EndDate: '',
// 图表1显示用的月份(YYYY-MM)
chart1StartMonth: '',
chart1EndMonth: '',
// 日期范围 - 图表2(邀约药师统计) // 日期范围 - 图表2(邀约药师统计)
chart2StartDate: '', chart2StartDate: '',
chart2EndDate: '', chart2EndDate: '',
// 图表2显示用的月份(YYYY-MM)
chart2StartMonth: '',
chart2EndMonth: '',
// 日期范围 - 图表3(邀约药店统计) // 日期范围 - 图表3(邀约药店统计)
chart3StartDate: '', chart3StartDate: '',
chart3EndDate: '', chart3EndDate: '',
// 图表3显示用的月份(YYYY-MM)
chart3StartMonth: '',
chart3EndMonth: '',
// 统计类型: day-日统计, month-月统计 // 统计类型: day-日统计, month-月统计
statType: 'day', statType: 'day',
@ -81,18 +92,27 @@ Page({
// 初始化日期 // 初始化日期
const today = this.formatDate(new Date()) 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 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({ this.setData({
today, today,
// 邀约患者统计卡片(单日)- 默认为今天 // 邀约患者统计卡片(单日)- 默认为今天
startDate: today, startDate: today,
startMonth: currentMonth,
// 图表1-3(日期范围)- 默认为最近30天 // 图表1-3(日期范围)- 默认为最近30天
chart1StartDate: defaultStartDate, chart1StartDate: defaultStartDate,
chart1EndDate: today, chart1EndDate: today,
chart1StartMonth: defaultStartMonth,
chart1EndMonth: currentMonth,
chart2StartDate: defaultStartDate, chart2StartDate: defaultStartDate,
chart2EndDate: today, chart2EndDate: today,
chart2StartMonth: defaultStartMonth,
chart2EndMonth: currentMonth,
chart3StartDate: defaultStartDate, chart3StartDate: defaultStartDate,
chart3EndDate: today, chart3EndDate: today,
chart3StartMonth: defaultStartMonth,
chart3EndMonth: currentMonth,
}) })
}, },
@ -104,6 +124,13 @@ Page({
return `${year}-${month}-${day}` 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() { getUserInfo() {
wx.ajax({ wx.ajax({
@ -292,8 +319,80 @@ Page({
// 切换统计类型 // 切换统计类型
switchStatType(e: WechatMiniprogram.CustomEvent) { switchStatType(e: WechatMiniprogram.CustomEvent) {
const type = e.currentTarget.dataset.type const type = e.currentTarget.dataset.type
const isMonth = type === 'month'
// 根据统计类型重置日期范围
let startDate = this.data.startDate
let startMonth = this.data.startMonth
let chart1StartDate = this.data.chart1StartDate
let chart1EndDate = this.data.chart1EndDate
let chart1StartMonth = this.data.chart1StartMonth
let chart1EndMonth = this.data.chart1EndMonth
let chart2StartDate = this.data.chart2StartDate
let chart2EndDate = this.data.chart2EndDate
let chart2StartMonth = this.data.chart2StartMonth
let chart2EndMonth = this.data.chart2EndMonth
let chart3StartDate = this.data.chart3StartDate
let chart3EndDate = this.data.chart3EndDate
let chart3StartMonth = this.data.chart3StartMonth
let chart3EndMonth = this.data.chart3EndMonth
if (isMonth) {
// 切换到月统计,设置默认月份
startMonth = this.formatMonth(new Date())
startDate = `${startMonth}-01`
// 图表月份范围为最近12个月
const currentMonth = this.formatMonth(new Date())
const defaultStartMonth = this.formatMonth(new Date(Date.now() - 365 * 24 * 60 * 60 * 1000))
chart1StartMonth = defaultStartMonth
chart1EndMonth = currentMonth
chart1StartDate = `${chart1StartMonth}-01`
chart1EndDate = `${chart1EndMonth}-01`
chart2StartMonth = defaultStartMonth
chart2EndMonth = currentMonth
chart2StartDate = `${chart2StartMonth}-01`
chart2EndDate = `${chart2EndMonth}-01`
chart3StartMonth = defaultStartMonth
chart3EndMonth = currentMonth
chart3StartDate = `${chart3StartMonth}-01`
chart3EndDate = `${chart3EndMonth}-01`
} else {
// 切换到日统计,设置默认日期为今天
startDate = this.formatDate(new Date())
startMonth = startDate.substring(0, 7)
// 图表日期范围为最近30天
const today = this.formatDate(new Date())
const defaultStartDate = this.formatDate(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000))
chart1StartDate = defaultStartDate
chart1EndDate = today
chart1StartMonth = chart1StartDate.substring(0, 7)
chart1EndMonth = chart1EndDate.substring(0, 7)
chart2StartDate = defaultStartDate
chart2EndDate = today
chart2StartMonth = chart2StartDate.substring(0, 7)
chart2EndMonth = chart2EndDate.substring(0, 7)
chart3StartDate = defaultStartDate
chart3EndDate = today
chart3StartMonth = chart3StartDate.substring(0, 7)
chart3EndMonth = chart3EndDate.substring(0, 7)
}
this.setData({ this.setData({
statType: type, statType: type,
startDate,
startMonth,
chart1StartDate,
chart1EndDate,
chart1StartMonth,
chart1EndMonth,
chart2StartDate,
chart2EndDate,
chart2StartMonth,
chart2EndMonth,
chart3StartDate,
chart3EndDate,
chart3StartMonth,
chart3EndMonth,
}) })
this.getPatientStatistics() this.getPatientStatistics()
this.getPatientChart() this.getPatientChart()
@ -303,10 +402,16 @@ Page({
// 日期选择变化(邀约患者统计卡片 - 单日选择) // 日期选择变化(邀约患者统计卡片 - 单日选择)
onDateChange(e: WechatMiniprogram.CustomEvent) { onDateChange(e: WechatMiniprogram.CustomEvent) {
const value = e.detail.value 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({ this.setData({
startDate: value, startDate: fullDate,
startMonth: monthValue,
}) })
// 重新加载统计数据 // 重新加载统计数据
this.getPatientStatistics() this.getPatientStatistics()
@ -315,19 +420,25 @@ Page({
// 图表1日期选择变化 // 图表1日期选择变化
onChart1DateChange(e: WechatMiniprogram.CustomEvent) { onChart1DateChange(e: WechatMiniprogram.CustomEvent) {
const { field } = e.currentTarget.dataset const { field } = e.currentTarget.dataset
const value = e.detail.value 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)
const startDate = this.data.chart1StartDate const startDate = this.data.chart1StartDate
const endDate = this.data.chart1EndDate const endDate = this.data.chart1EndDate
// 验证日期范围 // 验证日期范围
if (field === 'startDate' && endDate && value > endDate) { if (field === 'startDate' && endDate && fullDate > endDate) {
wx.showToast({ wx.showToast({
title: '开始时间不能大于结束时间', title: '开始时间不能大于结束时间',
icon: 'none', icon: 'none',
}) })
return return
} }
if (field === 'endDate' && startDate && value < startDate) { if (field === 'endDate' && startDate && fullDate < startDate) {
wx.showToast({ wx.showToast({
title: '结束时间不能小于开始时间', title: '结束时间不能小于开始时间',
icon: 'none', icon: 'none',
@ -335,28 +446,42 @@ Page({
return return
} }
if (field === 'startDate') {
this.setData({
chart1StartDate: fullDate,
chart1StartMonth: monthValue,
})
} else {
this.setData({ this.setData({
[field === 'startDate' ? 'chart1StartDate' : 'chart1EndDate']: value, chart1EndDate: fullDate,
chart1EndMonth: monthValue,
}) })
}
this.getPatientChart() this.getPatientChart()
}, },
// 图表2日期选择变化 // 图表2日期选择变化
onChart2DateChange(e: WechatMiniprogram.CustomEvent) { onChart2DateChange(e: WechatMiniprogram.CustomEvent) {
const { field } = e.currentTarget.dataset const { field } = e.currentTarget.dataset
const value = e.detail.value 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)
const startDate = this.data.chart2StartDate const startDate = this.data.chart2StartDate
const endDate = this.data.chart2EndDate const endDate = this.data.chart2EndDate
// 验证日期范围 // 验证日期范围
if (field === 'startDate' && endDate && value > endDate) { if (field === 'startDate' && endDate && fullDate > endDate) {
wx.showToast({ wx.showToast({
title: '开始时间不能大于结束时间', title: '开始时间不能大于结束时间',
icon: 'none', icon: 'none',
}) })
return return
} }
if (field === 'endDate' && startDate && value < startDate) { if (field === 'endDate' && startDate && fullDate < startDate) {
wx.showToast({ wx.showToast({
title: '结束时间不能小于开始时间', title: '结束时间不能小于开始时间',
icon: 'none', icon: 'none',
@ -364,28 +489,42 @@ Page({
return return
} }
if (field === 'startDate') {
this.setData({
chart2StartDate: fullDate,
chart2StartMonth: monthValue,
})
} else {
this.setData({ this.setData({
[field === 'startDate' ? 'chart2StartDate' : 'chart2EndDate']: value, chart2EndDate: fullDate,
chart2EndMonth: monthValue,
}) })
}
this.getPharmacistChart() this.getPharmacistChart()
}, },
// 图表3日期选择变化 // 图表3日期选择变化
onChart3DateChange(e: WechatMiniprogram.CustomEvent) { onChart3DateChange(e: WechatMiniprogram.CustomEvent) {
const { field } = e.currentTarget.dataset const { field } = e.currentTarget.dataset
const value = e.detail.value 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)
const startDate = this.data.chart3StartDate const startDate = this.data.chart3StartDate
const endDate = this.data.chart3EndDate const endDate = this.data.chart3EndDate
// 验证日期范围 // 验证日期范围
if (field === 'startDate' && endDate && value > endDate) { if (field === 'startDate' && endDate && fullDate > endDate) {
wx.showToast({ wx.showToast({
title: '开始时间不能大于结束时间', title: '开始时间不能大于结束时间',
icon: 'none', icon: 'none',
}) })
return return
} }
if (field === 'endDate' && startDate && value < startDate) { if (field === 'endDate' && startDate && fullDate < startDate) {
wx.showToast({ wx.showToast({
title: '结束时间不能小于开始时间', title: '结束时间不能小于开始时间',
icon: 'none', icon: 'none',
@ -393,28 +532,75 @@ Page({
return return
} }
if (field === 'startDate') {
this.setData({
chart3StartDate: fullDate,
chart3StartMonth: monthValue,
})
} else {
this.setData({ this.setData({
[field === 'startDate' ? 'chart3StartDate' : 'chart3EndDate']: value, chart3EndDate: fullDate,
chart3EndMonth: monthValue,
}) })
}
this.getPharmacyChart() this.getPharmacyChart()
}, },
// 切换到上一天(只更新邀约患者统计卡片) // 切换到上一天/上月(只更新邀约患者统计卡片)
prevDate() { 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) const currentDate = new Date(this.data.startDate)
const newDate = new Date(currentDate.getTime() - 24 * 60 * 60 * 1000) newDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1)
const startDate = this.formatDate(newDate) 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 }) this.setData({ startDate, startMonth })
// 只重新加载统计数据 // 只重新加载统计数据
this.getPatientStatistics() this.getPatientStatistics()
}, },
// 切换到下一天(只更新邀约患者统计卡片) // 切换到下一天/下月(只更新邀约患者统计卡片)
nextDate() { nextDate() {
const currentDate = new Date(this.data.startDate) const isMonth = this.data.statType === 'month'
const newDate = new Date(currentDate.getTime() + 24 * 60 * 60 * 1000)
const today = new Date() 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) { if (newDate > today) {
@ -425,8 +611,11 @@ Page({
return return
} }
const startDate = this.formatDate(newDate) startDate = this.formatDate(newDate)
this.setData({ startDate }) startMonth = startDate.substring(0, 7)
}
this.setData({ startDate, startMonth })
// 只重新加载统计数据 // 只重新加载统计数据
this.getPatientStatistics() this.getPatientStatistics()
}, },

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

@ -11,7 +11,7 @@
style="background:url('{{imageUrl}}bg1.png?t={{Timestamp}}') no-repeat top center/100% 602rpx; padding-top: {{pageTop+20}}px" style="background:url('{{imageUrl}}bg1.png?t={{Timestamp}}') no-repeat top center/100% 602rpx; padding-top: {{pageTop+20}}px"
> >
<view class="user"> <view class="user">
<image class="avatar" src="{{promoterAvatar || imageUrl + 'cache/a1.png'}}?t={{Timestamp}}"></image> <image class="avatar" mode="aspectFill" src="{{promoterAvatar}}"></image>
<view class="wrap"> <view class="wrap">
<view class="name">{{promoterName || '地推人员'}}</view> <view class="name">{{promoterName || '地推人员'}}</view>
<view class="label">{{label}}</view> <view class="label">{{label}}</view>
@ -95,10 +95,10 @@
<van-icon class="icon" name="arrow-down" /> <van-icon class="icon" name="arrow-down" />
</view> </view>
</view> </view>
<picker class="picker" mode="date" value="{{startDate}}" end="{{today}}" bindchange="onDateChange"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{startDate}}" end="{{today}}" bindchange="onDateChange">
<view class="p-content"> <view class="p-content">
<van-icon class="icon" name="arrow-left" catchtap="prevDate" /> <van-icon class="icon" name="arrow-left" catchtap="prevDate" />
<view class="content">{{startDate}}</view> <view class="content">{{statType === 'month' ? startMonth : startDate}}</view>
<van-icon class="icon" name="arrow" catchtap="nextDate" /> <van-icon class="icon" name="arrow" catchtap="nextDate" />
</view> </view>
</picker> </picker>
@ -140,16 +140,16 @@
</view> </view>
</view> </view>
<view class="chart-range"> <view class="chart-range">
<picker class="picker" mode="date" value="{{chart1StartDate}}" end="{{chart1EndDate}}" bindchange="onChart1DateChange" data-field="startDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{chart1StartDate}}" end="{{chart1EndDate}}" bindchange="onChart1DateChange" data-field="startDate">
<view class="p-content"> <view class="p-content">
<view class="content">{{chart1StartDate}}</view> <view class="content">{{statType === 'month' ? chart1StartMonth : chart1StartDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view> </view>
</picker> </picker>
<view class="line"></view> <view class="line"></view>
<picker class="picker" mode="date" value="{{chart1EndDate}}" start="{{chart1StartDate}}" bindchange="onChart1DateChange" data-field="endDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{chart1EndDate}}" start="{{chart1StartDate}}" bindchange="onChart1DateChange" data-field="endDate">
<view class="p-content"> <view class="p-content">
<view class="content">{{chart1EndDate}}</view> <view class="content">{{statType === 'month' ? chart1EndMonth : chart1EndDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view> </view>
</picker> </picker>
@ -168,16 +168,16 @@
<view class="title">邀约药师数统计</view> <view class="title">邀约药师数统计</view>
</view> </view>
<view class="chart-range"> <view class="chart-range">
<picker class="picker" mode="date" value="{{chart2StartDate}}" end="{{chart2EndDate}}" bindchange="onChart2DateChange" data-field="startDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{chart2StartDate}}" end="{{chart2EndDate}}" bindchange="onChart2DateChange" data-field="startDate">
<view class="p-content"> <view class="p-content">
<view class="content">{{chart2StartDate}}</view> <view class="content">{{statType === 'month' ? chart2StartMonth : chart2StartDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view> </view>
</picker> </picker>
<view class="line"></view> <view class="line"></view>
<picker class="picker" mode="date" value="{{chart2EndDate}}" start="{{chart2StartDate}}" bindchange="onChart2DateChange" data-field="endDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{chart2EndDate}}" start="{{chart2StartDate}}" bindchange="onChart2DateChange" data-field="endDate">
<view class="p-content"> <view class="p-content">
<view class="content">{{chart2EndDate}}</view> <view class="content">{{statType === 'month' ? chart2EndMonth : chart2EndDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view> </view>
</picker> </picker>
@ -192,16 +192,16 @@
<view class="title">邀约药店统计</view> <view class="title">邀约药店统计</view>
</view> </view>
<view class="chart-range"> <view class="chart-range">
<picker class="picker" mode="date" value="{{chart3StartDate}}" end="{{chart3EndDate}}" bindchange="onChart3DateChange" data-field="startDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{chart3StartDate}}" end="{{chart3EndDate}}" bindchange="onChart3DateChange" data-field="startDate">
<view class="p-content"> <view class="p-content">
<view class="content">{{chart3StartDate}}</view> <view class="content">{{statType === 'month' ? chart3StartMonth : chart3StartDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view> </view>
</picker> </picker>
<view class="line"></view> <view class="line"></view>
<picker class="picker" mode="date" value="{{chart3EndDate}}" start="{{chart3StartDate}}" bindchange="onChart3DateChange" data-field="endDate"> <picker class="picker" mode="date" fields="{{statType === 'month' ? 'month' : 'day'}}" value="{{chart3EndDate}}" start="{{chart3StartDate}}" bindchange="onChart3DateChange" data-field="endDate">
<view class="p-content"> <view class="p-content">
<view class="content">{{chart3EndDate}}</view> <view class="content">{{statType === 'month' ? chart3EndMonth : chart3EndDate}}</view>
<image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon8.png?t={{Timestamp}}"></image>
</view> </view>
</picker> </picker>

24
src/ground/pages/login/index.ts

@ -1,3 +1,4 @@
const app = getApp<IAppOption>()
let timer = null as null | number let timer = null as null | number
Page({ Page({
@ -91,16 +92,11 @@ Page({
phone: this.data.mobile, phone: this.data.mobile,
code: this.data.code, code: this.data.code,
}, },
}).then((res: any) => { }).then(() => {
const app = getApp<IAppOption>() app.startLogin(() => {
app.globalData.initLoginInfo = {
...app.globalData.initLoginInfo,
isLogin: 1,
loginIdentity: 3,
userId: res.userId,
}
this.submitCallback() this.submitCallback()
}) })
})
}, },
handleWxSubmit(e: WechatMiniprogram.CustomEvent) { handleWxSubmit(e: WechatMiniprogram.CustomEvent) {
if (!this.data.check) { if (!this.data.check) {
@ -112,7 +108,6 @@ Page({
} }
const { iv, encryptedData } = e.detail const { iv, encryptedData } = e.detail
if (iv && encryptedData) { if (iv && encryptedData) {
const app = getApp<IAppOption>()
const sessionKey = app.globalData.initLoginInfo?.sessionKey || '' const sessionKey = app.globalData.initLoginInfo?.sessionKey || ''
wx.ajax({ wx.ajax({
@ -123,16 +118,11 @@ Page({
encryptedData, encryptedData,
iv, iv,
}, },
}).then((res: any) => { }).then(() => {
// 更新登录信息 app.startLogin(() => {
app.globalData.initLoginInfo = {
...app.globalData.initLoginInfo,
isLogin: 1,
loginIdentity: 3,
userId: res.userId,
}
this.submitCallback() this.submitCallback()
}) })
})
} }
}, },
submitCallback() { submitCallback() {

6
src/ground/pages/my/index.ts

@ -55,7 +55,7 @@ Page({
filePath, filePath,
name: 'file', name: 'file',
header: { header: {
'loginState': app.globalData.loginState || '', loginState: app.globalData.loginState || '',
}, },
success: (res) => { success: (res) => {
wx.hideLoading() wx.hideLoading()
@ -130,12 +130,12 @@ Page({
method: 'POST', method: 'POST',
url: '/app/promoter/promoter/logout', url: '/app/promoter/promoter/logout',
}).finally(() => { }).finally(() => {
// 清除登录信息 app.startLogin(() => {
app.globalData.initLoginInfo = {}
wx.reLaunch({ wx.reLaunch({
url: '/pages/work/index', url: '/pages/work/index',
}) })
}) })
})
} }
}, },
}) })

2
src/ground/pages/my/index.wxml

@ -6,7 +6,7 @@
> >
<view class="user"> <view class="user">
<view class="avatar" bind:tap="handleAvatar"> <view class="avatar" bind:tap="handleAvatar">
<image class="a-img" src="{{promoterAvatar || imageUrl + 'cache/a1.png'}}?t={{Timestamp}}"></image> <image class="a-img" mode="aspectFill" src="{{promoterAvatar}}"></image>
<view class="edit"> <view class="edit">
<image class="icon" src="{{imageUrl}}icon3.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon3.png?t={{Timestamp}}"></image>
</view> </view>

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

@ -43,7 +43,7 @@
<view class="pharmacist-card" wx:for="{{pharmacistList}}" wx:key="id" data-id="{{item.id}}" bind:tap="handleInfo"> <view class="pharmacist-card" wx:for="{{pharmacistList}}" wx:key="id" data-id="{{item.id}}" bind:tap="handleInfo">
<!-- 药师基本信息 --> <!-- 药师基本信息 -->
<view class="user"> <view class="user">
<image class="avatar" src="{{item.avatar}}"></image> <image class="avatar" mode="aspectFill" src="{{item.avatar}}"></image>
<view class="wrap"> <view class="wrap">
<view class="pharmacist-info"> <view class="pharmacist-info">
<text class="pharmacist-name">{{item.name}}</text> <text class="pharmacist-name">{{item.name}}</text>

3
src/pages/index/index.scss

@ -1,7 +1,8 @@
page { page {
background-color: #f8fafa; background-color: #f8fafa;
} }
.page-title { .page-title,
.page-switch {
font-weight: 900; font-weight: 900;
font-size: 44rpx; font-size: 44rpx;
line-height: 52rpx; line-height: 52rpx;

93
src/pages/index/index.ts

@ -13,6 +13,9 @@ Page({
projectId: '', projectId: '',
projectName: '', projectName: '',
currentProjectName: '',
projectIndex: 0,
projectList: [] as Array<{ projectId: number; projectName: string; projectDescription: string }>,
// 扫码获取的药师ID // 扫码获取的药师ID
pharmacistId: '', pharmacistId: '',
@ -33,14 +36,67 @@ Page({
// 从 globalData 初始化扫码参数 // 从 globalData 初始化扫码参数
const pharmacistId = app.globalData.pharmacistId || '' const pharmacistId = app.globalData.pharmacistId || ''
const projectId = app.globalData.projectId || '0' const projectId = app.globalData.projectId || ''
this.setData({ this.setData({
pharmacistId, pharmacistId,
projectId, projectId,
}) })
app.waitLogin({ types: [1, 2] }).then(() => { app.waitLogin().then(() => {
this.getProjectList()
this.getBanner()
this.checkStatus()
})
},
// 获取项目列表
getProjectList() {
wx.ajax({
method: 'GET',
url: '/app/patient/patient/project-list',
}).then((res: any) => {
const projectList = res.list || []
const currentProjectId = res.currentProjectId
// 找到当前项目的索引
let projectIndex = 0
projectList.forEach((item: any, index: number) => {
if (item.projectId === currentProjectId) {
projectIndex = index
}
})
this.setData({
projectList,
projectIndex,
currentProjectName: projectList[projectIndex]?.projectName || '华观健康',
})
})
},
// 切换项目
onProjectChange(e: WechatMiniprogram.CustomEvent) {
const index = e.detail.value
const project = this.data.projectList[index]
if (!project || project.projectId === this.data.projectList[this.data.projectIndex]?.projectId) {
return
}
wx.ajax({
method: 'POST',
url: '/app/patient/patient/switch-project',
data: {
projectId: project.projectId,
},
}).then(() => {
this.setData({
projectIndex: index,
currentProjectName: project.projectName,
projectId: String(project.projectId),
})
// 刷新页面数据
this.getBanner() this.getBanner()
this.checkStatus() this.checkStatus()
}) })
@ -179,19 +235,7 @@ Page({
method: 'POST', method: 'POST',
url: '/app/patient/patient/wx-login', url: '/app/patient/patient/wx-login',
data: params, data: params,
}) }).then((res: any) => {
.then(() => {
// 选择适应症
return wx.ajax({
method: 'POST',
url: '/app/patient/patient/select-indication',
data: {
projectId: this.data.projectId,
indicationId: selectedOption.indicationId,
},
})
})
.then((res: any) => {
const jumpUrl = res.jumpUrl const jumpUrl = res.jumpUrl
// 如果有药师ID,创建绑定关系 // 如果有药师ID,创建绑定关系
@ -204,26 +248,22 @@ Page({
projectId: this.data.projectId, projectId: this.data.projectId,
indicationId: selectedOption.indicationId, indicationId: selectedOption.indicationId,
}, },
}) }).then(() => {
.then(() => {
// 绑定成功后跳转 // 绑定成功后跳转
wx.navigateToMiniProgram({ wx.navigateToMiniProgram({
appId: 'wx05551c5ee1fd1c12', appId: 'wx05551c5ee1fd1c12',
path: jumpUrl, path: jumpUrl,
}) })
}) this.checkStatus()
.catch(() => {
// 绑定失败也跳转
wx.navigateToMiniProgram({
appId: 'wx05551c5ee1fd1c12',
path: jumpUrl,
})
}) })
} else { } else {
// 没有药师ID,直接跳转 // 没有药师ID,直接跳转
wx.navigateToMiniProgram({ wx.navigateToMiniProgram({
appId: 'wx05551c5ee1fd1c12', appId: 'wx05551c5ee1fd1c12',
path: jumpUrl, path: jumpUrl,
success: () => {
this.checkStatus()
},
}) })
} }
}) })
@ -235,6 +275,11 @@ Page({
agreementChecked: !this.data.agreementChecked, agreementChecked: !this.data.agreementChecked,
}) })
}, },
handleAgreement() {
wx.navigateTo({
url: '/privacy/pages/policy/index',
})
},
handleWork() { handleWork() {
wx.navigateTo({ wx.navigateTo({

9
src/pages/index/index.wxml

@ -1,5 +1,10 @@
<navbar fixed custom-style="background:transparent" back> <navbar fixed custom-style="background:transparent" back>
<view slot="left" class="page-title">华观健康</view> <picker wx:if="{{projectList.length > 0}}" 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" />
</picker>
<view wx:else class="page-title">华观健康</view>
</navbar> </navbar>
<view <view
@ -40,7 +45,7 @@
<radio class="radio" checked="{{agreementChecked}}" color="#00B2A9"></radio> <radio class="radio" checked="{{agreementChecked}}" color="#00B2A9"></radio>
<view class="agreement-text"> <view class="agreement-text">
同意 同意
<text class="link">《用户与隐私保护协议》</text> <text class="link" catchtap="handleAgreement"> 《用户与隐私保护协议》</text>
</view> </view>
</view> </view>
</block> </block>

42
src/pages/start/index.ts

@ -5,12 +5,21 @@ Page({
data: {}, data: {},
onLoad(options) { onLoad(options) {
// 解析扫码参数 // 解析扫码参数
let pharmacistId = '' let t = ''
let pharmacistId = '' // 药店人员ID
let promoterId = '' // 地推人员ID
let projectId = '' let projectId = ''
if (options.scene) { if (options.scene) {
const sceneData = parseScene(options.scene) as { pharmacistId?: string; projectId?: string } const sceneData = parseScene(options.scene) as {
t: string
pharmacistId?: string
projectId?: string
promoterId?: string
}
t = sceneData.t || '' // 1-地推人员码,2-药店人员码
pharmacistId = sceneData.pharmacistId || '' pharmacistId = sceneData.pharmacistId || ''
promoterId = sceneData.promoterId || ''
projectId = sceneData.projectId || '' projectId = sceneData.projectId || ''
} }
@ -18,31 +27,44 @@ Page({
if (pharmacistId) { if (pharmacistId) {
app.globalData.pharmacistId = pharmacistId app.globalData.pharmacistId = pharmacistId
} }
if (promoterId) {
app.globalData.promoterId = promoterId
}
if (projectId) { if (projectId) {
app.globalData.projectId = projectId app.globalData.projectId = projectId
} }
app.waitLogin().then(() => { app.waitLogin().then(() => {
const { isLogin, loginIdentity } = app.globalData.initLoginInfo const { isLogin, isRegister, loginIdentity } = app.globalData.initLoginInfo
// 游客(1)或患者端(2)且有扫码参数,进入患者首页 // 扫码进入用户处理
if ((loginIdentity === 1 || loginIdentity === 2) && pharmacistId && projectId) { if (t == '1') {
if (loginIdentity === 4 && isLogin && isRegister) {
wx.reLaunch({ wx.reLaunch({
url: '/pages/index/index', url: '/doctor/pages/home/index?bind=1',
}) })
} else {
wx.reLaunch({
url: '/doctor/pages/login/index',
})
}
return return
} }
if (t == '2') {
// 游客(1)或患者端(2)无扫码参数,进入游客页面
if (loginIdentity === 1 || loginIdentity === 2) {
wx.reLaunch({ wx.reLaunch({
url: '/pages/tourists/index', url: '/pages/index/index',
}) })
return return
} }
// 未注册,根据身份跳转到对应注册页面 // 未注册,根据身份跳转到对应注册页面
if (!isLogin) { if (!isLogin) {
if (loginIdentity === 2) {
wx.reLaunch({
url: '/pages/index/index',
})
return
}
wx.reLaunch({ wx.reLaunch({
url: '/pages/tourists/index', url: '/pages/tourists/index',
}) })

2
src/pages/start/index.wxml

@ -1 +1 @@
<image src="{{imageUrl}}start1.png?t={{Timestamp}}" mode="aspectFill" class="page"></image> <image src="{{imageUrl}}start.png?t={{Timestamp}}" mode="aspectFill" class="page"></image>

20
src/pages/tourists/index.ts

@ -4,7 +4,25 @@ Page({
data: {}, data: {},
onLoad() { onLoad() {
app.waitLogin().then(() => { app.waitLogin().then(() => {
// 页面加载完成 // 检查用户是否已有绑定的项目
this.checkProjectStatus()
})
},
// 检查用户项目状态
checkProjectStatus() {
wx.ajax({
method: 'GET',
url: '/app/patient/patient/recent-project',
}).then((res: any) => {
if (res && res.projectId) {
// 已有绑定的项目,跳转到患者首页
wx.reLaunch({
url: '/pages/index/index',
})
}
// 没有项目,停留在当前页面
}).catch(() => {
// 接口失败,停留在当前页面
}) })
}, },
// 跳转到药店工作人员登录页 // 跳转到药店工作人员登录页

4
src/pages/tourists/index.wxml

@ -2,8 +2,8 @@
<view slot="left" class="page-title">华观健康</view> <view slot="left" class="page-title">华观健康</view>
</navbar> </navbar>
<view class="page" style="background: url('/images/bg11.png') no-repeat top center/100% 1624rpx;padding-top: {{pageTop+24}}px;"> <view class="page" style="background: url('{{imageUrl}}bg11.png?t={{Timestamp}}') no-repeat top center/100% 1624rpx;padding-top: {{pageTop+24}}px;">
<image class="page-banner" src="/images/start1.png"></image> <image class="page-banner" src="{{imageUrl}}start1.png?t={{Timestamp}}"></image>
<view class="page-options"> <view class="page-options">
<view class="o-item" bindtap="goToPharmacist">我是药店工作人员</view> <view class="o-item" bindtap="goToPharmacist">我是药店工作人员</view>
<view class="o-item" bindtap="goToPromoter">我是地推人员</view> <view class="o-item" bindtap="goToPromoter">我是地推人员</view>

2
src/pages/work/index.ts

@ -20,7 +20,7 @@ Page({
}, },
hadlePatient() { hadlePatient() {
wx.navigateTo({ wx.navigateTo({
url: '/pages/start/index', url: '/pages/tourists/index',
}) })
}, },
}) })

2
typings/index.d.ts vendored

@ -42,7 +42,7 @@ interface IAppOption {
initLoginInfo: Partial<{ initLoginInfo: Partial<{
isLogin: 0 | 1 isLogin: 0 | 1
isReg: 0 | 1 isReg: 0 | 1
isRegistered: 0 | 1 isRegister: 0 | 1
// 1-游客,2-患者端,3-地推人员端,4-药店人员端 // 1-游客,2-患者端,3-地推人员端,4-药店人员端
loginType: 1 | 2 | 3 | 4 loginType: 1 | 2 | 3 | 4
loginIdentity: 1 | 2 | 3 | 4 loginIdentity: 1 | 2 | 3 | 4

Loading…
Cancel
Save