doctorDetail.vue 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129
  1. <template>
  2. <view class="content es-pt-34">
  3. <view class="info">
  4. <view :style="{ height: statusBarHeight + 44 + 'px' }"></view>
  5. <view style="position: fixed; top: 0; left: 0; right: 0; z-index: 9999; background-color: #fff">
  6. <view :style="{ height: statusBarHeight + 'px' }"></view>
  7. <view class="u-f-ajc u-f-jsb" style="height: 44px; padding: 0 24rpx">
  8. <view class="u-f-ajc">
  9. <view class="es-mr-14" @tap="goBack">
  10. <image class="es-icon-64" src="/static/image/agent/back_black_icon.png" mode=""></image>
  11. </view>
  12. <view class="es-mr-24 avatar es-br-ban u-f-ajc">
  13. <image class="es-icon-60 es-br-ban"
  14. :src="data.avatar || '/static/image/hall/my_heads_icon.png'" mode=""></image>
  15. </view>
  16. <view class="">
  17. <view class="u-f-ajc">
  18. <view class="es-fs-28 es-c-22 es-fw-600 es-mr-12 u-f-ajc">
  19. {{ data.doctorName || '' }}
  20. </view>
  21. <view class="u-f-ajc">
  22. <image class="es-icon-36" src="/static/image/agent/ai_icon.png" mode=""></image>
  23. </view>
  24. </view>
  25. <view class="es-c-99 es-fs-24">
  26. {{ data.deptName || '' }}
  27. </view>
  28. </view>
  29. </view>
  30. <view class="">
  31. <!-- <image class="es-icon-48 es-mr-32" src="/static/image/agent/dialogue_icom.png" mode=""> -->
  32. <!-- </image> -->
  33. <image @tap="doShare(data.doctorName || '')" class="es-icon-48"
  34. src="/static/image/agent/share_icom.png" mode=""></image>
  35. </view>
  36. </view>
  37. </view>
  38. <view class="es-fw es-c-22 es-fs-48 es-mt-44">{{ data.doctorName || '' }}</view>
  39. <view class="es-mt-8 es-c-75 es-fs-24" v-if="data.deptName">{{ data.deptName || '' }} ·
  40. 主任{{ data.doctorType && data.doctorType == 2 ? '药师' : '医师' }}</view>
  41. <!-- 医生智能体 -->
  42. <view class="es-mt-26 agentBox">
  43. <view class="agentBox-avatar" :class="{'openTop':isOpen}">
  44. <image class="es-icon-60" :src="data.avatar || '/static/image/agent/ai_doctor2.png'" mode="">
  45. </image>
  46. </view>
  47. <view class="es-fw es-c-33 es-fs-40">医生智能体</view>
  48. <view class="intro-content es-mt-40 es-c-22 es-fs-28"
  49. :class="{ 'is-collapsed': !isOpen, 'is-expanded': isOpen }" ref="introRef">
  50. {{reminderWords || '' }}
  51. <text class="toggle-btn" v-if="showToggle" @click="isOpen = !isOpen">
  52. {{ isOpen ? '收起' : '展开' }}
  53. </text>
  54. </view>
  55. <view class="es-mt-40 u-f-ajc u-f-jsb" v-if="false">
  56. <view class="u-f">
  57. <!-- <view class="u-f-ajc" @tap="copyContent(data.reminderWords)">
  58. <image class="es-icon-32 es-mr-28" src="/static/image/agent/copy_icon.png" mode=""></image>
  59. </view> -->
  60. <!-- <view class="u-f-ajc es-mr-28">
  61. <u-icon name="thumb-up" color="#222222" size="38rpx"></u-icon>
  62. </view>
  63. <view class="u-f-ajc es-mr-28">
  64. <u-icon name="thumb-down" color="#222222" size="38rpx"></u-icon>
  65. </view> -->
  66. <view class="u-f-ajc" @tap="doShare()">
  67. <image class="es-icon-32" src="/static/image/agent/share_icom.png" mode=""></image>
  68. </view>
  69. </view>
  70. <view class="es-c-99 es-fs-24">AI生成仅供参考</view>
  71. </view>
  72. </view>
  73. </view>
  74. <!-- 消息 -->
  75. <view class="msgBox">
  76. <template v-for="(item, index) in msgs">
  77. <!-- <view class="msgBox-item" v-if="item.type == 1">
  78. <view class="es-mt-40 es-fs-28 es-c-22 leftMsg es-bc-white">
  79. {{item.content}}
  80. </view>
  81. </view> -->
  82. <view class="answer es-mt-40 es-bg-white" v-if="item.type == 1">
  83. <view class="es-c-22 es-fs-32">
  84. {{ item.content }}
  85. </view>
  86. <view class="es-fs-24 es-mt-30 es-c-99">内容由AI生成,非诊疗意见,不适请及时就医</view>
  87. <view class="line"></view>
  88. <view class="es-mt-40 u-f-ajc u-f-jsb">
  89. <view class="u-f">
  90. <view class="u-f-ajc" @tap="copyContent(item.content)">
  91. <image class="es-icon-32 es-mr-28" src="/static/image/agent/copy_icon.png" mode="">
  92. </image>
  93. </view>
  94. <!-- <view class="u-f-ajc es-mr-28">
  95. <u-icon name="thumb-up" color="#222222" size="38rpx"></u-icon>
  96. </view>
  97. <view class="u-f-ajc es-mr-28">
  98. <u-icon name="thumb-down" color="#222222" size="38rpx"></u-icon>
  99. </view> -->
  100. </view>
  101. <view class="es-c-99 es-fs-24"></view>
  102. </view>
  103. </view>
  104. <view class="msgBox-item jcEnd" v-if="item.type == 2">
  105. <view class="es-fs-32 es-c-white rightMsg es-mt-40">
  106. {{ item.content }}
  107. </view>
  108. </view>
  109. </template>
  110. <!-- <view class="msgBox-item jcEnd" v-if="rewardDoctor==1">
  111. <view class="es-fs-32 es-c-white rightMsg es-mt-40">
  112. 打赏医生
  113. </view>
  114. </view> -->
  115. </view>
  116. <view class="footerBox">
  117. <view class="u-f">
  118. <view class="u-f-ajc footerBox-tips es-mr-16" v-for="(item, index) in problemArr" :key="index"
  119. @tap="sendFixedTextFun(item)">
  120. <view class="u-f-ajc es-mr-12">
  121. <image class="es-icon-32" :src="item.imageUrl" mode=""></image>
  122. </view>
  123. <view class="es-c-22 es-fs-26">
  124. {{ item.title }}
  125. </view>
  126. </view>
  127. </view>
  128. <view class="es-mt-24 footerBox-btn u-f-ajc u-f-jsb">
  129. <view class="es-mr-16 u-f-ajc u-f-jsb footerBox-btnBox">
  130. <!-- <view class="footerBox-btnBox-recording u-f-ajc">
  131. <image class="es-icon-48" src="/static/image/agent/voice_icon.png" mode=""></image>
  132. </view> -->
  133. <view class="es-h-100 es-wp-100">
  134. <input class="es-fs-32 sendInput" type="text" placeholder="健康问题尽管问我" v-model="inputText"
  135. @confirm="handleInput" placeholder-style="color:#999999" />
  136. </view>
  137. <!-- <view class="es-mr-26" @click="handleInput()">
  138. <image class="es-icon-48" src="/static/image/agent/expand_function_icon.png" mode=""></image>
  139. </view> -->
  140. </view>
  141. <view class="" :style="{ whiteSpace: 'nowrap' }" @click="handleInput()">发送</view>
  142. <!-- <view class="u-f-ajc" @tap="navTo('/pages/agent/doctorCommunication')">
  143. <image class="es-icon-100" src="/static/image/agent/phone_icon50.png" mode=""></image>
  144. </view> -->
  145. </view>
  146. <!-- <view class="chat_action_bar">
  147. <u-row class="action_row">
  148. <u-col v-for="item in actionList" :key="item.idx" @click="actionClick(item)" span="3">
  149. <view class="action_item">
  150. <image :src="item.icon" alt="" srcset="" />
  151. <text class="action_item_title">{{ item.title }}</text>
  152. </view>
  153. </u-col>
  154. </u-row>
  155. </view> -->
  156. </view>
  157. <u-popup :show="rewardShow" mode="center" round="32rpx" @close="rewardShow = false"
  158. :customStyle="{ margin: '0 24rpx' }">
  159. <rewardDoctor ref="rewardDoctorRef" :rewardDoctor="rewardDoctor" :doctorId="doctorId"
  160. @close="rewardShow = false" />
  161. </u-popup>
  162. <!-- 分享弹窗 -->
  163. <u-popup :show="showShare" @close="showShare = false">
  164. <share-box :shareItem="shareItem" @closeShare="showShare = false"></share-box>
  165. </u-popup>
  166. <u-popup :show="showPatient" mode="center" round="32rpx" @close="showPatient = false">
  167. <view class="chose-patient">
  168. <view class="title-box" @click="navTo('/pages/user/patient')" v-if="patient == null">
  169. <view class="title">选择就诊人</view>
  170. <view class="right">
  171. <text class="value">请点击添加</text>
  172. <image src="/static/images/arrow_gray.png" mode=""></image>
  173. </view>
  174. </view>
  175. <view class="patient" @click="navTo('/pages/user/patient')" v-if="patient != null">
  176. <view class="left">
  177. <view class="name">{{ patient.patientName }}</view>
  178. <view class="info">
  179. <text class="text" v-if="patient.sex == 1">男</text>
  180. <text class="text" v-if="patient.sex == 2">女</text>
  181. <text class="text">{{ $getAge(patient.birthday) }}岁</text>
  182. <text class="text">{{ $parseIdCard(patient.idCard) }}</text>
  183. </view>
  184. </view>
  185. <view class="right">
  186. <image src="/static/images/arrow_gray.png" mode=""></image>
  187. </view>
  188. </view>
  189. </view>
  190. </u-popup>
  191. <!-- <chating-footer ref="chatingFooterRef" :footerOutsideFlag="footerOutsideFlag"
  192. @scrollToBottom="scrollToBottom" /> -->
  193. </view>
  194. </template>
  195. <script>
  196. import {
  197. aiChatListByUser
  198. } from '@/api/index.js';
  199. import rewardDoctor from '@/pages/agent/components/rewardDoctor.vue';
  200. import {
  201. getUserInfo
  202. } from '@/api/user';
  203. import {
  204. ChatingFooterActionTypes,
  205. ContactChooseTypes,
  206. PageEvents
  207. } from '@/pages_im/constant/index.js';
  208. import {
  209. premissionCheck
  210. } from '@/js_sdk/wa-permission/permission.js';
  211. import ChatingFooter from '@/pages_im/pages/conversation/chating/components/ChatingFooter/index.vue';
  212. import {
  213. getAiDoctorForDetails,
  214. getDictByKey,
  215. rewardAiDoctor
  216. } from '@/api/agent.js';
  217. export default {
  218. components: {
  219. ChatingFooter,
  220. rewardDoctor
  221. },
  222. data() {
  223. return {
  224. data: {},
  225. problemArr: [{
  226. imageUrl: '/static/image/agent/health_counseling_icon.png',
  227. title: '健康咨询',
  228. url: '/pages/doctor/doctorDetails'
  229. },
  230. {
  231. imageUrl: '/static/image/agent/course_study_icon.png',
  232. title: '课程学习',
  233. url: '/pages/course/index?activeTab=1'
  234. },
  235. {
  236. imageUrl: '/static/image/agent/fanghua_coin_icon.png',
  237. title: '打赏医生'
  238. }
  239. ],
  240. readFilePermission: false,
  241. actionList: [{
  242. idx: 0,
  243. type: ChatingFooterActionTypes.takePhoto,
  244. title: '拍照',
  245. icon: require('@/pages_im/static/images/chating_action_camera.png')
  246. },
  247. {
  248. idx: 1,
  249. type: ChatingFooterActionTypes.Album,
  250. title: '相册',
  251. icon: require('@/pages_im/static/images/chating_action_image.png')
  252. },
  253. {
  254. idx: 2,
  255. type: ChatingFooterActionTypes.Camera,
  256. title: '视频',
  257. icon: require('@/pages_im/static/images/take-photo.svg')
  258. },
  259. {
  260. idx: 3,
  261. type: ChatingFooterActionTypes.pickCamera,
  262. title: '录像',
  263. icon: require('@/pages_im/static/images/take-video.svg')
  264. }
  265. ],
  266. rewardDoctor: 0,
  267. showShare: false,
  268. shareItem: {
  269. imageUrl: '',
  270. title: '',
  271. path: '',
  272. isMini: true
  273. },
  274. content: '',
  275. msgEnd: false, //发送信息
  276. isSocketOpen: false,
  277. msgs: [],
  278. inputText: '',
  279. isSend: true,
  280. showPatient: false,
  281. patient: null,
  282. userInfo: null,
  283. statusBarHeight: '',
  284. doctorId: null,
  285. isOpen: false,
  286. showToggle: false,
  287. reminderWords: '',
  288. rewardShow: false
  289. };
  290. },
  291. onLoad(options) {
  292. const systemInfo = uni.getSystemInfoSync();
  293. this.statusBarHeight = systemInfo.statusBarHeight;
  294. if (options.doctorId != null) {
  295. this.doctorId = options.doctorId;
  296. this.problemArr[0].url = `/pages/doctor/doctorDetails?doctorId=${this.doctorId}&isAidoctor=1`;
  297. this.getDetailFun(this.doctorId);
  298. }
  299. let info = uni.getStorageSync('userInfo');
  300. this.userInfo = info && JSON.parse(info);
  301. this.getMsgList();
  302. this.initSocket();
  303. if (!this.patient) this.showPatient = true;
  304. uni.$on('refreshOrderPatient', (res) => {
  305. if (this.patient && this.patient.patientId == res.patientId) {
  306. return;
  307. }
  308. this.showPatient = false;
  309. this.msgEnd = false;
  310. this.patient = res;
  311. this.getMsgList();
  312. });
  313. },
  314. onShow() {},
  315. watch: {
  316. reminderWords: {
  317. handler(newVal, oldVal) {
  318. this.getContentHeight();
  319. },
  320. immediate: true,
  321. deep: false
  322. }
  323. },
  324. onReady() {
  325. this.getContentHeight();
  326. },
  327. methods: {
  328. getContentHeight() {
  329. this.$nextTick(() => {
  330. const query = uni.createSelectorQuery().in(this);
  331. query
  332. .select('.intro-content')
  333. .boundingClientRect((rect) => {
  334. if (!rect || rect.height === 0) {
  335. setTimeout(() => {
  336. this.getContentHeight();
  337. }, 100);
  338. return;
  339. }
  340. console.log('获取到的数据', rect);
  341. this.showToggle = rect.height >= 34;
  342. })
  343. .exec();
  344. });
  345. },
  346. handleInput() {
  347. if (this.patient && this.patient.patientId) {
  348. if (this.msgEnd || !this.isSocketOpen) {
  349. // 重新发起会话
  350. this.initSocket();
  351. } else {
  352. this.sendMsg();
  353. }
  354. } else {
  355. uni.showToast({
  356. title: '请选择就诊人',
  357. icon: 'none'
  358. });
  359. if (!this.patient) this.showPatient = true;
  360. }
  361. },
  362. initSocket() {
  363. //创建一个socket连接
  364. var userId = this.userInfo.userId;
  365. var that = this;
  366. if (this.socket) {
  367. this.socket.close();
  368. this.socket = null;
  369. }
  370. this.socket = uni.connectSocket({
  371. url: getApp().globalData.wsUrl + '/app/webSocket/' + userId,
  372. multiple: true,
  373. success: (res) => {
  374. console.log('WebSocket连接已打开1!');
  375. that.isSocketOpen = true;
  376. },
  377. error: (res) => {
  378. console.log(res);
  379. }
  380. });
  381. this.socket.onMessage((res) => {
  382. console.log('收到消息', res);
  383. that.isSend = true;
  384. that.addMsg(1, res.data, null, 2);
  385. });
  386. //监听socket打开
  387. this.socket.onOpen(() => {
  388. console.log('WebSocket连接已打开2!', that.msgEnd);
  389. that.isSocketOpen = true;
  390. if (that.msgEnd) {
  391. // 重新发起会话
  392. that.isSend = true;
  393. that.sendMsg();
  394. }
  395. });
  396. //监听socket关闭
  397. this.socket.onClose(() => {
  398. that.isSocketOpen = false;
  399. that.socket = null;
  400. console.log('WebSocket连接已关闭!');
  401. that.msgEnd = true;
  402. that.scrollToBottom();
  403. if (that.msgTimes) {
  404. clearInterval(that.msgTimes);
  405. that.msgTimes = null;
  406. }
  407. });
  408. //监听socket错误
  409. this.socket.onError(() => {
  410. that.isSocketOpen = false;
  411. that.socket = null;
  412. that.msgEnd = true;
  413. console.log('WebSocket连接打开失败');
  414. if (that.msgTimes) {
  415. clearInterval(that.msgTimes);
  416. that.msgTimes = null;
  417. }
  418. });
  419. },
  420. sendMsg() {
  421. if (this.inputText == '') {
  422. return;
  423. }
  424. if (!this.isSend) {
  425. return;
  426. }
  427. if (this.isSocketOpen) {
  428. var userId = this.userInfo.userId;
  429. var data = {
  430. userId: this.userInfo.userId,
  431. doctorId: this.doctorId,
  432. message: this.inputText,
  433. sessionId: this.sessionId,
  434. patientId: this.patient.patientId
  435. };
  436. this.socket.send({
  437. data: JSON.stringify(data),
  438. success: () => {
  439. console.log('发送成功');
  440. this.addMsg(2, this.inputText, null, 1);
  441. this.addMsg(1, '正在思考中...', null, 1);
  442. this.isSend = false;
  443. },
  444. fail: () => {
  445. console.log('发送失败');
  446. }
  447. });
  448. }
  449. },
  450. addMsg(type, content, msg, inputType) {
  451. this.msgEnd = false;
  452. var obj = {
  453. type: type,
  454. content: content,
  455. msg: msg
  456. };
  457. if (inputType == 2) {
  458. this.msgs.splice(-1);
  459. this.msgs.push(obj);
  460. } else if (inputType == 1) {
  461. this.msgs.push(obj);
  462. }
  463. this.inputText = '';
  464. var that = this;
  465. this.scrollToBottom();
  466. //先确保清除了之前的消息定时器
  467. if (that.msgTimes) {
  468. clearInterval(that.msgTimes);
  469. that.msgTimes = null;
  470. }
  471. // 5分钟无消息自动结束
  472. that.msgTimes = setInterval(() => {
  473. console.log('5分钟无消息自动结束');
  474. clearInterval(that.msgTimes);
  475. if (this.socket != null) {
  476. this.socket.close();
  477. }
  478. that.msgTimes = null;
  479. }, 300000);
  480. },
  481. scrollToBottom() {
  482. this.$nextTick(() => {
  483. uni.createSelectorQuery()
  484. .in(this)
  485. .select('.content')
  486. .boundingClientRect((res) => {
  487. if (res) {
  488. uni.pageScrollTo({
  489. scrollTop: res.height,
  490. duration: 100
  491. });
  492. }
  493. })
  494. .exec();
  495. });
  496. },
  497. getMsgList() {
  498. if (this.patient && this.patient.patientId) {
  499. const that = this;
  500. const userId = this.userInfo.userId;
  501. const param = {
  502. doctorId: this.doctorId,
  503. userId: this.userInfo.userId,
  504. patientId: this.patient.patientId
  505. };
  506. aiChatListByUser(param)
  507. .then((res) => {
  508. // setTimeout(() => {
  509. // this.getHeight()
  510. // }, 200)
  511. let list = [];
  512. if (res.data && res.data.length > 0) {
  513. list = list.concat(res.data);
  514. that.sessionId = res.data && res.data.length > 0 ? res.data[0].sessionId : undefined;
  515. }
  516. list.forEach(function(value, index, array) {
  517. that.addMsg(value.msgType == 1 ? 2 : 1, value.content, value, 1);
  518. });
  519. })
  520. .catch(() => {});
  521. }
  522. },
  523. async requestPressmition() {
  524. let result = await premissionCheck('EXTERNAL_STORAGE');
  525. console.log('premission result:' + result);
  526. if (result == 1) {
  527. this.readFilePermission = true;
  528. }
  529. },
  530. async actionClick(action) {
  531. switch (action.type) {
  532. case ChatingFooterActionTypes.takePhoto:
  533. if (uni.$u.os() != 'ios') {
  534. this.requestPressmition();
  535. if (!this.readFilePermission) {
  536. return;
  537. }
  538. }
  539. this.$emit('prepareMediaMessage', {
  540. type: ChatingFooterActionTypes.Camera,
  541. index: 0
  542. });
  543. break;
  544. case ChatingFooterActionTypes.Album:
  545. if (uni.$u.os() != 'ios') {
  546. this.requestPressmition();
  547. if (!this.readFilePermission) {
  548. return;
  549. }
  550. }
  551. this.$emit('prepareMediaMessage', {
  552. type: ChatingFooterActionTypes.Album,
  553. index: 0
  554. });
  555. break;
  556. case ChatingFooterActionTypes.Camera:
  557. if (uni.$u.os() != 'ios') {
  558. this.requestPressmition();
  559. if (!this.readFilePermission) {
  560. return;
  561. }
  562. }
  563. this.$emit('prepareMediaMessage', {
  564. type: ChatingFooterActionTypes.Album,
  565. index: 1
  566. });
  567. break;
  568. case ChatingFooterActionTypes.pickCamera:
  569. if (uni.$u.os() != 'ios') {
  570. this.requestPressmition();
  571. if (!this.readFilePermission) {
  572. return;
  573. }
  574. }
  575. this.$emit('prepareMediaMessage', {
  576. type: ChatingFooterActionTypes.Camera,
  577. index: 1
  578. });
  579. break;
  580. case ChatingFooterActionTypes.Call:
  581. if (!this.$store.getters.storeCurrentConversation.groupID) {
  582. uni.$emit(PageEvents.RtcCall, 'audio');
  583. return;
  584. }
  585. IMSDK.asyncApi('signalingGetRoomByGroupID', IMSDK.uuid(), this.$store.getters
  586. .storeCurrentConversation.groupID).then(({
  587. data
  588. }) => {
  589. if (data.invitation) {
  590. uni.showModal({
  591. title: '提示',
  592. content: '群通话进行中,是否直接加入?',
  593. confirmText: '确认',
  594. cancelText: '取消',
  595. success: (res) => {
  596. if (res.confirm) {
  597. callingModule.joinRoomLiveChat(data);
  598. }
  599. }
  600. });
  601. } else {
  602. uni.$emit(PageEvents.RtcCall, 'audio');
  603. }
  604. });
  605. break;
  606. case ChatingFooterActionTypes.VideoCall:
  607. if (!this.$store.getters.storeCurrentConversation.groupID) {
  608. uni.$emit(PageEvents.RtcCall, 'video');
  609. return;
  610. }
  611. IMSDK.asyncApi('signalingGetRoomByGroupID', IMSDK.uuid(), this.$store.getters
  612. .storeCurrentConversation.groupID).then(({
  613. data
  614. }) => {
  615. if (data.invitation) {
  616. uni.showModal({
  617. title: '提示',
  618. content: '群通话进行中,是否直接加入?',
  619. confirmText: '确认',
  620. cancelText: '取消',
  621. success: (res) => {
  622. if (res.confirm) {
  623. callingModule.joinRoomLiveChat(data);
  624. }
  625. }
  626. });
  627. } else {
  628. uni.$emit(PageEvents.RtcCall, 'video');
  629. }
  630. });
  631. break;
  632. case ChatingFooterActionTypes.Order: {
  633. if (this.$companyUserIsLogin()) {
  634. uni.navigateTo({
  635. url: '/pages/company/inquiryOrderIMList?userId=' + this.userID
  636. });
  637. } else {
  638. uni.navigateTo({
  639. url: '/pages/store/inquiryOrderDetails?orderId=' + this.timStore.orderId
  640. });
  641. }
  642. }
  643. break;
  644. case ChatingFooterActionTypes.Follow:
  645. uni.navigateTo({
  646. url: '/pages/user/followDetails?followId=' + this.timStore.followId
  647. });
  648. break;
  649. case ChatingFooterActionTypes.StoreOrder: {
  650. if (this.$companyUserIsLogin()) {
  651. uni.navigateTo({
  652. url: '/pages/company/storeOrderList?userId=' + this.userID
  653. });
  654. } else {
  655. uni.navigateTo({
  656. url: '/pages/store/storeOrderDetail?orderId=' + this.timStore.orderId
  657. });
  658. }
  659. }
  660. break;
  661. case ChatingFooterActionTypes.Package: //疗法
  662. {
  663. if (this.$companyUserIsLogin()) {
  664. uni.navigateTo({
  665. url: '/pages/company/packageList?isIM=1'
  666. });
  667. }
  668. }
  669. break;
  670. case ChatingFooterActionTypes.CouponPackage: {
  671. if (this.$companyUserIsLogin()) {
  672. uni.navigateTo({
  673. url: '/pages/company/couponList?couponType=5&isIM=1'
  674. });
  675. }
  676. }
  677. break;
  678. case ChatingFooterActionTypes.InquirySelect: {
  679. if (this.$companyUserIsLogin()) {
  680. let companyId = uni.getStorageSync('companyId');
  681. let companyUserId = uni.getStorageSync('companyUserId');
  682. uni.navigateTo({
  683. url: '/pages/store/inquirySelectType?companyId=' + companyId +
  684. '&companyUserId=' + companyUserId + '&isIM=1'
  685. });
  686. }
  687. }
  688. break;
  689. case ChatingFooterActionTypes.Card:
  690. uni.navigateTo({
  691. url: `/pages_im/pages/common/contactChoose/index?type=${ContactChooseTypes.Card}`
  692. });
  693. break;
  694. case ChatingFooterActionTypes.File:
  695. if (uni.$u.os() != 'ios') {
  696. this.requestPressmition();
  697. if (!this.readFilePermission) {
  698. return;
  699. }
  700. }
  701. IMSDK.pickFile().then(async (path) => {
  702. console.log(path);
  703. const idx = path.lastIndexOf('/');
  704. const fileName = path.slice(idx + 1);
  705. const message = await IMSDK.asyncApi(IMMethods.CreateFileMessageFromFullPath,
  706. IMSDK.uuid(), {
  707. filePath: getPurePath(path),
  708. fileName
  709. });
  710. this.$emit('sendMessage', message);
  711. });
  712. break;
  713. case ChatingFooterActionTypes.Location:
  714. uni.chooseLocation({
  715. success: async (res) => {
  716. if (res) {
  717. const options = {
  718. name: res.name,
  719. latng: `${res.latitude},${res.longitude}`,
  720. addr: res.address,
  721. city: res.address,
  722. module: 'locationPicker',
  723. latitude: res.latitude,
  724. longitude: res.longitude,
  725. url: `https://restapi.amap.com/v3/staticmap?size=600*300&markers=-1,https://cache.amap.com/lbs/static/cuntom_marker1.png,0:${res.longitude},${res.latitude}&key=${AmapWebKey}`
  726. };
  727. const message = await IMSDK.asyncApi(IMMethods.CreateLocationMessage,
  728. IMSDK.uuid(), {
  729. description: JSON.stringify(options),
  730. longitude: res.longitude,
  731. latitude: res.latitude
  732. });
  733. this.$emit('sendMessage', message);
  734. } else {
  735. uni.$u.toast('获取位置失败');
  736. }
  737. },
  738. fail: ({
  739. errMsg
  740. }) => {
  741. if (!errMsg.includes('cancel')) {
  742. uni.$u.toast('获取位置失败');
  743. }
  744. }
  745. });
  746. break;
  747. default:
  748. break;
  749. }
  750. },
  751. copyContent(content) {
  752. if (!content) return;
  753. uni.setClipboardData({
  754. data: content,
  755. success: () => {
  756. uni.showToast({
  757. title: '复制成功',
  758. icon: 'none'
  759. });
  760. },
  761. fail: () => {
  762. uni.showToast({
  763. title: '复制失败',
  764. icon: 'none'
  765. });
  766. }
  767. });
  768. },
  769. sendFixedTextFun(e) {
  770. if (e.title == '健康咨询') {
  771. return uni.navigateTo({
  772. url: e.url
  773. });
  774. }
  775. if (e.title == '课程学习') {
  776. uni.setStorageSync('activeTabCourse', true);
  777. return uni.switchTab({
  778. url: e.url
  779. });
  780. }
  781. if (e.title == '打赏医生') {
  782. this.rewardDoctor = 1;
  783. this.rewardShow = true;
  784. }
  785. },
  786. async getDetailFun(doctorId) {
  787. const res = await getAiDoctorForDetails({
  788. doctorId
  789. });
  790. if (res.code == 200) {
  791. this.data = res.data;
  792. this.reminderWords = this.data.reminderWords || ''
  793. } else {
  794. uni.showToast({
  795. icon: 'none',
  796. title: res.msg
  797. });
  798. }
  799. },
  800. goBack() {
  801. uni.navigateBack();
  802. },
  803. navTo(url) {
  804. uni.navigateTo({
  805. url: url
  806. });
  807. },
  808. doShare(title) {
  809. this.shareItem.title = title;
  810. this.shareItem.imageUrl = (this.doctor && this.doctor.avatar) || '';
  811. this.shareItem.compressImage = 1;
  812. this.shareItem.isMini = true;
  813. this.shareItem.path = '/pages_doctor/doctorDetails?doctorId=' + this.doctorId;
  814. let cdn = uni.getStorageSync('h5Path');
  815. this.shareItem.url = cdn + '/pages/doctor/doctorDetails?doctorId=' + this.doctorId;
  816. this.showShare = true;
  817. }
  818. }
  819. };
  820. </script>
  821. <style scoped lang="scss">
  822. .content {
  823. height: auto;
  824. min-height: 100vh;
  825. overflow-y: scroll;
  826. width: 100%;
  827. background: url('/static/image/agent/doctor-bg1.png') center top / 100% 50% no-repeat, url('/static/image/agent/doctor-bg2.png') center bottom / 100% 50% no-repeat;
  828. padding-bottom: 268rpx;
  829. }
  830. .info {
  831. margin: 0 24rpx;
  832. .avatar {
  833. padding: 4rpx;
  834. background: linear-gradient(180deg, #fff5eb 0%, #ffefdd 48.08%, #ffe9cd 100%);
  835. }
  836. .agentBox {
  837. background-image: url('/static/image/agent/znt_jj_bg.png');
  838. background-repeat: no-repeat;
  839. background-size: 100% 100%;
  840. min-height: 230rpx;
  841. padding: 24rpx 32rpx;
  842. position: relative;
  843. z-index: 1000;
  844. .agentBox-avatar {
  845. position: absolute;
  846. top: -224rpx;
  847. right: 20rpx;
  848. z-index: -1;
  849. width: 268rpx;
  850. height: 332rpx;
  851. image {
  852. width: 268rpx;
  853. height: 270rpx;
  854. }
  855. }
  856. }
  857. }
  858. .msgBox {
  859. margin: 0 24rpx;
  860. .msgBox-item {
  861. display: flex;
  862. align-items: flex-start;
  863. width: 100%;
  864. }
  865. .leftMsg {
  866. display: inline-block;
  867. padding: 16rpx 32rpx;
  868. border-radius: 16rpx;
  869. max-width: 80%;
  870. word-wrap: break-word;
  871. word-break: break-all;
  872. }
  873. .rightMsg {
  874. display: inline-block;
  875. max-width: 80%;
  876. word-wrap: break-word;
  877. word-break: break-all;
  878. background: linear-gradient(89deg, #ff5c03 0%, #ffab3b 100%);
  879. border-radius: 32rpx 8rpx 32rpx 32rpx;
  880. padding: 30rpx 24rpx;
  881. }
  882. .jcEnd {
  883. justify-content: flex-end;
  884. }
  885. .answer {
  886. border-radius: 32rpx;
  887. padding: 32rpx;
  888. background: #ffffff;
  889. .line {
  890. margin: 32rpx 0;
  891. background: #ececec;
  892. height: 2rpx;
  893. }
  894. }
  895. }
  896. .es-icon-36 {
  897. width: 36rpx;
  898. height: 36rpx;
  899. }
  900. .es-mt-60 {
  901. margin-top: 60rpx;
  902. }
  903. .footerBox {
  904. position: fixed;
  905. bottom: 0;
  906. width: 100%;
  907. z-index: 999;
  908. background-color: #ffffff;
  909. background-image: url('/static/image/agent/doctor-bg2.png');
  910. overflow: hidden;
  911. background-size: 100% 200%;
  912. background-position: bottom;
  913. background-repeat: no-repeat;
  914. box-sizing: border-box;
  915. padding: 32rpx 24rpx;
  916. .footerBox-tips {
  917. padding: 16rpx 24rpx;
  918. background: linear-gradient(180deg, #fff4ed 0%, #ffffff 17%, #ffffff 100%);
  919. box-shadow: inset 0rpx 16rpx 8rpx 0rpx rgba(230, 192, 172, 0.1);
  920. border-radius: 32rpx 32rpx 32rpx 32rpx;
  921. border: 2rpx solid #ffffff;
  922. }
  923. .footerBox-btn {
  924. width: 100%;
  925. height: 100rpx;
  926. box-sizing: border-box;
  927. .footerBox-btnBox {
  928. width: calc(100% - 64rpx);
  929. border-radius: 50rpx 50rpx 50rpx 50rpx;
  930. background: #ffffff;
  931. .footerBox-btnBox-recording {
  932. border-radius: 50rpx 50rpx 50rpx 50rpx;
  933. width: 100rpx;
  934. height: 100rpx;
  935. box-sizing: border-box;
  936. background: #ffffff;
  937. box-shadow: 4rpx 0rpx 8rpx 0rpx rgba(159, 64, 11, 0.05);
  938. }
  939. }
  940. }
  941. }
  942. .chat_action_bar {
  943. position: relative;
  944. // background: #f0f2f6;
  945. padding: 24rpx 36rpx;
  946. .action_row {
  947. flex-wrap: wrap;
  948. margin-bottom: 24rpx;
  949. }
  950. .action_item {
  951. @include centerBox();
  952. flex-direction: column;
  953. margin-top: 24rpx;
  954. image {
  955. width: 96rpx;
  956. height: 96rpx;
  957. }
  958. &_title {
  959. font-size: 24rpx;
  960. color: #999;
  961. margin-top: 6rpx;
  962. }
  963. }
  964. }
  965. .sendInput {
  966. padding: 28rpx 20rpx;
  967. width: 90%;
  968. }
  969. .chose-patient {
  970. // margin: 15rpx 15rpx;
  971. margin-bottom: 15rpx;
  972. padding: 30rpx 40rpx;
  973. box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.05);
  974. background-color: #fff;
  975. border-radius: 15rpx;
  976. width: 622rpx;
  977. height: 200rpx;
  978. .title-box {
  979. margin-top: 40rpx;
  980. display: flex;
  981. align-items: center;
  982. justify-content: space-between;
  983. .title {
  984. font-size: 32upx;
  985. font-family: PingFang SC;
  986. font-weight: bold;
  987. color: #111111;
  988. }
  989. .right {
  990. height: 100%;
  991. display: flex;
  992. align-items: center;
  993. justify-content: center;
  994. .value {
  995. font-size: 28upx;
  996. font-family: PingFang SC;
  997. color: #999;
  998. margin-right: 10rpx;
  999. }
  1000. image {
  1001. width: 15upx;
  1002. height: 30upx;
  1003. }
  1004. }
  1005. }
  1006. .patient {
  1007. display: flex;
  1008. align-items: center;
  1009. justify-content: space-between;
  1010. height: 110upx;
  1011. .left {
  1012. .name {
  1013. font-size: 30upx;
  1014. line-height: 1;
  1015. font-family: PingFang SC;
  1016. font-weight: bold;
  1017. color: #111111;
  1018. }
  1019. .info {
  1020. margin-top: 30rpx;
  1021. display: flex;
  1022. align-items: center;
  1023. .text {
  1024. font-size: 26upx;
  1025. font-family: PingFang SC;
  1026. line-height: 1;
  1027. font-weight: 500;
  1028. color: #999;
  1029. margin-right: 19upx;
  1030. }
  1031. }
  1032. }
  1033. .right {
  1034. display: flex;
  1035. align-items: center;
  1036. image {
  1037. width: 15upx;
  1038. height: 30upx;
  1039. }
  1040. }
  1041. }
  1042. }
  1043. .openTop {
  1044. top: -180rpx !important;
  1045. }
  1046. .intro-content {
  1047. font-size: 28rpx;
  1048. word-break: break-all;
  1049. position: relative;
  1050. &.is-expanded {
  1051. overflow: visible;
  1052. display: block;
  1053. }
  1054. &.is-collapsed {
  1055. display: -webkit-box;
  1056. -webkit-box-orient: vertical;
  1057. -webkit-line-clamp: 2;
  1058. overflow: hidden;
  1059. }
  1060. }
  1061. .toggle-btn {
  1062. position: absolute;
  1063. bottom: 0;
  1064. right: 0;
  1065. font-size: 30rpx;
  1066. color: #ff5c03;
  1067. background: #fff;
  1068. padding-left: 8rpx;
  1069. z-index: 10;
  1070. }
  1071. </style>