uni-app(优医咨询)项目实战 – 第7天

作者 : admin 本文共8275个字,预计阅读时间需要21分钟 发布时间: 2024-06-2 共3人阅读

学习目标:

  • 能够基于 WebSocket 完成问诊全流程

  • 能够使用 uniCloud 云存储上传文件

  • 能够完成查看电子处方的功能

  • 能够完成医生评价的功能

一、问诊室

以对话聊天的方式向医生介绍病情并获取诊断方案,聊天的内容支持文字和图片两种形式。

首先新建一个页面并完成分包的配置:

{
    "subPackages": [
    {
      "root": "subpkg_consult",
      "pages": [
        {
          "path": "room/index",
          "style": {
            "navigationBarTitleText": "问诊室"
          }
        }
      ]
    },
  ]
}

该页面的内容特别多我们分段来数据模板代码移到项目当中:


​

  
​
    
      
        
      
    
​
    
    
      
        
        
          
        
      
      
    
  

​

  @import './index.scss';
// subpkg_consult/room/index.scss
.room-page {
  display: flex;
  flex-direction: column;
  height: 100vh;
  /* #ifdef H5 */
  height: calc(100vh - 44px);
  /* #endif */
  overflow: hidden;
  box-sizing: border-box;
  background-color: #f2f2f2;
}
​
.message-container {
  padding: 0 30rpx 60rpx;
  overflow: hidden;
}
​
.message-bar {
  background-color: red;
  display: flex;
  padding: 30rpx 30rpx calc(env(safe-area-inset-bottom) + 40rpx);
  background-color: #fff;
​
  :deep(.is-disabled) {
    background-color: transparent !important;
  }
​
  :deep(.uni-easyinput__content-input) {
    height: 88rpx;
    padding: 0 44rpx !important;
    border-radius: 88rpx;
    color: #3c3e42;
    font-size: 32rpx;
    background-color: #f6f6f6;
  }
​
  .image-button {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 88rpx;
    width: 88rpx;
    margin-left: 30rpx;
  }
​
  .uni-button {
    flex: 1;
  }
}
1.1 WebSocket 连接

首先安装 Socket.IO

npm install socket.io-client

然后建立连接,在建立连接进需要传入参数和登录信息:

  • auth 登录状态信息,即 token

  • query 建立连接时传递的参数

  • transports 建立连接时使用的协议

  • timeout 超时设置




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  
1.2 接收消息

Socket.IO 是基于事件来实现数据通信的,事件的名称是由前后端商定好的,详见接口文档说明,消息的获取分成两种情况:

  • 历史消息,事件名称为 chatMsgList

  • 即时消息,事件名称为 receiveChatMsg

1.2.1 消息列表

在建立连接时服务端会通过 chatMsgList 传递历史数据,通过 on 方法进行监听来获取这些数据:




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  

在消息列表数据中包含了不同类型的消息且展示的方式也不相同,因此在对数据进行遍历的过程中需要通过 v-if 来渲染不同的模板,不同的类型对应了一个数值:

消息类型说明备注
21患者信息
22处方信息
23未提交评价
24已提交评价
31普通通知白底黑字
32温馨提示
33取消订单灰底黑字
4图片消息
1文字消息

首次进入问诊室返回的 3 条件的类型分别为患者信息(21)、普通通知(31)、温馨提示(32),我们逐个进行渲染。

1.2.2 患者消息

首先创建患者消息组件,组件的模板布局如下:



  
  
    
      李富贵 男 31岁
      一周内 | 未去医院就诊
    
    
      
        病情描述
        头痛、头晕、恶心
      
      
        图片
        点击查看
      
    
  

​

  .patient-info {
    padding: 30rpx;
    margin-top: 60rpx;
    border-radius: 20rpx;
    box-sizing: border-box;
    background-color: #fff;
​
    .header {
      padding-bottom: 20rpx;
      border-bottom: 1rpx solid #ededed;
​
      .title {
        font-size: 32rpx;
        color: #121826;
        margin-bottom: 10rpx;
      }
​
      .note {
        font-size: 26rpx;
        color: #848484;
      }
    }
​
    .content {
      margin-top: 20rpx;
      font-size: 26rpx;
​
      .list-item {
        display: flex;
        margin-top: 10rpx;
      }
​
      .label {
        width: 130rpx;
        color: #3c3e42;
      }
​
      .note {
        flex: 1;
        line-height: 1.4;
        color: #848484;
      }
    }
  }

