doctorIm.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. <template>
  2. <view class="content" ref="showPanel">
  3. <view class="chat-cont" @click="closeBottom">
  4. <!-- 大夫 -->
  5. <view class="chat-item" v-for="(item) in msg" :class="item.from==doctorId?'':'my'">
  6. <view class="time">{{utils.parseTime(item.time)}}</view>
  7. <view class="peop-info" v-if="item.from==doctorId">
  8. <view class="img-box">
  9. <image :src="item.avatar" mode=""></image>
  10. </view>
  11. <view class="info">
  12. <view class="name">{{item.nick}}</view>
  13. <view class="words">
  14. {{item.payload.text}}
  15. </view>
  16. </view>
  17. </view>
  18. <view class="peop-info" v-if="item.from==user.userId">
  19. <view class="info">
  20. <view class="name">{{item.nick}}</view>
  21. <view class="words">
  22. {{item.payload.text}}
  23. </view>
  24. </view>
  25. <view class="img-box">
  26. <image :src="item.avatar" mode=""></image>
  27. </view>
  28. </view>
  29. </view>
  30. <!-- 我 -->
  31. <!-- <view class="chat-item my">
  32. <view class="time">2021-03-02 10:10:10</view>
  33. <view class="peop-info">
  34. <view class="info">
  35. <view class="name">张雪勤</view>
  36. <view class="words">
  37. </view>
  38. </view>
  39. <view class="img-box">
  40. <image :src="item.avatar" mode=""></image>
  41. </view>
  42. </view>
  43. </view> -->
  44. <!-- 大夫 -->
  45. <!-- 我 -->
  46. <!-- <view class="chat-item my">
  47. <view class="time">2021-03-02 10:10:10</view>
  48. <view class="peop-info">
  49. <view class="info">
  50. <view class="name">张雪勤</view>
  51. <view class="words">
  52. </view>
  53. </view>
  54. <view class="img-box">
  55. <image src="@/static/images/head.jpg" mode=""></image>
  56. </view>
  57. </view>
  58. </view> -->
  59. </view>
  60. <view class="input-box" id="chatCont" :style="{paddingBottom:bottomBlackLineHeight + 'rpx'}">
  61. <!-- 常用话术 -->
  62. <view class="used-phrases">
  63. <view v-for="(item,index) in 2" :key="index" class="item">换个人问问</view>
  64. </view>
  65. <!-- 输入框 -->
  66. <view class="input-inner">
  67. <input
  68. type="text"
  69. value=""
  70. placeholder="请向医生详细描述您的症状"
  71. :focus='setFocus'
  72. placeholder-class="input-place"
  73. confirm-type="发送"
  74. v-model="sendText"
  75. @input="textInput"
  76. />
  77. <image v-if="!hasSendValue" src="@/static/images/add26.png" mode="" @click="showMoreMenu"></image>
  78. <view v-if="hasSendValue" class="send-btn" @click="sendMsg">发送</view>
  79. </view>
  80. <!-- 功能按钮 -->
  81. <view :class="showBottomMenu?'bottom-menu show':'bottom-menu'">
  82. <view class="item">
  83. <view class="img-box">
  84. <image src="@/static/images/health.png" mode=""></image>
  85. </view>
  86. <text class="text">投诉反馈</text>
  87. </view>
  88. <view class="item">
  89. <view class="img-box">
  90. <image src="@/static/images/health.png" mode=""></image>
  91. </view>
  92. <text class="text">常见问题</text>
  93. </view>
  94. </view>
  95. </view>
  96. <!-- 图片放大查看 -->
  97. <popupBottom ref="popup" :visible.sync="imgVisible" title="电子处方" radius="32" maxHeight="1200">
  98. <view class="popup-img-cont">
  99. <image :src="url" mode="widthFix"></image>
  100. </view>
  101. </popupBottom>
  102. </view>
  103. </template>
  104. <script>
  105. import {getUserInfo} from '@/api/user'
  106. import {getImOrderDetail} from '@/api/doctorOrder.js'
  107. import popupBottom from '@/components/px-popup-bottom/px-popup-bottom.vue'
  108. export default {
  109. components: {
  110. popupBottom
  111. },
  112. data() {
  113. return {
  114. order:null,
  115. doctor:null,
  116. user:null,
  117. // user:{
  118. // userId:'user2',
  119. // avatar:"https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoQkMEXbsBBmgltByzYibp97iaX23nibxKwSyj88yaHoqXS4H7aliaum7G9xbjLxydEtIPa84C5CUwMLA/132",
  120. // nickname:"张三"
  121. // },
  122. msg:[],
  123. doctorId:null,
  124. orderId:null,
  125. // 图片放大弹窗
  126. imgVisible: false,
  127. // 内容发送框是否有值
  128. hasSendValue: false,
  129. // 功能按钮是否显示
  130. showBottomMenu: false,
  131. // 聊天输入框是否聚焦
  132. setFocus: false,
  133. // 输入框要发送的内容
  134. sendText: '',
  135. // iphoneX底部一条黑线,有些页面要避开
  136. bottomBlackLineHeight: uni.getStorageSync('bottomBlackLineHeight'),
  137. url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F202007%2F06%2F20200706230613_ikvtn.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1650117742&t=f64aa5215aeda871eb9a69a70329f7a0'
  138. }
  139. },
  140. onLoad(option) {
  141. console.log(option.orderId)
  142. this.orderId=option.orderId;
  143. this.getImOrderDetail();
  144. this.getUserInfo()
  145. var that=this;
  146. //登录 可以放到IM外登录 考虑是否按时付费
  147. uni.$TUIKit.login({
  148. userID: that.user.userId,
  149. userSig: "eJwtzE0LgkAUheH-MttCruNcZYR2Qp*kqBC0E2a0S6XDaCJF-z1Tl*d54XxYfsqcXlsWMu4AW0*blK47KmniV6stX0Kr7oUxpFjoCgD0pSe8uejBkNWjIyIHgFk7ev7NFxK5BHfRlqrxtyqP8uG-d4fgVp-TeD-0mZBekgeRKLEp*uQSUyq31xU0G-b9ARDtMKA_"
  150. }).then((res) => {
  151. setTimeout(function(){
  152. let promise = uni.$TUIKit.updateMyProfile({
  153. nick: that.user.nickname,
  154. avatar: that.user.avatar,
  155. gender: uni.$TUIKitTIM.TYPES.GENDER_MALE,
  156. selfSignature: '我的个性签名',
  157. allowType: uni.$TUIKitTIM.TYPES.ALLOW_TYPE_ALLOW_ANY
  158. });
  159. promise.then(function(imResponse) {
  160. console.log(imResponse.data); // 更新资料成功
  161. }).catch(function(imError) {
  162. console.warn('updateMyProfile error:', imError); // 更新资料失败的相关信息
  163. });
  164. that.getMessageList();
  165. },1000);
  166. }).catch((error) => {
  167. });
  168. uni.$TUIKit.on(uni.$TUIKitTIM.EVENT.MESSAGE_RECEIVED, this.onMessageReceived);
  169. },
  170. methods: {
  171. getUserInfo(){
  172. getUserInfo().then(
  173. res => {
  174. if(res.code==200){
  175. if(res.user!=null){
  176. this.user=res.user;
  177. }
  178. }else{
  179. uni.showToast({
  180. icon:'none',
  181. title: "请求失败",
  182. });
  183. }
  184. },
  185. rej => {}
  186. );
  187. },
  188. getImOrderDetail(){
  189. let data = {orderId:this.orderId};
  190. var that=this;
  191. getImOrderDetail(data).then(
  192. res => {
  193. if(res.code==200){
  194. this.doctor=res.doctor;
  195. this.order=res.order;
  196. uni.setNavigationBarTitle({
  197. title:'与'+this.doctor.doctorName+'医生聊天中'
  198. })
  199. }else{
  200. uni.showToast({
  201. icon:'none',
  202. title: "请求失败",
  203. });
  204. }
  205. },
  206. rej => {}
  207. );
  208. },
  209. onMessageReceived(event){
  210. console.log(event)
  211. if(event.name=='onMessageReceived'){
  212. this.msg=this.msg.concat(event.data);
  213. console.log(this.msg)
  214. }
  215. },
  216. getMessageList(){
  217. var that=this;
  218. let promise = uni.$TUIKit.getMessageList({conversationID: 'C2C'+that.doctorId, count: 15});
  219. promise.then(function(imResponse) {
  220. that.msg = imResponse.data.messageList; // 消息列表。
  221. console.log(that.msg)
  222. // const nextReqMessageID = imResponse.data.nextReqMessageID; // 用于续拉,分页续拉时需传入该字段。
  223. // const isCompleted = imResponse.data.isCompleted; // 表示是否已经拉完所有消息。
  224. });
  225. },
  226. sendMessage(msg){
  227. var that=this;
  228. let message = uni.$TUIKit.createTextMessage({
  229. to: that.doctorId,
  230. conversationType: uni.$TUIKitTIM.TYPES.CONV_C2C,
  231. // 消息优先级,用于群聊(v2.4.2起支持)。如果某个群的消息超过了频率限制,后台会优先下发高优先级的消息,详细请参考:https://cloud.tencent.com/document/product/269/3663#.E6.B6.88.E6.81.AF.E4.BC.98.E5.85.88.E7.BA.A7.E4.B8.8E.E9.A2.91.E7.8E.87.E6.8E.A7.E5.88.B6)
  232. // 支持的枚举值:TIM.TYPES.MSG_PRIORITY_HIGH, TIM.TYPES.MSG_PRIORITY_NORMAL(默认), TIM.TYPES.MSG_PRIORITY_LOW, TIM.TYPES.MSG_PRIORITY_LOWEST
  233. // priority: TIM.TYPES.MSG_PRIORITY_NORMAL,
  234. payload: {
  235. text: msg
  236. },
  237. // 消息自定义数据(云端保存,会发送到对端,程序卸载重装后还能拉取到,v2.10.2起支持)
  238. // cloudCustomData: 'your cloud custom data'
  239. });
  240. // 2. 发送消息
  241. let promise = uni.$TUIKit.sendMessage(message);
  242. promise.then(function(imResponse) {
  243. // 发送成功
  244. console.log(imResponse);
  245. if(imResponse.code==0){
  246. that.msg.push(imResponse.data.message);
  247. that.hasSendValue = false
  248. that.sendText = ''
  249. that.setFocus = true
  250. }
  251. //更新列表
  252. }).catch(function(imError) {
  253. // 发送失败
  254. console.warn('sendMessage error:', imError);
  255. });
  256. },
  257. // 查看大图
  258. showBigImg() {
  259. this.imgVisible = true
  260. },
  261. // 展示更多菜单
  262. showMoreMenu() {
  263. if(!this.showBottomMenu) {
  264. this.showBottomMenu = true
  265. } else {
  266. if(this.setFocus) {
  267. this.setFocus = false
  268. } else {
  269. this.setFocus = true
  270. }
  271. }
  272. },
  273. // 输入框发送消息
  274. sendMsg() {
  275. this.sendMessage(this.sendText)
  276. },
  277. // 关闭底部更多菜单
  278. closeBottom(e) {
  279. if(e.target.id!=undefined && e.target.id!=="chatCont"){
  280. this.showBottomMenu = false
  281. }
  282. },
  283. // 监听输入框是否有值
  284. textInput(e) {
  285. if(e.detail.value) {
  286. this.hasSendValue = true
  287. } else {
  288. this.hasSendValue = false
  289. }
  290. }
  291. }
  292. }
  293. </script>
  294. <style lang="scss">
  295. page{
  296. height: 100%;
  297. }
  298. .content{
  299. height: 100%;
  300. display: flex;
  301. flex-direction: column;
  302. justify-content: space-between;
  303. .chat-cont{
  304. box-sizing: border-box;
  305. flex: 1;
  306. overflow-y: auto;
  307. background-color: #F2F5F9;
  308. padding: 0 30upx 60upx;
  309. .chat-item{
  310. padding-top: 60upx;
  311. .time{
  312. font-size: 26upx;
  313. font-family: PingFang SC;
  314. font-weight: 500;
  315. color: #999999;
  316. line-height: 1;
  317. margin-bottom: 30upx;
  318. text-align: center;
  319. }
  320. .peop-info{
  321. display: flex;
  322. .img-box{
  323. width: 78upx;
  324. height: 78upx;
  325. border-radius: 50%;
  326. overflow: hidden;
  327. flex-shrink: 0;
  328. margin-right: 20upx;
  329. image{
  330. width: 100%;
  331. height: 100%;
  332. }
  333. }
  334. .info{
  335. .name{
  336. font-size: 28upx;
  337. font-family: PingFang SC;
  338. font-weight: 500;
  339. color: #666666;
  340. line-height: 1;
  341. margin-bottom: 20upx;
  342. }
  343. .words{
  344. box-sizing: border-box;
  345. max-width: 520upx;
  346. font-size: 32upx;
  347. font-family: PingFang SC;
  348. font-weight: 500;
  349. color: #111111;
  350. line-height: 50upx;
  351. padding: 20upx 30upx;
  352. background: #FFFFFF;
  353. border-radius: 0 20upx 20upx 20upx;
  354. image{
  355. width: 364upx;
  356. height: auto;
  357. }
  358. }
  359. }
  360. }
  361. &.my{
  362. .peop-info{
  363. justify-content: flex-end;
  364. .img-box{
  365. margin-right: 0;
  366. margin-left: 20upx;
  367. }
  368. .info {
  369. .name{
  370. text-align: right;
  371. }
  372. .words{
  373. background: #018C39;
  374. color: #FFFFFF;
  375. border-radius: 20upx 0 20upx 20upx;
  376. }
  377. }
  378. }
  379. }
  380. }
  381. }
  382. .input-box{
  383. box-sizing: border-box;
  384. flex-shrink: 0;
  385. background: #FFFFFF;
  386. display: flex;
  387. flex-direction: column;
  388. padding: 20upx 30upx 0;
  389. .used-phrases{
  390. display: flex;
  391. flex-wrap: wrap;
  392. .item{
  393. height: 64upx;
  394. line-height: 64upx;
  395. padding: 0 30upx;
  396. border-radius: 32upx;
  397. border: 1px solid #F7F7F7;
  398. background-color: #FFFFFF;
  399. font-size: 28upx;
  400. font-family: PingFang SC;
  401. font-weight: 500;
  402. color: #111111;
  403. margin-right: 20upx;
  404. margin-bottom: 20upx;
  405. }
  406. }
  407. .input-inner{
  408. display: flex;
  409. align-items: center;
  410. justify-content: space-between;
  411. input{
  412. box-sizing: border-box;
  413. // width: calc(100% - 82upx);
  414. flex: 1;
  415. height: 80upx;
  416. background: #F2F2F2;
  417. border-radius: 40upx;
  418. padding: 0 30upx;
  419. font-size: 28upx;
  420. font-family: PingFang SC;
  421. font-weight: 500;
  422. color: #000000;
  423. }
  424. .input-place{
  425. font-size: 28upx;
  426. font-family: PingFang SC;
  427. font-weight: 500;
  428. color: #999999;
  429. }
  430. image{
  431. flex-shrink: 0;
  432. width: 52upx;
  433. height: 52upx;
  434. margin-left: 30upx;
  435. }
  436. .send-btn{
  437. flex-shrink: 0;
  438. height: 64upx;
  439. line-height: 64upx;
  440. border-radius: 32upx;
  441. background: #018C39;
  442. font-size: 28upx;
  443. font-family: PingFang SC;
  444. font-weight: 500;
  445. color: #FFFFFF;
  446. padding: 0 30upx;
  447. margin-left: 30upx;
  448. }
  449. }
  450. .bottom-menu{
  451. height: 0;
  452. display: flex;
  453. flex-wrap: wrap;
  454. overflow: hidden;
  455. opacity: 0;
  456. // transition: all 0.5s;
  457. &.show{
  458. padding: 30upx 30upx 0;
  459. height: auto;
  460. opacity: 1;
  461. }
  462. .item{
  463. display: flex;
  464. flex-direction: column;
  465. align-items: center;
  466. justify-content: center;
  467. margin-right: 77upx;
  468. margin-bottom: 30upx;
  469. &:nth-child(4n) {
  470. margin-right: 0;
  471. }
  472. .img-box{
  473. width: 100upx;
  474. height: 100upx;
  475. background-color: #F5F5F5;
  476. border-radius: 8upx;
  477. display: flex;
  478. align-items: center;
  479. justify-content: center;
  480. image{
  481. width: 40upx;
  482. height: 40upx;
  483. }
  484. }
  485. .text{
  486. font-size: 24upx;
  487. font-family: PingFang SC;
  488. font-weight: 500;
  489. color: #333333;
  490. margin-top: 20upx;
  491. }
  492. }
  493. }
  494. }
  495. }
  496. .popup-img-cont{
  497. display: flex;
  498. align-items: center;
  499. image{
  500. width: 100%;
  501. }
  502. }
  503. </style>