Browse Source

页面初步开发

master
kola-web 2 weeks ago
parent
commit
1c14b5db12
  1. 9
      .trae/rules/project_rules.md
  2. 23
      .trae/skills/wechat-miniprogram-skill/SKILL.md
  3. 2
      project.config.json
  4. 112
      project.private.config.json
  5. 28
      src/app.json
  6. 16
      src/app.ts
  7. 10
      src/components/pickerArea/index.scss
  8. 7
      src/components/pickerAreaBak/index.json
  9. 0
      src/components/pickerAreaBak/index.scss
  10. 76
      src/components/pickerAreaBak/index.ts
  11. 13
      src/components/pickerAreaBak/index.wxml
  12. 3
      src/components/popup/index.json
  13. 1214
      src/components/popup/index.scss
  14. 3
      src/components/popup/index.ts
  15. 382
      src/components/popup/index.wxml
  16. 4
      src/components/uploadFile/index.js
  17. 61
      src/components/uploadFile/index.wxml
  18. 11
      src/doctor/components/doctor-tab-bar/index.scss
  19. 52
      src/doctor/components/doctor-tab-bar/index.ts
  20. 13
      src/doctor/components/doctor-tab-bar/index.wxml
  21. 8
      src/doctor/pages/articleList/index.json
  22. 91
      src/doctor/pages/articleList/index.scss
  23. 8
      src/doctor/pages/articleList/index.ts
  24. 30
      src/doctor/pages/articleList/index.wxml
  25. 8
      src/doctor/pages/changeNickname/index.json
  26. 33
      src/doctor/pages/changeNickname/index.scss
  27. 11
      src/doctor/pages/changeNickname/index.ts
  28. 11
      src/doctor/pages/changeNickname/index.wxml
  29. 8
      src/doctor/pages/changeTel/index.json
  30. 53
      src/doctor/pages/changeTel/index.scss
  31. 78
      src/doctor/pages/changeTel/index.ts
  32. 33
      src/doctor/pages/changeTel/index.wxml
  33. 9
      src/doctor/pages/home/index.json
  34. 329
      src/doctor/pages/home/index.scss
  35. 142
      src/doctor/pages/home/index.ts
  36. 203
      src/doctor/pages/home/index.wxml
  37. 8
      src/doctor/pages/invite/index.json
  38. 101
      src/doctor/pages/invite/index.scss
  39. 11
      src/doctor/pages/invite/index.ts
  40. 34
      src/doctor/pages/invite/index.wxml
  41. 9
      src/doctor/pages/login/index.json
  42. 139
      src/doctor/pages/login/index.scss
  43. 154
      src/doctor/pages/login/index.ts
  44. 60
      src/doctor/pages/login/index.wxml
  45. 11
      src/doctor/pages/loginForm/index.json
  46. 163
      src/doctor/pages/loginForm/index.scss
  47. 165
      src/doctor/pages/loginForm/index.ts
  48. 65
      src/doctor/pages/loginForm/index.wxml
  49. 8
      src/doctor/pages/my/index.json
  50. 99
      src/doctor/pages/my/index.scss
  51. 23
      src/doctor/pages/my/index.ts
  52. 41
      src/doctor/pages/my/index.wxml
  53. 8
      src/doctor/pages/patientList/index.json
  54. 285
      src/doctor/pages/patientList/index.scss
  55. 28
      src/doctor/pages/patientList/index.ts
  56. 125
      src/doctor/pages/patientList/index.wxml
  57. 8
      src/doctor/pages/stat/index.json
  58. 199
      src/doctor/pages/stat/index.scss
  59. 11
      src/doctor/pages/stat/index.ts
  60. 125
      src/doctor/pages/stat/index.wxml
  61. 0
      src/ground/components/ground-tab-bar/index.json
  62. 15
      src/ground/components/ground-tab-bar/index.scss
  63. 47
      src/ground/components/ground-tab-bar/index.ts
  64. 9
      src/ground/components/ground-tab-bar/index.wxml
  65. 8
      src/ground/pages/changeNickname/index.json
  66. 33
      src/ground/pages/changeNickname/index.scss
  67. 11
      src/ground/pages/changeNickname/index.ts
  68. 11
      src/ground/pages/changeNickname/index.wxml
  69. 8
      src/ground/pages/changeTel/index.json
  70. 53
      src/ground/pages/changeTel/index.scss
  71. 78
      src/ground/pages/changeTel/index.ts
  72. 33
      src/ground/pages/changeTel/index.wxml
  73. 9
      src/ground/pages/home/index.json
  74. 345
      src/ground/pages/home/index.scss
  75. 252
      src/ground/pages/home/index.ts
  76. 273
      src/ground/pages/home/index.wxml
  77. 8
      src/ground/pages/invite/index.json
  78. 101
      src/ground/pages/invite/index.scss
  79. 11
      src/ground/pages/invite/index.ts
  80. 34
      src/ground/pages/invite/index.wxml
  81. 9
      src/ground/pages/login/index.json
  82. 119
      src/ground/pages/login/index.scss
  83. 154
      src/ground/pages/login/index.ts
  84. 55
      src/ground/pages/login/index.wxml
  85. 8
      src/ground/pages/my/index.json
  86. 95
      src/ground/pages/my/index.scss
  87. 23
      src/ground/pages/my/index.ts
  88. 37
      src/ground/pages/my/index.wxml
  89. 8
      src/ground/pages/pharmacist/index.json
  90. 172
      src/ground/pages/pharmacist/index.scss
  91. 13
      src/ground/pages/pharmacist/index.ts
  92. 84
      src/ground/pages/pharmacist/index.wxml
  93. 8
      src/ground/pages/stat/index.json
  94. 199
      src/ground/pages/stat/index.scss
  95. 11
      src/ground/pages/stat/index.ts
  96. 125
      src/ground/pages/stat/index.wxml
  97. BIN
      src/images/bg1.png
  98. BIN
      src/images/bg2.png
  99. BIN
      src/images/bg3.png
  100. BIN
      src/images/bg4.png
  101. Some files were not shown because too many files have changed in this diff Show More

9
.trae/rules/project_rules.md

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
1. 本项目是一个基于微信小程序的药品查询应用
2. 使用原生微信小程序+typescript+scss
3. figma设计稿的宽度是375px,1px=2rpx
4. 小程序的scss单位是rpx
5. 导航栏使用自定义导航栏,使用自定义组件 /components/navbar
6. 除了onLoad比寻存在外,其他生命周期函数,无须额外定义
7. onLoad函数中需要隐去getApp().waitLogin(),页面使用的接口需要在登录后调用
8. 生命周期函数和事件处理函数不应使用箭头函数
9. getApp()应提取到全局变量中,避免重复调用

23
.trae/skills/wechat-miniprogram-skill/SKILL.md

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
---
name: wm-skill
description: 本地微信小程序开发专家指南,重点关注性能、代码大小和原生兼容性。用于用原生typescript+scss开发微信小程序。
---
# 角色:微信小程序专家(原生 JS)
## 核心原则
- 你是一名专注于原生微信小程序开发(JavaScript)的高级开发者。
- 优先级:性能、代码大小和原生兼容性。
- 禁止使用:Taro、Uni-app 或任何跨平台框架。
## 技术规范
- **逻辑:** 使用 ES6+ TypeScript。
- **状态管理:** 使用 `this.setData()`。为了性能,始终使用 **数据路径** 进行部分更新(例如:`this.setData({ 'list[0].text': 'new' })`)。
- **视图(WXML):**`wx:for` 中始终包含 `wx:key`。使用 `bind:tap`(冒泡)或 `catch:tap`(非冒泡)。
- **样式(SCSS):** 对所有响应式布局使用 `rpx`。遵循 BEM 命名约定。
- **组件:** 优先使用 `Component()` 而不是 `Page()`,以获得可重用逻辑和更好的 `setData` 性能。
## 错误预防
- **iOS 日期:** 在传递给 `new Date()` 之前,始终将 `-` 替换为 `/`(例如:`str.replace(/-/g, '/')`)。
- **导航:** 对标签页使用 `wx.switchTab`。监控页面栈限制(10)。
- **原生组件:** 使用 `<cover-view>` 覆盖在 `<canvas>`、`<video>` 或 `<map>` 上。

2
project.config.json

@ -66,7 +66,7 @@ @@ -66,7 +66,7 @@
],
"include": []
},
"appid": "wxfc95e2961d481f58",
"appid": "wxe9f978b29ff5ab5d",
"scripts": {
"beforeCompile": "pnpm run beforeCompile",
"beforePreview": "pnpm run beforeCompile",

112
project.private.config.json

@ -19,6 +19,116 @@ @@ -19,6 +19,116 @@
"bigPackageSizeSupport": false
},
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"condition": {},
"condition": {
"miniprogram": {
"list": [
{
"name": "药店-教育",
"pathName": "doctor/pages/articleList/index",
"query": "",
"scene": null,
"launchMode": "default"
},
{
"name": "药店-患者列表",
"pathName": "doctor/pages/patientList/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "药店-注册",
"pathName": "doctor/pages/loginForm/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "药店-登录",
"pathName": "doctor/pages/login/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "药店-邀约",
"pathName": "doctor/pages/invite/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "药店-我的",
"pathName": "doctor/pages/my/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "药店-首页",
"pathName": "doctor/pages/home/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "地推端-邀约数明细",
"pathName": "ground/pages/stat/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "地推端-邀约",
"pathName": "ground/pages/invite/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "地推端-登录页",
"pathName": "ground/pages/login/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "工作人员起始页",
"pathName": "pages/work/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "患者-首页",
"pathName": "pages/index/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "地推端-我的",
"pathName": "ground/pages/my/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "地推端-药师管理",
"pathName": "ground/pages/pharmacist/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "地推-首页",
"pathName": "ground/pages/home/index",
"query": "",
"launchMode": "default",
"scene": null
}
]
}
},
"libVersion": "3.5.8"
}

28
src/app.json