接下来分成3个步骤来实现:

  1. 自定义组件的相关逻辑,要求组件能接收外部传入的数据



    ...
  1. 在页面应用组件并传入数据



    ...
  1. 在组件内部接收并渲染数据




  
  
    
      
        {{ props.info.patientInfo.name }}
        {{ props.info.patientInfo.genderValue }}
        {{ props.info.patientInfo.age }}岁
      
      
        {{ illnessTimes[props.info.illnessTime] }}
        |
        {{ consultFlags[props.info.illnessType] }}
      
    
    
      
        病情描述
        {{ props.info.illnessDesc }}
      
      
        图片
         点击查看 
        暂无图片
      
    
  
  1. 大图查看患者病情图片,uni-app 提供了大图查看图片的 API uni.previewImage



  
  
    
      ...
    
    
      
        病情描述
        {{ props.info.illnessDesc }}
      
      
        图片
        
          点击查看
        
        暂无图片
      
    
  
1.2.3 通知消息

通知消息分为3种,分别为:

消息类型说明备注
31普通通知白底黑字
32温馨提示
33取消订单灰底黑字

首先创建消息通知组伯,通知消息的模板如下:




  
  
    医护人员正在赶来,请耐心等候
  

  
  
    
      温馨提示:
      在线咨询不能代替面诊,医护人员建议仅供参考
    
  



  .message-tips {
    display: flex;
    justify-content: center;
    margin-top: 60rpx;

    &:first-child {
      margin-top: 30rpx;
    }
  }

  .wrapper {
    line-height: 1;
    text-align: center;
    padding: 20rpx 30rpx;
    // margin-top: 60rpx;
    font-size: 24rpx;
    border-radius: 70rpx;
    color: #848484;
    background-color: #fff;

    .label {
      color: #16c2a3;
    }
  }

接下来分成3个步骤来实现:

  1. 定义组件的逻辑,要求能区分通知的类型并通过插槽来展示内容



  
  
    温馨提示:
    
  
  1. 在页面应用通知消息组件并传入数据



  
		
    
      
        

          
          = 31" :type="message.msgType">
            {{ message.msg.content }}
          

          
        
      
		

    
    
      ...
    
  
  1. 接收并渲染组件数据



  
  
    温馨提示:
    
  
1.2.4 文字/图片消息

实时接收到医生发送过来的消息,包括文字消息和图片消息两种类型,使用超级医生来模拟医生端发送消息,根据订单 ID 来打通医生端和患者端的聊天连接。

首先接收医生端的回复的消息需要监听的事件为 receiveChatMsg




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  

然后创建文字消息组件,组件模板如下:




  
  
    
    
      14:13
      
        您好,我是医师王医生,已收到您的问诊信息,我会尽量及时、准确、负责的回复您的问题,请您稍等。
      
      
    
  



  .message-item {
    display: flex;
    align-self: flex-start;
    margin-top: 60rpx;

    .room-avatar {
      width: 80rpx;
      height: 80rpx;
      border-radius: 50%;
    }

    .room-message {
      margin-left: 20rpx;
    }

    .time {
      font-size: 26rpx;
      color: #979797;
    }

    .image {
      max-width: 420rpx;
      margin-top: 10rpx;
    }

    .text {
      max-width: 420rpx;
      line-height: 1.75;
      padding: 30rpx 40rpx;
      margin-top: 16rpx;
      border-radius: 20rpx;
      font-size: 30rpx;
      color: #3c3e42;
      background-color: #fff;
      position: relative;

      &::after {
        content: '';
        position: absolute;
        top: 0;
        left: -25rpx;
        width: 26rpx;
        height: 52rpx;
        background-image: url(/images/2024/0608/im-arrow-1.png);
        background-size: contain;
      }
    }

    &.reverse {
      flex-direction: row-reverse;
      align-self: flex-end;

      .room-message {
        margin-left: 0;
        margin-right: 20rpx;
      }

      .time {
        text-align: right;
      }

      .text {
        background-color: #16c2a3;
        color: #fff;

        &::after {
          left: auto;
          right: -25rpx;
          background-image: url(/images/2024/0608/im-arrow-2.png);
        }
      }
    }
  }

接下来分成3个步骤来实现:

  1. 定义组件的逻辑,要求能接收外部传入的数据




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  
  1. 到页面中应用组件并传入数据



  
		
    
      
        

          
          <message-info
            v-if="message.msgType 

          
        
      
		

    
    
      ...
    
  
  1. 到组件是接收并渲染数据




  
  
    
    
      {{ props.info.createTime }}
      
      
        {{ props.info.msg.content }}
      
      
      
    
  
  1. 处理消息的时间,安装 dayjs

npm install dayjs



  
  
    
    
      {{ dateFormat(props.info.createTime) }}
      
        {{ props.info.msg.content }}
      
      
    
  
