├── miniprogram ├── pages │ ├── doctor │ │ ├── doctor.json │ │ ├── consulting │ │ │ ├── consulting.json │ │ │ ├── consulting.wxss │ │ │ ├── consulting.wxml │ │ │ └── consulting.js │ │ ├── doctor.js │ │ ├── doctor.wxml │ │ └── doctor.wxss │ ├── index │ │ ├── index.json │ │ ├── index.wxss │ │ ├── index.js │ │ └── index.wxml │ ├── search │ │ ├── search.json │ │ ├── search.wxml │ │ ├── search.wxss │ │ └── search.js │ ├── account │ │ ├── account.json │ │ ├── family │ │ │ ├── family.json │ │ │ ├── family.wxml │ │ │ ├── family.js │ │ │ └── family.wxss │ │ ├── login │ │ │ ├── login.json │ │ │ ├── login.wxml │ │ │ ├── login.js │ │ │ └── login.wxss │ │ ├── register │ │ │ ├── register.json │ │ │ ├── register.wxss │ │ │ ├── register.js │ │ │ └── register.wxml │ │ ├── answer │ │ │ ├── answer.json │ │ │ ├── answer.wxml │ │ │ ├── answer.wxss │ │ │ └── answer.js │ │ ├── askList │ │ │ ├── askList.json │ │ │ ├── askList.wxml │ │ │ ├── askList.js │ │ │ └── askList.wxss │ │ ├── account.wxss │ │ ├── account.wxml │ │ └── account.js │ └── upload │ │ ├── page │ │ ├── page.json │ │ ├── page.wxml │ │ ├── page.wxss │ │ └── page.js │ │ └── idCard │ │ ├── idcard.json │ │ ├── idcard.wxss │ │ ├── idcard.wxml │ │ └── idcard.js ├── component │ └── Toast │ │ ├── Toast.json │ │ ├── Toast.wxml │ │ ├── Toast.wxss │ │ └── Toast.js ├── images │ ├── yn.jpg │ ├── beta.jpg │ ├── logo.png │ ├── logo2.jpg │ ├── avatar_0.jpg │ ├── avatar_1.jpg │ ├── account_bg.png │ ├── home_home.png │ ├── tagbar │ │ ├── me.png │ │ ├── me_on.png │ │ ├── consulting.png │ │ └── consulting_on.png │ └── avatar_user_0.png ├── app.json ├── app.wxss └── app.js ├── text.txt ├── cloud └── getOpenId │ ├── index.js │ └── package.json ├── png ├── dc.jpg ├── msg.jpg ├── card.jpg ├── home.jpg ├── msg2.jpg ├── msg3.jpg ├── user.jpg └── register.jpg ├── project.config.json └── README.md /miniprogram/pages/doctor/doctor.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/index/index.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/search/search.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/account/account.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/upload/page/page.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/account/family/family.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/account/login/login.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/upload/idCard/idcard.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/account/register/register.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/doctor/consulting/consulting.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /miniprogram/pages/upload/page/page.wxml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /text.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/text.txt -------------------------------------------------------------------------------- /cloud/getOpenId/index.js: -------------------------------------------------------------------------------- 1 | exports.main = async (event, context) => event.userInfo; -------------------------------------------------------------------------------- /miniprogram/pages/account/answer/answer.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /miniprogram/pages/account/askList/askList.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /png/dc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/png/dc.jpg -------------------------------------------------------------------------------- /png/msg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/png/msg.jpg -------------------------------------------------------------------------------- /miniprogram/pages/upload/page/page.wxss: -------------------------------------------------------------------------------- 1 | /* miniprogram/pages/upload/page/page.wxss */ -------------------------------------------------------------------------------- /png/card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/png/card.jpg -------------------------------------------------------------------------------- /png/home.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/png/home.jpg -------------------------------------------------------------------------------- /png/msg2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/png/msg2.jpg -------------------------------------------------------------------------------- /png/msg3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/png/msg3.jpg -------------------------------------------------------------------------------- /png/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/png/user.jpg -------------------------------------------------------------------------------- /png/register.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/png/register.jpg -------------------------------------------------------------------------------- /miniprogram/component/Toast/Toast.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /miniprogram/pages/doctor/consulting/consulting.wxss: -------------------------------------------------------------------------------- 1 | /* miniprogram/pages/doctor/consulting/consulting.wxss */ -------------------------------------------------------------------------------- /miniprogram/images/yn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/yn.jpg -------------------------------------------------------------------------------- /miniprogram/images/beta.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/beta.jpg -------------------------------------------------------------------------------- /miniprogram/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/logo.png -------------------------------------------------------------------------------- /miniprogram/images/logo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/logo2.jpg -------------------------------------------------------------------------------- /miniprogram/images/avatar_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/avatar_0.jpg -------------------------------------------------------------------------------- /miniprogram/images/avatar_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/avatar_1.jpg -------------------------------------------------------------------------------- /miniprogram/images/account_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/account_bg.png -------------------------------------------------------------------------------- /miniprogram/images/home_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/home_home.png -------------------------------------------------------------------------------- /miniprogram/images/tagbar/me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/tagbar/me.png -------------------------------------------------------------------------------- /miniprogram/images/avatar_user_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/avatar_user_0.png -------------------------------------------------------------------------------- /miniprogram/images/tagbar/me_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/tagbar/me_on.png -------------------------------------------------------------------------------- /miniprogram/images/tagbar/consulting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/tagbar/consulting.png -------------------------------------------------------------------------------- /miniprogram/images/tagbar/consulting_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shi-lai-mu/hospital-wxapp/HEAD/miniprogram/images/tagbar/consulting_on.png -------------------------------------------------------------------------------- /miniprogram/pages/doctor/consulting/consulting.wxml: -------------------------------------------------------------------------------- 1 | 2 | miniprogram/pages/doctor/consulting/consulting.wxml 3 | -------------------------------------------------------------------------------- /miniprogram/pages/upload/page/page.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | 3 | Page({ 4 | 5 | data: { 6 | 7 | }, 8 | 9 | onLoad: function (options) { 10 | 11 | app.bar({ 12 | title: "空页面", 13 | bgColor: "#b5cfff" 14 | }); 15 | 16 | }, 17 | 18 | }) -------------------------------------------------------------------------------- /cloud/getOpenId/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "getOpenId", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "wx-server-sdk": "latest" 13 | } 14 | } -------------------------------------------------------------------------------- /miniprogram/component/Toast/Toast.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{msg._text}}{{msg.icon?'iconfont icon-'+msg.icon:''}} 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /miniprogram/pages/account/askList/askList.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ doctor ? item.patient_name : item.doctor_name }} 6 | {{ item.status == 1 ? '会话已结束' : item.status == -1 ? '待医生回复' : '医生已回复' }} 7 | {{ item.content }} 8 | {{ item.create_day }} 9 | 10 | 11 | 12 | 暂无任何咨询消息! 13 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "miniprogramRoot": "miniprogram/", 4 | "cloudfunctionRoot": "cloud/", 5 | "packOptions": { 6 | "ignore": [] 7 | }, 8 | "setting": { 9 | "urlCheck": false, 10 | "es6": true, 11 | "postcss": true, 12 | "minified": true, 13 | "newFeature": true, 14 | "uglifyFileName": false 15 | }, 16 | "compileType": "miniprogram", 17 | "libVersion": "2.4.2", 18 | "appid": "wx5db8bb3e34cd9234", 19 | "projectname": "%E7%94%A8%E8%83%BD%E5%85%AC%E5%8F%B8", 20 | "debugOptions": { 21 | "hidedInDevtools": [] 22 | }, 23 | "isGameTourist": false, 24 | "condition": { 25 | "search": { 26 | "current": -1, 27 | "list": [] 28 | }, 29 | "conversation": { 30 | "current": -1, 31 | "list": [] 32 | }, 33 | "game": { 34 | "currentL": -1, 35 | "list": [] 36 | }, 37 | "miniprogram": { 38 | "current": -1, 39 | "list": [] 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /miniprogram/pages/doctor/consulting/consulting.js: -------------------------------------------------------------------------------- 1 | // miniprogram/pages/doctor/consulting/consulting.js 2 | Page({ 3 | 4 | /** 5 | * 页面的初始数据 6 | */ 7 | data: { 8 | 9 | }, 10 | 11 | /** 12 | * 生命周期函数--监听页面加载 13 | */ 14 | onLoad: function (options) { 15 | 16 | }, 17 | 18 | /** 19 | * 生命周期函数--监听页面初次渲染完成 20 | */ 21 | onReady: function () { 22 | 23 | }, 24 | 25 | /** 26 | * 生命周期函数--监听页面显示 27 | */ 28 | onShow: function () { 29 | 30 | }, 31 | 32 | /** 33 | * 生命周期函数--监听页面隐藏 34 | */ 35 | onHide: function () { 36 | 37 | }, 38 | 39 | /** 40 | * 生命周期函数--监听页面卸载 41 | */ 42 | onUnload: function () { 43 | 44 | }, 45 | 46 | /** 47 | * 页面相关事件处理函数--监听用户下拉动作 48 | */ 49 | onPullDownRefresh: function () { 50 | 51 | }, 52 | 53 | /** 54 | * 页面上拉触底事件的处理函数 55 | */ 56 | onReachBottom: function () { 57 | 58 | }, 59 | 60 | /** 61 | * 用户点击右上角分享 62 | */ 63 | onShareAppMessage: function () { 64 | 65 | } 66 | }) -------------------------------------------------------------------------------- /miniprogram/pages/account/family/family.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 家庭成员 ( 5 / {{familyList.length}} ) 6 | 7 | 8 | 9 | 获取中... 10 | 11 | 12 | 13 | 14 | 姓名: 15 | {{item.patientname}} 16 | 17 | 18 | 出生: 19 | {{item.csrq}} 20 | 21 | 22 | 手机号: 23 | {{item.phone}} 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /miniprogram/pages/account/family/family.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | Page({ 3 | 4 | data: { 5 | familyList: [] 6 | }, 7 | 8 | onShow: function() { 9 | app.bar("title", "家庭成员"); 10 | // 读取家庭成员列表 11 | app.request(`token=${app.globalData.userInfo.token}`, "getFamilyList", res => { 12 | if (res.data.length) this.setData({ 13 | familyList: res.data 14 | }); 15 | }); 16 | }, 17 | 18 | /** 19 | * 刪除家庭成员 20 | */ 21 | click: function(e) { 22 | let target = e.target.dataset; 23 | if (target.no) { 24 | app.request(`${target.no}?token=${app.globalData.userInfo.token}`, 'deleteFamilyUser', res => { 25 | // 删除后重新获取 26 | app.request(`token=${app.globalData.userInfo.token}`, "getFamilyList", res => { 27 | if (res.data.length) this.setData({ 28 | familyList: res.data 29 | }); 30 | }); 31 | }); 32 | } 33 | }, 34 | 35 | /** 36 | * 添加家庭成员 37 | */ 38 | addFamily: function(e) { 39 | wx.navigateTo({ 40 | url: '../../upload/idCard/idcard?addFamily=1', 41 | }); 42 | } 43 | }) -------------------------------------------------------------------------------- /miniprogram/pages/account/login/login.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 24 | 25 | 26 | 32 | 33 | 34 | 35 | 还未注册 36 |
37 | 38 | -------------------------------------------------------------------------------- /miniprogram/pages/account/askList/askList.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | Page({ 3 | data: { 4 | doctor: false, 5 | empty: !1 6 | }, 7 | onLoad: function(e) { 8 | 9 | app.bar({ 10 | title: "我的咨询", 11 | bgColor: "#B5CFFF" 12 | }); 13 | 14 | this.setData({ 15 | doctor: app.globalData.doctor 16 | }); 17 | 18 | // 按页面参数 进行请求 19 | e.type && app.request(app.globalData.userInfo.token, `getDocAskListBy${e.type}`, res => { 20 | console.log(res.data) 21 | if (res.data.length) { 22 | 23 | //排序 已回复 > 待回复 > 已结束 24 | let sorting = [ 25 | [],// 已回复 26 | [],// 待回复 27 | [] // 已结束 28 | ]; 29 | res.data.forEach(value => { 30 | if (value.status == 1) { 31 | sorting[2].push(value); 32 | } else if (value.status == -1) { 33 | sorting[1].push(value); 34 | } else sorting[0].push(value); 35 | }); 36 | let newArr = [] 37 | newArr.push(...sorting[0], ...sorting[1], ...sorting[2]); 38 | 39 | this.setData({ 40 | list: newArr 41 | }); 42 | } else { 43 | this.setData({ 44 | empty: !0 45 | }); 46 | } 47 | }); 48 | 49 | }, 50 | 51 | }) -------------------------------------------------------------------------------- /miniprogram/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/account/account", 4 | "pages/account/askList/askList", 5 | "pages/index/index", 6 | "pages/doctor/doctor", 7 | "pages/account/register/register", 8 | "pages/account/login/login", 9 | "pages/search/search", 10 | "pages/account/family/family", 11 | "pages/upload/page/page", 12 | "pages/doctor/consulting/consulting" 13 | ], 14 | "window": { 15 | "backgroundTextStyle": "light", 16 | "navigationBarBackgroundColor": "#fff", 17 | "navigationBarTitleText": "康达互联网医院", 18 | "navigationBarTextStyle": "black" 19 | }, 20 | "tabBar": { 21 | "color": "#a9b7b7", 22 | "selectedColor": "#11cd6e", 23 | "borderStyle": "black", 24 | "list": [ 25 | { 26 | "text": "咨询", 27 | "pagePath": "pages/index/index", 28 | "iconPath": "images/tagbar/consulting.png", 29 | "selectedIconPath": "images/tagbar/consulting_on.png" 30 | }, 31 | { 32 | "text": "我的", 33 | "pagePath": "pages/account/account", 34 | "iconPath": "images/tagbar/me.png", 35 | "selectedIconPath": "images/tagbar/me_on.png" 36 | } 37 | ] 38 | }, 39 | "usingComponents": { 40 | "msg": "/component/Toast/Toast" 41 | } 42 | } -------------------------------------------------------------------------------- /miniprogram/pages/account/register/register.wxss: -------------------------------------------------------------------------------- 1 | @import "../login/login.wxss"; 2 | form { 3 | margin-top: 180rpx; 4 | } 5 | scroll-view, 6 | swiper { 7 | height: 100vh; 8 | } 9 | radio-group { 10 | display: flex; 11 | justify-content: space-around; 12 | } 13 | .select-user { 14 | display: block; 15 | width: 50vw; 16 | margin: 0 auto; 17 | margin-top: 200rpx; 18 | padding: 10rpx; 19 | background-color: white; 20 | border-radius: 100rpx; 21 | box-shadow: -10rpx -5rpx 20rpx rgba(0, 0, 0, .3); 22 | } 23 | .select-user-type { 24 | display: inline-block; 25 | width: 100%; 26 | padding: 10rpx 0; 27 | text-align: center; 28 | color: #333; 29 | } 30 | .select-user-type.on,.onL ,.onR { 31 | color: white; 32 | border-radius: 100rpx; 33 | background-image: linear-gradient(90deg,#00c6fb, #005bea); 34 | box-shadow: 3px 2px 5px rgba(0, 0, 0, .3); 35 | } 36 | 37 | .onL { 38 | transform: translateX(-100%); 39 | animation: onAnL .5s; 40 | animation-fill-mode: forwards; 41 | } 42 | @keyframes onAnL { 43 | to { 44 | transform: translateX(0); 45 | } 46 | } 47 | 48 | .onR { 49 | transform: translateX(100%); 50 | animation: onAnR .5s; 51 | animation-fill-mode: forwards; 52 | } 53 | @keyframes onAnR { 54 | to { 55 | transform: translateX(0); 56 | } 57 | } -------------------------------------------------------------------------------- /miniprogram/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | margin-bottom: 30rpx; 3 | } 4 | 5 | .inputFocus { 6 | position: fixed; 7 | transform: translateY(-100px); 8 | border-radius: 50px; 9 | box-shadow: 2px 2px 5px 1600px rgba(0, 0, 0, .2); 10 | } 11 | .search-list { 12 | display: none; 13 | } 14 | .inputFocus .search-list { 15 | position: absolute; 16 | display: block; 17 | width: 100%; 18 | margin-top: 3px; 19 | color: #555; 20 | background-color: white; 21 | border-radius: 5px; 22 | box-shadow: 2px 2px 5px rgba(0, 0, 0, .3); 23 | } 24 | .inputFocus .search-list > view { 25 | margin: 0 20rpx; 26 | padding: 10rpx; 27 | border-bottom: 1px solid #eee; 28 | } 29 | .inputFocus .search-list > view text { 30 | color: red; 31 | } 32 | .consulting-type { 33 | margin-top: 400rpx; 34 | padding: 20rpx 0; 35 | } 36 | .consulting-type>view { 37 | float: left; 38 | width: 50%; 39 | padding: 0 20px; 40 | text-align: center; 41 | line-height: 60rpx; 42 | color: #555; 43 | box-sizing: border-box; 44 | font-size: 40rpx; 45 | text-shadow: 1px 2px 1px var(--shadow-color); 46 | transition: 0.5s; 47 | } 48 | 49 | .consulting-type>view icon { 50 | margin-right: 15rpx; 51 | } 52 | 53 | .consulting-type>view:nth-child(2) { 54 | border-left: 1px solid #eee; 55 | } 56 | 57 | .consulting-type>view:active { 58 | color: #474747; 59 | text-shadow: 0 0 1px #a9b7b7; 60 | } 61 | -------------------------------------------------------------------------------- /miniprogram/pages/account/account.wxss: -------------------------------------------------------------------------------- 1 | .account { 2 | position: relative; 3 | margin-top: 20px; 4 | padding: 20rpx 0; 5 | } 6 | 7 | .notPage, .notPage icon { 8 | color: #ddd !important; 9 | } 10 | 11 | .account image { 12 | width: 120rpx; 13 | height: 120rpx; 14 | margin: 0 30rpx; 15 | vertical-align: middle; 16 | border-radius: 60rpx; 17 | box-shadow: 2px 2px 10px var(--shadow-color); 18 | } 19 | 20 | .account>view { 21 | display: flex; 22 | flex-wrap: wrap; 23 | flex-direction: row; 24 | align-items: center; 25 | float: right; 26 | width: calc(100% - 180rpx); 27 | height: 120rpx; 28 | } 29 | 30 | .account>view text { 31 | width: 100%; 32 | color: #888; 33 | } 34 | 35 | .account .nickName { 36 | color: #333; 37 | font-size: 1.2rem; 38 | text-shadow: 1px 2px 2px var(--shadow-color); 39 | } 40 | 41 | .row-box:nth-child(1) { 42 | margin-bottom: 50rpx; 43 | } 44 | 45 | .row-box:nth-child(n+2) { 46 | margin-top: 20rpx; 47 | } 48 | 49 | .get-user-info, .get-user-info::after { 50 | position: absolute; 51 | top: 0; 52 | left: 0; 53 | width: 100%; 54 | height: 100%; 55 | border: none; 56 | color: transparent; 57 | background-color: transparent; 58 | } 59 | .icon-shenfenzhengzheng { 60 | font-size: 1em; 61 | margin-top: -10px; 62 | } 63 | .account-error { 64 | font-size: .8rem; 65 | } 66 | .padding-empty { 67 | min-height:0; 68 | padding: 0; 69 | } 70 | .padding-empty > view { 71 | padding: 10rpx; 72 | } -------------------------------------------------------------------------------- /miniprogram/pages/account/askList/askList.wxss: -------------------------------------------------------------------------------- 1 | .row-box { 2 | position: relative; 3 | overflow: hidden; 4 | padding: 10rpx 30rpx; 5 | margin: 20rpx auto; 6 | box-sizing: border-box; 7 | } 8 | .user-icon { 9 | position: absolute; 10 | top: 0; 11 | bottom: 0; 12 | margin: auto; 13 | margin-right: 20rpx; 14 | height: 110rpx; 15 | width: 110rpx; 16 | border-radius: 50%; 17 | } 18 | text { 19 | display: inline-block; 20 | width: calc(50% - 75rpx); 21 | } 22 | 23 | .docName, 24 | .descript { 25 | margin-left: 130rpx; 26 | } 27 | .state, 28 | .createTime { 29 | float: right; 30 | font-size: .8rem; 31 | text-align: right; 32 | color: #999; 33 | } 34 | 35 | .createTime { 36 | font-size: .7rem; 37 | color: #ccc; 38 | } 39 | .docName { 40 | font-size: 1.2rem; 41 | } 42 | .descript { 43 | overflow: hidden; 44 | width: calc(100% - 130rpx); 45 | text-overflow: ellipsis; 46 | text-indent: 1rem; 47 | white-space: nowrap; 48 | color: #888; 49 | } 50 | 51 | .nick::after, 52 | .waiting::after { 53 | content: ""; 54 | position: absolute; 55 | top: 0; 56 | right: 0; 57 | width: 70rpx; 58 | height: 30rpx; 59 | background-color: rgba(0, 95, 0, .6); 60 | transform: rotateZ(45deg) translateY(-20rpx) translateX(10rpx) 61 | } 62 | .waiting::after { 63 | background-color: rgba(214, 86, 0, 0.6); 64 | } 65 | 66 | .end::after { 67 | content: ""; 68 | position: absolute; 69 | top: 0; 70 | left: 0; 71 | height: 100%; 72 | background-color: rgba(0, 0, 0, .05); 73 | } 74 | .not-content { 75 | display: flex; 76 | justify-content: center; 77 | align-items: center; 78 | height: 100vh; 79 | color: #888; 80 | } 81 | .not-content text { 82 | width: 100%; 83 | text-align: center; 84 | } -------------------------------------------------------------------------------- /miniprogram/pages/upload/idCard/idcard.wxss: -------------------------------------------------------------------------------- 1 | @import "../../account/login/login.wxss"; 2 | 3 | .row-box { 4 | margin-top: 30rpx; 5 | padding: 10rpx; 6 | } 7 | 8 | .mar-top { 9 | margin-top: 50rpx; 10 | } 11 | 12 | .tag { 13 | display: block; 14 | font-weight: bold; 15 | } 16 | 17 | .upload-box { 18 | display: flex; 19 | flex-direction: row; 20 | justify-content: center; 21 | align-items: center; 22 | float: left; 23 | overflow: hidden; 24 | position: relative; 25 | width: calc(100% - 20rpx); 26 | height: 50vw; 27 | margin: 10rpx; 28 | padding: 20rpx; 29 | border-radius: 20rpx; 30 | border: 3px dashed #ccc; 31 | box-sizing: border-box; 32 | } 33 | 34 | .upload-box image { 35 | position: absolute; 36 | margin-top: -30rpx; 37 | width: 100%; 38 | } 39 | 40 | .icon-tianjia { 41 | position: relative; 42 | display: block; 43 | color: #999; 44 | text-align: center; 45 | font-size: 3em; 46 | } 47 | 48 | .icon-shenfenzhengfan, .icon-shenfenzhengzheng { 49 | position: absolute; 50 | transform: translateY(-35rpx); 51 | color: #eee; 52 | font-size: 25vw; 53 | z-index: 0; 54 | } 55 | 56 | .upload-tag { 57 | position: absolute; 58 | bottom: 0; 59 | width: 100%; 60 | padding: 5rpx 0; 61 | text-align: center; 62 | color: #fff; 63 | background-color: #437ff9; 64 | } 65 | .content { 66 | text-indent: 2em; 67 | color: #888; 68 | font-size: .8em; 69 | } 70 | .content text { 71 | color: #e64340; 72 | } 73 | 74 | .button-blue { 75 | position: absolute; 76 | bottom: 150rpx; 77 | width: 90vw; 78 | margin-left: 5vw; 79 | color: #fff; 80 | background-color: #437ff9; 81 | box-shadow: 4rpx 6rpx 9rpx rgba(0, 0, 0, .3); 82 | } 83 | 84 | form { 85 | margin: 170rpx auto 0; 86 | } -------------------------------------------------------------------------------- /miniprogram/pages/upload/idCard/idcard.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 拍摄正面 10 | 11 | 12 | 13 | 14 | 拍摄身份证要求: 15 | 拍摄时确保身份证 16 | 边框完整,字体清晰,亮度均匀,无涂抹遮盖 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 45 | 46 | 47 |
48 |
49 |
50 | 51 | -------------------------------------------------------------------------------- /miniprogram/pages/index/index.js: -------------------------------------------------------------------------------- 1 | var a = getApp(), 2 | change = null; 3 | 4 | Page({ 5 | data: { 6 | searchClass: "", 7 | department: [{ 8 | tag: "皮肤科", 9 | icon: "pifuke color1" 10 | }, { 11 | tag: "推拿", 12 | icon: "tuina color2" 13 | }, { 14 | tag: "骨科", 15 | icon: "guke color3" 16 | }, { 17 | tag: "耳鼻咽喉", 18 | icon: "erbihouke color4" 19 | }, { 20 | tag: "检验", 21 | icon: "jianyan color5" 22 | }, { 23 | tag: "B超", 24 | icon: "Bchaoyuyue-K color6" 25 | }, { 26 | tag: "科室7", 27 | icon: "wrong color7" 28 | }, { 29 | tag: "科室8", 30 | icon: "wrong color8" 31 | }], 32 | searchDoctor: [] 33 | }, 34 | /** 35 | * 搜索栏聚焦 36 | */ 37 | searchFocus: function() { 38 | this.setData({ 39 | searchClass: "inputFocus" 40 | }); 41 | }, 42 | /** 43 | * 搜索栏失焦 44 | */ 45 | searchBlur: function() { 46 | this.setData({ 47 | searchClass: "" 48 | }) 49 | }, 50 | /** 51 | * 搜索关键词 52 | */ 53 | searchKey: function(e) { 54 | 55 | // 节流算法 56 | change && clearTimeout(change); 57 | 58 | change = setTimeout(() => { 59 | change = null; 60 | let val = e.detail.value; 61 | val && a.request({ 62 | "doc_name": val, 63 | "depId": -1, 64 | "subdepId": -1 65 | }, "searchDoctor", data => { 66 | data = data.data; 67 | if (typeof data == "object") { 68 | data.map && data.map(res => { 69 | res.split = res.name.split(val); 70 | res.key = val; 71 | return res; 72 | }); 73 | this.setData({ 74 | searchDoctor: data 75 | }); 76 | } 77 | }); 78 | }, 500); 79 | } 80 | }); -------------------------------------------------------------------------------- /miniprogram/pages/search/search.wxml: -------------------------------------------------------------------------------- 1 | 14 | 按照科室查找 15 | 16 | 17 | 查找结果({{ results.length }}) 18 | 19 | 20 | 21 | 22 | 29 | 30 | {{item.tag}} 31 | 32 | 33 | 34 | 35 | 36 | {{item.name}} 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 52 | 53 | {{item.name}} 54 | {{item.tag}} 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /miniprogram/component/Toast/Toast.wxss: -------------------------------------------------------------------------------- 1 | @import "../../app.wxss"; 2 | 3 | .toast { 4 | position: fixed; 5 | bottom: 5vh; 6 | right: 0; 7 | padding-right: 10px; 8 | min-width: 50vw; 9 | line-height: 10vw; 10 | background-color: white; 11 | box-shadow: 5px 10px 5px -5px rgba(0, 0, 0, 0.3); 12 | border-radius: 5px 0 0 5px; 13 | transition: 1s; 14 | transform: translateX(100%); 15 | } 16 | 17 | .select { 18 | animation: 0.5s 1s marTop; 19 | animation-fill-mode: forwards; 20 | } 21 | 22 | @keyframes marTop { 23 | to { 24 | bottom: calc(10vh + 30rpx); 25 | } 26 | } 27 | 28 | .toast-show { 29 | transform: translateX(0); 30 | } 31 | 32 | .toast.error { 33 | background-color: #ffa7a1; 34 | color: red; 35 | } 36 | 37 | .toast.success { 38 | background-color: #a7ffab; 39 | color: #00b12c; 40 | } 41 | 42 | .toast.warning { 43 | background-color: #ffcb9a; 44 | color: #cc7400; 45 | } 46 | 47 | .toast.zhiwen, .saoma { 48 | background-color: #aafff4; 49 | color: #0087b1; 50 | } 51 | 52 | .toast.loading { 53 | background-color: #aeadff; 54 | color: #0003a8; 55 | } 56 | 57 | .toast icon { 58 | margin: 0 10px; 59 | vertical-align: middle; 60 | font-size: 25px; 61 | } 62 | 63 | .toast text { 64 | vertical-align: middle; 65 | font-size: 15px; 66 | } 67 | 68 | .select + .toast { 69 | display: flex; 70 | flex-wrap: wrap; 71 | flex-direction: row; 72 | align-items: center; 73 | justify-content: center; 74 | overflow: hidden; 75 | height: 10vw; 76 | min-width: 50vw; 77 | max-height: 0; 78 | padding: 0 10rpx; 79 | animation: 0.5s 1s maxH; 80 | animation-fill-mode: forwards; 81 | } 82 | 83 | @keyframes maxH { 84 | to { 85 | transform: translateX(0); 86 | max-height: 10vw; 87 | } 88 | } 89 | 90 | .toast button { 91 | display: inline-block; 92 | padding: 5rpx 10rpx; 93 | line-height: 5vh; 94 | color: white; 95 | } 96 | 97 | .toast button.green { 98 | background-color: #00b100; 99 | } 100 | 101 | .toast button.red { 102 | background-color: #f11c1c; 103 | } 104 | 105 | .toast button { 106 | background-color: #999; 107 | } 108 | -------------------------------------------------------------------------------- /miniprogram/pages/account/family/family.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | background-color: #aeba4e !important; 3 | } 4 | 5 | .background { 6 | position: relative; 7 | } 8 | 9 | .family.row-box { 10 | padding: 0; 11 | margin-bottom: 20rpx; 12 | background-color: #c8e6c9; 13 | box-shadow: 0 0 7px rgba(0, 0, 0, 0.4); 14 | border-radius: 5px; 15 | } 16 | 17 | .title { 18 | display: block; 19 | width: 100%; 20 | padding: 20rpx; 21 | color: white; 22 | background-color: #43a047; 23 | border-radius: 5px 5px 0 0; 24 | box-sizing: border-box; 25 | } 26 | 27 | .tag { 28 | float: left; 29 | font-weight: bold; 30 | font-size: 1.2em; 31 | text-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 32 | } 33 | 34 | .tag + icon { 35 | float: right; 36 | vertical-align: middle; 37 | } 38 | 39 | .row-box > view:nth-child(1n+2) { 40 | position: relative; 41 | padding: 10px; 42 | border-bottom: 2px solid rgba(255, 255, 255, .3); 43 | box-sizing: border-box; 44 | } 45 | .row-box > view:last-child { 46 | border-bottom: none; 47 | } 48 | .row-box image { 49 | float: left; 50 | width: 100rpx; 51 | height: 100rpx; 52 | margin: 10rpx; 53 | margin-right: 15px; 54 | border-radius: 10px; 55 | } 56 | .row-box .button-list { 57 | position: absolute; 58 | display: flex; 59 | flex-direction: row; 60 | flex-wrap: wrap; 61 | justify-content: center; 62 | align-items: center; 63 | top: 0; 64 | right: 0; 65 | width: 15%; 66 | height: 100%; 67 | padding: 0 10rpx; 68 | } 69 | .row-box .button-list button { 70 | display: block; 71 | padding: 10rpx 0; 72 | width: 90%; 73 | line-height: 100%; 74 | height: auto; 75 | color: white; 76 | background-color: #ef5350; 77 | box-shadow: 0 8px 5px -5px rgba(0, 0, 0, .3); 78 | transition: .1s; 79 | } 80 | .row-box .button-list button:active { 81 | color: #ddd; 82 | background-color: #f14744; 83 | box-shadow: 0 1px 4px 0 rgba(206, 57, 54, 0.8); 84 | } 85 | .row-box > view:nth-child(1n+2) text:nth-child(1) { 86 | display: inline-block; 87 | min-width: 90rpx; 88 | } 89 | .row-box > view:nth-child(1n+2) text:nth-child(2) { 90 | margin-left: 10rpx; 91 | color: #555; 92 | } 93 | .loading { 94 | width: 100%; 95 | text-align: center; 96 | color: #555; 97 | } -------------------------------------------------------------------------------- /miniprogram/pages/account/answer/answer.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ doctor ? detail.patient_name : detail.doctor_name}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {{ detail.patient_name + " " + detail.l_sex + " " + detail.age }} 16 | 咨询原因:{{ detail.content }} 17 | 18 | 19 | 20 | {{ item.addDate }} 21 | 22 | 23 | {{ item.l_content }} 24 | {{ item.error }} 25 | 26 | 27 | 28 | 以上是历史消息 29 | 30 | 31 | 32 | 33 | 刷新中... 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 |
44 | 45 | 46 | 47 | 申请开药 48 | 申请开检验检查单 49 | 我已经知道 50 | 51 | 52 |
-------------------------------------------------------------------------------- /miniprogram/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{item.split[0]}} 13 | {{item.key}}{{item.split[1]}} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 未搜索到包含此关键词的专家! 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 专家咨询 34 | 35 | 36 | 37 | 38 | 39 | 快速咨询 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 按科室选择 50 | 51 | 更多 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {{item.tag}} 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 推荐医生 73 | 74 | 更多 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 胡铖杰 83 | 84 | 85 | 86 | 大佬 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /miniprogram/pages/doctor/doctor.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | let token = app.globalData.userInfo.token; 3 | Page({ 4 | data: { 5 | 6 | // 显示简介 7 | introduce: true, 8 | 9 | // 菜单标签 10 | tag: { 11 | consulting: { 12 | page1: true 13 | } 14 | }, 15 | 16 | // 家庭列表 17 | family: [], 18 | focusFamily: 0, 19 | familyList: [{ 20 | patientname: '--', 21 | sex: '--', 22 | age: '--', 23 | }] 24 | }, 25 | onLoad: function (options) { 26 | options && this.setData(options); 27 | }, 28 | onShow: function() { 29 | app.bar({ 30 | title: '医生信息', 31 | bgColor: '#B5CFFF' 32 | }); 33 | 34 | app.request(`token=${token}`, "getFamilyList", res => { 35 | let data = []; 36 | for (let obj of res.data) data.push(`${obj.patientname} ${obj.sex} ${obj.age}`); 37 | (res.data.length < 5) && data.push(`+ 添加家庭成员`); 38 | this.setData({ 39 | family: data, 40 | familyList: res.data 41 | }); 42 | }); 43 | 44 | // 默认选中 咨询 45 | this.showContent('consulting'); 46 | }, 47 | 48 | /** 49 | * 菜单点击后显示 50 | */ 51 | showContent: function(e) { 52 | let tag = e.target ? e.target.dataset.tag : e; 53 | if (this.data.tag[tag]) return; 54 | this.setData({ 55 | tag: { 56 | [tag]: {} 57 | }, 58 | introduce: true 59 | }); 60 | }, 61 | 62 | /** 63 | * 切換内页 64 | */ 65 | switchPage: function(e) { 66 | this.setData({ 67 | [e.target.dataset.page]: true, 68 | introduce: false 69 | }); 70 | }, 71 | 72 | /** 73 | * 姓名选择 74 | */ 75 | con_picker: function(e) { 76 | if (e.detail.value == this.data.family.length - 1) { 77 | wx.navigateTo({ 78 | url: '../account/family/family', 79 | }) 80 | return; 81 | } 82 | this.setData({ 83 | focusFamily: e.detail.value 84 | }); 85 | }, 86 | 87 | /** 88 | * 咨询提交 89 | */ 90 | consulting: function(e) { 91 | if (e.detail.value.content.length < 4) { 92 | this.setData({ 93 | toast: { 94 | text: "请至少输入4个字符!", 95 | icon: "error" 96 | } 97 | }) 98 | return; 99 | } 100 | 101 | let data = this.data; 102 | app.request({ 103 | patient_id: data.familyList[data.focusFamily].id, 104 | doctor_id: data.id, 105 | content: e.detail.value.content 106 | }, "addDoctorAsk", res => { 107 | console.log(res.data) 108 | if (res.data.ask_id) { 109 | wx.navigateTo({ 110 | url: '../account/answer/answer?id=' + res.data.ask_id, 111 | }); 112 | } else this.setData({ 113 | toast: { 114 | text: res.data.error, 115 | icon: 'error' 116 | } 117 | }); 118 | }, token); 119 | 120 | }, 121 | }) -------------------------------------------------------------------------------- /miniprogram/pages/search/search.wxss: -------------------------------------------------------------------------------- 1 | .search-box { 2 | top: 25rpx; 3 | } 4 | .type-list-tag { 5 | position: relative; 6 | display: inline-block; 7 | width: 90vw; 8 | margin: 110rpx 0 0 5vw; 9 | padding: 10rpx 20rpx; 10 | text-align: center; 11 | color: #6d6d6d; 12 | vertical-align: middle; 13 | background-color: #f8f8f8; 14 | border-radius: 5px 5px 0 0; 15 | box-sizing: border-box; 16 | } 17 | .icon-sousuo button { 18 | position: absolute; 19 | top: 0; 20 | right: 0; 21 | height: 100%; 22 | opacity: 0; 23 | } 24 | .type-list { 25 | position: relative; 26 | overflow: hidden; 27 | height: calc(100vh - 190rpx); 28 | background-color: white; 29 | border-radius: 5px; 30 | } 31 | .type-list-left { 32 | overflow-x: hidden; 33 | width: 35%; 34 | height: 100%; 35 | font-size: 1em; 36 | } 37 | .type-list-left text { 38 | pointer-events: none; 39 | } 40 | .type-list-left icon { 41 | margin: -10rpx 10rpx 0 0; 42 | font-size: 1em; 43 | color: #555; 44 | } 45 | .type-list-right { 46 | overflow-x: hidden; 47 | right: 0; 48 | width: 65%; 49 | height: 100%; 50 | } 51 | .type-list-left, .type-list-right { 52 | position: absolute; 53 | } 54 | .type-list-left > view, 55 | .type-list-right > view { 56 | padding: 10rpx; 57 | line-height: 40rpx; 58 | border-bottom: 1px solid #d8d8d8; 59 | } 60 | .type-list-right > view:active { 61 | background-color: #eee; 62 | transition: .2s; 63 | } 64 | .type-list-right > view { 65 | border-bottom: 1px solid #eee; 66 | } 67 | view.select { 68 | margin-top: -1px; 69 | color: #444; 70 | background-color: white; 71 | border-top: 1px solid #fff; 72 | border-bottom: none; 73 | } 74 | .select::before { 75 | content: ''; 76 | position: absolute; 77 | left: 0; 78 | width: 100%; 79 | height: 100%; 80 | margin-top: 50rpx; 81 | background-color: rgba(0, 0, 0, .1); 82 | border-top-right-radius: 8px; 83 | pointer-events: none; 84 | } 85 | .select::after { 86 | content: ''; 87 | position: absolute; 88 | left: 0; 89 | width: 100%; 90 | height: 100%; 91 | margin-top: -10rpx; 92 | background-color: rgba(0, 0, 0, .1); 93 | border-bottom-right-radius: 8px; 94 | transform: translateY(-100%); 95 | pointer-events: none; 96 | } 97 | /* 搜索结果医生 */ 98 | .doctor-scroll { 99 | height: 100%; 100 | } 101 | .doctor { 102 | width: 90%; 103 | padding: 2%; 104 | margin: 10rpx auto; 105 | background-color: #eee; 106 | border-radius: 5px; 107 | } 108 | .user-icon { 109 | display: inline-block; 110 | margin-right: 2%; 111 | vertical-align: middle; 112 | pointer-events: none; 113 | } 114 | .doctor-name { 115 | display: inline-block; 116 | width: 40%; 117 | text-indent: .5em; 118 | font-weight: 500; 119 | pointer-events: none; 120 | } 121 | .doctor-tag { 122 | color: #888; 123 | pointer-events: none; 124 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 微信小程序-前端 [开发版] 2 | > `文档更新: 2018-12-23` 3 | > `体验版本: v0.7.0 [Alpha]` 4 | > `本来是公司的项目,但因某些原因项目终止,所以才可以开源` 5 | ### 内部原创组件说明 6 | >`Toast` 组件: [查看 说明/源码](https://gitee.com/slm47888/wechat_applet__component_toast) 7 | ### 部分截图预览: 8 |
9 | SLM-BLOG LOGO 10 | SLM-BLOG LOGO 11 | SLM-BLOG LOGO 12 | SLM-BLOG LOGO 13 | SLM-BLOG LOGO 14 | SLM-BLOG LOGO 15 | SLM-BLOG LOGO 16 | SLM-BLOG LOGO 17 |
18 | 19 | ### 修改接口[开源设定]: 20 | 修改 [app.js](https://github.com/shi-lai-mu/hospital-wxapp/blob/master/miniprogram/app.js) 文件内的URL即可,接口传回数据参考下方的后端文档 21 | 22 | ### 进度浏览: 23 | `删除线代表未完成` 24 | >##### `页面/布局:` 25 | >>- 首页 26 | >>- 我的账号 27 | >>- 绑定小程序 28 | >>- 注册账号[用户] 29 | >>- 注册账号[医生] 30 | >>- 科室搜索 31 | >>- 我的家庭 32 | >>- 短信验证 33 | >>- 身份证上传 34 | >>- 短信验证[注册页] 35 | >>- 医生信息页 36 | >>- 全部咨询记录页面 37 | >>- 发消息页面 38 | >> 39 | >>- ~~我的药店~~ 40 | >##### `搜索机制:` 41 | >>- 子部门搜索 42 | >>- 姓名搜索 43 | >>- 筛选搜索 44 | >>- 搜索节流 45 | >>- 搜索绑定 46 | >>- 专家咨询 47 | >> 48 | >>- ~~快速咨询~~ 49 | >##### `我的家庭:` 50 | >>- 家庭列表 51 | >>- 添加成员 52 | >>- 删除成员 53 | >##### `账号机制:` 54 | >>- openId登录 55 | >>- openId注册 56 | >>- openId绑定 57 | >>- 身份证识别 58 | >>- 主账号注册[用户] 59 | >##### `咨询机制:` 60 | >>- 全部咨询进行权重排序 已回复 > 待回复 > 已结束 61 | >>- 历史消息无动画,发消息包含动态 62 | >>- 底部工具栏 63 | 64 | ### 本地存储调用说明: 65 | ##### `主要起到提高体验度、减轻服务器压力` 66 | | 数据 | 调用页 | 函数名 | 存储条件 | 有效时间 | 67 | | :--------| :-------- | :-------- | :--------| :------: | 68 | | 用户数据[账号/token/主账号] | account | settingAccount | 无数据/数据过期 | 3天 | 69 | | 部门信息[主部门/子部门/科室] | app | onLaunch | 无数据/数据过期 | 1小时 | 70 | | 专家列表[专家信息] | search | onLoad | 专家咨询 | 1小时 | 71 | 72 | 73 | ```javascript 74 | // 以下为小程序页面目录注释[方便快速查找] 75 | /* 76 | +---cloud [云函数] 77 | | \---getOpenId [获取openId] 78 | | 79 | +---miniprogram [主目录] 80 | | +---component [组件] 81 | | | \---Toast [Toast 消息组件] 82 | | | 83 | | +---images [图片库] 84 | | | \---tagbar [底部选项卡] 85 | | | 86 | | \---pages [页面] 87 | | +---account [账号] 88 | | | +---family [我的家庭] 89 | | | +---answer [咨询界面] 90 | | | +---docAskList [咨询历史] 91 | | | +---login [登录] 92 | | | \---register [注册] 93 | | | 94 | | +---doctor [医生] 95 | | | \---consulting [待定] 96 | | | 97 | | +---index [首页] 98 | | +---search [搜索] 99 | | \---upload [上传] 100 | | +---idCard [身份证] 101 | | \---page [空白页] 102 | 103 | */ 104 | ``` 105 | 106 | -------------------------------------------------------------------------------- /miniprogram/pages/account/login/login.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | // 手机号返回的mssion_id 3 | let mssion_id = null, 4 | outInter = null, 5 | outTime = 0; 6 | Page({ 7 | data: { 8 | sendState: "发送", 9 | }, 10 | onReady: function() { 11 | app.bar({ 12 | title: '绑定账号', 13 | bgColor: '#3285FF' 14 | }); 15 | }, 16 | 17 | /** 18 | * 聚焦事件 19 | */ 20 | inputFocus: function(t) { 21 | var a = {}; 22 | a[t.target.dataset.id] = "changed", this.setData(a); 23 | }, 24 | 25 | /** 26 | * 失焦事件 27 | */ 28 | inputBlur: function(t) { 29 | var a = {}; 30 | a[t.target.dataset.id] = t.detail.value ? "nick" : "", this.setData(a); 31 | }, 32 | 33 | /** 34 | * 绑定账号事件 35 | */ 36 | bind: function (e) { 37 | let value = e.detail.value; 38 | 39 | // 获取token 40 | let token = wx.getStorageSync('login'); 41 | if (!token) return; 42 | 43 | // 判断 手机号和验证码 是否输入 44 | if (value.phone) { 45 | if (value.codes) { 46 | // 判断是否存在验证码 47 | if (!mssion_id) return this.setData({ 48 | toast: { 49 | text: "未找到验证信息!", 50 | icon: "error" 51 | } 52 | }); 53 | 54 | // 请求验证码是否正确 销毁mssion_id 55 | app.request(`${mssion_id}/${value.codes}/?token=${token.data.data.token}`, "finishBind", res => { 56 | if (res.error) { 57 | this.setData({ 58 | toast: { 59 | text: "验证码错误!", 60 | icon: "error" 61 | } 62 | }); 63 | } else { 64 | wx.switchTab({ 65 | url: '../account?reload' 66 | }); 67 | } 68 | }); 69 | mssion_id = null; 70 | } else { 71 | // 检测冷却 72 | if (outTime) return; 73 | 74 | // 如果未输入验证码 则 发送验证码 75 | app.request(`${value.phone}/?token=${token.data.data.token}`, "existAccount", res => { 76 | if (!isNaN(res)) { 77 | outTime = (res / 1000).toFixed(0); 78 | this.countDown(outTime); 79 | return 80 | } 81 | if (res.data.mssion_id) { 82 | mssion_id = res.data.mssion_id; 83 | this.setData({ 84 | toast: { 85 | text: "验证码已发送!请输入...", 86 | icon: "success", 87 | hideTime: 3000 88 | } 89 | }); 90 | this.countDown(60); 91 | } else this.setData({ 92 | toast: { 93 | text: "验证码发送失败:" + res.data.error, 94 | icon: "error" 95 | } 96 | }); 97 | 98 | }, false, 60); 99 | } 100 | } else return this.setData({ 101 | toast: { 102 | text: "手机信息为空!", 103 | icon: "error" 104 | } 105 | }); 106 | }, 107 | 108 | /** 109 | * 倒计时 110 | */ 111 | countDown: function(outTime) { 112 | outInter = setInterval(() => { 113 | if (!outTime) { 114 | clearInterval(outInter); 115 | outTime = "发送"; 116 | } 117 | this.setData({ 118 | sendState: outTime 119 | }); 120 | outTime--; 121 | }, 1000); 122 | } 123 | }); -------------------------------------------------------------------------------- /miniprogram/pages/account/login/login.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | overflow: hidden; 3 | } 4 | 5 | .bgColor { 6 | position: absolute; 7 | z-index: -1; 8 | height: 100vh; 9 | width: 100vw; 10 | background-image: linear-gradient(180deg, #fff 80%, #ccc); 11 | } 12 | 13 | .flex { 14 | display: flex; 15 | justify-content: center; 16 | flex-direction: row; 17 | align-items: center; 18 | flex-wrap: wrap; 19 | height: calc(80vh - 400rpx); 20 | margin-top: 250rpx; 21 | } 22 | 23 | form { 24 | display: block; 25 | width: 80vw; 26 | margin: 300rpx auto 0; 27 | } 28 | 29 | form view, form radio-group { 30 | position: relative; 31 | padding: 40rpx 0; 32 | } 33 | 34 | input { 35 | width: calc(80vw - 3em); 36 | padding: 0 0 10rpx 3em; 37 | margin: 0 auto; 38 | color: var(--main-icon-color); 39 | border-bottom: 2px solid #eee; 40 | vertical-align: middle; 41 | transition: 0.5s linear; 42 | } 43 | 44 | input+.iconfont { 45 | position: absolute; 46 | top: 25rpx; 47 | color: var(--main-icon-color); 48 | transition: 0.5s linear; 49 | } 50 | 51 | input~label { 52 | position: absolute; 53 | top: 35rpx; 54 | left: 3em; 55 | color: #ccc; 56 | transition: 0.5s linear; 57 | pointer-events: none; 58 | } 59 | 60 | .placeholder { 61 | color: #ccc; 62 | } 63 | 64 | .changed input { 65 | color: var(--main-icon-color); 66 | border-bottom: 2px solid var(--main-icon-color); 67 | } 68 | 69 | .changed .iconfont { 70 | opacity: 0; 71 | transform: translateX(-100%); 72 | } 73 | 74 | .changed>label { 75 | color: var(--main-icon-color); 76 | transform: translateX(calc(-100% - 10rpx)); 77 | } 78 | 79 | .changed>label::after { 80 | content: ':'; 81 | } 82 | 83 | .nick input { 84 | border-bottom: 2px solid transparent; 85 | } 86 | 87 | .nick label { 88 | opacity: 0; 89 | } 90 | 91 | button { 92 | width: 80vw; 93 | color: white; 94 | font-weight: bold; 95 | background-color: #2b6efb; 96 | box-shadow: 0 3px 5px rgba(0, 0, 0, 0.5); 97 | } 98 | 99 | button:active { 100 | box-shadow: 0 5px 15px 2px rgba(0, 0, 0, 0.4); 101 | } 102 | 103 | .form-input-left { 104 | float: left; 105 | width: calc(50vw - 3em); 106 | transition: 0.1s; 107 | } 108 | 109 | .form-input-left ~ icon { 110 | left: 0; 111 | } 112 | 113 | .form-input-right { 114 | float: right; 115 | width: calc(20vw - 20px); 116 | padding: 0 20px; 117 | margin-top: -2px; 118 | box-sizing: content-box; 119 | } 120 | .clearfix button { 121 | background-color: #fff; 122 | } 123 | .form-button-right { 124 | position: absolute; 125 | right: 0; 126 | width: 20vw; 127 | margin-top: -30rpx; 128 | color: #555; 129 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4); 130 | box-sizing: content-box; 131 | opacity: 1; 132 | transition: .7s; 133 | } 134 | 135 | .row-two { 136 | display: flex; 137 | } 138 | .row-two button { 139 | margin: 0 30rpx; 140 | } 141 | 142 | .none { 143 | position: absolute; 144 | right: 0; 145 | width: 20vw; 146 | opacity: 0; 147 | } 148 | 149 | .right-navigator { 150 | display: block; 151 | width: 80vw; 152 | margin-top: 20rpx; 153 | text-align: right; 154 | } 155 | 156 | .code-cooling { 157 | color: #ccc; 158 | } 159 | -------------------------------------------------------------------------------- /miniprogram/pages/doctor/doctor.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{name}} 8 | 9 | {{tags}}主任医师 10 | 11 | 12 | 13 | 简介: 14 | {{name}}医生是我院{{tags}}的主任医师,其技术精湛,深受广大患者信赖! 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 二维码 24 | 咨询 25 | 预约 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 欢迎使用咨询服务,我将利用我的空余时间, 39 | 尽快为您答疑解惑! 40 | 咨询 41 | 42 | 43 | 44 | 45 |
46 | 47 | 咨询者: 48 | 49 | 50 | {{ 51 | familyList[focusFamily].patientname + " " 52 | + familyList[focusFamily].sex + " " 53 | + familyList[focusFamily].age 54 | }} 55 | 56 | 57 | 58 | 59 | 60 | 61 | 哪不舒服: 62 | 63 | 请至少输入4个字符 64 | 65 | 66 | *为保护您的隐私,请不要输入微信号、住址等信息。 67 | 68 | 69 |
70 |
71 | 72 |
73 | 74 | 75 | 76 | 77 | 78 | 欢迎使用预约服务,此服务将节省您排队挂号时间! 79 | 预约 80 | 81 | 82 | 83 | 预约界面 84 | 85 | 86 | 87 | 88 |
89 | 90 |
91 | 92 | -------------------------------------------------------------------------------- /miniprogram/component/Toast/Toast.js: -------------------------------------------------------------------------------- 1 | // component/Toast.js 2 | // 组件作者: 郑余国 https://gitee.com/slm47888/wechat_applet__component_toast 3 | 4 | // 任务列表 5 | let Task = [], show = null, self = null, hide = null, fn = []; 6 | 7 | Component({ 8 | properties: { 9 | // 传入参数 10 | data: { 11 | type: Object, 12 | value: {} 13 | } 14 | }, 15 | 16 | data: { 17 | // icon图标 18 | error: "wrong", 19 | success: "chenggong", 20 | warning: "jinggao", 21 | loading: "loading", 22 | zhiwen: "zhiwen", 23 | saoma: "saoma", 24 | }, 25 | methods: { 26 | selectClick: function (e) { 27 | // 点击按钮时执行函数 28 | let Id = e.target.dataset.fn; 29 | fn[Id - 1] && fn[Id - 1](); 30 | } 31 | }, 32 | ready: function () { 33 | // 监听 data 数据变化 34 | Object.defineProperty(this.data, "data", { 35 | // 当数据被改变时 被设置 36 | set: function (data) { 37 | let Toast = new Message(data); 38 | // 如果 没有正在显示的Toast则 显示 否则 如果是无限期显示的Toast则隐藏后显示 39 | !show ? Toast.send() : !show.data.hide && show.hide(); 40 | } 41 | }); 42 | }, 43 | pageLifetimes: { 44 | // 修复切换页面的BUG 45 | hide: function () { 46 | show && (Task = [], show = null, clearTimeout(hide), this.setData({ 47 | msg: {} 48 | })); 49 | }, 50 | show: function () { 51 | self = this; 52 | }, 53 | } 54 | }); 55 | 56 | function Message(data) { 57 | if (typeof data !== "object") throw Error("data 必须为 Object!"); 58 | // 隐藏时间或持续显示 否则 1500ms 后消失 59 | data.hideTime = (data.hideTime || data.hideTime === false) ? data.hideTime : 2500; 60 | // 修复耦合度 短时间内最多重复两条相同消息 61 | if (Task.length) { 62 | let t = Task[Task.length - 1]; 63 | if (t.text == data.text && t.icon == self.data[data.icon]) return; 64 | } 65 | // 加入任务列队 66 | Task.push({ 67 | text: data.text, 68 | icon: self.data[data.icon] || "", 69 | back: data.icon, 70 | hide: data.hideTime, 71 | callback: data.callback, 72 | select: data.select || false 73 | }); 74 | } 75 | 76 | Message.prototype = { 77 | data: {}, 78 | // 显示Toast 79 | send: function () { 80 | let after = Task[0]; 81 | if (after && !show) { 82 | // 记录触发函数 83 | for (let key in after["select"]) { 84 | let val = after["select"][key]; 85 | after["select"][key]._fn = val.click ? fn.push(val.click) : false 86 | } 87 | // 触发驱动 88 | self.setData({ 89 | msg: { 90 | _text: after["text"], 91 | _type: after["back"], 92 | _icon: after["icon"], 93 | select: after["select"] 94 | } 95 | }); 96 | // 如果Toast不是false则有消失时间 97 | after["hide"] && (hide = setTimeout(this.hide, after["hide"])); 98 | this.data = after; 99 | show = this; 100 | Task.shift(); 101 | } 102 | }, 103 | 104 | // 隐藏Toast 105 | hide: function () { 106 | show.data.callback && show.data.callback(); 107 | // 清空显示 108 | show = null; 109 | self.setData({ 110 | msg: { 111 | _text: "", 112 | _type: "", 113 | _icon: "" 114 | } 115 | }); 116 | // 400毫秒后检测列队 117 | setTimeout(Message.check, 400); 118 | } 119 | }; 120 | 121 | Message.check = function () { 122 | if (Task[0]) !show ? Message.prototype.send() : !show.data.hide && show.hide(); 123 | } -------------------------------------------------------------------------------- /miniprogram/pages/doctor/doctor.wxss: -------------------------------------------------------------------------------- 1 | .doctor-info { 2 | margin-top: 50rpx; 3 | padding: 30rpx 0; 4 | } 5 | .doctor-img { 6 | width: 120rpx; 7 | height: 120rpx; 8 | margin: 0 30rpx; 9 | vertical-align: middle; 10 | border-radius: 60rpx; 11 | box-shadow: 2px 2px 10px var(--shadow-color); 12 | } 13 | .doctor-info .img-right { 14 | display: flex; 15 | flex-wrap: wrap; 16 | flex-direction: row; 17 | align-items: center; 18 | float: right; 19 | width: calc(100% - 180rpx); 20 | height: 120rpx; 21 | } 22 | .doctor-info text { 23 | width: 100%; 24 | color: #888; 25 | } 26 | text.doctor-name { 27 | font-size: 1.2em; 28 | color: #222; 29 | } 30 | text.doctor-tag { 31 | margin-top: -10rpx; 32 | font-size: .9em; 33 | } 34 | .doctor-introduce { 35 | overflow: hidden; 36 | max-height: 0; 37 | padding: 20rpx; 38 | padding-bottom: 0; 39 | margin: 30rpx; 40 | margin-bottom: 0; 41 | border-top: 1px solid transparent; 42 | transition: .8s; 43 | } 44 | .doctor-introduce.focus { 45 | border-top: 1px solid #eee; 46 | max-height: 100vh; 47 | } 48 | text.introduce-tag { 49 | display: block; 50 | color: #333; 51 | } 52 | text.introduce-content { 53 | padding-left: 2em; 54 | font-size: .8em; 55 | } 56 | .doctor-name .iconfont { 57 | margin-left: 20rpx; 58 | color: #ccc; 59 | font-size: .9em; 60 | } 61 | 62 | .muen { 63 | position: relative; 64 | overflow: hidden; 65 | margin-top: 30rpx; 66 | } 67 | .muen-list { 68 | display: flex; 69 | } 70 | .muen-list text { 71 | position: relative; 72 | width: 100%; 73 | padding: 5px; 74 | z-index: 5; 75 | color: #fff; 76 | text-align: center; 77 | box-sizing: border-box; 78 | } 79 | .muen-list .focus { 80 | z-index: 1; 81 | color: #333; 82 | } 83 | .muen-list .focus::after, 84 | .muen-list .focus::before { 85 | content: ''; 86 | position: absolute; 87 | top: 0; 88 | width: 100vw; 89 | height: 100%; 90 | background-color: rgba(181, 207, 255, .6); 91 | border-radius: 0 0 20rpx 20rpx; 92 | box-shadow: 0 -2px 2px rgba(0, 0, 0, .05) inset; 93 | pointer-events: none; 94 | } 95 | .muen-list .focus::after { 96 | left: 0; 97 | margin-left: 100%; 98 | } 99 | .muen-list .focus::before { 100 | right: 0; 101 | margin-right: 100%; 102 | } 103 | .muen-content { 104 | padding: 20rpx 10rpx; 105 | } 106 | .muen-content .page > view { 107 | overflow: hidden; 108 | max-height: 0; 109 | transition: .8s; 110 | } 111 | .muen-content .page .focus { 112 | max-height: 100vh; 113 | } 114 | .center-text { 115 | display: block; 116 | margin: 10rpx 0; 117 | font-size: .85rem; 118 | text-align: center; 119 | color: #888; 120 | } 121 | .button { 122 | display: block; 123 | width: 40vw; 124 | padding: 5rpx 20rpx; 125 | margin: 25rpx auto; 126 | color: #75a5ff; 127 | font-size: 1rem; 128 | line-height: 50rpx; 129 | text-align: center; 130 | border: 2rpx solid; 131 | border-radius: 20px; 132 | } 133 | .button:active { 134 | color: #fff; 135 | background-color: #75a5ff; 136 | } 137 | 138 | .qrcode { 139 | display: block; 140 | width: 50vw; 141 | height: 50vw; 142 | margin: 0 auto; 143 | } 144 | 145 | /* 咨询 */ 146 | .con-list { 147 | width: 95%; 148 | padding: 10rpx 0; 149 | margin: 0 auto; 150 | font-size: 1.1rem; 151 | color: #777; 152 | border-bottom: 1px solid #eee; 153 | } 154 | .con-list text { 155 | color: #222; 156 | font-weight: 500; 157 | } 158 | .con-list .con-right { 159 | float: right; 160 | text-align: right; 161 | min-width: 50%; 162 | } 163 | .icon-fangxiangyou { 164 | float: right; 165 | margin-top: -1.5rpx; 166 | font-size: 1rem; 167 | color: #ccc; 168 | } 169 | .con-list textarea { 170 | width: 100%; 171 | min-height: 6rem; 172 | padding-bottom: 1rem; 173 | font-size: .95rem; 174 | } 175 | text.ps4 { 176 | position: absolute; 177 | right: 4%; 178 | color: #ccc; 179 | font-size: .8rem; 180 | transform: translateY(-100%) 181 | } 182 | .ps { 183 | color: #bbb; 184 | font-size: .7rem; 185 | } 186 | button { 187 | width: 60vw; 188 | margin: 20rpx auto 10rpx; 189 | font-weight: bold; 190 | color: #fff; 191 | text-shadow: 0 0 1rpx #777; 192 | background-color: #D3E2FF; 193 | } -------------------------------------------------------------------------------- /miniprogram/pages/search/search.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | 3 | Page({ 4 | 5 | /** 6 | * 页面的初始数据 7 | */ 8 | data: { 9 | listSelect: 0, 10 | results: [], 11 | tag: '' 12 | }, 13 | onLoad: function(e) { 14 | 15 | app.bar({ 16 | title: "查找", 17 | bcColor: "#F7F7F7,000" 18 | }); 19 | 20 | // 选中 指定的部门 21 | e.tag && this.setData(e); 22 | 23 | // 搜索 指定的医生 24 | e.name && this.search({}, e); 25 | 26 | // 显示 专家列表 27 | e.expertDoc && app.request("", "getExpertDoc", res => { 28 | 29 | // 判断部门标签是否注明 否则写入 30 | let dept = app.globalData.dept; 31 | console.log(res.data) 32 | if (!res.data[0].tag && dept[1]) { 33 | let deptList = {}; 34 | 35 | // 写入医生信息 36 | for (let index in res.data) { 37 | let info = res.data[index], 38 | tag = `${info.dept_id}.${info.sub_dept_id}`; 39 | 40 | if (tag in app.globalData.deptList) { 41 | res.data[index].tag = app.globalData.deptList[tag]; 42 | } else res.data[index].tag = 'not dept'; 43 | } 44 | } 45 | this.setData({ 46 | results: res.data 47 | }); 48 | }, 3600); 49 | }, 50 | 51 | onShow: function() { 52 | 53 | // 整理部门 54 | let all = [], 55 | icon = { 56 | '疼痛科': 'tengtongke', 57 | '其他': "qitake", 58 | "皮肤科": "pifuke", 59 | "内科": "neike", 60 | "口腔科": "kouqiangke", 61 | "骨科": "guke", 62 | "妇产科": "fuchanke", 63 | "耳鼻咽喉科": "erbihouke", 64 | "儿科": "erke", 65 | }, 66 | tag = this.data.tag, 67 | i = 0; 68 | 69 | let dept = app.globalData.dept; 70 | // 主部门 71 | for (let id in dept) { 72 | let name = dept[id].name; 73 | 74 | // 外面图标点入时 自动选中部门 75 | (name == tag) && this.setData({ 76 | listSelect: i 77 | }); 78 | 79 | let value = { 80 | tag: name, 81 | icon: icon[name] || 'wrong', 82 | list: [] 83 | }; 84 | // 子部门 85 | let subDrpt = dept[id].subDept; 86 | for (let subId in subDrpt) { 87 | value.list.push({ 88 | name: subDrpt[subId].name, 89 | id: subDrpt[subId].id 90 | }); 91 | } 92 | all.push(value); 93 | i++; 94 | } 95 | this.setData({ 96 | all 97 | }); 98 | }, 99 | 100 | // 大类选择 101 | unSelect: function(e) { 102 | if (e.target.dataset.i !== undefined) { 103 | this.setData({ 104 | listSelect: e.target.dataset.i 105 | }); 106 | } 107 | }, 108 | 109 | // 搜索子部门医生 110 | search: function(e, data = {}) { 111 | 112 | // 兼容非事件 113 | let tar = e.target ? e.target.dataset : {}; 114 | 115 | // 不允许全局[无条件]搜索 116 | if (!Object.keys(tar).length && !Object.keys(data).length) return; 117 | 118 | // 搜索请求 119 | app.request({ 120 | "doc_name": data.name || tar.name || "", 121 | "depId": data.depId || tar.depid || -1, 122 | "subdepId": data.subdepId || tar.subdepid || -1 123 | }, 'searchDoctor', res => { 124 | 125 | let data = res.data, 126 | dept = app.globalData.dept; 127 | 128 | if (data.error) return this.setData({ 129 | toast: { 130 | text: "未找到属于此部门的医生...", 131 | icon: "error" 132 | } 133 | }); 134 | 135 | // 写入 子部门ID 136 | let results = data.map(value => { 137 | let sub = dept[value.dept_id].subDept; 138 | for (let subId in sub) { 139 | if (sub[subId].id == value.sub_dept_id) { 140 | value.tag = sub[subId].name; 141 | break; 142 | } 143 | } 144 | return value; 145 | }); 146 | this.setData({ 147 | results 148 | }); 149 | console.log(results) 150 | }); 151 | }, 152 | 153 | /** 154 | * 【返回】清空搜索结果 155 | */ 156 | clearResults: function() { 157 | this.setData({ 158 | results: [] 159 | }); 160 | }, 161 | 162 | /** 163 | * 按 医生名字 搜索 164 | */ 165 | searchName: function(e) { 166 | let val = e.detail.value; 167 | 168 | // 兼容 键盘按下搜索 169 | (typeof val == 'string') && (val = { 170 | name: val 171 | }); 172 | this.search({}, val); 173 | }, 174 | 175 | /** 176 | * 打开医生信息页 177 | */ 178 | doctorPage: function(e) { 179 | if(!app.isLogin()) return this.setData({ 180 | toast: { 181 | text: app.getMessage("not login"), 182 | icon: "error" 183 | } 184 | }); 185 | let doctor = e.target.dataset.doctor; 186 | doctor && wx.navigateTo({ 187 | url: '../doctor/doctor?' + doctor, 188 | }); 189 | }, 190 | }) -------------------------------------------------------------------------------- /miniprogram/pages/account/account.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ 9 | userInfo.bind_account.patientname ? 10 | userInfo.bind_account.patientname : 11 | userInfo.bind_account.name ? 12 | userInfo.bind_account.name : 13 | userInfo.nickName ? 14 | userInfo.nickName : 15 | '点击授权' 16 | }} 17 | 医生代码: {{ userInfo.bind_account.ysdm }} 18 | 19 | 病号: {{ userInfo.bind_account.zxyy_id }} 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 待咨询 41 | 42 | 43 | 44 | 已结束 45 | 46 | 47 | 48 | 49 | 家庭成员 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 待咨询 60 | 61 | 62 | 63 | 64 | 65 | 已完成 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 身份证 [上传] 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 预约 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 处方 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 我的药店 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 检查单 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 药店分组 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 诊断分组 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 版本号: {{version}} 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /miniprogram/pages/account/register/register.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | let sendState = null, 3 | colling = 0, 4 | mssion = 0; 5 | Page({ 6 | data: { 7 | // 【0: 用户/1:医生】 8 | userType: 0, 9 | // 部门列表 10 | bmArray: [], 11 | // 部门选择器 [已选择] 12 | bmIndex: [-1, 0], 13 | // 部门选择器 [对象] 14 | bmObject: [], 15 | // 验证码冷却时间 16 | sendState: '发送' 17 | }, 18 | 19 | onShow: function() { 20 | // 设置标题 21 | app.bar({ 22 | title: '注册', 23 | bgColor: '#3285FF' 24 | }); 25 | 26 | // 整理部门数据 27 | let dept = app.globalData.dept, 28 | bmArray = [[], []], 29 | bmObject = []; 30 | 31 | if (dept[1]) { 32 | for (let id in dept) { 33 | // 存入主部门ID 34 | dept[id].uid = id; 35 | bmObject.push(dept[id]); 36 | bmArray[0].push(dept[id].name); 37 | } 38 | // 写入第一个部门的子部门 39 | for (let id in dept[1].subDept) { 40 | bmArray[1].push(dept[1].subDept[id].name); 41 | } 42 | this.setData({ 43 | bmArray, 44 | bmObject 45 | }); 46 | } 47 | 48 | }, 49 | 50 | /** 51 | * 选择结束 52 | */ 53 | select: function(e) { 54 | this.setData({ 55 | [e.target.dataset.key]: e.detail.value 56 | }); 57 | this.inputBlur(e); 58 | }, 59 | 60 | /** 61 | * 更新选择内容 62 | */ 63 | updateSelect: function(e) { 64 | // 滑动子部门 不更新 65 | if (e.detail.column) return; 66 | 67 | let dept = this.data.bmObject[e.detail.value] 68 | if (dept) { 69 | let arr = []; 70 | for (let id in dept.subDept) arr.push(dept.subDept[id].name); 71 | this.setData({ 72 | bmArray: [this.data.bmArray[0], arr] 73 | }) 74 | } 75 | }, 76 | 77 | /** 78 | * 聚焦函数 79 | */ 80 | inputFocus: function(t) { 81 | this.setData({ 82 | [t.target.dataset.id]: "changed" 83 | }); 84 | }, 85 | 86 | /** 87 | * 失焦函数 88 | */ 89 | inputBlur: function (t) { 90 | this.setData({ 91 | [t.target.dataset.id]: t.detail.value.length ? "nick" : "" 92 | }); 93 | }, 94 | 95 | /** 96 | * 用户提交注册事件 97 | */ 98 | register: function(e) { 99 | let error = ""; 100 | let val = e.detail.value; 101 | 102 | // 倒序检查!!! 103 | 104 | // 医生注册 105 | if ('ysdm' in val) { 106 | !val.ysbm && (error = "所在部门 不能为空!"); 107 | !val.ysdm && (error = "医生代码 不能为空!"); 108 | } 109 | // 条件判断 110 | if (!val.csrq || !(/^(\d){4}-(\d){1,2}-(\d){1,2}$/g).test(val.csrq)) 111 | error = "出生日期 格式错误: 1999-01-01!" 112 | if (!val.phone || !(/^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/g).test(val.phone)) 113 | error = "手机号 格式错误!"; 114 | if (!val.name || !(/^[\u4E00-\u9FA5\uf900-\ufa2d]{2,4}$/g).test(val.name)) 115 | error = "姓名 格式错误!"; 116 | 117 | if (error) return this.setData({ 118 | toast: { 119 | text: error, 120 | icon: "error" 121 | } 122 | }); 123 | 124 | // 都没问题开始注册 125 | let api = 'userRegister'; 126 | if ('ysdm' in val) { 127 | let dept = this.data.bmObject[this.data.bmIndex[0]]; 128 | val.hospital_id = ""; 129 | val.dept_id = dept.uid; 130 | val.sub_dept_id = dept.subDept[this.data.bmIndex[1]].id; 131 | val.ksdm = dept.ksdm; 132 | delete val.ysbm; 133 | api = 'doctorRegister'; 134 | } 135 | 136 | app.request(val, api, res => { 137 | console.log(res) 138 | if (res.data.mssion_id) { 139 | this.setData({ 140 | showCode: 1 141 | }); 142 | mssion = res.data.mssion_id; 143 | } else this.setData({ 144 | toast: { 145 | text: res.data.error, 146 | icon: "error" 147 | } 148 | }); 149 | }, app.globalData.token); 150 | 151 | console.log(val) 152 | }, 153 | 154 | /** 155 | * 发送验证码 156 | */ 157 | sendCode: function(e) { 158 | let code = e.detail.value.codes; 159 | if(!code) return this.setData({ 160 | toast: { 161 | text: '验证码不能为空!', 162 | icon: "error" 163 | } 164 | }); 165 | app.request(`${mssion}/${code}?token=${app.globalData.token}`, "finishBindAndRegMssion", res => { 166 | console.log(res) 167 | if (res.data.status) { 168 | wx.navigateBack({ 169 | delta: 3 170 | }); 171 | } this.setData({ 172 | toast: { 173 | text: res.data.error, 174 | icon: "error" 175 | } 176 | }); 177 | }); 178 | }, 179 | 180 | /** 181 | * 隐藏验证码界面 182 | */ 183 | hideCode: function() { 184 | this.setData({ 185 | showCode: 0 186 | }); 187 | }, 188 | 189 | /** 190 | * 选择用户类型事件 191 | */ 192 | selectUserType: function(e) { 193 | e.target.dataset.i && this.setData({ 194 | userType: e.target.dataset.i 195 | }); 196 | }, 197 | 198 | /** 199 | * 页面滑动事件 200 | */ 201 | pageChange: function(e) { 202 | this.setData({ 203 | userType: e.detail.current 204 | }); 205 | }, 206 | }) -------------------------------------------------------------------------------- /miniprogram/pages/account/account.js: -------------------------------------------------------------------------------- 1 | var app = getApp(); 2 | let register = false; 3 | 4 | Page({ 5 | data: { 6 | 7 | // 小程序版本 8 | version: "1.0.0", 9 | 10 | // 用户信息 11 | userInfo: { 12 | avatarUrl: "/images/avatar_user_0.png", 13 | bind_account: { 14 | zxyy_id: "------" 15 | }, 16 | doctor: false 17 | } 18 | }, 19 | 20 | onShow: function() { 21 | if (!Boolean(app.globalData.userInfo + []) || 22 | !app.globalData.userInfo.bind_account) { 23 | wx.getSetting({ 24 | success: setting => { 25 | if (setting.authSetting["scope.userInfo"]) { 26 | wx.getUserInfo({ 27 | success: res => { 28 | this.settingAccount(res, true); 29 | } 30 | }); 31 | } 32 | } 33 | }) 34 | } else { 35 | this.setData({ 36 | userInfo: app.globalData.userInfo, 37 | doctor: !!app.globalData.userInfo.bind_account.ysdm 38 | }); 39 | } 40 | 41 | }, 42 | 43 | onLoad: function(a) { 44 | app.bar({ 45 | title: "我的", 46 | bgColor: "#b5cfff" 47 | }); 48 | 49 | // 初始化版本 50 | this.setData({ 51 | version: app.globalData.version 52 | }); 53 | 54 | // 监听数据 同步全局 55 | Object.defineProperty(this.data, "userInfo", { 56 | set: data => { 57 | app.globalData.userInfo = data; 58 | } 59 | }); 60 | }, 61 | 62 | // 提示版本 63 | printVersion: function() { 64 | this.setData({ 65 | toast: { 66 | text: "VERSION " + this.data.version, 67 | icon: "loading", 68 | hideTime: 4e3 69 | } 70 | }); 71 | }, 72 | 73 | // 设置账号 74 | settingAccount: function (res, load) { 75 | // if (this.__viewData__.userInfo.xcxid) return; 76 | 77 | // 兼容事件处理 78 | res.detail && (res = res.detail); 79 | 80 | // 检测授权 81 | if (res.userInfo) { 82 | this.setData({ 83 | userInfo: res.userInfo 84 | }); 85 | 86 | // 如果本地已存储数据且没过期则用本地的 87 | // let storage = wx.getStorageSync("userInfo"); 88 | // if (storage && storage.bind_account && storage.endTime > Date.now() / 1000) return this.setData({ 89 | // userInfo: storage, 90 | // doctor: storage.bind_account ? !!storage.bind_account.ysdm : false 91 | // }); 92 | 93 | // 获取openid 94 | wx.cloud.callFunction({ 95 | name: "getOpenId", 96 | complete: data => { 97 | 98 | // 拉取主系统数据 99 | let getLoginData = e => { 100 | data.result.openId = 'o-PgA5R0PU-6L-JS_XN0jHGDp-3w'; 101 | app.request(data.result.openId, "login", login => { 102 | // 用户是否注册 103 | if (login.data.token) { 104 | 105 | app.globalData.token = login.data.token; 106 | // 获取账号数据 107 | app.request(login.data.token, "accountData", info => { 108 | let user = Object.assign(res.userInfo, login.data, info.data); 109 | // 判断绑定 110 | if (user.bind_account) { 111 | res.userInfo.endTime = user.token.split("-")[2] || Date.now() + 259200; 112 | this.setData({ 113 | userInfo: user, 114 | doctor: user.bind_account ? !!user.bind_account.ysdm : false 115 | }); 116 | wx.setStorage({ 117 | key: "userInfo", 118 | data: user 119 | }); 120 | 121 | } else { 122 | !load && wx.navigateTo({ 123 | url: "login/login?token=" + login.data.token 124 | }); 125 | } 126 | }); 127 | } else if (!register) { 128 | 129 | // 注册账号 130 | register = true; 131 | app.request(data.result.openId, "register", getLoginData, false, 20); 132 | } 133 | }, 5); 134 | }; 135 | 136 | // 主动执行一次 137 | getLoginData(); 138 | 139 | } 140 | }); 141 | } else { 142 | this.setData({ 143 | toast: { 144 | text: "获取授权失败!请允许授权...", 145 | icon: "error", 146 | hideTime: 2000 147 | } 148 | }); 149 | } 150 | }, 151 | 152 | /** 153 | * 权限检测 154 | */ 155 | navgiate: function(e) { 156 | 157 | let data = e.currentTarget.dataset; 158 | if (data.page) { 159 | if (data.pro) { 160 | let error = false; 161 | console.log(app.globalData.doctor) 162 | if (data.pro == 'put' && !app.globalData.userInfo.nickName) { 163 | error = '请先登录!'; 164 | } else if (data.pro == 'doc' && !app.globalData.doctor) { 165 | error = '非医生不能进行此操作!'; 166 | } else if (data.pro == 'card' && !app.globalData.userInfo.bind_account.patientname) { 167 | error = '此操作必须在实名后!'; 168 | } 169 | if (error) return this.setData({ 170 | toast: { 171 | text: error, 172 | icon: 'error' 173 | } 174 | }); 175 | } 176 | wx.navigateTo({ 177 | url: data.page, 178 | }); 179 | } 180 | console.log(e, data) 181 | if (!app.globalData.userInfo.nickName) {} 182 | }, 183 | 184 | }); -------------------------------------------------------------------------------- /miniprogram/pages/upload/idCard/idcard.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | let outInter = null, 3 | mssion_id = 0; 4 | 5 | Page({ 6 | 7 | data: { 8 | isId: "", 9 | sendState: "发送", 10 | res: {} 11 | }, 12 | 13 | onLoad: function(e) { 14 | e && this.setData(e); 15 | }, 16 | 17 | onShow: function() { 18 | app.bar({ 19 | title: "身份认证", 20 | bgColor: "#b5cfff" 21 | }); 22 | }, 23 | 24 | /** 25 | * 聚焦函数 26 | */ 27 | inputFocus: function(t) { 28 | this.setData({ 29 | [t.target.dataset.id]: "changed" 30 | }); 31 | }, 32 | 33 | /** 34 | * 失焦函数 35 | */ 36 | inputBlur: function(t) { 37 | this.setData({ 38 | [t.target.dataset.id]: t.detail.value.length ? "nick" : "" 39 | }); 40 | }, 41 | 42 | /** 43 | * 选择图片 44 | */ 45 | camera: function(e) { 46 | let self = this; 47 | wx.chooseImage({ 48 | count: 1, 49 | success: function(res) { 50 | self.setData({ 51 | isId: res.tempFilePaths[0] 52 | }); 53 | } 54 | }); 55 | }, 56 | 57 | /** 58 | * 身份证上传 59 | */ 60 | upload: function() { 61 | 62 | if (!this.data.isId) return this.setData({ 63 | toast: { 64 | text: '请拍摄或者选择一张身份证正面照片!', 65 | icon: 'error' 66 | } 67 | }); 68 | 69 | // 如果为上传家庭成员身份证 70 | if (this.data.addFamily) return this.addFamily(); 71 | 72 | this.uploadFile(res => { 73 | if (res.status) { 74 | app.globalData.userInfo = []; 75 | wx.removeStorageSync('userInfo'); 76 | wx.switchTab({ 77 | url: '../../account/account' 78 | }); 79 | } 80 | }); 81 | }, 82 | 83 | /** 84 | * 上传家庭成员身份证 85 | */ 86 | addFamily: function() { 87 | this.uploadFile(res => { 88 | 89 | this.setData({ 90 | code: true, 91 | res 92 | }); 93 | }); 94 | 95 | }, 96 | 97 | /** 98 | * 返回按钮 99 | */ 100 | hideCode: function() { 101 | this.setData({ 102 | code: false 103 | }); 104 | }, 105 | 106 | /** 107 | * 发送验证码 108 | */ 109 | sendCode: function (e) { 110 | e = e.detail.value; 111 | if (e.codes) { 112 | // 验证 验证码是否正确 113 | app.request(`${mssion_id}/${e.codes}?token=${app.globalData.userInfo.token}`, 'addFamilySendCode', res => { 114 | if (res.data.status) { 115 | wx.navigateBack({ 116 | delta: 1 117 | }); 118 | } else this.setData({ 119 | toast: { 120 | text: "身份证验证失败:" + res.data.error, 121 | icon: "error" 122 | } 123 | }); 124 | }); 125 | } else if (e.phone) { 126 | let res = this.data.res; 127 | app.request(`${res.mssion_id}/${res.code}/${e.phone}?token=${app.globalData.userInfo.token}`, 'addFamilyGetCode', res => { 128 | 129 | // 冷却 130 | if (!isNaN(res)) return this.countDown((res / 1000).toFixed(0)); 131 | 132 | // 如果存在mssion_id 133 | if (res.data.mssion_id) { 134 | 135 | mssion_id = res.data.mssion_id; 136 | this.setData({ 137 | toast: { 138 | text: "验证码已发送!请输入...", 139 | icon: "success", 140 | hideTime: 3000 141 | } 142 | }); 143 | // 冷却倒计时 144 | this.countDown(60); 145 | } else this.setData({ 146 | toast: { 147 | text: "验证码发送失败:" + res.data.error, 148 | icon: "error" 149 | } 150 | }); 151 | }, false, 60); 152 | } 153 | }, 154 | 155 | /** 156 | * 身份证错误信息翻译 157 | */ 158 | idCardError: function(error) { 159 | let err = error; 160 | switch (error) { 161 | case "not a patient account": 162 | err = "不是病人的账号!"; 163 | break; 164 | case "Unbound main system account": 165 | err = "未绑定的主系统账号!"; 166 | break; 167 | case "no image file upload": 168 | err = "图片上传程序错误!"; 169 | break; 170 | case "recognize error": 171 | err = "图片无法识别,请按要求拍摄!"; 172 | break; 173 | case "Image type error": 174 | err = "图片类型错误,无法识别为身份证!"; 175 | break; 176 | case "please upload face side": 177 | err = "请上传身份证正面的照片!"; 178 | break; 179 | case "card number is empty": 180 | err = "卡号为空!"; 181 | break; 182 | } 183 | return err; 184 | }, 185 | 186 | uploadFile: function(callback) { 187 | 188 | let self = this, 189 | url = !this.data.addFamily ? 190 | app.globalData.ip + "api/SetIDCard?token=" + app.globalData.userInfo.token : 191 | app.globalData.ip + "api/addFamilyUserStep1?token=" + app.globalData.userInfo.token; 192 | 193 | wx.uploadFile({ 194 | url, 195 | filePath: this.data.isId, 196 | name: "idcard", 197 | success: function(res) { 198 | 199 | let data = JSON.parse(res.data); 200 | if (data.error) { 201 | let err = self.idCardError(data.error); 202 | return self.setData({ 203 | toast: { 204 | text: err, 205 | icon: 'error', 206 | hideTime: 4000 207 | } 208 | }); 209 | } else callback(data); 210 | }, 211 | fail: console.error 212 | }); 213 | }, 214 | 215 | /** 216 | * 倒计时 217 | */ 218 | countDown: function (outTime) { 219 | outInter = setInterval(() => { 220 | if (!outTime) { 221 | clearInterval(outInter); 222 | outTime = "发送"; 223 | } 224 | this.setData({ 225 | sendState: outTime 226 | }); 227 | outTime--; 228 | }, 1000); 229 | } 230 | }) -------------------------------------------------------------------------------- /miniprogram/pages/account/register/register.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 用户 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 41 | 42 | 43 | 44 |
45 | 46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
57 | 58 |
59 | 60 | 61 | 62 | 134 | 135 |
136 | 137 |
138 | -------------------------------------------------------------------------------- /miniprogram/pages/account/answer/answer.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | max-height: 100vh; 3 | overflow: hidden; 4 | } 5 | .row-box { 6 | width: 100vw; 7 | height: 100rpx; 8 | padding: 20rpx 0; 9 | } 10 | .row-box .user-icon { 11 | float: left; 12 | margin: 0 20rpx; 13 | } 14 | .doc-name { 15 | font-size: 1.2rem; 16 | color: #333; 17 | } 18 | .doc-type { 19 | margin-left: 20rpx; 20 | font-size: .8rem; 21 | color: #ccc; 22 | } 23 | .doc-department { 24 | display: block; 25 | width: clac(100% - 150rpx); 26 | font-size: .9rem; 27 | color: #777; 28 | } 29 | 30 | 31 | .msg-box { 32 | height: calc(100vh - 225rpx); 33 | transition: .5s; 34 | } 35 | .msg-show { 36 | height: calc(100vh - 300rpx); 37 | } 38 | .put-info { 39 | width: 90vw; 40 | margin: 30rpx auto; 41 | padding: 20rpx; 42 | color: #555; 43 | background-color: #eee; 44 | border: 10rpx dashed #ddd; 45 | border-radius: 20rpx; 46 | box-sizing: border-box; 47 | } 48 | .descript { 49 | display: block; 50 | text-indent: 2rem; 51 | color: #888; 52 | } 53 | .put-box, 54 | .doc-box { 55 | width: 100vw; 56 | margin: 10rpx 0; 57 | display: flex; 58 | flex-direction: row; 59 | flex-wrap: wrap; 60 | align-items: center; 61 | justify-content: flex-end; 62 | } 63 | .doc-box { 64 | flex-direction: row-reverse; 65 | } 66 | /* 医生 */ 67 | .doctor .doc-box { 68 | flex-direction: inherit; 69 | } 70 | .doctor .doc-box .doc { 71 | margin-right: 30rpx; 72 | } 73 | .doctor .put-box { 74 | flex-direction: row-reverse; 75 | } 76 | .doctor .put-box .put { 77 | margin-left: 30rpx; 78 | } 79 | .doctor .doc-box .doc::after { 80 | right: -27rpx; 81 | left: auto; 82 | border-color: transparent transparent transparent #53DB95; 83 | } 84 | .doctor .put-box .put::after { 85 | right: auto; 86 | left: -27rpx; 87 | border-color: transparent #29CCC1 transparent transparent; 88 | } 89 | /* 公用对话 */ 90 | .msg-box .put, 91 | .doc-box .doc { 92 | float: left; 93 | position: relative; 94 | max-width: 60vw; 95 | padding: 20rpx; 96 | margin-right: 30rpx; 97 | color: #fff; 98 | line-height: 1.75; 99 | word-wrap: break-word; 100 | background-image: linear-gradient(90deg, #29CCC1, #53DB95); 101 | border-radius: 20rpx; 102 | } 103 | .nick .put, 104 | .nick .doc { 105 | transform-origin: right; 106 | animation: 1s .5s msg; 107 | animation-fill-mode: forwards; 108 | transform: rotateY(90deg); 109 | } 110 | @keyframes msg { 111 | to { 112 | transform: rotateY(0deg); 113 | } 114 | } 115 | .msg-box .put::after, 116 | .doc-box .doc::after { 117 | content: ""; 118 | position: absolute; 119 | right: -27rpx; 120 | top: 0; 121 | bottom: 0; 122 | height: 0; 123 | margin: auto; 124 | border-style: solid; 125 | border-width: 15rpx; 126 | border-color: transparent transparent transparent #53DB95; 127 | transform: translateY(50%); 128 | } 129 | .put text, 130 | .doc text { 131 | font-size: .7rem; 132 | color: #888; 133 | } 134 | 135 | .doc-box .doc { 136 | margin-right: 0; 137 | margin-left: 30rpx; 138 | } 139 | .doc-box .doc::after { 140 | right: auto; 141 | left: -27rpx; 142 | border-color: transparent #29CCC1 transparent transparent; 143 | } 144 | .msg-box image { 145 | float: right; 146 | width: 100rpx; 147 | height: 100rpx; 148 | margin: 10rpx; 149 | border: 1rpx dashed #ccc; 150 | border-radius: 10rpx; 151 | } 152 | .nick image { 153 | animation: .5s icon; 154 | } 155 | @keyframes icon { 156 | from { 157 | transform: translateY(50%); 158 | opacity: 0; 159 | } 160 | to { 161 | transform: translateY(0); 162 | } 163 | } 164 | .fix { 165 | height: 100rpx; 166 | } 167 | 168 | 169 | .input-box { 170 | width: 100%; 171 | /* background-color: #eee; */ 172 | border-top: 1px solid #ddd; 173 | } 174 | .input-box .icon-fangxiangshang { 175 | float: left; 176 | width: calc(10% - 2rpx); 177 | height: 10%; 178 | margin: 15rpx 0; 179 | text-align: center; 180 | color: #999; 181 | background-color: #ddd; 182 | border: 1px solid #ccc; 183 | border-radius: 100px; 184 | transition: .5s; 185 | } 186 | .deg { 187 | transform: rotate(180deg) 188 | } 189 | .input-box input { 190 | float: left; 191 | width: 60%; 192 | height: 60rpx; 193 | padding: 0 .5rem; 194 | margin: 15rpx 10rpx; 195 | font-size: 1rem; 196 | color: #444; 197 | border: 1px solid #ddd; 198 | background-color: #fff; 199 | border-radius: 100px; 200 | box-sizing: border-box; 201 | } 202 | .input-box button { 203 | float: left; 204 | width: calc(30% - 40rpx); 205 | height: 60rpx; 206 | margin: 15rpx 10rpx; 207 | line-height: initial; 208 | white-space: nowrap; 209 | color: #666; 210 | background-color: #ddd; 211 | border-radius: 100px; 212 | border: 1px solid #ccc; 213 | outline: 0; 214 | } 215 | .tool-box { 216 | max-height: 0; 217 | width: 100vw; 218 | transition: 1s; 219 | } 220 | .show { 221 | max-height: 10vh; 222 | } 223 | .tool { 224 | min-height: 2.5rem; 225 | white-space: nowrap; 226 | } 227 | .tool icon, 228 | .tool text { 229 | padding: 0 20rpx; 230 | margin: 0 10rpx; 231 | vertical-align: middle; 232 | color: #666; 233 | background-color: #ddd; 234 | border-radius: 100px; 235 | border: 1px solid #ccc; 236 | } 237 | 238 | .loading { 239 | display: flex; 240 | flex-direction: row; 241 | justify-content: center; 242 | align-items: center; 243 | font-size: .8rem; 244 | color: #ccc; 245 | } 246 | .loading icon { 247 | margin: -10rpx 10rpx 0; 248 | font-size: 1rem; 249 | vertical-align: middle; 250 | } 251 | .date { 252 | display: block; 253 | font-size: .8rem; 254 | text-align: center; 255 | color: #ccc; 256 | } 257 | .old { 258 | display: block; 259 | padding: 10rpx 0 30rpx; 260 | text-align: center; 261 | color: #999; 262 | font-size: .8rem; 263 | } 264 | .old::after, 265 | .old::before { 266 | content: ''; 267 | display: inline-block; 268 | margin: 0 5vw .3rem; 269 | width: calc(40vw - 2.8rem); 270 | height: 2rpx; 271 | background-color: currentColor; 272 | } -------------------------------------------------------------------------------- /miniprogram/pages/account/answer/answer.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | const timeC = 60 * 1000; 3 | let msgBox = {}, 4 | token = false, 5 | last = 0, 6 | scroll = null; 7 | 8 | let unRead = null; 9 | 10 | Page({ 11 | 12 | data: { 13 | msg: [], 14 | end: 0, 15 | inputValue: '', 16 | scrollTop: 0, 17 | loading: true 18 | }, 19 | 20 | onLoad: function(option) { 21 | 22 | option.id = 659; 23 | this.setData({ 24 | user: app.globalData.userInfo, 25 | id: option.id, 26 | doctor: app.globalData.doctor 27 | }); 28 | app.bar({ 29 | title: "咨询医生", 30 | bgColor: "#B5CFFF" 31 | }); 32 | token = app.globalData.userInfo.token; 33 | let value = `${option.id}?token=${token}`; 34 | 35 | // 未读读内容获取[权重 高] 36 | app.request(value, "getUnreadQA", res => { 37 | 38 | setTimeout(() => { 39 | this.setData({ 40 | loading: false 41 | }); 42 | }, 5000); 43 | 44 | if (!res.data.length) return; 45 | 46 | // 计算时差 47 | let list = this.unDate(res.data); 48 | 49 | // 如果 未读先得到则合并 但是 已读一定得在未读后面 50 | if (this.data.msg.length) { 51 | this.data.msg.push(...res.data); 52 | list = this.data.msg; 53 | } 54 | 55 | this.setData({ 56 | msg: list, 57 | end: list.length - 1, 58 | loading: false 59 | }); 60 | 61 | }); 62 | // 咨询消息读取[权重 中] 63 | app.request(value, "getAskDoctorDetail", res => { 64 | if (res.data) { 65 | this.setData({ 66 | detail: res.data 67 | }); 68 | } else this.setData({ 69 | toast: { 70 | text: "咨询数据读取错误,不存在或无权限!", 71 | icon: "error" 72 | } 73 | }); 74 | }); 75 | 76 | 77 | // 已读内容获取[权重 低] 78 | app.request(value, "getHistoryQA", res => { 79 | if (!res.data.length) return; 80 | 81 | // 计算时差 82 | let list = this.unDate(res.data); 83 | 84 | // 未读位置 85 | last = list.length; 86 | 87 | // 最后一条消息后面显示历史消息 88 | // (list.length > 0) && (list[list.length - 1].old = true); 89 | let listLast = list.length; 90 | // 如果 未读先得到则合并 但是 已读一定得在未读后面 91 | this.data.msg.length && list.push(...this.data.msg); 92 | 93 | if (listLast) { 94 | if (!this.data.doctor) { 95 | // 最后一条消息后面显示历史消息 但如果已读的前几条为病人的消息 则往下直到医生 96 | while (list[listLast] && list[listLast].is_question) { 97 | listLast++; 98 | } 99 | } else { 100 | // 与上条相反 直到病人 101 | while (list[listLast] && !list[listLast].is_question) { 102 | listLast++; 103 | } 104 | } 105 | list[listLast - 1].old = true 106 | } 107 | 108 | this.setData({ 109 | msg: list, 110 | end: list.length - 1, 111 | loading: false 112 | }); 113 | 114 | this.update(); 115 | // 滑动到历史位置[测试] 116 | let query = wx.createSelectorQuery(); 117 | query.select('.old').boundingClientRect(); 118 | query.exec(res => { 119 | (res[0].top && msgBox.box) && this.setData({ 120 | scrollTop: res[0].top + msgBox.box.height + 'rpx' 121 | }); 122 | }); 123 | 124 | }); 125 | 126 | unRead = setInterval(() => { 127 | 128 | app.request(value, "getUnreadQA", res => { 129 | 130 | if (!this.data.msg.length && !res.data.length) return; 131 | 132 | // 计算时差 133 | let list = this.unDate(res.data); 134 | // 过滤出自己的消息 135 | for (let i = 0, l = res.data.length - 1; i < l; i++) { 136 | if (this.data.doctor) { 137 | if (!res.data[i].is_question) res.data.splice(i, 1) 138 | } else { 139 | if (res.data[i].is_question) res.data.splice(i, 1) 140 | } 141 | } 142 | if (res.data.length) { 143 | this.data.msg.push(...res.data); 144 | this.setData({ 145 | msg: this.data.msg 146 | }); 147 | let oldLast = last; 148 | // 根据 得到消息进行判断 149 | for (let i = last, l = this.data.msg.length; i < l; i ++) { 150 | if (!this.data.doctor && !this.data.msg[i].is_question) last = i; 151 | if (this.data.doctor && this.data.msg[i].is_question) last = i; 152 | } 153 | if (oldLast < last) { 154 | app.request(`${this.data.id}/${res.data[res.data.length - 1].id}?token=${token}`, "qaMarkAsRead"); 155 | } 156 | 157 | this.update(); 158 | // 滑动到历史位置[测试] 159 | let query = wx.createSelectorQuery(); 160 | query.select('.msg-box').boundingClientRect(); 161 | query.exec(res => { 162 | (res[0].top && msgBox.box) && this.setData({ 163 | scrollTop: (last * 150) + 'rpx' 164 | }); 165 | }); 166 | } 167 | 168 | }); 169 | }, 5000) 170 | }, 171 | 172 | 173 | onUnload: function () { 174 | clearInterval(unRead); 175 | }, 176 | 177 | /** 178 | * 视图大小更新 179 | */ 180 | update: function() { 181 | let query = wx.createSelectorQuery(); 182 | // 得到聊天视图大小 183 | query.select('.msg-box').boundingClientRect(); 184 | query.exec(res => { 185 | msgBox.box = res[0]; 186 | let child = wx.createSelectorQuery(); 187 | child.selectAll('.in-box').boundingClientRect(); 188 | child.selectViewport() 189 | 190 | child.exec(res => { 191 | msgBox.child = res[0]; 192 | }); 193 | }); 194 | }, 195 | 196 | onShow: function() { 197 | 198 | }, 199 | 200 | /** 201 | * 发送咨询消息 202 | */ 203 | sendInput: function(e) { 204 | let con = e.detail.value.content || e.detail.value; 205 | if (con && typeof con == 'string') { 206 | let msg = this.data.msg; 207 | // 时差计算 208 | let time = app.getDate("yyyy-MM-dd HH:mm:ss"); 209 | let index = msg.push({ 210 | l_content: con, 211 | is_question: this.data.doctor ? 0 : 1, 212 | create_time: time, 213 | addDate: msg[msg.length - 1] ? (new Date(time) - new Date(msg[msg.length - 1].create_time) > timeC) ? time : false : time 214 | }); 215 | 216 | // 写入数据 并 滚动至底部 217 | this.setData({ 218 | msg, 219 | inputValue: '', 220 | scrollTop: msg.length * 100 + 'px' 221 | }); 222 | 223 | // 向服务器发送消息 224 | app.request({ 225 | ask_id: this.data.id, 226 | content: con 227 | }, this.data.doctor ? "docAddAnswer" : "patAddAnswer", res => { 228 | if (!res.data.status) { 229 | this.data.msg[index - 1].error = ' [发送失败]'; 230 | this.setData({ 231 | msg: this.data.msg 232 | }); 233 | } 234 | }, token); 235 | } 236 | }, 237 | 238 | /** 239 | * 切换工具栏 240 | */ 241 | toggleTool: function() { 242 | this.setData({ 243 | tool: !!!this.data.tool 244 | }); 245 | }, 246 | 247 | /** 248 | * 直接发送内容 249 | */ 250 | addContent: function(e) { 251 | if (e._relatedInfo) { 252 | this.sendInput({ 253 | detail: { 254 | value: e._relatedInfo.anchorTargetText 255 | } 256 | }); 257 | } 258 | }, 259 | 260 | /** 261 | * 滚动时节流算法触发 [已读算法] 262 | */ 263 | lower: function(e) { 264 | // 节流 265 | clearTimeout(scroll); 266 | scroll = setTimeout(() => { 267 | this.update(); 268 | let height = msgBox.box ? msgBox.box.height : 0; 269 | // 计算可视角大小 270 | let top = e.detail.scrollTop + height, 271 | newVl = last; 272 | 273 | // 从最后一条开始往下遍历 防止多余的遍历 274 | for (let i = last, l = msgBox.child.length; i < l; i++) { 275 | (msgBox.child[i].top <= top && 276 | ( 277 | // 标记医生消息 278 | (!this.data.doctor && !this.data.msg[i].is_question) || 279 | // 标记用户消息 280 | (this.data.doctor && this.data.msg[i].is_question) 281 | ) 282 | ) && (last = i); 283 | } 284 | 285 | // 得到屏幕最后一条可见消息 标记已读 286 | if (newVl < last) { 287 | app.request(`${this.data.id}/${this.data.msg[last].id}?token=${token}`,"qaMarkAsRead"); 288 | } 289 | }, 1000); 290 | }, 291 | 292 | /** 293 | * 时差计算 294 | */ 295 | unDate: function(date) { 296 | // 计算时间差 297 | return date.map((val, ind, arr) => { 298 | let date = new Date(val.create_time), 299 | date2 = arr[ind - 1] ? new Date(arr[ind - 1].create_time) : 0; 300 | 301 | val.addDate = date2 - date < -timeC ? val.create_time : false; 302 | return val; 303 | }); 304 | }, 305 | }) -------------------------------------------------------------------------------- /miniprogram/app.wxss: -------------------------------------------------------------------------------- 1 | page { 2 | --shadow-color: rgba(0, 0, 0, .15); 3 | --main-icon-color: #4684f7; 4 | --main-font-color: #11cd6e; 5 | --main-fontSelect-color: #a9b7b7; 6 | background-color: #f7f7f7; 7 | } 8 | 9 | 10 | /* 背景 */ 11 | .background { 12 | position: absolute; 13 | top: 0; 14 | left: 0; 15 | width: 750rpx; 16 | z-index: -1; 17 | } 18 | 19 | .backgroundColor { 20 | position: absolute; 21 | z-index: -1; 22 | top: 0; 23 | left: 0; 24 | width: 100vw; 25 | height: 120rpx; 26 | background-color: #b5cfff; 27 | } 28 | 29 | 30 | /* LOGO */ 31 | .logo { 32 | display: block; 33 | width: 180rpx; 34 | height: 180rpx; 35 | margin: 50rpx auto; 36 | border-radius: 90rpx; 37 | box-shadow: 0 0 100rpx #1831c2; 38 | border: 5rpx solid rgba(255, 255, 255, 0.3); 39 | } 40 | 41 | /* 修复浮动 */ 42 | .clearfix::after { 43 | content: ''; 44 | display: block; 45 | width: 100%; 46 | height: 100%; 47 | clear: both; 48 | } 49 | 50 | 51 | /* 主盒子 */ 52 | .row-box { 53 | width: 94vw; 54 | min-height: 30rpx; 55 | margin: 0 auto; 56 | background-color: white; 57 | border-radius: 10rpx; 58 | box-shadow: 0 2px 5px var(--shadow-color); 59 | } 60 | 61 | 62 | /* 四列列表 */ 63 | .four-list { 64 | margin-top: 25rpx; 65 | padding: 0; 66 | font-size: 30rpx; 67 | } 68 | .four-list-tag { 69 | display: flex; 70 | justify-content: space-between; 71 | align-items: center; 72 | width: 95%; 73 | margin: 0 2.5%; 74 | padding: 20rpx 10rpx; 75 | text-align: left; 76 | color: #888; 77 | font-weight: bold; 78 | border-bottom: 1px solid #eee; 79 | } 80 | 81 | .four-list .four-list-tag > view > text:active, 82 | .four-list .four-list-tag > view > text:active + icon { 83 | color: #666; 84 | } 85 | 86 | .four-list-all .icon-fangxiangyou { 87 | font-size: 15px; 88 | margin: -17rpx 0 0 10rpx; 89 | } 90 | 91 | .four-list-all { 92 | color: #ccc; 93 | font-weight: normal; 94 | text-shadow: none; 95 | font-size: 15px; 96 | } 97 | 98 | .four-list-icon > view { 99 | float: left; 100 | width: 25%; 101 | padding: 15rpx 10rpx; 102 | box-sizing: border-box; 103 | text-align: center; 104 | color: #777; 105 | } 106 | 107 | .four-list-icon icon:nth-child(1), 108 | .four-list-icon image, 109 | .user-icon { 110 | display: block; 111 | width: 50rpx; 112 | height: 50rpx; 113 | margin: 0 auto 10rpx; 114 | padding: 20rpx; 115 | color: rgba(255, 255, 255, .8); 116 | font-size: 50rpx; 117 | text-align: center; 118 | background-color: #149be7; 119 | border-radius: 50rpx; 120 | box-shadow: 0 2px 3px var(--shadow-color); 121 | text-shadow: 1px 1px 2px rgba(0, 0, 0, .3); 122 | transition: .1s; 123 | } 124 | 125 | .four-list > view icon:nth-child(1):active { 126 | text-shadow: .5px .5px 1px rgba(0, 0, 0, .6); 127 | box-shadow: 0 3px 10px rgba(0, 0, 0, .3) 128 | } 129 | 130 | .four-list > view image, 131 | .user-icon { 132 | padding: 0; 133 | width: 90rpx; 134 | height: 90rpx; 135 | background-color: #fff; 136 | border: 1px solid #eee; 137 | } 138 | 139 | 140 | /* 图标颜色 */ 141 | .four-list-icon .color1 { background-image: linear-gradient(135deg, #FFA7E7, #EA6362) } 142 | .four-list-icon .color2 { background-image: linear-gradient(135deg, #17EAD9, #6078EA) } 143 | .four-list-icon .color3 { background-image: linear-gradient(135deg, #45E994, #23BCBB) } 144 | .four-list-icon .color4 { background-image: linear-gradient(135deg, #FFDEA7, #EA6362) } 145 | .four-list-icon .color5 { background-image: linear-gradient(135deg, #fa71cd, #c471f5) } 146 | .four-list-icon .color6 { background-image: linear-gradient(135deg, #7C4DFF, #7B1FA2) } 147 | .four-list-icon .color7 { background-image: linear-gradient(135deg, #00c6fb, #005bea) } 148 | .four-list-icon .color8 { background-image: linear-gradient(135deg, #F57C00, #CF360C) } 149 | 150 | /* 搜索栏 */ 151 | .search-box { 152 | position: absolute; 153 | top: 270rpx; 154 | width: 90vw; 155 | margin: 0 5vw; 156 | padding: 0; 157 | background-color: white; 158 | transition: .25s; 159 | } 160 | .search-box input { 161 | height: 70rpx; 162 | padding: 0 40px 0 .5em; 163 | color: #555; 164 | } 165 | .search-box .icon-sousuo { 166 | position: absolute; 167 | top: 0; 168 | right: 0; 169 | padding: 0 25rpx; 170 | line-height: 70rpx; 171 | font-size: 40rpx; 172 | color: #888; 173 | } 174 | .search-placeholder { 175 | color: #ddd; 176 | } 177 | 178 | 179 | /* 横轴列表 */ 180 | .row-list { 181 | margin-top: 20px; 182 | padding: 5rpx 0; 183 | color: #777; 184 | font-size: 30rpx; 185 | } 186 | .row-list > view { 187 | margin: 0 10rpx; 188 | padding: 10rpx; 189 | border-bottom: 1px solid #eee; 190 | } 191 | .row-list > view icon { 192 | margin-right: 10rpx; 193 | color: var(--main-icon-color); 194 | vertical-align: middle; 195 | } 196 | .row-list > view text { 197 | vertical-align: middle; 198 | } 199 | .row-list > view:last-child { 200 | border-bottom: none; 201 | } 202 | .row-list .icon-fangxiangyou { 203 | float: right; 204 | color: #ccc; 205 | font-size: 30rpx; 206 | } 207 | .navigator-hover { 208 | background: transparent; 209 | } 210 | 211 | 212 | /* 字体图标 */ 213 | @font-face { 214 | font-family: 'iconfont'; /* project id 906741 */ 215 | src: url('//at.alicdn.com/t/font_906741_fjs57q4lyma.eot'); 216 | src: url('//at.alicdn.com/t/font_906741_fjs57q4lyma.eot?#iefix') format('embedded-opentype'), 217 | url('//at.alicdn.com/t/font_906741_fjs57q4lyma.woff') format('woff'), 218 | url('//at.alicdn.com/t/font_906741_fjs57q4lyma.ttf') format('truetype'), 219 | url('//at.alicdn.com/t/font_906741_fjs57q4lyma.svg#iconfont') format('svg'); 220 | } 221 | .iconfont { 222 | font-family: "iconfont" !important; 223 | font-size: 50rpx; 224 | font-style: normal; 225 | color: currentColor; 226 | vertical-align: middle; 227 | -webkit-font-smoothing: antialiased; 228 | -moz-osx-font-smoothing: grayscale; 229 | } 230 | 231 | .icon-tupianpx-:before { content: "\e644"; } 232 | .icon-nvyisheng-mian:before { content: "\e7da"; } 233 | .icon-nanyisheng-mian:before { content: "\e7db"; } 234 | .icon-tianjia:before { content: "\e60a"; } 235 | .icon-shenfenzhengzheng:before { content: "\e60f"; } 236 | .icon-shenfenzhengfan:before { content: "\e611"; } 237 | .icon-shangchuan:before { content: "\e6b7"; } 238 | .icon-qiyejianchadan:before { content: "\e8d6"; } 239 | .icon-chufang:before { content: "\e651"; } 240 | .icon-bumen:before { content: "\e7d4"; } 241 | .icon-code:before { content: "\e616"; } 242 | .icon-qianbao:before { content: "\e637"; } 243 | .icon-yaodian:before { content: "\e668"; } 244 | .icon-aixin-copy:before { content: "\e60e"; } 245 | .icon-neike:before { content: "\e677"; } 246 | .icon-fuchanke:before { content: "\e61e"; } 247 | .icon-fangxiangxia:before { content: "\e684"; } 248 | .icon-fangxiangshang:before { content: "\e685"; } 249 | .icon-idcard:before { content: "\e6f1"; } 250 | .icon-pifuke:before { content: "\e6bb"; } 251 | .icon-guanjiaowangtubiao59:before { content: "\e64d"; } 252 | .icon-trun:before { content: "\e605"; } 253 | .icon-kouqiangke:before { content: "\e659"; } 254 | .icon-qitake:before { content: "\e8b0"; } 255 | .icon-chengyuan:before { content: "\e65c"; } 256 | .icon-xiaoxi:before { content: "\e600"; } 257 | .icon-tuina:before { content: "\e749"; } 258 | .icon-yinhangqia:before { content: "\e64b"; } 259 | .icon-xingbie:before { content: "\e650"; } 260 | .icon-shouji:before { content: "\e634"; } 261 | .icon-guke:before { content: "\e628"; } 262 | .icon-anquan:before { content: "\e610"; } 263 | .icon-chusheng:before { content: "\e624"; } 264 | .icon-chenggong:before { content: "\e609"; } 265 | .icon-wrong:before { content: "\e615"; } 266 | .icon-tengtongke:before { content: "\e635"; } 267 | .icon-jinggao:before { content: "\e604"; } 268 | .icon-erbihouke:before { content: "\e990"; } 269 | .icon-xiugai:before { content: "\e84d"; } 270 | .icon-fangxiang-zuo:before { content: "\e6a6"; } 271 | .icon-yanzhengma:before { content: "\e8a0"; } 272 | .icon-erke:before { content: "\e636"; } 273 | .icon-fangxiang:before { content: "\e606"; } 274 | .icon-zongjie:before { content: "\e603"; } 275 | .icon-zhuanjia:before { content: "\e6a5"; } 276 | .icon-fangxiangyou:before { content: "\e608"; } 277 | .icon-zhiwen:before { content: "\e60b"; } 278 | .icon-jianyan:before { content: "\e814"; } 279 | .icon-loading:before { content: "\e6dc"; } 280 | .icon-duanxin:before { content: "\e63f"; } 281 | .icon-suo:before { content: "\e6a9"; } 282 | .icon-banben:before { content: "\e607"; } 283 | .icon-Bchaoyuyue-K:before { content: "\e7b8"; } 284 | .icon-add:before { content: "\e60c"; } 285 | .icon-yichu:before { content: "\e623"; } 286 | .icon-Micon-zixun:before { content: "\e7e2"; } 287 | .icon-location:before { content: "\e601"; } 288 | .icon-wode:before { content: "\e72a"; } 289 | .icon-sousuo:before { content: "\e602"; } -------------------------------------------------------------------------------- /miniprogram/app.js: -------------------------------------------------------------------------------- 1 | let loading = null; 2 | App({ 3 | /** 4 | * 公共数据 5 | */ 6 | globalData: { 7 | version: "0.8.0 [Alpha]", 8 | title: "康达互联网医院", 9 | 10 | // 域名 11 | ip: "http://127.0.0.1/", 12 | // 全部部门列表 13 | dept: [], 14 | 15 | // 接口 16 | url: { 17 | // 小程序登录 18 | login: "login/", 19 | // 小程序注册 20 | register: "register/", 21 | 22 | // 获取用户信息 23 | accountData: "getUserDetail/?token=", 24 | // 绑定到主系统[第一步] 25 | existAccount: "bindExistAccount/", 26 | // 绑定到主系统[第二步] 27 | finishBind: "finishBind/", 28 | 29 | // 搜索医生 30 | searchDoctor: "searchDoctor", 31 | // 获取所有部门列表 32 | getAllDept: "getAllDept", 33 | // 获取 专家列表 34 | getExpertDoc: "getExpertDoc", 35 | 36 | // 医生注册 37 | doctorRegister: "bindAndRegMainSysAccountDoc/?token=", 38 | // 用户注册 39 | userRegister: "bindAndRegMainSysAccountPat/?token=", 40 | // 注册 [验证 验证码] 41 | finishBindAndRegMssion: "finishBindAndRegMssion/", 42 | 43 | // 获取 家庭成员列表 44 | getFamilyList: "getFamilyList?", 45 | // 添加 家庭成员[发送验证码] 46 | addFamilyGetCode: "addFamilyUserStep2/", 47 | // 添加 家庭成员[验证码验证] 48 | addFamilySendCode: "addFamilyUserStep3/", 49 | // 删除 家庭成员 50 | deleteFamilyUser: "deleteFamilyUser/", 51 | 52 | // 添加医生咨询 53 | addDoctorAsk: "addDoctorAsk?token=", 54 | // 医生发送聊天:回复 55 | docAddAnswer: "docAddAnswer?token=", 56 | // 病人发送聊天:咨询 57 | patAddAnswer: "patAddAnswer?token=", 58 | // 获取咨询信息 59 | getAskDoctorDetail: "getAskDoctorDetail/", 60 | // 获取未读的聊天信息 61 | getUnreadQA: "getUnreadQA/", 62 | // 设置 标记聊天消息已读 63 | qaMarkAsRead: "QAMarkAsRead/", 64 | // 获取 历史聊天记录 65 | getHistoryQA: "getHistoryQA/", 66 | // 获取 [病人]活跃的咨询列表 67 | getDocAskListByPatAlive: "getDocAskListByPatAlive?token=", 68 | // 获取 [病人]活跃的咨询列表 69 | getDocAskListByPatClose: "getDocAskListByPatClose?token=", 70 | // 获取 [医生]活跃的咨询列表 71 | getDocAskListByDocAlive: "getDocAskListByDocAlive?token=", 72 | // 获取 [医生]关闭的咨询列表 73 | getDocAskListByDocClose: "getDocAskListByDocClose?token=", 74 | }, 75 | userInfo: {}, 76 | doctor: false 77 | }, 78 | 79 | 80 | 81 | onLaunch: function() { 82 | wx.cloud.init(); 83 | 84 | let storage = wx.getStorageSync("userInfo"); 85 | if (storage && storage.bind_account && storage.endTime > Date.now() / 1000) { 86 | this.globalData.userInfo = storage; 87 | this.globalData.doctor = this.isDoctor(); 88 | } 89 | 90 | ///////////////// 91 | 92 | // 初始化本地缓存 93 | !wx.getStorageSync('colling') && wx.setStorage({ 94 | key: 'colling', 95 | data: {}, 96 | }); 97 | 98 | 99 | // 获取全部部门列表 [读取本地,超过一小时则重新获取] 100 | 101 | this.request("", "getAllDept", res => { 102 | 103 | let deptList = []; 104 | // 主部门 105 | for (let id in res.data) { 106 | // 子部门 107 | let subDrpt = res.data[id].subDept; 108 | for (let subId of subDrpt) { 109 | // 格式 主部门ID.子部门ID = 子部门名字 110 | deptList[`${id}.${subId.id}`] = subId.name; 111 | } 112 | } 113 | 114 | this.globalData.dept = res.data; 115 | this.globalData.deptList = deptList; 116 | }, 3600); 117 | }, 118 | 119 | 120 | 121 | /** 122 | * 判断是否登录 123 | */ 124 | isLogin: function() { 125 | return this.globalData.userInfo.bind_account ? this.globalData.userInfo : false; 126 | }, 127 | 128 | 129 | 130 | /** 131 | * 判断是否上传身份证 132 | */ 133 | isCard: function() { 134 | return this.isLogin() ? this.globalData.userInfo.bind_account.patientname : false; 135 | }, 136 | 137 | 138 | 139 | /** 140 | * 判断是否为医生 141 | */ 142 | isDoctor: function() { 143 | return this.isLogin() ? !!this.globalData.userInfo.bind_account.ysdm : false; 144 | }, 145 | 146 | 147 | /** 148 | * 获取公共信息 149 | */ 150 | getMessage: function(tag) { 151 | 152 | let msg = { 153 | 'not login': '请先登录!' 154 | } 155 | 156 | if (tag in msg) return msg[tag]; 157 | 158 | return 'error msg!'; 159 | }, 160 | 161 | 162 | 163 | /** 164 | * 请求函数封装: 165 | * @param {string} data get请求 166 | * {object} data post 请求 167 | * @param {string} api 调用设定好的url接口,如果不存在则会被当成url 168 | * @param {function} callback 当得到请求内容时的回调 169 | * @param {string} note 当为post请求时,url需要额外添加的参数 170 | * {number} note 缓存过期时间/下次在过期时间内读取直接返回缓存数据 171 | */ 172 | request: function(data, api, callback, note, colling) { 173 | 174 | let post = (typeof data == "string"), 175 | 176 | url = this.globalData.ip + 177 | (this.globalData.url[api] ? "api/" + this.globalData.url[api] : api) + 178 | (post ? data : "") + 179 | (note && isNaN(note) ? note : ""); 180 | 181 | let storage_coll = wx.getStorageSync('colling'); 182 | 183 | // 查看是否存在缓存,有则直接返回[GET] 184 | if (post && note) { 185 | let storage = wx.getStorageSync(api); 186 | 187 | // 存在数据 && url相等 && 数据未过期 188 | if (storage && 189 | storage.url == url && 190 | storage.end >= Date.now() 191 | ) { 192 | // 添加缓存识别 193 | storage.data.storage = true; 194 | return callback(storage.data); 195 | } 196 | } else if (colling) { 197 | // 非缓存数据 才有冷却 198 | if (api in storage_coll) { 199 | if (storage_coll[api] > Date.now()) { 200 | return callback(storage_coll[api] - Date.now()); 201 | } 202 | } 203 | } 204 | 205 | // 设定过久显示互动 206 | let showToast = false; 207 | // 禁止显示toast api列表 208 | let notLoading = { 209 | getHistoryQA : 1, 210 | patAddAnswer : 1, 211 | qaMarkAsRead : 1, 212 | docAddAnswer : 1, 213 | getUnreadQA: 1 214 | }; 215 | // 如果不在不显示toast列表内 216 | if (!(api in notLoading)) { 217 | loading = setTimeout(() => { 218 | wx.showToast({ 219 | title: '加载中...', 220 | icon: 'loading', 221 | mask: true, 222 | duration: 10000 223 | }); 224 | showToast = true; 225 | }, 1500); 226 | } 227 | 228 | let req = wx.request({ 229 | url, 230 | method: post ? "GET" : "POST", 231 | data: post ? false : data, 232 | success: res => { 233 | // 是否有计数器 有则 清除 234 | if (loading) { 235 | clearTimeout(loading); 236 | loading = null; 237 | 238 | // 判断是否正在显示图标 239 | if (showToast) { 240 | wx.hideToast(); 241 | showToast = false; 242 | } 243 | } 244 | 245 | if (res.statusCode == 200 || res.statusCode == 304) { 246 | callback && (!res.error ? callback(res) : callback(false)); 247 | 248 | // 设置了缓存过期时间 [只缓存GET|且正常请求] 249 | // ps: 过期请求会被直接覆盖 250 | if (post && !res.error) { 251 | if (!isNaN(note) && note) { 252 | res.header && delete res.header; 253 | wx.setStorage({ 254 | key: api, 255 | data: { 256 | url, 257 | end: Date.now() + note * 1000, 258 | data: res 259 | }, 260 | }); 261 | } 262 | if (colling) { 263 | storage_coll[api] = Date.now() + colling * 1000; 264 | wx.setStorage({ 265 | key: 'colling', 266 | data: storage_coll, 267 | }); 268 | } 269 | } 270 | } else { 271 | wx.showToast({ 272 | title: `内部服务器出现问题!请稍后再试[ERROR: ${api}]`, 273 | icon: "none", 274 | mask: true, 275 | duration: 2000 276 | }); 277 | } 278 | }, 279 | fail: err => { 280 | console.log('请求调用出错: ', err); 281 | } 282 | }); 283 | //console.log("发送请求 <" + (new Date().toTimeString()) + ">: " + url + (post ? data : "") + (note ? note : "")); 284 | }, 285 | 286 | 287 | 288 | /** 289 | * 设置顶部封装 290 | * @param {string/object} data 传入string为单项属性设置 反之 多项设定 291 | * @param {string} value 单项设定时调用,当包含","文字将会是黑色反之白色[格式 "#ffffff,000"] 292 | */ 293 | bar: function(json, value) { 294 | 295 | let setBar = (key, val) => { 296 | key == 'title' ? 297 | wx.setNavigationBarTitle({ 298 | title: `${this.globalData.title} - ${val}` 299 | }) : 300 | wx.setNavigationBarColor({ 301 | frontColor: val.indexOf(',') == -1 ? "#ffffff" : "#000000", 302 | backgroundColor: val.split(',')[0], 303 | }); 304 | } 305 | 306 | value ? setBar(json, value) : Object.keys(json).forEach((val, key) => 307 | setBar(val, json[val]) 308 | ); 309 | }, 310 | 311 | 312 | 313 | /** 314 | * 返回格式的时间 315 | * 对Date的扩展,将 Date 转化为指定格式的String 316 | * 月(M)、日(d)、12小时(h)、24小时(H)、分(m)、秒(s)、周(E)、季度(q) 可以用 1-2 个占位符 317 | * 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) 318 | * eg: 319 | * "yyyy-MM-dd hh:mm:ss.S" ==> 2006-07-02 08:09:04.423 320 | * "yyyy-MM-dd E HH:mm:ss" ==> 2009-03-10 二 20:09:04 321 | * "yyyy-MM-dd EE hh:mm:ss" ==> 2009-03-10 周二 08:09:04 322 | * "yyyy-MM-dd EEE hh:mm:ss" ==> 2009-03-10 星期二 08:09:04 323 | * "yyyy-M-d h:m:s.S" ==> 2006-7-2 8:9:4.18 324 | */ 325 | getDate: function(fmt) { 326 | let date = new Date(); 327 | let o = { 328 | "M+": date.getMonth() + 1, 329 | "d+": date.getDate(), 330 | "h+": date.getHours() % 12 == 0 ? 12 : date.getHours() % 12, 331 | "H+": date.getHours(), 332 | "m+": date.getMinutes(), 333 | "s+": date.getSeconds(), 334 | "q+": Math.floor((date.getMonth() + 3) / 3), 335 | "S": date.getMilliseconds() 336 | }; 337 | let week = { 338 | "0": "日", 339 | "1": "一", 340 | "2": "二", 341 | "3": "三", 342 | "4": "四", 343 | "5": "五", 344 | "6": "六" 345 | }; 346 | if (/(y+)/.test(fmt)) { 347 | fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); 348 | } 349 | if (/(E+)/.test(fmt)) { 350 | fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "星期" : "周") : "") + week[date.getDay() + ""]); 351 | } 352 | for (let k in o) { 353 | if (new RegExp("(" + k + ")").test(fmt)) { 354 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 355 | } 356 | } 357 | return fmt; 358 | } 359 | 360 | }); --------------------------------------------------------------------------------