@ -1,14 +1,34 @@ @@ -1,14 +1,34 @@
{
"$schema": "https://dldir1.qq.com/WechatWebDev/editor-extension/wx-json/app.schema.json",
"pages": ["pages/start/index", "pages/index/index"],
"pages": ["pages/start/index", "pages/work/index", "pages/index/index"],
"subPackages": [
{
"root": "patient",
"pages": []
"root": "ground",
"pages": [
"pages/login/index",
"pages/home/index",
"pages/pharmacist/index",
"pages/my/index",
"pages/invite/index",
"pages/stat/index",
"pages/changeNickname/index",
"pages/changeTel/index"
]
},
{
"root": "doctor",
"pages": []
"pages": [
"pages/home/index",
"pages/my/index",
"pages/invite/index",
"pages/login/index",
"pages/loginForm/index",
"pages/patientList/index",
"pages/articleList/index",
"pages/changeNickname/index",
"pages/changeTel/index",
"pages/stat/index"
]
},
{
"root": "doc",

16
src/app.ts

@ -24,17 +24,17 @@ import page from '@/utils/page' @@ -24,17 +24,17 @@ import page from '@/utils/page'
App<IAppOption>({
globalData: {
// dev
// appid:wxa4ece062e60e93a5
// url: 'https://m.wtx.hbraas.com',
// upFileUrl: 'https://m.wtx.hbraas.com/',
// imageUrl: 'https://m.wtx.hbraas.com/GeneB/',
// appid:wxe9f978b29ff5ab5d
url: 'https://app.yd.hbraas.com',
upFileUrl: 'https://app.yd.hbraas.com/',
imageUrl: 'https://app.yd.hbraas.com/images/',
// pro
// appid:wx96104303877e3fd9 老的正式环境,已弃用
// appid:wxfc95e2961d481f58
url: 'https://m.hbgene.hbsaas.com',
upFileUrl: 'https://m.hbgene.hbsaas.com/',
imageUrl: 'https://m.hbgene.hbsaas.com/GeneB/',
// url: 'https://m.hbgene.hbsaas.com',
// upFileUrl: 'https://m.hbgene.hbsaas.com/',
// imageUrl: 'https://m.hbgene.hbsaas.com/GeneB/',
Timestamp: new Date().getTime(),
@ -65,7 +65,7 @@ App<IAppOption>({ @@ -65,7 +65,7 @@ App<IAppOption>({
if (options.query.scene) {
this.globalData.scene = parseScene(options.query.scene) as { workerId: string }
}
this.startLogin()
// this.startLogin()
},
startLogin(callback?: () => void) {
wx.login({

10
src/components/pickerArea/index.scss

@ -41,7 +41,7 @@ @@ -41,7 +41,7 @@
padding: 18rpx 30rpx;
box-shadow: 0rpx 4rpx 12rpx 0rpx rgba(0, 0, 0, 0.11);
border-radius: 12rpx 12rpx 12rpx 12rpx;
border: 2rpx solid #f23a2f;
border: 2rpx solid #FF8A4C;
display: flex;
align-items: center;
justify-content: space-between;
@ -69,7 +69,7 @@ @@ -69,7 +69,7 @@
display: flex;
align-items: center;
justify-content: center;
background: #f23a2f;
background: #FF8A4C;
border-radius: 12rpx 12rpx 12rpx 12rpx;
}
}
@ -91,7 +91,7 @@ @@ -91,7 +91,7 @@
background: #f7f8f9;
&.active {
color: #fff;
background-color: #f23a2f;
background-color: #FF8A4C;
}
}
}
@ -118,9 +118,9 @@ @@ -118,9 +118,9 @@
height: 36rpx;
}
&.active {
color: #f23a2f;
color: #FF8A4C;
.word {
color: #f23a2f;
color: #FF8A4C;
}
}
}

7
src/components/pickerAreaBak/index.json

@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
{
"component": true,
"usingComponents": {
"van-popup": "@vant/weapp/popup/index",
"van-cascader": "@vant/weapp/cascader/index"
}
}

0
src/components/pickerAreaBak/index.scss

76
src/components/pickerAreaBak/index.ts

@ -1,76 +0,0 @@ @@ -1,76 +0,0 @@
const app = getApp<IAppOption>()
Component({
properties: {
level: {
type: Number,
value: 3,
},
value: {
type: String,
value: '',
},
},
data: {
imageUrl: app.globalData.imageUrl,
Timestamp: app.globalData.Timestamp,
show: false,
options: [],
fieldNames: {
text: 'label',
value: 'value',
children: 'children',
},
},
lifetimes: {
attached() {
this.getArea()
},
},
methods: {
handleShow() {
this.setData({
show: true,
})
},
getArea() {
const { level } = this.data
wx.ajax({
method: 'GET',
url: '/js/area.json',
data: {},
isJSON: true,
}).then((res) => {
if (level === 1) {
res.forEach((item: any) => {
delete item.children
})
}
if (level === 2) {
res.forEach((item: any) => {
item.children.forEach((child: any) => {
delete child.children
})
})
}
this.setData({
options: res,
})
})
},
onFinish(e: any) {
this.triggerEvent('change', e.detail.selectedOptions)
this.setData({
show: false,
})
},
onClose() {
this.setData({
show: false,
})
this.triggerEvent('cancel')
},
},
})

13
src/components/pickerAreaBak/index.wxml

@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
<van-popup show="{{ show }}" round position="bottom">
<van-cascader
wx:if="{{ show }}"
value="{{ value }}"
title="请选择所在地区"
fieldNames="{{fieldNames}}"
options="{{ options }}"
bind:close="onClose"
bind:finish="onFinish"
/>
</van-popup>
<slot bind:tap="handleShow"></slot>

3
src/components/popup/index.json

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
{
"component": true,
"usingComponents": {
"van-popup": "@vant/weapp/popup/index"
"van-popup": "@vant/weapp/popup/index",
"uploadFile": "/components/uploadFile/index"
}
}

1214
src/components/popup/index.scss

File diff suppressed because it is too large Load Diff

3
src/components/popup/index.ts

@ -121,9 +121,6 @@ Component({ @@ -121,9 +121,6 @@ Component({
})
},
handlePopup1Check1() {
if (this.data.popup1Check1) {
app.mpBehavior({ PageName: 'BTN_PATIENTPRIVACY' })
}
},
handleSelectStatus(e) {
const { status } = e.currentTarget.dataset

382
src/components/popup/index.wxml

@ -9,377 +9,35 @@ @@ -9,377 +9,35 @@
safe-area-inset-bottom="{{false}}"
root-portal
>
<view class="popup1" wx:if="{{type==='argument'}}">
<image class="logo" src="{{imageUrl}}logo1.png?t={{Timestamp}}"></image>
<view class="title">欢迎加入“愈见守护”</view>
<view class="content">
亲爱的用户,为了更好地向您提供平台服务保护您的权益,我们完善了
<text class="link" bind:tap="routerTo" data-url="/doc/pages/doc1/index">《个人信息及隐私政策》</text>
,请您仔细阅读。一旦您开始使用,即表示您已充分理解并同意协议内容。
</view>
<view class="check">
<checkbox
class="checkbox"
model:checked="{{popup1Check1}}"
bind:tap="handlePopup1Check1"
color="#f23a2f"
></checkbox>
<view class="c-content">
我特此同意
<text class="link" bind:tap="routerTo" data-url="/doc/pages/doc1/index">《个人信息及隐私政策》</text>
规定收集我的相关敏感个人信息
</view>
</view>
<view class="btn1" bind:tap="handleOk">同意并继续</view>
<view class="btn2" bind:tap="handleCancel">不同意</view>
</view>
<view class="popup2" wx:elif="{{type==='stayTuned'}}">
<image class="photo" src="{{imageUrl}}stayTuned.png?t={{Timestamp}}"></image>
<view class="content">
<view>努力建设中</view>
<view>敬请期待</view>
</view>
</view>
<view class="popup3" wx:elif="{{type==='bindDoctor'}}">
<image class="icon" src="{{imageUrl}}icon23.png?t={{Timestamp}}"></image>
<view class="container">
<!-- <image class="title" src="{{imageUrl}}title1.png?t={{Timestamp}}"></image> -->
<view class="title">绑定成功</view>
<view class="card">
<image class="avatar" src="{{params.avatar}}"></image>
<view class="wrap">
<view class="name">{{params.name}}</view>
<view class="hostipal">
<view class="content">{{params.hostipal}}</view>
<view class="tag">{{params.className}}{{params.levelName}}</view>
</view>
</view>
</view>
<view class="btn" bind:tap="handleOk">确定</view>
</view>
</view>
<view class="popup4" wx:elif="{{type==='bindDoctorReject'}}">
<image class="icon" src="{{imageUrl}}icon24.png?t={{Timestamp}}"></image>
<view class="container">
<image class="title" src="{{imageUrl}}title2.png?t={{Timestamp}}"></image>
<view class="content">{{params.msg}}</view>
<view class="btn" bind:tap="handleOk">重新扫码</view>
</view>
</view>
<view class="popup5" wx:elif="{{type==='selectIdentity'}}">
<view class="container">
<image class="title" src="{{imageUrl}}title3.png?t={{Timestamp}}"></image>
<view class="popup1" wx:if="{{type==='popup1'}}">
<view class="title">新患者注册通知</view>
<view class="row">
<image class="avatar" src="{{imageUrl}}icon26.png?t={{Timestamp}}"></image>
<view class="wrap">
<view class="name">还未开启基因治疗</view>
<view class="content">随便看看</view>
</view>
<image class="icon" src="{{imageUrl}}icon12.png?t={{Timestamp}}"></image>
<view class="label">患者姓名</view>
<view class="content">钱多多</view>
</view>
<view class="row">
<image class="avatar" src="{{imageUrl}}icon27.png?t={{Timestamp}}"></image>
<view class="wrap">
<view class="name">还未开启基因治疗</view>
<view class="content">随便看看</view>
</view>
<image class="icon" src="{{imageUrl}}icon12.png?t={{Timestamp}}"></image>
</view>
</view>
</view>
<view class="popup6" wx:elif="{{type==='selectHostipalComplete'}}">
<view class="container" style="background: url('{{imageUrl}}bg8.png?t={{Timestamp}}') no-repeat top center/100%">
<view class="title">你真棒!</view>
<view class="content">就诊医院选择成功!</view>
</view>
</view>
<view class="popup6" wx:elif="{{type==='casesAddComplete'}}">
<view class="container" style="background: url('{{imageUrl}}bg8.png?t={{Timestamp}}') no-repeat top center/100%">
<view class="title">你真棒!</view>
<view class="content">您的病史信息已填写完成!</view>
</view>
</view>
<view class="popup6" wx:elif="{{type==='lastDiagnosisReportComplete'}}">
<view class="container" style="background: url('{{imageUrl}}bg8.png?t={{Timestamp}}') no-repeat top center/100%">
<view class="title">你真棒!</view>
<view class="content">您的信息已填写完成!</view>
</view>
</view>
<view class="popup6" wx:elif="{{type==='preReportComplete'}}">
<view class="container" style="background: url('{{imageUrl}}bg8.png?t={{Timestamp}}') no-repeat top center/100%">
<view class="title">你真棒!</view>
<view class="content">信息录入完成!</view>
</view>
</view>
<view class="popup7" wx:elif="{{type==='selectStatus'}}">
<view class="container">
<view class="title">记录下您此次的检查情况吧</view>
<view class="content">请基于您的实际检查结果点选合适的检查状态</view>
<view class="status-wrap">
<view class="s-item active" bind:tap="handleSelectStatus" data-status="1">
<image class="icon" src="{{imageUrl}}icon42.png?t={{Timestamp}}"></image>
<view class="s-content">
<view>多项不达标</view>
<view>需要关注</view>
<view class="radio">
<image class="r-icon" src="{{imageUrl}}icon45.png?t={{Timestamp}}"></image>
</view>
</view>
</view>
<view class="s-item" bind:tap="handleSelectStatus" data-status="1">
<image class="icon" src="{{imageUrl}}icon43.png?t={{Timestamp}}"></image>
<view class="s-content">
<view>少量不达标</view>
<view>但无需担心</view>
<view class="radio">
<image class="r-icon" src="{{imageUrl}}icon45.png?t={{Timestamp}}"></image>
</view>
</view>
</view>
<view class="s-item" bind:tap="handleSelectStatus" data-status="1">
<image class="icon" src="{{imageUrl}}icon44.png?t={{Timestamp}}"></image>
<view class="s-content">
<view>整体不错</view>
<view>保持住!</view>
<view class="radio">
<image class="r-icon" src="{{imageUrl}}icon45.png?t={{Timestamp}}"></image>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="popup8" wx:elif="{{type==='selectStatusComplete'}}">
<view class="bg" style="background: url({{imageUrl}}bg10.png) no-repeat top center/492rpx 492rpx?t={{Timestamp}}">
<view class="header">
<image class="icon1" src="{{imageUrl}}icon46.png?t={{Timestamp}}"></image>
<view class="name">
<view>整体不错</view>
<view>保持住!</view>
</view>
<image class="icon2" src="{{imageUrl}}icon47.png?t={{Timestamp}}"></image>
</view>
</view>
<view class="container">
<image class="icon" src="{{imageUrl}}icon42.png?t={{Timestamp}}"></image>
<view class="title">您选择的:诊前筛查结果</view>
<view class="footer">
<view class="cancel">重新选择</view>
<view class="submit">提交</view>
</view>
</view>
</view>
<view class="popup9" wx:elif="{{type==='TCenter'}}">
<view class="container">
<view class="title">请选择您的基因治疗中心</view>
<view class="list">
<view
class="list-item"
wx:for="{{params.list}}"
wx:key="index"
bind:tap="handleSelectTCenter"
data-id="{{item.hospitalId}}"
>
<view class="radio">
<image
class="r-icon"
wx:if="{{TCenterId == item.hospitalId}}"
src="{{imageUrl}}icon34.png?t={{Timestamp}}"
></image>
</view>
<view class="content">{{item.hospitalName}}</view>
</view>
</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="submit" bind:tap="handleOk">提交</view>
</view>
</view>
</view>
<view class="popup10" wx:elif="{{type==='TCenterEnd'}}">
<image class="status" src="{{imageUrl}}icon23.png?t={{Timestamp}}"></image>
<view class="container">
<image class="title" src="{{imageUrl}}title4.png?t={{Timestamp}}"></image>
</view>
</view>
<view class="popup11" wx:elif="{{type==='inhibitors'}}">
<view class="container">
<view class="title">请选择您的免疫抑制剂</view>
<view class="list">
<view
class="list-item"
wx:for="{{params.list}}"
wx:key="index"
bind:tap="handleSelectInhibitors"
data-id="{{index}}"
data-name="{{item}}"
>
<view class="radio">
<image
wx:if="{{inhibitorsId == index}}"
class="r-icon"
src="{{imageUrl}}icon34.png?t={{Timestamp}}"
></image>
</view>
<view class="content">{{item}}</view>
</view>
</view>
<textarea
wx:if="{{inhibitorsName == '其他'}}"
focus="{{inhibitorsName == '其他'}}"
class="texcarea"
model:value="{{inhibitorsContent}}"
placeholder-style="color:rgba(207, 209, 213, 1)"
placeholder="请输入您的药品名称"
disable-default-padding
cursor-spacing="40"
></textarea>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="submit" bind:tap="handleOk">提交</view>
</view>
</view>
</view>
<view class="popup12" wx:elif="{{type==='bindDoctorQuestion'}}">
<image class="icon" src="{{imageUrl}}icon62.png?t={{Timestamp}}"></image>
<view class="container">
<image class="title" src="{{imageUrl}}title5.png?t={{Timestamp}}"></image>
<view class="content">
绑定医生后
<view></view>
医生可以实时看到您的检查进展
</view>
<view class="tip">您可以扫描不同医生邀约码绑定多个医生</view>
<view class="footer">
<view class="cancel">重新选择</view>
<view class="submit">提交</view>
</view>
</view>
</view>
<view class="popup13" wx:elif="{{type==='conformBindDoctorQuestion'}}">
<image class="icon" src="{{imageUrl}}icon62.png?t={{Timestamp}}"></image>
<view class="container">
<image class="title" src="{{imageUrl}}title6.png?t={{Timestamp}}"></image>
<view class="card">
<image class="avatar" src="{{params.avatar}}"></image>
<view class="wrap">
<view class="name">{{params.name}}</view>
<view class="hostipal">
<view class="content">{{params.hostipal}}</view>
<view class="tag">{{params.className}}{{params.levelName}}</view>
</view>
</view>
</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="submit" bind:tap="handleOk">确定</view>
</view>
</view>
</view>
<view class="popup14" wx:elif="{{type==='preDiagnosisReportDate'}}">
<view class="container">
<image class="title" src="{{imageUrl}}title7.png?t={{Timestamp}}"></image>
<picker mode="date">
<view class="picker-content" data-place="请选择检查日期"></view>
</picker>
<view class="footer">
<view class="cancel">取消</view>
<view class="submit">提交</view>
</view>
</view>
</view>
<view class="popup15" wx:elif="{{type==='conformBindDoctorConform'}}">
<image class="icon" src="{{imageUrl}}icon24.png?t={{Timestamp}}"></image>
<view class="container">
<image class="title" src="{{imageUrl}}title10.png?t={{Timestamp}}"></image>
<view class="card">
<image class="avatar" src="{{params.avatar}}"></image>
<view class="wrap">
<view class="name">{{params.name}}</view>
<view class="hostipal">
<view class="content">{{params.hostipal}}</view>
<view class="tag">{{params.className}}{{params.levelName}}</view>
</view>
</view>
</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">暂不绑定</view>
<view class="submit" bind:tap="handleOk">注册并绑定></view>
</view>
</view>
</view>
<view class="popup16" wx:elif="{{type==='selectDoctor'}}">
<view class="container">
<image class="title" src="{{imageUrl}}title12.png?t={{Timestamp}}"></image>
<view class="list">
<view
class="list-item"
wx:for="{{params.list}}"
wx:key="index"
bind:tap="handleSelectDoctor"
data-id="{{item.doctorId}}"
>
<view class="radio">
<image
wx:if="{{selectDoctorId == item.doctorId}}"
class="r-icon"
src="{{imageUrl}}icon34.png?t={{Timestamp}}"
></image>
</view>
<image class="avatar" src="{{item.doctorAvatar}}"></image>
<view class="wrap">
<view class="name">{{item.doctorName}}</view>
<view class="hostipal">
<view class="content">{{item.hospitalName}}</view>
<view class="tag">{{item.hospitalClassificationName}}{{item.hospitalLevelName}}</view>
</view>
</view>
</view>
</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="submit" bind:tap="handleOk">确定</view>
</view>
</view>
</view>
<view class="popup17" wx:elif="{{type==='selectHostipal'}}">
<image class="icon" src="{{imageUrl}}icon23.png?t={{Timestamp}}"></image>
<view class="container">
<view class="title">确认为您的检查医院?</view>
<view class="hostipal">{{params.hospitalName}}</view>
<view class="address">{{params.provinceName}}{{params.cityName}}{{params.countyName}}{{params.address}}</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="submit" bind:tap="handleOk">确定</view>
</view>
</view>
</view>
<view class="popup18" wx:elif="{{type==='publicCard'}}">
<view class="container">
<image class="title" src="{{imageUrl}}title16.png?t={{Timestamp}}"></image>
<view
class="code-wrap"
style="background:url('{{imageUrl}}bg31.png?t={{Timestamp}}') no-repeat top center/382rpx 430rpx"
>
<image class="code" src="{{codeImg}}" show-menu-by-longpress></image>
</view>
<view class="label">手机号</view>
<view class="content">13800138000</view>
</view>
<view class="row">
<view class="label">项目</view>
<view class="content">特诺雅项目</view>
</view>
<view class="popup19" wx:elif="{{type==='coltStatFile'}}">
<image class="badge" src="{{imageUrl}}icon119.png?t={{Timestamp}}"></image>
<view class="container">
<view class="title">
凝血因子数据
<view></view>
通过您的复诊随访档案生成
<view class="row">
<view class="label">适应症</view>
<view class="content">IBD</view>
</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">好的</view>
<view class="submit" bind:tap="handleOk">去看档案</view>
<uploadFile class="upload-file">
<view class="upload">
<view class="place">
<image class="icon" src="/images/icon21.png"></image>
<view class="tip">拍照/从相册选择</view>
</view>
</view>
</uploadFile>
<view class="btn">确定并提交审核</view>
</view>
<image
wx:if="{{params.close}}"
class="close"

4
src/components/uploadFile/index.js

@ -222,9 +222,7 @@ Component({ @@ -222,9 +222,7 @@ Component({
})
},
handleAction() {
this.setData({
show: true,
})
this.selectMedia()
},
onSelect(e) {
const { id } = e.currentTarget.dataset

61
src/components/uploadFile/index.wxml

@ -1,60 +1,3 @@ @@ -1,60 +1,3 @@
<view class="upload-list">
<view class="item" wx:for="{{fileList}}" wx:key="index" data-index="{{index}}" catchtap="viewFile">
<image wx:if="{{item.fileType==='image'}}" class="image" mode="aspectFill" src="{{item.url}}"></image>
<image wx:elif="{{item.fileType==='video'}}" class="image" mode="aspectFill" src="{{item.url}}"></image>
<image
wx:elif="{{item.fileType==='audio'}}"
class="sub-image"
mode="aspectFill"
src="{{imageUrl}}file.png?t={{Timestamp}}"
></image>
<image wx:else class="sub-image" mode="aspectFill" src="{{imageUrl}}{{item.fileType}}.png?t={{Timestamp}}"></image>
<view class="item_mask">
<van-icon
wx:if="{{item.fileType === 'video'}}"
size="48rpx"
color="rgba(0,0,0,0.6)"
name="play-circle"
class="item_mask_icon"
/>
<image
wx:if="{{delete}}"
class="clear"
src="{{imageUrl}}icon97.png?t={{Timestamp}}"
catchtap="deleteFile"
data-item="{{item}}"
data-index="{{index}}"
></image>
</view>
</view>
<view wx:if="{{upload && (maxNum === -1 || maxNum > fileList.length)}}" catchtap="handleAction">
<slot wx:if="{{isSlot}}"></slot>
<view wx:else class="btn">
<van-icon name="plus" color="rgba(207, 209, 213, 1)" size="50rpx" />
<view class="name">请上传</view>
</view>
</view>
<view catchtap="handleAction">
<slot></slot>
</view>
<!-- <van-action-sheet title=" " show="{{ show }}" actions="{{ actions }}" bind:close="onClose" bind:select="onSelect" /> -->
<van-popup
show="{{ show }}"
custom-styple="background-color: rgba(247, 247, 250, 1);"
safe-area-inset-bottom="{{false}}"
round
position="bottom"
closeable
bind:close="onClose"
>
<view class="popup">
<view class="item" bind:tap="onSelect" data-id="1">
<view class="title">选择视频或图片</view>
<image class="icon" src="{{imageUrl}}icon117.png?t={{Timestamp}}"></image>
</view>
<view class="item" bind:tap="onSelect" data-id="2">
<view class="title">选择聊天文件</view>
<image class="icon" src="{{imageUrl}}icon118.png?t={{Timestamp}}"></image>
</view>
</view>
</van-popup>

11
src/doctor/components/doctor-tab-bar/index.scss

@ -1,16 +1,15 @@ @@ -1,16 +1,15 @@
/* custom-tab-bar/index.wxss */
.tab-item {
.icon {
width: 50rpx;
height: 50rpx;
width: 40rpx;
height: 40rpx;
}
.name {
font-size: 24rpx;
color: #010105;
&.active{
color: rgba(28, 107, 255, 1);
color: #6a605c;
&.active {
color: #ff8a4c;
}
}
}

52
src/doctor/components/doctor-tab-bar/index.ts

@ -1,56 +1,50 @@ @@ -1,56 +1,50 @@
import { getCurrentPageUrl } from '@/utils/util'
const app = getApp()
Component({
properties: {},
properties: {
active: {
type: Number,
value: 0,
},
},
data: {
imageUrl: app.globalData.imageUrl,
isChild: 0,
active: 0,
list: [
{
pagePath: '/doctor/pages/index/index',
text: '基因疗法',
pageName: 'BTN_HOME_NAV_CLICK',
icon: 'tabbar3-1',
iconActive: 'tabbar3-1-active',
pagePath: '/doctor/pages/home/index',
text: '首页',
icon: 'tab4',
iconActive: 'tab4-active',
},
{
pagePath: '/doctor/pages/patientList/index',
text: '患者列表',
icon: 'tab5',
iconActive: 'tab5-active',
},
{
pagePath: '/doctor/pages/knowledge/index',
text: '小助手',
pageName: 'BTN_ASSISTANT_NAV_CLICK',
icon: 'tabbar3-3',
iconActive: 'tabbar3-3-active',
pagePath: '/doctor/pages/articleList/index',
text: '教育',
icon: 'tab7',
iconActive: 'tab7-active',
},
{
pagePath: '/doctor/pages/my/index',
text: '我的',
pageName: 'BTN_MY_NAV_CLICK',
icon: 'tabbar3-2',
iconActive: 'tabbar3-2-active',
icon: 'tab6',
iconActive: 'tab6-active',
},
],
},
observers: {},
lifetimes: {
ready() {
const pagePath = getCurrentPageUrl()
const active = this.data.list.findIndex((item) => item.pagePath === pagePath)
this.setData({
active,
anyWhere: app.globalData.anyWhere,
})
},
},
methods: {
onChange() {},
handleNav(e) {
const { index } = e.currentTarget.dataset
const { list } = this.data
const { pagePath, pageName } = list[index]
if (pageName) {
app.mpBehavior({ PageName: pageName })
}
const { pagePath } = list[index]
wx.reLaunch({
url: pagePath,
})

13
src/doctor/components/doctor-tab-bar/index.wxml

@ -1,14 +1,9 @@ @@ -1,14 +1,9 @@
<van-tabbar active="{{ active }}" active-color="rgba(28, 107, 255, 1)" bind:change="onChange" inactive-color="#010105">
<van-tabbar active="{{ active }}" active-color="#F23A2F" bind:change="onChange" inactive-color="#010105" placeholder>
<block wx:for="{{list}}" wx:key="*this">
<van-tabbar-item
class="tab-item"
wx:if="{{ index != 3 || !anyWhere}}"
bind:tap="handleNav"
data-index="{{index}}"
icon="{{imageUrl}}tabbar/{{active==index ? item.iconActive : item.icon}}.png?t={{Timestamp}}"
>
<van-tabbar-item class="tab-item" wx:if="{{ index != 3 || !anyWhere}}" bind:tap="handleNav" data-index="{{index}}">
<image class="icon" slot="icon" src="/images/tabbar/{{item.icon}}.png?t={{Timestamp}}"></image>
<image class="icon" slot="icon-active" src="/images/tabbar/{{item.iconActive}}.png?t={{Timestamp}}"></image>
<view class="name {{index==active && 'active'}}">{{item.text}}</view>
<view class="hot"></view>
</van-tabbar-item>
</block>
</van-tabbar>

8
src/doctor/pages/articleList/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"doctor-tab-bar": "/doctor/components/doctor-tab-bar/index"
}
}

91
src/doctor/pages/articleList/index.scss

@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
page {
background-color: #f8fafa;
}
.page-title {
font-size: 32rpx;
color: #342317;
text-align: center;
}
.page {
.page-header {
position: sticky;
left: 0;
top: 0;
z-index: 1;
background-color: #fff;
.tabs {
display: flex;
align-items: start;
.tab {
padding: 24rpx 30rpx;
font-size: 28rpx;
color: #342317;
line-height: 48rpx;
&.active {
position: relative;
color: #ff8a4c;
&::after {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
content: '';
width: 32rpx;
height: 6rpx;
background: #ff8a4c;
border-radius: 1998rpx 1998rpx 1998rpx 1998rpx;
}
}
}
}
}
.banner {
padding: 32rpx 40rpx 0;
height: 204rpx;
.s-img {
display: block;
width: 100%;
height: 204rpx;
border-radius: 24rpx;
}
}
.list {
margin: 32rpx 40rpx 0;
padding: 0 32rpx;
border-radius: 24rpx;
background-color: #fff;
.card {
padding: 32rpx 0;
display: flex;
gap: 24rpx;
border-bottom: 1px solid rgba(239, 239, 239, 0.8);
.photo {
flex-shrink: 0;
width: 212rpx;
height: 140rpx;
}
.wrap {
flex: 1;
overflow: hidden;
.title {
font-size: 32rpx;
color: #342317;
line-height: 40rpx;
font-weight: bold;
}
.content {
margin-top: 24rpx;
font-size: 28rpx;
color: #b7b7b7;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
&:last-of-type{
border-bottom: none;
}
}
}
}

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

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
const _app = getApp<IAppOption>();
Page({
data: {},
onLoad() {},
});
export {}

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

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
<navbar fixed custom-style="background:#fff">
<view slot="title" class="page-title">教育</view>
</navbar>
<view class="page" style="padding-top: {{pageTop}}px;">
<view class="page-header" style="top:{{pageTop}}px">
<view class="tabs">
<view class="tab active">学习专栏</view>
<view class="tab">社区热帖</view>
<view class="tab">行业热点</view>
<view class="tab">中国药店</view>
</view>
</view>
<swiper class="banner">
<swiper-item class="swiper-item">
<image class="s-img" src="/images/cache/bg2.png"></image>
</swiper-item>
</swiper>
<view class="list">
<view class="card" wx:for="{{10}}" wx:key="index">
<image class="photo" src="/images/cache/p{{index%5+1}}.png"></image>
<view class="wrap">
<view class="title">从强降糖到防事件,那些糖尿病指南走过的路</view>
<view class="content">眼睛是心灵的窗户,但对于糖尿病患者来说,这扇窗显得十分脆弱d</view>
</view>
</view>
</view>
</view>
<doctor-tab-bar active="{{ 2 }}"></doctor-tab-bar>

8
src/doctor/pages/changeNickname/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"login":"/components/login/index"
}
}

33
src/doctor/pages/changeNickname/index.scss

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
page {
background-color: #f8fafa;
}
.page-title {
display: flex;
align-items: center;
gap: 22rpx;
font-size: 36rpx;
color: #1a2020;
}
.page {
padding: 48rpx 32rpx;
.input {
padding: 32rpx;
font-size: 32rpx;
border-radius: 24rpx;
background-color: #fff;
}
.place-input {
color: #b5b8bb;
}
.btn {
margin-top: 160rpx;
height: 96rpx;
font-size: 32rpx;
color: #ffffff;
line-height: 96rpx;
text-align: center;
background: linear-gradient( 90deg, #FECE55 0%, #FF8A4C 100%);
border-radius: 120rpx 120rpx 120rpx 120rpx;
}
}

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

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleBack() {
wx.navigateBack()
},
})
export {}

11
src/doctor/pages/changeNickname/index.wxml

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
<navbar fixed custom-style="background:#fff">
<view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
资料姓名
</view>
</navbar>
<view class="page" style="padding-top: {{pageTop+28}}px;">
<input class="input" placeholder-class="place-input" type="text" placeholder="请输入新昵称" />
<view class="btn">确认</view>
</view>

8
src/doctor/pages/changeTel/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"login":"/components/login/index"
}
}

53
src/doctor/pages/changeTel/index.scss

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
page {
background-color: #f8fafa;
}
.page-title {
display: flex;
align-items: center;
gap: 22rpx;
font-size: 36rpx;
color: #1a2020;
}
.page {
padding: 48rpx 32rpx;
.container {
width: 100%;
.form {
padding: 0 32rpx;
background: #ffffff;
border-radius: 24rpx;
.row {
display: flex;
align-items: center;
border-bottom: 1px solid #eef5f5;
&:last-of-type {
border: none;
}
.input {
flex: 1;
padding: 32rpx 0;
height: 40rpx;
font-size: 28rpx;
}
.place-input {
color: #b5b8bb;
}
.code {
font-size: 32rpx;
color: #FF8A4C;
}
}
}
.submit {
margin-top: 160rpx;
height: 96rpx;
font-size: 32rpx;
color: #ffffff;
line-height: 96rpx;
text-align: center;
background: linear-gradient( 90deg, #FECE55 0%, #FF8A4C 100%);
border-radius: 120rpx 120rpx 120rpx 120rpx;
}
}
}

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

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
const app = getApp<IAppOption>();
let timer = null as null | number;
Page({
data: {
mobile: "",
code: "",
codeText: "发送验证码",
},
onLoad() {},
getCode() {
if (timer) return;
const mobile = this.data.mobile;
if (!mobile) {
wx.showToast({
title: "手机号不能为空",
icon: "none",
});
return;
}
// 验证手机号
if (!/^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/.test(mobile)) {
wx.showToast({
title: "手机号格式不正确",
icon: "none",
});
return;
}
wx.ajax({
method: "POST",
url: "?r=zd/login/send-verify-code",
data: {
mobile,
},
}).then((res) => {
console.log(res);
wx.showToast({
icon: "none",
title: "验证码已发送~",
});
let time = 60;
timer = setInterval(() => {
time--;
this.setData({
codeText: time + "s后重新发送",
});
if (time <= 0) {
clearInterval(timer as number);
timer = null;
this.setData({
codeText: "发送验证码",
});
}
}, 1000);
});
},
handleSubmit() {
const { mobile, code } = this.data;
const { registrationSource, registChannel, regBusinessId } = app.globalData;
wx.ajax({
method: "POST",
url: "?r=zd/account/update-telephone",
data: {
mobile,
code,
registrationSource,
registChannel,
regBusinessId,
},
}).then((_res) => {
wx.navigateBack();
});
},
handleBack() {
wx.navigateBack();
},
});

33
src/doctor/pages/changeTel/index.wxml

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
<navbar fixed custom-style="background:#fff">
<view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
修改手机号
</view>
</navbar>
<view class="page" style="padding-top: {{pageTop+28}}px;">
<view class="container">
<view class="form">
<view class="row">
<input
type="number"
model:value="{{mobile}}"
class="input"
placeholder-class="place-input"
placeholder="请输入手机号"
/>
</view>
<view class="row">
<input
type="number"
model:value="{{code}}"
class="input"
placeholder-class="place-input"
placeholder="请输入验证码"
/>
<view class="code" bind:tap="getCode">{{codeText}}</view>
</view>
</view>
<view class="submit" bind:tap="handleSubmit">修改手机号</view>
</view>
</view>

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

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
{
"navigationBarTitleText": "地推端",
"navigationStyle": "custom",
"usingComponents": {
"navbar": "../../../components/navbar/index",
"doctor-tab-bar": "/doctor/components/doctor-tab-bar/index",
"ec-canvas": "/components/ec-canvas/ec-canvas"
}
}

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

@ -0,0 +1,329 @@ @@ -0,0 +1,329 @@
page {
background: #f8fafa;
}
.page-switch {
color: #fff;
text-align: right;
font-family: 'Alibaba PuHuiTi 2.0';
font-size: 44rpx;
font-style: normal;
font-weight: 700;
line-height: 52rpx;
.arrow {
font-size: 28rpx;
}
}
.page {
min-height: 60vh;
.user {
margin: 48rpx 0 0 32rpx;
display: flex;
justify-content: space-between;
align-items: start;
gap: 20rpx;
.avatar {
flex-shrink: 0;
width: 102rpx;
height: 102rpx;
border-radius: 50%;
border: 1px solid #fff;
}
.wrap {
padding-top: 8rpx;
flex: 1;
.name {
font-size: 36rpx;
color: #ffffff;
.label {
margin-top: 8rpx;
padding: 0 12rpx;
display: inline-block;
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
border-radius: 6rpx;
background: linear-gradient(84deg, #fece55 0%, #ffb700 100%);
}
}
.site {
font-size: 28rpx;
color: #ffffff;
}
}
.code {
padding: 16rpx 28rpx;
border: 1px solid #fff;
border-radius: 24rpx 0 0 24rpx;
border-right: none;
background: linear-gradient(180deg, #f57b3d 0%, #ffa64d 100%);
display: flex;
align-items: center;
gap: 8rpx;
.icon {
display: block;
width: 52rpx;
height: 52rpx;
}
.arrow {
font-size: 28rpx;
color: #ffffff;
}
}
}
.stat-data {
margin: 32rpx 32rpx 0;
padding: 32rpx;
background: linear-gradient(180deg, #ffeede 0%, #ffffff 12.04%, #ffffff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 1px solid #ffffff;
.s-header {
display: flex;
align-items: center;
justify-content: space-between;
.title {
font-size: 36rpx;
color: #1a2020;
font-weight: bold;
}
.tip {
font-size: 28rpx;
color: #b5b8bb;
}
}
.card {
margin-top: 32rpx;
border: 1px solid #f5f4f3;
border-radius: 16rpx;
overflow: hidden;
.row2 {
display: flex;
background: linear-gradient(90deg, #ff8a4c 0%, #fece55 100%);
border-radius: 16rpx 16rpx 0 0;
.col {
flex: 1;
padding: 28rpx 34rpx;
.name {
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #ffffff;
line-height: 48rpx;
}
}
.line {
width: 1px;
background-color: rgba(238, 245, 245, 0.35);
}
}
.row3 {
background-color: #fff;
display: flex;
.col {
position: relative;
padding: 28rpx 34rpx;
flex: 1;
.name {
font-size: 24rpx;
color: #b7b7b7;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #342317;
line-height: 48rpx;
}
.line {
position: absolute;
left: 20rpx;
bottom: 0;
width: 168rpx;
height: 1px;
background-color: #f5f4f3;
}
&:nth-of-type(2) {
borer: 1px solid #f2f6f8;
border-right: none;
border-left: none;
background-color: #f9f9f9;
}
}
}
}
}
.chat-data {
margin: 32rpx 32rpx;
padding: 32rpx;
background: linear-gradient(180deg, #fff6ed 0%, #ffffff 7.03%, #ffffff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 1px solid #ffffff;
.c-header {
display: flex;
align-items: center;
justify-content: space-between;
.title {
font-size: 36rpx;
color: #342317;
font-weight: bold;
}
.switch-btns {
display: flex;
align-items: center;
gap: 24rpx;
.btn {
width: 148rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
font-size: 28rpx;
color: #342317;
border-radius: 1748rpx 1748rpx 1748rpx 1748rpx;
border: 1px solid rgba(175, 171, 169, 0.2);
&.active {
background-color: #ff8a4c;
color: #fff;
border-color: #ff8a4c;
}
}
}
}
.c-options {
margin-top: 28rpx;
display: flex;
align-items: center;
justify-content: space-between;
.name {
font-size: 32rpx;
color: #342317;
font-weight: bold;
}
.picker {
color: #ffa64d;
font-size: 28rpx;
.p-content {
display: flex;
align-items: center;
.content {
color: #6a605c;
}
.icon {
padding: 20rpx 10rpx;
}
}
}
}
.card {
margin-top: 32rpx;
border: 1px solid #f5f4f3;
border-radius: 16rpx;
overflow: hidden;
.row2 {
display: flex;
background: linear-gradient(90deg, #ff8a4c 0%, #fece55 100%);
border-radius: 16rpx 16rpx 0 0;
.col {
flex: 1;
padding: 28rpx 34rpx;
.name {
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #ffffff;
line-height: 48rpx;
}
}
.line {
width: 1px;
background-color: rgba(238, 245, 245, 0.35);
}
}
.row3 {
background-color: #fff;
display: flex;
.col {
position: relative;
padding: 28rpx 34rpx;
flex: 1;
.name {
font-size: 24rpx;
color: #b7b7b7;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #342317;
line-height: 48rpx;
}
.line {
position: absolute;
left: 20rpx;
bottom: 0;
width: 168rpx;
height: 1px;
background-color: #f5f4f3;
}
&:nth-of-type(2) {
borer: 1px solid #f2f6f8;
border-right: none;
border-left: none;
background-color: #f9f9f9;
}
}
}
}
.chart-range {
margin-top: 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
.picker {
.p-content {
padding: 8rpx 38rpx;
display: flex;
align-items: center;
gap: 18rpx;
border-radius: 12rpx 12rpx 12rpx 12rpx;
border: 1px solid #f2f6f8;
.content {
font-size: 28rpx;
color: #b5b8bb;
}
.icon {
width: 32rpx;
height: 32rpx;
}
}
}
.line {
width: 24rpx;
height: 1px;
background-color: #f2f6f8;
}
}
.chart-container {
margin-top: 16rpx;
padding: 15rpx 30rpx;
width: 100%;
height: 546rpx;
box-sizing: border-box;
}
.more {
padding: 20rpx 0 0;
font-size: 28rpx;
color: #FF8A4C;
text-align: center;
}
}
}

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

@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@
import { color } from 'echarts'
const echarts = require('../../../components/ec-canvas/echarts.js')
Page({
data: {},
ecDataTrendComponent1_1: null as any,
async onLoad() {
const app = getApp<IAppOption>()
app.waitLogin().then(() => {
const list = [
{ StatMonth: '2026-01', MonthInvitePCount: 1 },
{ StatMonth: '2026-02', MonthInvitePCount: 2 },
]
this.initChartBar(list)
})
},
initChartBar(list: any[]) {
return new Promise((reslove) => {
this.ecDataTrendComponent1_1 = this.selectComponent('#chart1_1')
this.ecDataTrendComponent1_1.init((canvas, width, height, dpr) => {
const chart = echarts.init(canvas, null, {
width,
height,
devicePixelRatio: dpr, // new
})
canvas.setChart(chart)
const x: string[] = []
const y1: string[] = []
list.forEach((item) => {
x.push(item.StatMonth)
y1.push(item.MonthInvitePCount)
})
const option = {
legend: {
top: 0,
right: 0,
itemWidth: 8,
itemHeight: 8,
icon: 'rect',
lineStyle: {
width: '0',
},
textStyle: {
color: '#B5B8BB',
fontSize: '12',
},
},
grid: {
top: '10%',
left: '3%',
right: '4%',
bottom: '0',
containLabel: true,
},
xAxis: [
{
type: 'category',
axisTick: {
show: false,
},
axisLabel: {
fontSize: 10,
color: '#B5B8BB',
},
axisLine: {
show: false,
},
data: x,
},
],
yAxis: [
{
type: 'value',
minInterval: 1,
splitLine: {
lineStyle: {
type: 'dashed',
},
},
axisLabel: {
fontSize: 10,
color: '#B5B8BB',
formatter(value) {
return Math.abs(value)
},
},
},
],
series: [
{
name: '入组患者数',
type: 'bar',
stack: 'a',
color: '#FF5722',
barWidth: 12,
data: y1,
},
{
name: '跳转患者数',
type: 'bar',
stack: 'a',
color: '#FF8A4C',
barWidth: 12,
data: y1,
},
{
name: '邀约患者数',
type: 'bar',
stack: 'a',
width: 4,
color: '#FFA64D',
barWidth: 12,
data: y1,
},
],
dataZoom: {
type: 'inside', // 有type这个属性,滚动条在最下面,也可以不行,写y:36,这表示距离顶端36px,一般就是在图上面。
startValue: x.length - 6,
endValue: x.length - 1,
filterMode: 'none',
},
}
chart.setOption(option)
reslove(chart)
return chart
})
})
},
handleInvite() {
wx.navigateTo({
url: '/doctor/pages/invite/index',
})
},
handleStat() {
wx.navigateTo({
url: '/doctor/pages/stat/index',
})
},
})

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

@ -0,0 +1,203 @@ @@ -0,0 +1,203 @@
<navbar fixed custom-style="background: {{background}};">
<view class="page-switch" slot="left" style="color: {{background=='transparent'?'#fff':'#4A8DFF'}};">
特诺雅
<van-icon class="arrow" name="arrow-down" />
</view>
</navbar>
<view
class="page"
style="background:url('/images/bg7.png') no-repeat top center/100% 602rpx; padding-top: {{pageTop+20}}px"
>
<view class="user">
<image class="avatar" src="/images/cache/a1.png"></image>
<view class="wrap">
<view class="name">
刘平安
<view class="label">药师</view>
</view>
<div class="site">康泰大药房(人民路店)</div>
</view>
<view class="code" bind:tap="handleInvite">
<image class="icon" src="/images/icon7.png"></image>
<van-icon class="arrow" name="arrow" />
</view>
</view>
<view class="stat-data">
<view class="s-header">
<view class="title">累计邀约</view>
<view class="tip">截止昨日数据</view>
</view>
<view class="card">
<view class="row2">
<view class="col">
<view class="name">邀约患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">跳转患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">入组患者数</view>
<view class="num">750</view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">入组患者数</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">300</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
</view>
</view>
</view>
<view class="chat-data">
<view class="c-header">
<view class="title">邀约患者统计</view>
<view class="switch-btns">
<view class="btn">月统计</view>
<view class="btn active">日统计</view>
</view>
</view>
<view class="c-options">
<view class="name">日统计</view>
<picker class="picker">
<view class="p-content">
<van-icon class="icon" name="arrow-left" />
<view class="content">2025/02/26</view>
<van-icon class="icon" name="arrow" />
</view>
</picker>
</view>
<view class="card">
<view class="row2">
<view class="col">
<view class="name">邀约患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">跳转患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">入组患者数</view>
<view class="num">750</view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">入组患者数</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">300</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
</view>
</view>
<view class="chart-range">
<picker class="picker" mode="date" end="{{end}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon13.png"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" start="{{satrt}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
</view>
<view class="chart-container">
<ec-canvas id="chart1_1" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>
</view>
<view class="more" bind:tap="handleStat">
查看明细
<van-icon name="arrow" />
</view>
</view>
</view>
<doctor-tab-bar active="{{ 0 }}"></doctor-tab-bar>

8
src/doctor/pages/invite/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"login":"/components/login/index"
}
}

101
src/doctor/pages/invite/index.scss

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
.page-title {
display: flex;
align-items: center;
gap: 22rpx;
font-size: 36rpx;
color: #ffffff;
}
.page {
height: 100vh;
box-sizing: border-box;
.page-container {
margin: 0 40rpx;
padding: 32rpx 48rpx;
height: 960rpx;
box-sizing: border-box;
.user {
display: flex;
gap: 24rpx;
height: 200rpx;
.avatar {
width: 126rpx;
height: 126rpx;
border: 1px solid #fff;
border-radius: 50%;
}
.wrap {
padding-top: 16rpx;
.nickname {
font-size: 36rpx;
color: #1a2020;
font-weight: bold;
}
.label {
display: inline-block;
margin-top: 8rpx;
padding: 0 12rpx;
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
border-radius: 6rpx;
background: linear-gradient(86deg, #fcd675 0%, #ffb700 100%);
}
}
}
.title {
font-size: 40rpx;
color: #342317;
text-align: center;
}
.brand {
margin-top: 12rpx;
.name {
font-size: 44rpx;
color: #ff8a4c;
font-weight: bold;
text-align: center;
}
.bg {
margin: -12rpx auto 0;
width: 140rpx;
height: 16rpx;
background: linear-gradient(90deg, #fdd260 0%, rgba(253, 210, 96, 0.07) 100%);
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
}
.code-wrap {
margin: 64rpx auto 0;
padding: 10rpx;
width: 328rpx;
height: 328rpx;
border-radius: 50%;
border: 10rpx solid rgba(255, 166, 77, 0.13);
.code {
display: block;
border-radius: 50%;
width: 100%;
height: 100%;
}
}
.tip {
margin: 52rpx auto 0;
width: 340rpx;
height: 76rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 10rpx;
font-size: 40rpx;
color: #ffffff;
background: #ff8a4c;
border-radius: 92rpx 92rpx 92rpx 92rpx;
.dot {
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #fff;
}
}
}
}

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

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleBack() {
wx.navigateBack()
},
})
export {}

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

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
<navbar fixed custom-style="background:transparent">
<view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
专属邀约码
</view>
</navbar>
<view
class="page"
style="background: url('/images/bg8.png') no-repeat top center/100% 100vh;padding-top: {{pageTop+87}}px;"
>
<view class="page-container" style="background: url('/images/bg9.png') no-repeat top center/100% 964rpx">
<view class="user">
<image class="avatar" src="/images/cache/a1.png" mode="aspectFill"></image>
<view class="wrap">
<view class="nickname">刘平安</view>
<view class="label">药师</view>
</view>
</view>
<view class="title">邀请您加入健康管理项目</view>
<view class="brand">
<view class="name">特诺雅</view>
<view class="bg"></view>
</view>
<view class="code-wrap">
<image class="code" src="/images/cache/c1.png" show-menu-by-longpress></image>
</view>
<view class="tip">
<view class="dot"></view>
扫码立即加入
<view class="dot"></view>
</view>
</view>
</view>

9
src/doctor/pages/login/index.json

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
{
"navigationBarTitleText": "登录",
"navigationStyle": "custom",
"usingComponents": {
"van-divider": "@vant/weapp/divider/index",
"van-icon": "@vant/weapp/icon/index",
"navbar": "/components/navbar/index"
}
}

139
src/doctor/pages/login/index.scss

@ -0,0 +1,139 @@ @@ -0,0 +1,139 @@
page {
background-color: #f8fafa;
}
.page-order {
display: flex;
align-items: center;
gap: 22rpx;
.item {
width: 72rpx;
height: 72rpx;
font-size: 30rpx;
color: #342317;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border-radius: 50%;
&.active{
color: #fff;
background-color: #FF8A4C;
}
}
}
.page {
min-height: 100vh;
padding: 460rpx 0 80rpx 0;
box-sizing: border-box;
.page-title {
margin: 0 40rpx;
width: 614rpx;
height: 184rpx;
}
.container {
padding: 0 40rpx;
.content {
margin-top: 40rpx;
font-size: 32rpx;
color: #342317;
line-height: 48rpx;
.link {
color: #ff8a4c;
}
}
}
.phone {
margin: 54rpx 40rpx 0;
padding: 30rpx 20rpx;
border-radius: 64rpx;
background: linear-gradient(90deg, #fece55 0%, #ff8a4c 100%);
font-size: 32rpx;
color: rgba(255, 255, 255, 1);
line-height: 1;
&::after {
border: none;
outline: none;
}
}
.divider {
margin: 48rpx auto 0;
width: 338rpx;
}
.tel-code {
margin: 32rpx auto 0;
width: 278rpx;
height: 52rpx;
display: flex;
justify-content: center;
font-size: 32rpx;
color: #342317;
}
.form {
margin: 42rpx 40rpx 0;
padding: 48rpx 32rpx;
border-radius: 24rpx;
background-color: #fff;
.row {
margin-bottom: 32rpx;
display: flex;
justify-content: space-between;
border-radius: 12rpx;
background: #f7f7f7;
.input {
flex: 1;
padding: 22rpx 32rpx;
height: 40rpx;
font-size: 32rpx;
color: #000;
}
.input-placeholade {
color: #b7b7b7;
}
.code {
margin-left: 24rpx;
flex-shrink: 0;
width: 262rpx;
border-radius: 24rpx;
font-size: 32rpx;
color: #ff8a4c;
display: flex;
align-items: center;
justify-content: center;
}
}
.submit {
margin-top: 32px;
padding: 30rpx 20rpx;
background: linear-gradient(90deg, #fece55 0%, #ff8a4c 100%);
border-radius: 64rpx;
font-size: 32rpx;
color: #ffffff;
text-align: center;
line-height: 1;
}
}
.check {
margin: 68rpx 50rpx 0;
display: flex;
line-height: 60rpx;
color: #b7b7b7;
.icon {
margin-top: 14rpx;
margin-right: 10rpx;
flex-shrink: 0;
width: 32rpx;
height: 32rpx;
}
.link {
color: #ff8a4c;
}
}
.partient {
margin-top: 58rpx;
font-size: 32rpx;
color: rgba(161, 164, 172, 1);
display: flex;
align-items: center;
justify-content: center;
}
}

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

@ -0,0 +1,154 @@ @@ -0,0 +1,154 @@
const app = getApp<IAppOption>()
let timer = null as null | number
Page({
data: {
mobile: '',
code: '',
codeText: '发送验证码',
back: false,
showForm: false,
check: false,
},
onLoad(option) {
if (option.back) {
this.setData({
back: true,
})
}
},
getCode() {
if (timer) return
const mobile = this.data.mobile
if (!mobile) {
wx.showToast({
title: '手机号不能为空',
icon: 'none',
})
return
}
// 验证手机号
if (!/^1[3-9,]\d{9}$/.test(mobile)) {
wx.showToast({
title: '手机号格式不正确',
icon: 'none',
})
return
}
wx.ajax({
method: 'POST',
url: '?r=zd/login/send-verify-code',
data: {
mobile,
},
}).then((_res) => {
wx.showToast({
icon: 'none',
title: '验证码已发送~',
})
let time = 60
timer = setInterval(() => {
time--
this.setData({
codeText: `${time}s后重新发送`,
})
if (time <= 0) {
clearInterval(timer as number)
timer = null
this.setData({
codeText: '发送验证码',
})
}
}, 1000)
})
},
handleSubmit() {
if (!this.data.mobile) {
wx.showToast({
icon: 'none',
title: '请输入手机号',
})
return
}
if (!this.data.code) {
wx.showToast({
icon: 'none',
title: '请输入验证码',
})
return
}
if (!this.data.check) {
wx.showToast({
icon: 'none',
title: '请同意用户协议',
})
return
}
wx.ajax({
method: 'POST',
url: '?r=zd/doctor/login/reg-login',
data: {
mobile: this.data.mobile,
code: this.data.code,
},
}).then((_res) => {
this.submitCallback()
})
},
handleWxSubmit(e: WechatMiniprogram.CustomEvent) {
if (!this.data.check) {
wx.showToast({
icon: 'none',
title: '请同意用户协议',
})
return
}
wx.navigateTo({
url: '/doctor/pages/loginForm/index',
})
return
const { iv, encryptedData } = e.detail
if (iv && encryptedData) {
wx.ajax({
method: 'POST',
url: '?r=zd/doctor/login/wx-reg-login',
data: {
iv: encodeURIComponent(iv),
encryptedData: encodeURIComponent(encryptedData),
},
}).then((_res) => {
this.submitCallback()
})
}
},
submitCallback() {
app.globalData.loginType = 2
app.globalData.isLogin = true
wx.reLaunch({
url: '/doctor/pages/d_home/index',
})
},
handlePatient() {
wx.redirectTo({
url: '/pages/login/index',
})
},
handleTelCode() {
this.setData({
showForm: !this.data.showForm,
})
},
handleLink() {
wx.navigateTo({
url: '/doc/pages/doc1/index',
})
},
handleCheck() {
this.setData({
check: !this.data.check,
})
},
handleBack() {
wx.navigateBack()
},
})

60
src/doctor/pages/login/index.wxml

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
<navbar fixed custom-style="background:transparent" back>
<view class="page-order" slot="left">
<view class="item active">1</view>
<view class="item">2</view>
</view>
</navbar>
<view
class="page"
style="background: url('/images/bg4.png') no-repeat top center / 100% 710rpx;padding-top: {{pageTop+80}}px;"
>
<image class="page-title" src="/images/content2.png"></image>
<view class="container">
<view class="content">
在您加入华观健康之前,请您阅读并充分理解
<text class="link" bind:tap="handleLink">《个人信息及隐私保护政策》</text>
了解您的权益及相关数据处理方法,我们将严格按照法律法规及
<text class="link" bind:tap="handleLink">《个人信息及隐私保护政策》</text>
的相关规定保证您的个人信息不受侵犯。
</view>
</view>
<button wx:if="{{check}}" class="phone" open-type="getPhoneNumber" bindgetphonenumber="handleWxSubmit">
手机号快捷登录
</button>
<button wx:else class="phone" bind:tap="handleWxSubmit">手机号快捷登录</button>
<view class="divider">
<van-divider contentPosition="center" textColor="rgba(183,183,183, 0.5)">或者</van-divider>
</view>
<view class="tel-code" bind:tap="handleTelCode">使用手机号验证码</view>
<view class="form" wx:if="{{showForm}}">
<view class="row">
<input
type="number"
model:value="{{mobile}}"
class="input"
placeholder-class="input-placeholade"
placeholder="请输入手机号"
/>
</view>
<view class="row">
<input
type="number"
model:value="{{code}}"
class="input"
placeholder-class="input-placeholade"
placeholder="请输入验证码"
/>
<view class="code" bind:tap="getCode">{{codeText}}</view>
</view>
<view class="submit" bind:tap="handleSubmit">立即加入</view>
</view>
<view class="check">
<image wx:if="{{check}}" class="icon" src="/images/icon18.png" bind:tap="handleCheck"></image>
<image wx:else class="icon" src="/images/icon12.png" bind:tap="handleCheck"></image>
<view class="p">
我特此同意依照此
<text class="link" bind:tap="handleLink">《隐私协议保护政策》</text>
规定收集我的个人敏感信息
</view>
</view>
</view>

11
src/doctor/pages/loginForm/index.json

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
{
"navigationBarTitleText": "登录",
"navigationStyle": "custom",
"usingComponents": {
"van-divider": "@vant/weapp/divider/index",
"van-icon": "@vant/weapp/icon/index",
"navbar": "/components/navbar/index",
"van-popup": "@vant/weapp/popup/index",
"pickerArea": "/components/pickerArea/index"
}
}

163
src/doctor/pages/loginForm/index.scss

@ -0,0 +1,163 @@ @@ -0,0 +1,163 @@
page {
background-color: #f8fafa;
}
.page-order {
display: flex;
align-items: center;
gap: 22rpx;
.item {
width: 72rpx;
height: 72rpx;
font-size: 30rpx;
color: #342317;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border-radius: 50%;
&.active {
color: #fff;
background-color: #ff8a4c;
}
}
}
.page {
min-height: 100vh;
padding: 460rpx 0 80rpx 0;
box-sizing: border-box;
.page-title {
margin: 0 40rpx;
width: 614rpx;
height: 184rpx;
}
.phone {
margin: 54rpx 40rpx 0;
padding: 30rpx 20rpx;
border-radius: 64rpx;
background: linear-gradient(90deg, #fece55 0%, #ff8a4c 100%);
font-size: 32rpx;
color: rgba(255, 255, 255, 1);
line-height: 1;
&::after {
border: none;
outline: none;
}
}
.form {
margin: 102rpx 40rpx 0;
.row {
margin-bottom: 40rpx;
padding: 0 32rpx;
display: flex;
align-items: center;
border-radius: 12rpx;
background-color: #fff;
.label {
font-size: 32rpx;
color: #342317;
}
.picker,
.wrap {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.input {
flex: 1;
padding: 22rpx;
font-size: 32rpx;
line-height: 1;
color: #000;
}
.place-input {
color: #b7b7b7;
}
.icon {
width: 48rpx;
height: 48rpx;
}
}
}
}
}
.popup {
.p-header {
background-color: #fff;
box-shadow: 0rpx 4rpx 24rpx 0rpx rgba(0, 0, 0, 0.1);
.title {
padding: 48rpx 0 32rpx;
font-size: 36rpx;
color: #342317;
font-weight: bold;
text-align: center;
}
.search {
margin: 0 32rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
background: #f8fafa;
border-radius: 24rpx 24rpx 24rpx 24rpx;
gap: 8rpx;
.icon {
width: 44rpx;
height: 44rpx;
}
.input {
height: 80rpx;
font-size: 32rpx;
line-height: 40rpx;
color: #1a2020;
}
.place-input {
color: #b7b7b7;
}
}
.options {
display: flex;
align-items: center;
.o-item {
flex: 1;
padding: 24rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
.content {
font-size: 32rpx;
color: #342317;
}
.icon {
width: 48rpx;
height: 48rpx;
}
}
}
}
.p-list {
padding: 16rpx 32rpx;
min-height: 30vh;
max-height: 50vh;
overflow-y: auto;
overflow-x: hidden;
.l-item {
padding: 32rpx 0;
.name {
font-size: 32rpx;
color: #342317;
line-height: 40rpx;
}
.site {
margin-top: 16rpx;
font-size: 28rpx;
color: #b7b7b7;
line-height: 40rpx;
border-bottom: 1px solid rgba(245, 244, 243, 0.4);
&:last-of-type {
border-bottom: none;
}
}
}
}
}

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

@ -0,0 +1,165 @@ @@ -0,0 +1,165 @@
const app = getApp<IAppOption>()
let timer = null as null | number
Page({
data: {
mobile: '',
code: '',
codeText: '发送验证码',
back: false,
showForm: false,
check: false,
show: false,
},
onLoad(option) {
if (option.back) {
this.setData({
back: true,
})
}
},
getCode() {
if (timer) return
const mobile = this.data.mobile
if (!mobile) {
wx.showToast({
title: '手机号不能为空',
icon: 'none',
})
return
}
// 验证手机号
if (!/^1[3-9,]\d{9}$/.test(mobile)) {
wx.showToast({
title: '手机号格式不正确',
icon: 'none',
})
return
}
wx.ajax({
method: 'POST',
url: '?r=zd/login/send-verify-code',
data: {
mobile,
},
}).then((_res) => {
wx.showToast({
icon: 'none',
title: '验证码已发送~',
})
let time = 60
timer = setInterval(() => {
time--
this.setData({
codeText: `${time}s后重新发送`,
})
if (time <= 0) {
clearInterval(timer as number)
timer = null
this.setData({
codeText: '发送验证码',
})
}
}, 1000)
})
},
handleSubmit() {
if (!this.data.mobile) {
wx.showToast({
icon: 'none',
title: '请输入手机号',
})
return
}
if (!this.data.code) {
wx.showToast({
icon: 'none',
title: '请输入验证码',
})
return
}
if (!this.data.check) {
wx.showToast({
icon: 'none',
title: '请同意用户协议',
})
return
}
wx.ajax({
method: 'POST',
url: '?r=zd/doctor/login/reg-login',
data: {
mobile: this.data.mobile,
code: this.data.code,
},
}).then((_res) => {
this.submitCallback()
})
},
handleWxSubmit(e: WechatMiniprogram.CustomEvent) {
wx.redirectTo({
url: '/doctor/pages/home/index',
})
return
if (!this.data.check) {
wx.showToast({
icon: 'none',
title: '请同意用户协议',
})
return
}
const { iv, encryptedData } = e.detail
if (iv && encryptedData) {
wx.ajax({
method: 'POST',
url: '?r=zd/doctor/login/wx-reg-login',
data: {
iv: encodeURIComponent(iv),
encryptedData: encodeURIComponent(encryptedData),
},
}).then((_res) => {
this.submitCallback()
})
}
},
submitCallback() {
app.globalData.loginType = 2
app.globalData.isLogin = true
wx.reLaunch({
url: '/doctor/pages/d_home/index',
})
},
handlePatient() {
wx.redirectTo({
url: '/pages/login/index',
})
},
handleTelCode() {
this.setData({
showForm: !this.data.showForm,
})
},
handleLink() {
wx.navigateTo({
url: '/doc/pages/doc1/index',
})
},
handleCheck() {
this.setData({
check: !this.data.check,
})
},
handleBack() {
wx.navigateBack()
},
handleDrug() {
this.setData({
show: true,
})
},
onClose() {
this.setData({
show: false,
})
},
})

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

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
<navbar fixed custom-style="background:transparent" back>
<view class="page-order" slot="left">
<view class="item active">1</view>
<view class="item active">2</view>
</view>
</navbar>
<view
class="page"
style="background: url('/images/bg4.png') no-repeat top center / 100% 710rpx;padding-top: {{pageTop+80}}px;"
>
<image class="page-title" src="/images/content2.png"></image>
<view class="form">
<view class="row">
<view class="label">您的身份</view>
<view class="wrap">
<input type="text" class="input" placeholder-class="place-input" placeholder="请输入姓名" />
</view>
</view>
<view class="row">
<view class="label">所属药店</view>
<view class="wrap" bind:tap="handleDrug">
<input disabled type="text" class="input" placeholder-class="place-input" placeholder="选择所属药店" />
<image class="icon" src="/images/icon2.png"></image>
</view>
</view>
</view>
<button class="phone" bind:tap="handleWxSubmit">注册</button>
</view>
<van-popup show="{{ show }}" title="选择所属药店" position="bottom" round closeable bind:close="onClose">
<view class="popup">
<view class="p-header">
<view class="title">选择所属药店</view>
<view class="search">
<image class="icon" src="/images/icon1.png"></image>
<input
type="text"
placeholder="搜索药店名/药师姓名"
class="input"
placeholder-class="place-input"
confirm-type="search"
bindconfirm="handleSearch"
/>
</view>
<pickerArea bindchange="handleChange">
<view class="options">
<view class="o-item">
<view class="content">请选择省份</view>
<image class="icon" src="/images/icon2.png"></image>
</view>
<view class="o-item">
<view class="content">请选择省份</view>
<image class="icon" src="/images/icon2.png"></image>
</view>
</view>
</pickerArea>
</view>
<view class="p-list">
<view class="l-item">
<view class="name">北京同仁堂昌平东关药店(医保定点)</view>
<view class="site">北京市昌平区府学路3号一层101号(昌平东关地铁站A西北口步行180米)</view>
</view>
</view>
</view>
</van-popup>

8
src/doctor/pages/my/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationBarTitleText": "地推端",
"navigationStyle": "custom",
"usingComponents": {
"navbar": "../../../components/navbar/index",
"doctor-tab-bar": "/doctor/components/doctor-tab-bar/index"
}
}

99
src/doctor/pages/my/index.scss

@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
page {
background: #f8fafa;
}
.page {
min-height: 60vh;
.user {
position: relative;
margin: 100rpx 32rpx 0;
padding: 112rpx 32rpx 32rpx;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.72) 0%, #ffffff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 2rpx solid #ffffff;
backdrop-filter: blur(16rpx);
.avatar {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
.a-img {
width: 186rpx;
height: 186rpx;
border-radius: 50%;
border: 1px solid #fff;
}
.edit {
position: absolute;
bottom: 16rpx;
right: 16rpx;
width: 34rpx;
height: 34rpx;
border-radius: 50%;
border: 1px solid #fff;
background-color: #ff8a4c;
display: flex;
align-items: center;
justify-content: center;
.icon {
width: 20rpx;
height: 20rpx;
}
}
}
.name {
font-size: 40rpx;
color: #342317;
font-weight: bold;
text-align: center;
}
.phone {
margin-top: 12rpx;
font-size: 32rpx;
color: #b5b8bb;
text-align: center;
}
}
.list {
margin: 32rpx 32rpx 0;
border-radius: 24rpx;
background-color: #fff;
.list-item {
padding: 34rpx 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 24rpx;
.icon {
flex-shrink: 0;
width: 44rpx;
height: 44rpx;
}
.title {
flex: 1;
font-size: 32rpx;
color: #342317;
line-height: 48rpx;
.content {
font-size: 28rpx;
color: #9b9998;
}
}
.arrow {
font-size: 36rpx;
color: #958b86;
}
}
}
.exit {
margin: 64rpx 32rpx 0;
font-size: 32rpx;
color: #342317;
height: 96rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
border-radius: 24rpx;
}
}

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

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleNickname() {
wx.navigateTo({
url: '/doctor/pages/changeNickname/index',
})
},
handleTel() {
wx.navigateTo({
url: '/doctor/pages/changeTel/index',
})
},
handleInvite() {
wx.navigateTo({
url: '/doctor/pages/invite/index',
})
},
})
export {}

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

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
<navbar fixed custom-style="background: transparent;"></navbar>
<view
class="page"
style="background:url('/images/bg7.png') no-repeat top center/100% 602rpx; padding-top: {{pageTop+20}}px"
>
<view class="user">
<view class="avatar">
<image class="a-img" src="/images/cache/a1.png"></image>
<view class="edit">
<image class="icon" src="/images/icon3.png"></image>
</view>
</view>
<view class="name">刘平安</view>
<view class="phone">康泰大药房(人民路店)</view>
</view>
<view class="list">
<view class="list-item" bind:tap="handleNickname">
<image class="icon" src="/images/icon14.png"></image>
<view class="title">修改姓名</view>
<van-icon class="arrow" name="arrow" />
</view>
<view class="list-item" bind:tap="handleTel">
<image class="icon" src="/images/icon15.png"></image>
<view class="title">修改手机号</view>
<van-icon class="arrow" name="arrow" />
</view>
<view class="list-item" bind:tap="handleInvite">
<image class="icon" src="/images/icon16.png"></image>
<view class="title">我的邀约码</view>
<van-icon class="arrow" name="arrow" />
</view>
<view class="list-item">
<image class="icon" src="/images/icon17.png"></image>
<view class="title">我的邀约人 <text class="content">(王建设 12345678901)</text></view>
</view>
</view>
<view class="exit">退出登录</view>
</view>
<doctor-tab-bar active="{{ 2 }}"></doctor-tab-bar>

8
src/doctor/pages/patientList/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"navbar": "../../../components/navbar/index",
"doctor-tab-bar": "/doctor/components/doctor-tab-bar/index",
"popup":"/components/popup/index"
}
}

285
src/doctor/pages/patientList/index.scss

@ -0,0 +1,285 @@ @@ -0,0 +1,285 @@
page {
background-color: #f7f7f7;
}
.page-switch {
color: #ff8a4c;
text-align: right;
font-size: 40rpx;
font-style: normal;
font-weight: 700;
line-height: 52rpx;
.arrow {
font-size: 28rpx;
color: #b7b7b7;
}
}
.page {
.page-header {
padding-bottom: 32rpx;
background: linear-gradient(0, #ffffff 0%, #fff1ea 100%);
box-shadow: 0rpx 16rpx 40rpx 0rpx rgba(26, 32, 32, 0.04);
.search {
margin: 0 32rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
background: #ffffff;
border-radius: 24rpx 24rpx 24rpx 24rpx;
gap: 8rpx;
border: 1px solid rgba(245, 244, 243, 0.47);
.icon {
width: 44rpx;
height: 44rpx;
}
.input {
height: 80rpx;
font-size: 32rpx;
line-height: 40rpx;
color: #1a2020;
}
.place-input {
color: #b7b7b7;
}
}
.row {
margin: 24rpx 32rpx 0;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 22rpx;
.col {
padding: 10rpx 16rpx 10rpx 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #f7f7f7;
border-radius: 12rpx;
.label {
flex-shrink: 0;
font-size: 32rpx;
color: #342317;
}
.content {
flex: 1;
font-size: 32rpx;
color: #b5b8bb;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.icon {
flex-shrink: 0;
width: 44rpx;
height: 44rpx;
}
}
.total {
font-size: 32rpx;
color: #342317;
text-align: right;
.num {
color: #ff8a4c;
}
}
}
.range {
margin: 22rpx 32rpx 0;
padding: 0 16rpx 0 24rpx;
background-color: #f7f7f7;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: space-between;
.label {
flex-shrink: 0;
font-size: 32rpx;
color: #342317;
}
.picker {
flex: 1;
.date {
padding: 10rpx 0;
text-align: center;
font-size: 32rpx;
color: #b5b8bb;
line-height: 44rpx;
}
}
.line {
margin: 0 10rpx;
width: 24rpx;
height: 1px;
background-color: rgba(181, 184, 187, 0.25);
}
.icon {
width: 44rpx;
height: 44rpx;
}
}
}
.card {
margin: 32rpx;
padding: 32rpx;
background: linear-gradient(0deg, #fff6ed 0%, #ffffff 21.63%, #ffffff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 2rpx solid #ffffff;
.user {
display: flex;
.avatar {
flex-shrink: 0;
width: 116rpx;
height: 116rpx;
border-radius: 50%;
}
.wrap {
padding-top: 8rpx;
padding-left: 24rpx;
.info {
.name {
padding-right: 12rpx;
font-size: 32rpx;
color: #342317;
}
.tel {
font-size: 28rpx;
color: #342317;
}
}
.site {
margin-top: 8rpx;
font-size: 28rpx;
color: #342317;
}
.date {
margin-top: 8rpx;
font-size: 28rpx;
color: #b7b7b7;
}
}
}
.container {
margin-top: 32rpx;
padding-bottom: 32rpx;
border-radius: 12rpx;
background-color: rgba(247, 247, 247, 0.6);
.c-item {
display: flex;
.aside {
display: flex;
flex-direction: column;
align-items: flex-end;
.line-top {
flex-shrink: 0;
margin-right: 9rpx;
height: 32rpx;
border-right: 1px dashed #d9d9d9;
}
.step {
margin: -6rpx 0;
display: flex;
align-items: center;
gap: 12rpx;
.name {
padding: 0 0 0 12rpx;
font-size: 28rpx;
color: #b7b7b7;
}
.order {
flex-shrink: 0;
width: 20rpx;
height: 20rpx;
background: rgba(217, 217, 217, 0.26);
border-radius: 50%;
&::after {
margin: 4rpx auto;
content: '';
display: block;
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: #d9d9d9;
}
}
}
.line-bottom {
flex: 1;
margin-right: 9rpx;
height: 32rpx;
border-right: 1px dashed #d9d9d9;
}
}
.wrap {
flex: 1;
margin: 0 16rpx;
padding-top: 24rpx;
padding-bottom: 32rpx;
border-bottom: 1px solid #efefef;
.date {
font-size: 32rpx;
color: #342317;
}
.status {
margin-top: 28rpx;
display: flex;
align-items: center;
gap: 32rpx;
font-size: 32rpx;
.s1 {
color: #4a8dff;
}
.s2 {
color: #e86854;
}
.btn1 {
color: #ff8a4c;
text-decoration: underline;
text-underline-offset: 4rpx;
}
.btn2 {
width: 160rpx;
height: 48rpx;
background: #ff8a4c;
border-radius: 88rpx 88rpx 88rpx 88rpx;
text-align: center;
line-height: 48rpx;
font-size: 28rpx;
color: #ffffff;
}
}
.remark {
margin-top: 16rpx;
font-size: 32rpx;
color: #e86854;
}
}
&.active {
.aside {
.step {
.name {
color: #ff8a4c;
background: linear-gradient(to right, rgba(255, 138, 76, 0.16) 0%, transparent 100%);
}
.order {
background: rgba(255, 138, 76, 0.18);
&::after {
background: #ff8a4c;
}
}
}
}
}
&:first-of-type {
.line-top {
border-right: none;
}
}
&:last-of-type {
.wrap {
padding-bottom: 0;
border-bottom: none;
}
}
}
}
}
}

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

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
const _app = getApp<IAppOption>()
Page({
data: {
popupShow: false,
popupType: 'popup1',
popupParams: {},
},
onLoad() {},
handleUpload() {
this.setData({
popupShow: true,
popupType: 'popup1',
})
},
handlePopupOk() {
this.setData({
popupShow: false,
})
},
handlePopupCancel() {
this.setData({
popupShow: false,
})
},
})
export {}

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

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
<navbar fixed custom-style="background: {{background}};">
<view class="page-switch" slot="left">
特诺雅
<van-icon class="arrow" name="arrow-down" />
</view>
</navbar>
<view class="page">
<view class="page-header" style="padding-top: {{pageTop+20}}px">
<view class="search">
<image class="icon" src="/images/icon1.png"></image>
<input
type="text"
placeholder="搜索药店名/药师姓名"
class="input"
placeholder-class="place-input"
confirm-type="search"
bindconfirm="handleSearch"
/>
</view>
<view class="row">
<picker mode="region">
<view class="col">
<view class="label">跳转:</view>
<view class="content">全部</view>
<image class="icon" src="/images/icon2.png"></image>
</view>
</picker>
<picker mode="region">
<view class="col">
<view class="label">入组:</view>
<view class="content">全部</view>
<image class="icon" src="/images/icon2.png"></image>
</view>
</picker>
</view>
<view class="range">
<view class="label">时间筛选:</view>
<picker class="picker" mode="date">
<view class="date">开始时间</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date">
<view class="date">开始时间</view>
</picker>
<image class="icon" src="/images/icon2.png"></image>
</view>
<view class="row">
<picker mode="region">
<view class="col">
<view class="label">时间类型:</view>
<view class="content">全部</view>
<image class="icon" src="/images/icon2.png"></image>
</view>
</picker>
<view class="total">
已邀约总人数:
<text class="num">28人</text>
</view>
</view>
</view>
<view class="page-container">
<view class="card">
<view class="user">
<image class="avatar" src="/images/cache/a2.png"></image>
<view class="wrap">
<view class="info">
<text class="name">张患者</text>
<text class="tel">13800138000</text>
</view>
<view class="site">康泰大药房(人民路店)</view>
<view class="date">绑定时间:2026/01/10 16:27:35</view>
</view>
</view>
<view class="container">
<view class="c-item">
<view class="aside">
<view class="line-top"></view>
<view class="step">
<view class="name">未跳转</view>
<view class="order"></view>
</view>
<view class="line-bottom"></view>
</view>
<view class="wrap">
<view class="date">2026/01/10 16:27:35</view>
<view class="status">
<view class="s1">审核中</view>
<view class="btn1">查看提交材料</view>
</view>
<view class="remark">材料信息不全</view>
</view>
</view>
<view class="c-item active">
<view class="aside">
<view class="line-top"></view>
<view class="step">
<view class="name">未跳转</view>
<view class="order"></view>
</view>
<view class="line-bottom"></view>
</view>
<view class="wrap">
<view class="date">2026/01/10 16:27:35</view>
<view class="status">
<view class="s2">驳回</view>
<view class="btn2" bind:tap="handleUpload">重新提交</view>
</view>
<view class="remark">材料信息不全</view>
</view>
</view>
</view>
</view>
</view>
</view>
<doctor-tab-bar active="{{ 1 }}"></doctor-tab-bar>
<popup
show="{{popupShow}}"
type="{{popupType}}"
params="{{popupParams}}"
bind:ok="handlePopupOk"
bind:cancel="handlePopupCancel"
></popup>

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

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"login":"/components/login/index"
}
}

199
src/doctor/pages/stat/index.scss

@ -0,0 +1,199 @@ @@ -0,0 +1,199 @@
page {
background-color: #f8fafa;
}
.page-title {
display: flex;
align-items: center;
gap: 22rpx;
font-size: 36rpx;
color: #1A2020;
}
.page {
.page-header {
position: sticky;
left: 0;
top: 0;
padding: 32rpx;
background-color: #fff;
.chart-range {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
.picker {
flex: 1;
.p-content {
padding: 8rpx 38rpx;
display: flex;
align-items: center;
gap: 18rpx;
border-radius: 12rpx 12rpx 12rpx 12rpx;
border: 1px solid #f2f6f8;
.content {
font-size: 28rpx;
color: #b5b8bb;
}
.icon {
width: 32rpx;
height: 32rpx;
}
}
}
.line {
width: 24rpx;
height: 1px;
background-color: #f2f6f8;
}
}
}
.stat-card {
margin: 24rpx 32rpx 0;
padding: 32rpx 0;
background-color: #fff;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
.col {
flex: 1;
text-align: center;
.num {
font-size: 48rpx;
color: #FF8A4C;
font-weight: bold;
line-height: 56rpx;
.sub {
font-size: 24rpx;
color: #b5b8bb;
font-weight: normal;
}
}
.title {
margin-top: 6rpx;
font-size: 24rpx;
color: #1a2020;
line-height: 36rpx;
}
}
}
.stat-list {
margin: 0 32rpx 0;
.module {
display: flex;
gap: 10rpx;
.aside {
display: flex;
align-items: center;
flex-direction: column;
gap: 14rpx;
.line-top {
flex-shrink: 0;
height: 40rpx;
width: 0;
border-right: 1px dashed #FF8A4C;
}
.dot {
flex-shrink: 0;
width: 24rpx;
height: 24rpx;
background: rgba(255,138,76,0.18);
border-radius: 50%;
&::after {
margin: 4rpx auto;
content: '';
display: block;
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background-color: #FF8A4C;
}
}
.line-bottom {
flex: 1;
height: 40rpx;
width: 0;
border-right: 1px dashed #FF8A4C;
}
}
.m-container {
padding-top: 46rpx;
.date {
font-size: 32rpx;
color: #4a5555;
}
.card {
margin-top: 24rpx;
border: 1px solid #f2f6f8;
border-radius: 16rpx;
overflow: hidden;
.row2 {
display: flex;
background: linear-gradient( 90deg, #FF8A4C 0%, #FECE55 100%);
border-radius: 16rpx 16rpx 0 0;
.col {
flex: 1;
padding: 28rpx 34rpx;
.name {
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #ffffff;
line-height: 48rpx;
}
}
.line {
width: 1px;
background-color: rgba(238, 245, 245, 0.35);
}
}
.row3 {
display: flex;
.col {
position: relative;
padding: 28rpx 34rpx;
flex: 1;
background-color: #fff;
.name {
font-size: 24rpx;
color: #b5b8bb;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #1a2020;
line-height: 48rpx;
}
.line {
position: absolute;
left: 20rpx;
bottom: 0;
width: 168rpx;
height: 1px;
background-color: rgba(242, 246, 248, 0.47);
}
&:nth-of-type(2) {
borer: 1px solid #eef5f5;
border-right: none;
border-left: none;
background-color: #f8fafa;
}
}
}
}
}
&:first-of-type {
.aside {
.line-top {
opacity: 0;
}
}
}
}
}
}

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

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleBack() {
wx.navigateBack()
},
})
export {}

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

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
<navbar fixed custom-style="background:#fff">
<view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
专属邀约码
</view>
</navbar>
<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}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon13.png"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" start="{{satrt}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon13.png"></image>
</view>
</picker>
</view>
</view>
<view class="stat-card">
<view class="col">
<view class="num">
1893
<text class="sub">人</text>
</view>
<view class="title">邀约患者总数</view>
</view>
<view class="col">
<view class="num">
1893
<text class="sub">人</text>
</view>
<view class="title">跳转患者数</view>
</view>
<view class="col">
<view class="num">
1893
<text class="sub">人</text>
</view>
<view class="title">跳转患者数</view>
</view>
</view>
<view class="stat-list">
<view class="module">
<view class="aside">
<view class="line-top"></view>
<view class="dot"></view>
<view class="line-bottom"></view>
</view>
<view class="m-container">
<view class="date">2025/02/26</view>
<view class="card">
<view class="row2">
<view class="col">
<view class="name">邀约患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">跳转患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">入组患者数</view>
<view class="num">750</view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">入组患者数</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">300</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>

0
src/patient/components/patient-tab-bar/index.json → src/ground/components/ground-tab-bar/index.json

15
src/ground/components/ground-tab-bar/index.scss

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
/* custom-tab-bar/index.wxss */
.tab-item {
.icon {
width: 40rpx;
height: 40rpx;
}
.name {
font-size: 24rpx;
color: #4a5555;
&.active {
color: #4a8dff;
}
}
}

47
src/ground/components/ground-tab-bar/index.ts

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
const app = getApp()
Component({
properties: {
active: {
type: Number,
value: 0,
},
},
data: {
imageUrl: app.globalData.imageUrl,
isChild: 0,
active: 0,
list: [
{
pagePath: '/ground/pages/home/index',
text: '首页',
icon: 'tab1',
iconActive: 'tab1-active',
},
{
pagePath: '/ground/pages/pharmacist/index',
text: '药师管理',
icon: 'tab2',
iconActive: 'tab2-active',
},
{
pagePath: '/ground/pages/my/index',
text: '我的',
icon: 'tab3',
iconActive: 'tab3-active',
},
],
},
observers: {},
methods: {
onChange() {},
handleNav(e) {
const { index } = e.currentTarget.dataset
const { list } = this.data
const { pagePath } = list[index]
wx.reLaunch({
url: pagePath,
})
},
},
})

9
src/ground/components/ground-tab-bar/index.wxml

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<van-tabbar active="{{ active }}" active-color="#F23A2F" bind:change="onChange" inactive-color="#010105" placeholder>
<block wx:for="{{list}}" wx:key="*this">
<van-tabbar-item class="tab-item" wx:if="{{ index != 3 || !anyWhere}}" bind:tap="handleNav" data-index="{{index}}">
<image class="icon" slot="icon" src="/images/tabbar/{{item.icon}}.png?t={{Timestamp}}"></image>
<image class="icon" slot="icon-active" src="/images/tabbar/{{item.iconActive}}.png?t={{Timestamp}}"></image>
<view class="name {{index==active && 'active'}}">{{item.text}}</view>
</van-tabbar-item>
</block>
</van-tabbar>

8
src/ground/pages/changeNickname/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"login":"/components/login/index"
}
}

33
src/ground/pages/changeNickname/index.scss

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
page {
background-color: #f8fafa;
}
.page-title {
display: flex;
align-items: center;
gap: 22rpx;
font-size: 36rpx;
color: #1a2020;
}
.page {
padding: 48rpx 32rpx;
.input {
padding: 32rpx;
font-size: 32rpx;
border-radius: 24rpx;
background-color: #fff;
}
.place-input {
color: #b5b8bb;
}
.btn {
margin-top: 160rpx;
height: 96rpx;
font-size: 32rpx;
color: #ffffff;
line-height: 96rpx;
text-align: center;
background: linear-gradient(268deg, #5393ff 0%, #3edec9 100%);
border-radius: 120rpx 120rpx 120rpx 120rpx;
}
}

11
src/ground/pages/changeNickname/index.ts

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleBack() {
wx.navigateBack()
},
})
export {}

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

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
<navbar fixed custom-style="background:#fff">
<view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
资料姓名
</view>
</navbar>
<view class="page" style="padding-top: {{pageTop+28}}px;">
<input class="input" placeholder-class="place-input" type="text" placeholder="请输入新昵称" />
<view class="btn">确认</view>
</view>

8
src/ground/pages/changeTel/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"login":"/components/login/index"
}
}

53
src/ground/pages/changeTel/index.scss

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
page {
background-color: #f8fafa;
}
.page-title {
display: flex;
align-items: center;
gap: 22rpx;
font-size: 36rpx;
color: #1a2020;
}
.page {
padding: 48rpx 32rpx;
.container {
width: 100%;
.form {
padding: 0 32rpx;
background: #ffffff;
border-radius: 24rpx;
.row {
display: flex;
align-items: center;
border-bottom: 1px solid #eef5f5;
&:last-of-type {
border: none;
}
.input {
flex: 1;
padding: 32rpx 0;
height: 40rpx;
font-size: 28rpx;
}
.place-input {
color: #b5b8bb;
}
.code {
font-size: 32rpx;
color: #4a8dff;
}
}
}
.submit {
margin-top: 160rpx;
height: 96rpx;
font-size: 32rpx;
color: #ffffff;
line-height: 96rpx;
text-align: center;
background: linear-gradient(268deg, #5393ff 0%, #3edec9 100%);
border-radius: 120rpx 120rpx 120rpx 120rpx;
}
}
}

78
src/ground/pages/changeTel/index.ts

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
const app = getApp<IAppOption>();
let timer = null as null | number;
Page({
data: {
mobile: "",
code: "",
codeText: "发送验证码",
},
onLoad() {},
getCode() {
if (timer) return;
const mobile = this.data.mobile;
if (!mobile) {
wx.showToast({
title: "手机号不能为空",
icon: "none",
});
return;
}
// 验证手机号
if (!/^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/.test(mobile)) {
wx.showToast({
title: "手机号格式不正确",
icon: "none",
});
return;
}
wx.ajax({
method: "POST",
url: "?r=zd/login/send-verify-code",
data: {
mobile,
},
}).then((res) => {
console.log(res);
wx.showToast({
icon: "none",
title: "验证码已发送~",
});
let time = 60;
timer = setInterval(() => {
time--;
this.setData({
codeText: time + "s后重新发送",
});
if (time <= 0) {
clearInterval(timer as number);
timer = null;
this.setData({
codeText: "发送验证码",
});
}
}, 1000);
});
},
handleSubmit() {
const { mobile, code } = this.data;
const { registrationSource, registChannel, regBusinessId } = app.globalData;
wx.ajax({
method: "POST",
url: "?r=zd/account/update-telephone",
data: {
mobile,
code,
registrationSource,
registChannel,
regBusinessId,
},
}).then((_res) => {
wx.navigateBack();
});
},
handleBack() {
wx.navigateBack();
},
});

33
src/ground/pages/changeTel/index.wxml

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
<navbar fixed custom-style="background:#fff">
<view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
修改手机号
</view>
</navbar>
<view class="page" style="padding-top: {{pageTop+28}}px;">
<view class="container">
<view class="form">
<view class="row">
<input
type="number"
model:value="{{mobile}}"
class="input"
placeholder-class="place-input"
placeholder="请输入手机号"
/>
</view>
<view class="row">
<input
type="number"
model:value="{{code}}"
class="input"
placeholder-class="place-input"
placeholder="请输入验证码"
/>
<view class="code" bind:tap="getCode">{{codeText}}</view>
</view>
</view>
<view class="submit" bind:tap="handleSubmit">修改手机号</view>
</view>
</view>

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

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
{
"navigationBarTitleText": "地推端",
"navigationStyle": "custom",
"usingComponents": {
"navbar": "../../../components/navbar/index",
"ground-tab-bar": "/ground/components/ground-tab-bar/index",
"ec-canvas": "/components/ec-canvas/ec-canvas"
}
}

345
src/ground/pages/home/index.scss

@ -0,0 +1,345 @@ @@ -0,0 +1,345 @@
page {
background: #f8fafa;
}
.page-switch {
color: #fff;
text-align: right;
font-family: 'Alibaba PuHuiTi 2.0';
font-size: 44rpx;
font-style: normal;
font-weight: 700;
line-height: 52rpx;
.arrow {
font-size: 28rpx;
}
}
.page {
min-height: 60vh;
.user {
margin: 48rpx 0 0 32rpx;
display: flex;
justify-content: space-between;
align-items: start;
gap: 20rpx;
.avatar {
flex-shrink: 0;
width: 102rpx;
height: 102rpx;
border-radius: 50%;
border: 1px solid #fff;
}
.wrap {
padding-top: 8rpx;
flex: 1;
.name {
font-size: 36rpx;
color: #ffffff;
}
.label {
margin-top: 8rpx;
padding: 0 12rpx;
display: inline-block;
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
border-radius: 6rpx;
background: linear-gradient(86deg, #fcd675 0%, #ffb700 100%);
}
}
.code {
padding: 16rpx 28rpx;
border: 1px solid #fff;
border-radius: 24rpx 0 0 24rpx;
border-right: none;
background: linear-gradient(193deg, #4a8dff 0%, #3bddc9 100%);
display: flex;
align-items: center;
gap: 8rpx;
.icon {
display: block;
width: 52rpx;
height: 52rpx;
}
.arrow {
font-size: 28rpx;
color: #ffffff;
}
}
}
.stat-data {
margin: 32rpx 32rpx 0;
padding: 32rpx;
background: linear-gradient(180deg, #e6efff 0%, #ffffff 8.19%, #ffffff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 1px solid #ffffff;
.s-header {
display: flex;
align-items: center;
justify-content: space-between;
.title {
font-size: 36rpx;
color: #1a2020;
font-weight: bold;
}
.tip {
font-size: 28rpx;
color: #b5b8bb;
}
}
.row1 {
margin-top: 32rpx;
display: flex;
background: linear-gradient(265deg, #5393ff 0%, #3edec9 100%);
border-radius: 16rpx;
.col {
flex: 1;
padding: 28rpx 0;
text-align: center;
.name {
font-size: 28rpx;
color: #ffffff;
}
.num {
margin-top: 8rpx;
font-size: 60rpx;
color: #ffffff;
}
}
.line {
margin: 28rpx 0;
width: 1px;
background-color: rgba(238, 245, 245, 0.35);
}
}
.card {
margin-top: 32rpx;
border: 1px solid #f2f6f8;
border-radius: 16rpx;
overflow: hidden;
.row2 {
display: flex;
background: linear-gradient(265deg, #5393ff 0%, #3edec9 100%);
border-radius: 16rpx 16rpx 0 0;
.col {
flex: 1;
padding: 28rpx 34rpx;
.name {
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #ffffff;
line-height: 48rpx;
}
}
.line {
width: 1px;
background-color: rgba(238, 245, 245, 0.35);
}
}
.row3 {
display: flex;
.col {
position: relative;
padding: 28rpx 34rpx;
flex: 1;
.name {
font-size: 24rpx;
color: #b5b8bb;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #1a2020;
line-height: 48rpx;
}
.line {
position: absolute;
left: 20rpx;
bottom: 0;
width: 168rpx;
height: 1px;
background-color: rgba(242, 246, 248, 0.47);
}
&:nth-of-type(2) {
borer: 1px solid #f2f6f8;
border-right: none;
border-left: none;
background-color: #f2f6f8;
}
}
}
}
}
.chat-data {
margin: 32rpx 32rpx;
padding: 32rpx;
background: linear-gradient(180deg, #e6efff 0%, #ffffff 8.19%, #ffffff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 1px solid #ffffff;
.c-header {
display: flex;
align-items: center;
justify-content: space-between;
.title {
font-size: 36rpx;
color: #1a2020;
font-weight: bold;
}
.switch-btns {
display: flex;
align-items: center;
gap: 24rpx;
.btn {
width: 148rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border-radius: 1748rpx 1748rpx 1748rpx 1748rpx;
border: 1px solid #edf2f2;
&.active {
background-color: #4a8dff;
color: #fff;
border-color: #4a8dff;
}
}
}
}
.c-options {
margin-top: 28rpx;
display: flex;
align-items: center;
justify-content: space-between;
.name {
font-size: 32rpx;
color: #1a2020;
font-weight: bold;
}
.picker {
color: #4a8dff;
font-size: 28rpx;
.p-content {
display: flex;
align-items: center;
.content {
color: #4a5555;
}
.icon {
padding: 20rpx 10rpx;
}
}
}
}
.card {
margin-top: 32rpx;
border: 1px solid #f2f6f8;
border-radius: 16rpx;
.row2 {
display: flex;
background: linear-gradient(265deg, #5393ff 0%, #3edec9 100%);
border-radius: 16rpx 16rpx 0 0;
.col {
flex: 1;
padding: 28rpx 34rpx;
.name {
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #ffffff;
line-height: 48rpx;
}
}
.line {
width: 1px;
background-color: rgba(238, 245, 245, 0.35);
}
}
.row3 {
display: flex;
.col {
position: relative;
padding: 28rpx 34rpx;
flex: 1;
.name {
font-size: 24rpx;
color: #b5b8bb;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #1a2020;
line-height: 48rpx;
}
.line {
position: absolute;
left: 20rpx;
bottom: 0;
width: 168rpx;
height: 1px;
background-color: rgba(242, 246, 248, 0.47);
}
&:nth-of-type(2) {
borer: 1px solid #f2f6f8;
border-right: none;
border-left: none;
background-color: #f2f6f8;
}
}
}
}
.chart-range {
margin-top: 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
.picker {
.p-content {
padding: 8rpx 38rpx;
display: flex;
align-items: center;
gap: 18rpx;
border-radius: 12rpx 12rpx 12rpx 12rpx;
border: 1px solid #f2f6f8;
.content {
font-size: 28rpx;
color: #b5b8bb;
}
.icon {
width: 32rpx;
height: 32rpx;
}
}
}
.line {
width: 24rpx;
height: 1px;
background-color: #f2f6f8;
}
}
.chart-container {
margin-top: 16rpx;
padding: 15rpx 30rpx;
width: 100%;
height: 546rpx;
box-sizing: border-box;
}
.more {
padding: 20rpx 0 0;
font-size: 28rpx;
color: #4a8dff;
text-align: center;
}
}
}

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

@ -0,0 +1,252 @@ @@ -0,0 +1,252 @@
import { color } from 'echarts'
const echarts = require('../../../components/ec-canvas/echarts.js')
Page({
data: {},
ecDataTrendComponent1_1: null as any,
ecDataTrendComponent2_1: null as any,
ecDataTrendComponent3_1: null as any,
async onLoad() {
const app = getApp<IAppOption>()
app.waitLogin().then(() => {
const list = [
{ StatMonth: '2026-01', MonthInvitePCount: 1 },
{ StatMonth: '2026-02', MonthInvitePCount: 2 },
]
this.initChartBar(list)
this.initChartLine(list, '#chart2_1', this.ecDataTrendComponent2_1)
this.initChartLine(list, '#chart3_1', this.ecDataTrendComponent3_1)
})
},
initChartBar(list: any[]) {
return new Promise((reslove) => {
this.ecDataTrendComponent1_1 = this.selectComponent('#chart1_1')
this.ecDataTrendComponent1_1.init((canvas, width, height, dpr) => {
const chart = echarts.init(canvas, null, {
width,
height,
devicePixelRatio: dpr, // new
})
canvas.setChart(chart)
const x: string[] = []
const y1: string[] = []
list.forEach((item) => {
x.push(item.StatMonth)
y1.push(item.MonthInvitePCount)
})
const option = {
legend: {
top: 0,
right: 0,
itemWidth: 8,
itemHeight: 8,
icon: 'rect',
lineStyle: {
width: '0',
},
textStyle: {
color: '#B5B8BB',
fontSize: '12',
},
},
grid: {
top: '10%',
left: '3%',
right: '4%',
bottom: '0',
containLabel: true,
},
xAxis: [
{
type: 'category',
axisTick: {
show: false,
},
axisLabel: {
fontSize: 10,
color: '#B5B8BB',
},
axisLine: {
show: false,
},
data: x,
},
],
yAxis: [
{
type: 'value',
minInterval: 1,
splitLine: {
lineStyle: {
type: 'dashed',
},
},
axisLabel: {
fontSize: 10,
color: '#B5B8BB',
formatter(value) {
return Math.abs(value)
},
},
},
],
series: [
{
name: '邀约患者数',
type: 'bar',
stack: 'a',
width: 4,
color: '#FED877',
barWidth: 12,
data: y1,
},
{
name: '跳转患者数',
type: 'bar',
stack: 'a',
color: '#4A8DFF',
barWidth: 12,
data: y1,
},
{
name: '入组患者数',
type: 'bar',
stack: 'a',
color: '#3ADDC8',
barWidth: 12,
data: y1,
},
],
dataZoom: {
type: 'inside', // 有type这个属性,滚动条在最下面,也可以不行,写y:36,这表示距离顶端36px,一般就是在图上面。
startValue: x.length - 6,
endValue: x.length - 1,
filterMode: 'none',
},
}
chart.setOption(option)
reslove(chart)
return chart
})
})
},
initChartLine(list: any[], name: string, componentName: string) {
return new Promise((reslove) => {
this[componentName] = this.selectComponent(name)
this[componentName].init((canvas, width, height, dpr) => {
const chart = echarts.init(canvas, null, {
width,
height,
devicePixelRatio: dpr, // new
})
canvas.setChart(chart)
const x: string[] = []
const y1: string[] = []
list.forEach((item) => {
x.push(item.StatMonth)
y1.push(item.MonthInvitePCount)
})
const option = {
legend: {
top: 0,
right: 0,
itemWidth: 8,
itemHeight: 8,
icon: 'rect',
lineStyle: {
width: '0',
},
textStyle: {
color: '#B5B8BB',
fontSize: '12',
},
data: [],
},
grid: {
top: '10%',
left: '3%',
right: '4%',
bottom: '0',
containLabel: true,
},
xAxis: [
{
type: 'category',
axisTick: {
show: false,
},
axisLabel: {
fontSize: 10,
color: '#B5B8BB',
},
axisLine: {
show: false,
},
data: x,
},
],
yAxis: [
{
type: 'value',
minInterval: 1,
splitLine: {
lineStyle: {
type: 'dashed',
},
},
axisLabel: {
fontSize: 10,
color: '#B5B8BB',
formatter(value) {
return Math.abs(value)
},
},
},
],
series: [
{
name: '邀约患者数',
type: 'line',
stack: 'a',
width: 4,
color: '#FED877',
barWidth: 12,
data: y1,
smooth: 0.5,
label: {
show: true,
position: 'top',
fontSize: 12,
color: '#B5B8BB',
},
},
],
dataZoom: {
type: 'inside', // 有type这个属性,滚动条在最下面,也可以不行,写y:36,这表示距离顶端36px,一般就是在图上面。
startValue: x.length - 6,
endValue: x.length - 1,
filterMode: 'none',
},
}
chart.setOption(option)
reslove(chart)
return chart
})
})
},
handleInvite() {
wx.navigateTo({
url: '/ground/pages/invite/index',
})
},
handleInfo() {
wx.navigateTo({
url: '/ground/pages/stat/index',
})
},
})

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

@ -0,0 +1,273 @@ @@ -0,0 +1,273 @@
<navbar fixed custom-style="background: {{background}};">
<view class="page-switch" slot="left" style="color: {{background=='transparent'?'#fff':'#4A8DFF'}};">
特诺雅
<van-icon class="arrow" name="arrow-down" />
</view>
</navbar>
<view
class="page"
style="background:url('/images/bg1.png') no-repeat top center/100% 602rpx; padding-top: {{pageTop+20}}px"
>
<view class="user">
<image class="avatar" src="/images/cache/a1.png"></image>
<view class="wrap">
<view class="name">刘平安</view>
<view class="label">邀约专员</view>
</view>
<view class="code" bind:tap="handleInvite">
<image class="icon" src="/images/icon7.png"></image>
<van-icon class="arrow" name="arrow" />
</view>
</view>
<view class="stat-data">
<view class="s-header">
<view class="title">累计邀约</view>
<view class="tip">截止昨日数据</view>
</view>
<view class="row1">
<view class="col">
<view class="name">药店数</view>
<view class="num">400</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">药店数</view>
<view class="num">400</view>
</view>
</view>
<view class="card">
<view class="row2">
<view class="col">
<view class="name">邀约患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">跳转患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">入组患者数</view>
<view class="num">750</view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">入组患者数</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">300</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
</view>
</view>
</view>
<view class="chat-data">
<view class="c-header">
<view class="title">邀约患者统计</view>
<view class="switch-btns">
<view class="btn">月统计</view>
<view class="btn active">日统计</view>
</view>
</view>
<view class="c-options">
<view class="name">日统计</view>
<picker class="picker">
<view class="p-content">
<van-icon class="icon" name="arrow-left" />
<view class="content">2025/02/26</view>
<van-icon class="icon" name="arrow" />
</view>
</picker>
</view>
<view class="card">
<view class="row2">
<view class="col">
<view class="name">邀约患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">跳转患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">入组患者数</view>
<view class="num">750</view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">入组患者数</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">300</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
</view>
</view>
<view class="chart-range">
<picker class="picker" mode="date" end="{{end}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" start="{{satrt}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
</view>
<view class="chart-container">
<ec-canvas id="chart1_1" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>
</view>
<view class="more">
查看明细
<van-icon name="arrow" />
</view>
</view>
<view class="chat-data">
<view class="c-header">
<view class="title">邀约药师数统计</view>
<view class="switch-btns">
<view class="btn">月统计</view>
<view class="btn active">日统计</view>
</view>
</view>
<view class="chart-range">
<picker class="picker" mode="date" end="{{end}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" start="{{satrt}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
</view>
<view class="chart-container">
<ec-canvas id="chart2_1" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>
</view>
<view class="more">
查看明细
<van-icon name="arrow" />
</view>
</view>
<view class="chat-data">
<view class="c-header">
<view class="title">邀约药店统计</view>
<view class="switch-btns">
<view class="btn">月统计</view>
<view class="btn active">日统计</view>
</view>
</view>
<view class="chart-range">
<picker class="picker" mode="date" end="{{end}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" start="{{satrt}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
</view>
<view class="chart-container">
<ec-canvas id="chart3_1" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>
</view>
<view class="more" bind:tap="handleInfo">
查看明细
<van-icon name="arrow" />
</view>
</view>
</view>
<ground-tab-bar active="{{ 0 }}"></ground-tab-bar>

8
src/ground/pages/invite/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"login":"/components/login/index"
}
}

101
src/ground/pages/invite/index.scss

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
.page-title {
display: flex;
align-items: center;
gap: 22rpx;
font-size: 36rpx;
color: #ffffff;
}
.page {
height: 100vh;
box-sizing: border-box;
.page-container {
margin: 0 40rpx;
padding: 32rpx 48rpx;
height: 960rpx;
box-sizing: border-box;
.user {
display: flex;
gap: 24rpx;
height: 200rpx;
.avatar {
width: 126rpx;
height: 126rpx;
border: 1px solid #fff;
border-radius: 50%;
}
.wrap {
padding-top: 16rpx;
.nickname {
font-size: 36rpx;
color: #1a2020;
font-weight: bold;
}
.label {
display: inline-block;
margin-top: 8rpx;
padding: 0 12rpx;
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
border-radius: 6rpx;
background: linear-gradient(86deg, #fcd675 0%, #ffb700 100%);
}
}
}
.title {
font-size: 40rpx;
color: #4a8dff;
text-align: center;
}
.brand {
margin-top: 12rpx;
.name {
font-size: 44rpx;
color: #4a8dff;
font-weight: bold;
text-align: center;
}
.bg {
margin: -12rpx auto 0;
width: 140rpx;
height: 16rpx;
background: linear-gradient(90deg, #fdd260 0%, rgba(253, 210, 96, 0.07) 100%);
border-radius: 0rpx 0rpx 0rpx 0rpx;
}
}
.code-wrap {
margin: 64rpx auto 0;
padding: 10rpx;
width: 328rpx;
height: 328rpx;
border-radius: 50%;
border: 10rpx solid #ecf3ff;
.code {
display: block;
border-radius: 50%;
width: 100%;
height: 100%;
}
}
.tip {
margin: 52rpx auto 0;
width: 340rpx;
height: 76rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 10rpx;
font-size: 40rpx;
color: #ffffff;
background: linear-gradient(265deg, #5393ff 0%, #3edec9 100%);
border-radius: 92rpx 92rpx 92rpx 92rpx;
.dot{
width: 10rpx;
height: 10rpx;
border-radius: 50%;
background-color: #fff;
}
}
}
}

11
src/ground/pages/invite/index.ts

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleBack() {
wx.navigateBack()
},
})
export {}

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

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
<navbar fixed custom-style="background:transparent">
<view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
专属邀约码
</view>
</navbar>
<view
class="page"
style="background: url('/images/bg5.png') no-repeat top center/100% 100vh;padding-top: {{pageTop+87}}px;"
>
<view class="page-container" style="background: url('/images/bg6.png') no-repeat top center/100% 964rpx">
<view class="user">
<image class="avatar" src="/images/cache/a1.png" mode="aspectFill"></image>
<view class="wrap">
<view class="nickname">刘平安</view>
<view class="label">邀约专员</view>
</view>
</view>
<view class="title">邀请您加入健康管理项目</view>
<view class="brand">
<view class="name">特诺雅</view>
<view class="bg"></view>
</view>
<view class="code-wrap">
<image class="code" src="/images/cache/c1.png" show-menu-by-longpress></image>
</view>
<view class="tip">
<view class="dot"></view>
扫码立即加入
<view class="dot"></view>
</view>
</view>
</view>

9
src/ground/pages/login/index.json

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
{
"navigationBarTitleText": "登录",
"navigationStyle": "custom",
"usingComponents": {
"van-divider": "@vant/weapp/divider/index",
"van-icon": "@vant/weapp/icon/index",
"navbar": "/components/navbar/index"
}
}

119
src/ground/pages/login/index.scss

@ -0,0 +1,119 @@ @@ -0,0 +1,119 @@
page {
background-color: #f8fafa;
}
.page {
min-height: 100vh;
padding: 460rpx 0 80rpx 0;
box-sizing: border-box;
.page-title {
margin: 0 40rpx;
width: 614rpx;
height: 184rpx;
}
.container {
padding: 0 40rpx;
.content {
margin-top: 40rpx;
font-size: 32rpx;
color: #1a2020;
line-height: 48rpx;
.link {
color: #4a8dff;
}
}
}
.phone {
margin: 54rpx 40rpx 0;
padding: 24rpx 20rpx;
border-radius: 64rpx;
background: linear-gradient(268deg, #5393ff 0%, #3edec9 100%);
font-size: 32rpx;
color: rgba(255, 255, 255, 1);
line-height: 1;
&::after {
border: none;
outline: none;
}
}
.divider {
margin: 48rpx auto 0;
width: 338rpx;
}
.tel-code {
margin: 32rpx auto 0;
width: 278rpx;
height: 52rpx;
display: flex;
justify-content: center;
font-size: 32rpx;
color: #1a2020;
}
.form {
margin: 42rpx 40rpx 0;
padding: 48rpx 32rpx;
border-radius: 24rpx;
background-color: #fff;
.row {
margin-bottom: 32rpx;
display: flex;
justify-content: space-between;
border-radius: 12rpx;
background: #f8fafa;
.input {
flex: 1;
padding: 22rpx 32rpx;
height: 40rpx;
font-size: 32rpx;
color: #000;
}
.input-placeholade {
color: #94a3a3;
}
.code {
margin-left: 24rpx;
flex-shrink: 0;
width: 262rpx;
border-radius: 24rpx;
font-size: 32rpx;
color: #4a8dff;
display: flex;
align-items: center;
justify-content: center;
}
}
.submit {
margin-top: 32px;
padding: 24rpx 20rpx;
background: linear-gradient(268deg, #5393ff 0%, #3edec9 100%);
border-radius: 64rpx;
font-size: 32rpx;
color: #ffffff;
text-align: center;
line-height: 1;
}
}
.check {
margin: 68rpx 50rpx 0;
display: flex;
line-height: 60rpx;
color: rgba(32, 33, 33, 1);
.icon {
margin-top: 14rpx;
margin-right: 10rpx;
flex-shrink: 0;
width: 32rpx;
height: 32rpx;
}
.link {
color: #4a8dff;
}
}
.partient {
margin-top: 58rpx;
font-size: 32rpx;
color: rgba(161, 164, 172, 1);
display: flex;
align-items: center;
justify-content: center;
}
}

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

@ -0,0 +1,154 @@ @@ -0,0 +1,154 @@
const app = getApp<IAppOption>()
let timer = null as null | number
Page({
data: {
mobile: '',
code: '',
codeText: '发送验证码',
back: false,
showForm: false,
check: false,
},
onLoad(option) {
if (option.back) {
this.setData({
back: true,
})
}
},
getCode() {
if (timer) return
const mobile = this.data.mobile
if (!mobile) {
wx.showToast({
title: '手机号不能为空',
icon: 'none',
})
return
}
// 验证手机号
if (!/^1[3-9,]\d{9}$/.test(mobile)) {
wx.showToast({
title: '手机号格式不正确',
icon: 'none',
})
return
}
wx.ajax({
method: 'POST',
url: '?r=zd/login/send-verify-code',
data: {
mobile,
},
}).then((_res) => {
wx.showToast({
icon: 'none',
title: '验证码已发送~',
})
let time = 60
timer = setInterval(() => {
time--
this.setData({
codeText: `${time}s后重新发送`,
})
if (time <= 0) {
clearInterval(timer as number)
timer = null
this.setData({
codeText: '发送验证码',
})
}
}, 1000)
})
},
handleSubmit() {
if (!this.data.mobile) {
wx.showToast({
icon: 'none',
title: '请输入手机号',
})
return
}
if (!this.data.code) {
wx.showToast({
icon: 'none',
title: '请输入验证码',
})
return
}
if (!this.data.check) {
wx.showToast({
icon: 'none',
title: '请同意用户协议',
})
return
}
wx.ajax({
method: 'POST',
url: '?r=zd/doctor/login/reg-login',
data: {
mobile: this.data.mobile,
code: this.data.code,
},
}).then((_res) => {
this.submitCallback()
})
},
handleWxSubmit(e: WechatMiniprogram.CustomEvent) {
if (!this.data.check) {
wx.showToast({
icon: 'none',
title: '请同意用户协议',
})
return
}
wx.reLaunch({
url: '/ground/pages/home/index',
})
return
const { iv, encryptedData } = e.detail
if (iv && encryptedData) {
wx.ajax({
method: 'POST',
url: '?r=zd/doctor/login/wx-reg-login',
data: {
iv: encodeURIComponent(iv),
encryptedData: encodeURIComponent(encryptedData),
},
}).then((_res) => {
this.submitCallback()
})
}
},
submitCallback() {
app.globalData.loginType = 2
app.globalData.isLogin = true
wx.reLaunch({
url: '/doctor/pages/d_home/index',
})
},
handlePatient() {
wx.redirectTo({
url: '/pages/login/index',
})
},
handleTelCode() {
this.setData({
showForm: !this.data.showForm,
})
},
handleLink() {
wx.navigateTo({
url: '/doc/pages/doc1/index',
})
},
handleCheck() {
this.setData({
check: !this.data.check,
})
},
handleBack() {
wx.navigateBack()
},
})

55
src/ground/pages/login/index.wxml

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
<navbar fixed custom-style="background:transparent" back></navbar>
<view
class="page"
style="background: url('/images/bg4.png') no-repeat top center / 100% 710rpx;padding-top: {{pageTop+80}}px;"
>
<image class="page-title" src="/images/content1.png"></image>
<view class="container">
<view class="content">
在您加入华观健康之前,请您阅读并充分理解
<text class="link" bind:tap="handleLink">《个人信息及隐私保护政策》</text>
了解您的权益及相关数据处理方法,我们将严格按照法律法规及
<text class="link" bind:tap="handleLink">《个人信息及隐私保护政策》</text>
的相关规定保证您的个人信息不受侵犯。
</view>
</view>
<button wx:if="{{check}}" class="phone" open-type="getPhoneNumber" bindgetphonenumber="handleWxSubmit">
手机号快捷登录
</button>
<button wx:else class="phone" bind:tap="handleWxSubmit">手机号快捷登录</button>
<view class="divider">
<van-divider contentPosition="center" textColor="rgba(148,163,163,0.5)">或者</van-divider>
</view>
<view class="tel-code" bind:tap="handleTelCode">使用手机号验证码</view>
<view class="form" wx:if="{{showForm}}">
<view class="row">
<input
type="number"
model:value="{{mobile}}"
class="input"
placeholder-class="input-placeholade"
placeholder="请输入手机号"
/>
</view>
<view class="row">
<input
type="number"
model:value="{{code}}"
class="input"
placeholder-class="input-placeholade"
placeholder="请输入验证码"
/>
<view class="code" bind:tap="getCode">{{codeText}}</view>
</view>
<view class="submit" bind:tap="handleSubmit">立即加入</view>
</view>
<view class="check">
<image wx:if="{{check}}" class="icon" src="/images/icon11.png" bind:tap="handleCheck"></image>
<image wx:else class="icon" src="/images/icon12.png" bind:tap="handleCheck"></image>
<view class="p">
我特此同意依照此
<text class="link" bind:tap="handleLink">《隐私协议保护政策》</text>
规定收集我的个人敏感信息
</view>
</view>
</view>

8
src/ground/pages/my/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationBarTitleText": "地推端",
"navigationStyle": "custom",
"usingComponents": {
"navbar": "../../../components/navbar/index",
"ground-tab-bar": "/ground/components/ground-tab-bar/index"
}
}

95
src/ground/pages/my/index.scss

@ -0,0 +1,95 @@ @@ -0,0 +1,95 @@
page {
background: #F8FAFA;
}
.page {
min-height: 60vh;
.user {
position: relative;
margin: 100rpx 32rpx 0;
padding: 112rpx 32rpx 32rpx;
background: linear-gradient(0deg, rgba(255, 255, 255, 0.42) 0%, #ffffff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 2rpx solid #ffffff;
backdrop-filter: blur(16rpx);
.avatar {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
.a-img {
width: 186rpx;
height: 186rpx;
border-radius: 50%;
border: 1px solid #fff;
}
.edit {
position: absolute;
bottom: 16rpx;
right: 16rpx;
width: 34rpx;
height: 34rpx;
border-radius: 50%;
border: 1px solid #fff;
background-color: #4a8dff;
display: flex;
align-items: center;
justify-content: center;
.icon {
width: 20rpx;
height: 20rpx;
}
}
}
.name {
font-size: 40rpx;
color: #1a2020;
font-weight: bold;
text-align: center;
}
.phone {
margin-top: 12rpx;
font-size: 32rpx;
color: #b5b8bb;
text-align: center;
}
}
.list {
margin: 32rpx 32rpx 0;
border-radius: 24rpx;
background-color: #fff;
.list-item {
padding: 34rpx 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 24rpx;
.icon {
flex-shrink: 0;
width: 44rpx;
height: 44rpx;
}
.title {
flex: 1;
font-size: 32rpx;
color: #1a2020;
line-height: 48rpx;
}
.arrow {
font-size: 36rpx;
color: #94a3a3;
}
}
}
.exit {
margin: 64rpx 32rpx 0;
font-size: 32rpx;
color: #1a2020;
height: 96rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
border-radius: 24rpx;
}
}

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

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleNickname() {
wx.navigateTo({
url: '/ground/pages/changeNickname/index',
})
},
handleTel() {
wx.navigateTo({
url: '/ground/pages/changeTel/index',
})
},
handleInvite() {
wx.navigateTo({
url: '/ground/pages/stat/index',
})
},
})
export {}

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

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
<navbar fixed custom-style="background: transparent;"></navbar>
<view
class="page"
style="background:url('/images/bg1.png') no-repeat top center/100% 602rpx; padding-top: {{pageTop+20}}px"
>
<view class="user">
<view class="avatar">
<image class="a-img" src="/images/cache/a1.png"></image>
<view class="edit">
<image class="icon" src="/images/icon3.png"></image>
</view>
</view>
<view class="name">刘平安</view>
<view class="phone">13800138000</view>
</view>
<view class="list">
<view class="list-item" bind:tap="handleNickname">
<image class="icon" src="/images/icon4.png"></image>
<view class="title">修改姓名</view>
<van-icon class="arrow" name="arrow" />
</view>
<view class="list-item" bind:tap="handleTel">
<image class="icon" src="/images/icon5.png"></image>
<view class="title">修改手机号</view>
<van-icon class="arrow" name="arrow" />
</view>
<view class="list-item" bind:tap="handleInvite">
<image class="icon" src="/images/icon6.png"></image>
<view class="title">我的邀约码</view>
<van-icon class="arrow" name="arrow" />
</view>
</view>
<view class="exit">退出登录</view>
</view>
<ground-tab-bar active="{{ 2 }}"></ground-tab-bar>

8
src/ground/pages/pharmacist/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationBarTitleText": "地推端",
"navigationStyle": "custom",
"usingComponents": {
"navbar": "../../../components/navbar/index",
"ground-tab-bar": "/ground/components/ground-tab-bar/index"
}
}

172
src/ground/pages/pharmacist/index.scss

@ -0,0 +1,172 @@ @@ -0,0 +1,172 @@
page {
background: #f8fafa;
}
.page-switch {
color: #4a8dff;
font-size: 40rpx;
font-weight: 700;
line-height: 44rpx;
.arrow {
font-size: 28rpx;
color: #b5b8bb;
}
}
.page {
min-height: 60vh;
.page-header {
padding: 16rpx 32rpx;
background-color: #fff;
box-shadow: 0rpx 16rpx 40rpx 0rpx rgba(26, 32, 32, 0.04);
.search {
padding: 0 24rpx;
display: flex;
align-items: center;
background: #f8fafa;
border-radius: 24rpx 24rpx 24rpx 24rpx;
gap: 8rpx;
.icon {
width: 48rpx;
height: 48rpx;
}
.input {
height: 80rpx;
font-size: 32rpx;
color: #1a2020;
}
.place-input {
color: #b5b8bb;
}
}
.options {
margin-top: 8rpx;
display: flex;
align-items: center;
justify-content: space-between;
.date {
padding: 24rpx 22rpx;
display: flex;
align-items: center;
font-size: 32rpx;
color: #1a2020;
.icon {
width: 48rpx;
height: 48rpx;
}
}
.total {
font-size: 32rpx;
color: #1a2020;
.num {
color: #4a8dff;
}
}
}
}
.page-container {
padding: 32rpx;
.pharmacist-card {
margin-bottom: 32rpx;
padding: 32rpx 32rpx 0;
background: linear-gradient(0deg, #ffffff 0%, #ffffff 73.04%, #eff5ff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 2rpx solid #ffffff;
/* 药师基本信息 */
.user {
display: flex;
gap: 20rpx;
.avatar {
flex-shrink: 0;
width: 116rpx;
height: 116rpx;
border-radius: 50%;
}
.wrap {
.pharmacist-info {
margin-bottom: 12rpx;
.pharmacist-name {
font-weight: 600;
font-size: 36rpx;
color: #1a2020;
margin-right: 12rpx;
}
.pharmacist-phone {
font-family: 'PingFang SC';
font-size: 32rpx;
color: #b5b8bb;
line-height: 36rpx;
}
}
.pharmacy-info {
.pharmacy-name {
font-size: 28rpx;
color: #b5b8bb;
}
}
}
}
/* 数据统计 */
.data-stats {
margin-top: 24rpx;
padding: 32rpx 10rpx;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #fff;
background-color: #f8fafa;
.stat-item {
flex: 1;
text-align: center;
.stat-value {
display: flex;
justify-content: center;
align-items: baseline;
.stat-number {
font-weight: 600;
font-size: 48rpx;
color: #4a8dff;
}
.stat-unit {
font-size: 24rpx;
color: #b5b8bb;
margin-left: 8rpx;
}
}
.stat-label {
margin-top: 12rpx;
font-size: 24rpx;
color: #1a2020;
display: block;
}
}
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
.bind-time {
padding: 24rpx 0;
font-size: 28rpx;
color: #b5b8bb;
}
.detail-btn {
padding: 24rpx 0;
font-size: 28rpx;
color: #4a8dff;
}
}
}
}
}

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

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleInfo() {
wx.navigateTo({
url: '/ground/pages/stat/index',
})
},
})
export {}

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

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
<navbar fixed custom-style="background: #fff;">
<view class="page-switch" slot="left">
特诺雅
<van-icon class="arrow" name="arrow-down" />
</view>
</navbar>
<view class="page" style="padding-top:{{pageTop}}px">
<view class="page-header">
<view class="search">
<image class="icon" src="/images/icon1.png"></image>
<input
type="text"
placeholder="搜索药店名/药师姓名"
class="input"
placeholder-class="place-input"
confirm-type="search"
bindconfirm="handleSearch"
/>
</view>
<view class="options">
<picker class="picker" mode="date">
<view class="date">
时间筛选
<image class="icon" src="/images/icon2.png"></image>
</view>
</picker>
<view class="total">
已邀约总人数:
<text class="num">28</text>
</view>
</view>
</view>
<view class="page-container">
<!-- 药师信息卡片 -->
<view class="pharmacist-card">
<!-- 药师基本信息 -->
<view class="user">
<image class="avatar" src="/images/cache/a2.png"></image>
<view class="wrap">
<view class="pharmacist-info">
<text class="pharmacist-name">张药师</text>
<text class="pharmacist-phone">13800138000</text>
</view>
<view class="pharmacy-info">
<text class="pharmacy-name">康泰大药房(人民路店)</text>
</view>
</view>
</view>
<!-- 数据统计 -->
<view class="data-stats">
<view class="stat-item">
<view class="stat-value">
<text class="stat-number">750</text>
<text class="stat-unit">人</text>
</view>
<text class="stat-label">邀约患者总数</text>
</view>
<view class="stat-item">
<view class="stat-value">
<text class="stat-number">700</text>
<text class="stat-unit">人</text>
</view>
<text class="stat-label">跳转患者数</text>
</view>
<view class="stat-item">
<view class="stat-value">
<text class="stat-number">700</text>
<text class="stat-unit">人</text>
</view>
<text class="stat-label">入组患者数</text>
</view>
</view>
<view class="card-footer">
<text class="bind-time">绑定时间:2026-01-10</text>
<view class="detail-btn" bind:tap="handleInfo">数据详情</view>
</view>
</view>
</view>
</view>
<ground-tab-bar active="{{ 1 }}"></ground-tab-bar>

8
src/ground/pages/stat/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationStyle": "custom",
"usingComponents": {
"popup": "/components/popup/index",
"navbar": "/components/navbar/index",
"login":"/components/login/index"
}
}

199
src/ground/pages/stat/index.scss

@ -0,0 +1,199 @@ @@ -0,0 +1,199 @@
page {
background-color: #f8fafa;
}
.page-title {
display: flex;
align-items: center;
gap: 22rpx;
font-size: 36rpx;
color: #1a2020;
}
.page {
.page-header {
position: sticky;
left: 0;
top: 0;
padding: 32rpx;
background-color: #fff;
.chart-range {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
.picker {
flex: 1;
.p-content {
padding: 8rpx 38rpx;
display: flex;
align-items: center;
gap: 18rpx;
border-radius: 12rpx 12rpx 12rpx 12rpx;
border: 1px solid #f2f6f8;
.content {
font-size: 28rpx;
color: #b5b8bb;
}
.icon {
width: 32rpx;
height: 32rpx;
}
}
}
.line {
width: 24rpx;
height: 1px;
background-color: #f2f6f8;
}
}
}
.stat-card {
margin: 24rpx 32rpx 0;
padding: 32rpx 0;
background-color: #fff;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
.col {
flex: 1;
text-align: center;
.num {
font-size: 48rpx;
color: #4a8dff;
font-weight: bold;
line-height: 56rpx;
.sub {
font-size: 24rpx;
color: #b5b8bb;
font-weight: normal;
}
}
.title {
margin-top: 6rpx;
font-size: 24rpx;
color: #1a2020;
line-height: 36rpx;
}
}
}
.stat-list {
margin: 0 32rpx 0;
.module {
display: flex;
gap: 10rpx;
.aside {
display: flex;
align-items: center;
flex-direction: column;
gap: 14rpx;
.line-top {
flex-shrink: 0;
height: 40rpx;
width: 0;
border-right: 1px dashed #4a8dff;
}
.dot {
flex-shrink: 0;
width: 24rpx;
height: 24rpx;
background-color: rgba(74, 141, 255, 0.18);
border-radius: 50%;
&::after {
margin: 4rpx auto;
content: '';
display: block;
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background-color: #4a8dff;
}
}
.line-bottom {
flex: 1;
height: 40rpx;
width: 0;
border-right: 1px dashed #4a8dff;
}
}
.m-container {
padding-top: 46rpx;
.date {
font-size: 32rpx;
color: #4a5555;
}
.card {
margin-top: 24rpx;
border: 1px solid #f2f6f8;
border-radius: 16rpx;
overflow: hidden;
.row2 {
display: flex;
background: linear-gradient(265deg, #5393ff 0%, #3edec9 100%);
border-radius: 16rpx 16rpx 0 0;
.col {
flex: 1;
padding: 28rpx 34rpx;
.name {
font-size: 28rpx;
color: #ffffff;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #ffffff;
line-height: 48rpx;
}
}
.line {
width: 1px;
background-color: rgba(238, 245, 245, 0.35);
}
}
.row3 {
display: flex;
.col {
position: relative;
padding: 28rpx 34rpx;
flex: 1;
background-color: #fff;
.name {
font-size: 24rpx;
color: #b5b8bb;
line-height: 36rpx;
}
.num {
margin-top: 8rpx;
font-size: 40rpx;
color: #1a2020;
line-height: 48rpx;
}
.line {
position: absolute;
left: 20rpx;
bottom: 0;
width: 168rpx;
height: 1px;
background-color: rgba(242, 246, 248, 0.47);
}
&:nth-of-type(2) {
borer: 1px solid #eef5f5;
border-right: none;
border-left: none;
background-color: #f8fafa;
}
}
}
}
}
&:first-of-type {
.aside {
.line-top {
opacity: 0;
}
}
}
}
}
}

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

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
const _app = getApp<IAppOption>()
Page({
data: {},
onLoad() {},
handleBack() {
wx.navigateBack()
},
})
export {}

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

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
<navbar fixed custom-style="background:#fff">
<view slot="left" class="page-title">
<van-icon class="back" slot="left" name="arrow-left" bind:tap="handleBack" />
专属邀约码
</view>
</navbar>
<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}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
<view class="line"></view>
<picker class="picker" mode="date" start="{{satrt}}">
<view class="p-content">
<view class="content">2025/02/26</view>
<image class="icon" src="/images/icon8.png"></image>
</view>
</picker>
</view>
</view>
<view class="stat-card">
<view class="col">
<view class="num">
1893
<text class="sub">人</text>
</view>
<view class="title">邀约患者总数</view>
</view>
<view class="col">
<view class="num">
1893
<text class="sub">人</text>
</view>
<view class="title">跳转患者数</view>
</view>
<view class="col">
<view class="num">
1893
<text class="sub">人</text>
</view>
<view class="title">跳转患者数</view>
</view>
</view>
<view class="stat-list">
<view class="module">
<view class="aside">
<view class="line-top"></view>
<view class="dot"></view>
<view class="line-bottom"></view>
</view>
<view class="m-container">
<view class="date">2025/02/26</view>
<view class="card">
<view class="row2">
<view class="col">
<view class="name">邀约患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">跳转患者数</view>
<view class="num">750</view>
</view>
<view class="line"></view>
<view class="col">
<view class="name">入组患者数</view>
<view class="num">750</view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">入组患者数</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">斑块状银屑病</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">300</view>
<view class="line"></view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">溃疡性结肠炎</view>
<view class="num">280</view>
<view class="line"></view>
</view>
</view>
<view class="row3">
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">300</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
<view class="col">
<view class="name">克罗恩病</view>
<view class="num">280</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>

BIN
src/images/bg1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 KiB

BIN
src/images/bg2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 KiB

BIN
src/images/bg3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 675 KiB

BIN
src/images/bg4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save