1.2.5 处方消息

医生根据问诊的情况开具诊断结果即为处方消息,到消息的类型值为 22,首先创建组件,布局模板如下所示:

1

接下来分成3个步骤来实现:

  1. 定义组件逻辑,要求能接收组件外部传入的数据




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  
  1. 在页面中应用组件并传入数据



    ...
  1. 在组件中接收并渲染数据




  
  
    
      
        电子处方
        
          原始处方
          
        
      
      
        {{ props.info.name }}
        {{ props.info.genderValue }}
        {{ props.info.age }}岁
        {{ props.info.diagnosis }}
      
      开方时间:{{ props.info.createTime }}

      

      
        
          
            {{ medicine.name }}
            85ml
            x{{ medicine.quantity }}
          
        
        {{ medicine.usageDosag }}
      
    
    
      购买药品
    
  
1.2.6 原始处方

在医生开完处方后会生成电子版的处方,通过调用接口进行查看。

1.2.7 医生评价

在医生端结束问诊后,患者可以对医生进行评价,医生评价的布局模板为:



  
  
    医生服务评价
    本次在线问诊服务您还满意吗?
    
      
    
    
      
      0/150
    
    
      
      
      匿名评价
    
    
  




  .doctor-rating {
    padding: 30rpx 30rpx 40rpx;
    border-radius: 20rpx;
    background-color: #fff;
    margin-top: 60rpx;

    .title {
      text-align: center;
      font-size: 30rpx;
      color: #121826;
    }

    .subtitle {
      text-align: center;
      font-size: 24rpx;
      color: #6f6f6f;
      margin: 10rpx 0 20rpx;
    }

    .rating {
      display: flex;
      justify-content: center;
    }

    .text {
      padding: 20rpx 30rpx;
      margin-top: 20rpx;
      background-color: #f6f6f6;
      border-radius: 20rpx;
      position: relative;
    }

    :deep(.uni-easyinput__content-textarea) {
      font-size: 28rpx;
    }

    .word-count {
      position: absolute;
      bottom: 20rpx;
      right: 30rpx;
      line-height: 1;
      font-size: 24rpx;
      color: #6f6f6f;
    }

    .anonymous {
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 30rpx 0;
      color: #6f6f6f;
      font-size: 24rpx;

      .label {
        margin-left: 6rpx;
      }
    }

    .uni-button[disabled] {
      color: #a6dbd5;
      background-color: #eaf8f6;
    }
  }

接下来分成5个步骤来实现:

  1. 到页面中应用该组件,消息的类型值是 23



    ...
  1. 获取评价数据并对数据进行验证:

    • v-model 获取数据

    • 字数统计使用计算属性

    • 控制字数使用 maxlength




  
  
    医生服务评价
    本次在线问诊服务您还满意吗?
    
      
    
    
      
      {{ wordCount }}/150
    
    
      
      
      匿名评价
    
    
  
  1. 在提交评价时,需要获取问诊订单详情,在问诊订单详情中包含了医生的 ID,接口文档在这里

// services/consult.js
import { http } from '@/utils/http'

// 省略前面小节的代码...

/**
 * 问诊订单详情
 */
export const orderDetailApi = (orderId) => {
  return http.get('/patient/consult/order/detail', { params: { orderId } })
}

将订单 ID 和医生 ID 传入组件



    ...
  1. 调用接口提交评价的数据,接口文档在这里

// services/doctor.js
import { http } from '@/utils/http'

// 省略了前面小节的代码...

/**
 * 评价医生
 */
export const evaluateDoctorApi = (data) => {
  return http.post('/patient/order/evaluate', data)
}



  
  
    医生服务评价
    本次在线问诊服务您还满意吗?
    
      
    
    
      
      {{ wordCount }}/150
    
    
      
      
      匿名评价
    
    
  
  1. 已评价状态,消息类型值 为 24




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  



  
		
    
      
        

          
          

          
        
      
		

    
    

    
  
1.3 发送消息

患者向医生告之病情及询问诊断方法,分为文字图片消息两种类型,且只有问诊订单状态处理咨询中时才以发送消息,问诊订单的状态包含在订单详情数据中。



  
		
    
      
        
      
  	

    
    
      
        
        
          
        
      
      
    
  
1.3.1 文字消息

发送文字消息分3个步骤来实现:

  1. 监听 uni-easyinput 组件的 confirm 事件并使用 v-model 获取表单的内容




  
		
    
      
        ...
      
  	

    
    
      
        
        
          
        
      
      
    
  
  1. 触发服务端正在监听的事件类型,文档地址在这里

在用户登录成功时,只记录了用户的 token 在患者向医生发送消息时还需要传递用户的 ID,在 Pinia 中添加数据来记录登录用户的 ID

// stores/user.js
import { ref } from 'vue'
import { defineStore } from 'pinia'

export const useUserStore = defineStore(
  'user',
  () => {
    // 记录用户登录状态
    const token = ref('')
    // 记录登录成功后要路转的地址(默认值为首页)
    const redirectURL = ref('/pages/index/index')
    // 跳转地址时采用的 API 名称
    const openType = ref('switchTab')
    
    // 用户ID
    const userId = ref('')

    return { token, userId, redirectURL, openType }
  },
  {
    persist: {
      paths: ['token', 'userId', 'redirectURL', 'openType'],
    },
  }
)



  
		
    
      
        

          
          

          
        
      
		

    
    

    
  
  1. 调整消息的对齐方式,患者消息靠右显示

在消息中包含的属性 from 是消息发送者的 ID,如果与登录用户的 ID 一致,则表示是患者发送的消息,消息的内容要靠右显示,类名 reverse 可以控制靠右对齐。




  
  
    
    
      {{ dateFormat(props.info.createTime) }}
      
        {{ props.info.msg.content }}
      
      
    
  
1.3.2 图片消息

发送图片消息需要将图片上传到云空间,需要调用 uniCloud 提供的 API chooseAndUploadFile,我们分x步来实现:

  1. 判断问诊订单状态是否为问诊中




  
		
    
      
        ...
      
  	

    
    
      
        
        
          
        
      
      
    
  
  1. 调用 API 上传到 uniCloud 存储空间



    ...
  1. 向医生发送图片消息,文档地址在这里




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  
1.4 问诊订单状态

患者在与医生对话的过程中问诊订单状态会发生改变,包括待支付、待接诊、咨询中、已完成、已取消,在页面的顶部要根据订单的状态展示不同的内容。

  1. 将问诊状态的布局模板独立到组件中,要求组件能接收3个数据

    • status 问诊订单的状态值

    • statusValue 问诊订单的文字描述

    • countdown 倒计时剩余时长



  
  
    
      咨询中
      
        剩余时间:
        
      
    
    
      已通知医生尽快接诊,24小时内医生未回复将自动退款
    
    
      
      已结束
    
  



  .room-status {
    font-size: 26rpx;
    position: sticky;
    top: 0;
    z-index: 99;

    .status {
      display: flex;
      padding: 30rpx;
      background-color: #fff;
    }

    .waiting {
      color: #16c2a3;
      background-color: #eaf8f6;
    }

    .countdown {
      justify-content: space-between;
    }

    .label {
      color: #16c2a3;
    }

    .icon-done {
      color: #121826;
      font-size: 28rpx;
      margin-right: 5rpx;
    }

    .time {
      display: flex;
      color: #3c3e42;
    }

    :deep(.uni-countdown) {
      margin-left: 6rpx;
    }
  }
  1. 在页面中应用组件并传入数据,查询订单状态的的 API 在前面小节中已经调用了,即 getOrderDetail




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  
  1. 根据传入组件的订单状态展示数据


  
  
    
    
      {{ props.statusValue }}
    

    
    
      {{ props.statusValue }}
      
        剩余时间:
        
      
    

    
    
      
        
        {{ props.statusValue }}
      
    
  
1.5 消息分段

每次重新建立 Socket 连接后(刷新页面),后端都会对数据进行分组,前端在进行展示时也相应的需要展示分段的时间节点,这个时间节点按通知消息类型处理




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  

在返回的数据中 data 是一个数组,每个单元是一个消息的分组,在对该数组遍历时前端构造一条数据放到数组单元中,被构告的这条件数据仅仅是要显示一个时间节点。

1.6 历史消息

用户下拉操作时分页获取聊天记录,按以下几个步骤来实现:

  1. 启动下拉刷新并监听下拉操作



    ...
  1. 触发后端定义的事件类型获取历史消息,文档地址在这里。



    ...
  1. 更新时间节点,获取的历史消息会返回给客户端




  
		
    
      
        

          
          

          
        
      
		

    
    

    
  

注意事项:

  • 历史消息是以从后往前的顺序获取,将历史消息中第1个分组的时间节点做为下一次获取历史消息的起始点

  • 获取数据即表示请求结束,要关闭下拉交互的动画

  • 判断是否还存在更多的历史消息

支付宝支付账号,密码为 111111

scobys4865@sandbox.com

askgxl8276@sandbox.com

本站无任何商业行为
个人在线分享 » uni-app(优医咨询)项目实战 – 第7天
E-->