与牧同行-小程序用户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
12 KiB

  1. <view class="consult-page">
  2. <!-- 头部专家信息 -->
  3. <view class="consult-header">
  4. <view class="header-content">
  5. <view class="header-left">
  6. <button class="back-btn" bindtap="goBack">
  7. <image src="/images/icons/back.png" class="back-icon"></image>
  8. </button>
  9. </view>
  10. <view class="header-center">
  11. <text class="expert-name">{{expertInfo.name}}</text>
  12. <view class="expert-status">
  13. <view class="status-dot {{expertInfo.online ? 'online' : 'offline'}}"></view>
  14. <text class="status-text">{{expertInfo.online ? '在线' : '离线'}}</text>
  15. </view>
  16. </view>
  17. <view class="header-right">
  18. <button class="header-action-btn" bindtap="makePhoneCall">
  19. <image src="/images/icons/phone.png" class="header-action-icon"></image>
  20. </button>
  21. </view>
  22. </view>
  23. </view>
  24. <!-- 聊天内容区域 -->
  25. <scroll-view class="chat-container" scroll-y scroll-into-view="{{scrollToView}}" scroll-with-animation="true">
  26. <!-- 首次咨询欢迎语 -->
  27. <view class="system-welcome" wx:if="{{isFirstLoad}}">
  28. <view class="welcome-avatar">
  29. <image src="{{expertInfo.avatar}}"></image>
  30. </view>
  31. <text class="welcome-name">{{expertInfo.name}}</text>
  32. <text class="welcome-title">{{expertInfo.title}} · {{expertInfo.expertise}}</text>
  33. <text class="welcome-tip">您好,我是{{expertInfo.name}},很高兴为您服务!</text>
  34. </view>
  35. <!-- 日期分隔线 -->
  36. <view class="date-divider" wx:if="{{showDateDivider}}">
  37. <text class="date-text">{{todayDate}}</text>
  38. </view>
  39. <!-- 消息列表 -->
  40. <block wx:for="{{messageList}}" wx:key="id">
  41. <!-- 时间分隔 -->
  42. <view class="time-divider" wx:if="{{item.showTime}}">
  43. <text>{{formatTime(item.timestamp)}}</text>
  44. </view>
  45. <!-- 对方消息 -->
  46. <view class="message-item message-left" wx:if="{{item.sender === 'expert'}}">
  47. <view class="message-avatar">
  48. <image src="{{expertInfo.avatar}}"></image>
  49. </view>
  50. <view class="message-content-wrapper">
  51. <!-- 文本消息 -->
  52. <view class="message-bubble message-bubble-left" wx:if="{{item.type === 'text'}}">
  53. <text class="message-text">{{item.content}}</text>
  54. </view>
  55. <!-- 图片消息 -->
  56. <view class="message-bubble message-bubble-left" wx:elif="{{item.type === 'image'}}">
  57. <image src="{{item.content}}" class="message-image" mode="widthFix" bindtap="previewImage" data-url="{{item.content}}"></image>
  58. </view>
  59. <!-- 视频消息 -->
  60. <view class="message-bubble message-bubble-left" wx:elif="{{item.type === 'video'}}">
  61. <video src="{{item.content}}" class="message-video" controls poster="{{item.thumb}}"></video>
  62. <view class="video-play-btn">
  63. <image src="/images/icons/play.png"></image>
  64. </view>
  65. </view>
  66. <!-- 语音消息 -->
  67. <view class="message-bubble message-bubble-left message-audio" wx:elif="{{item.type === 'audio'}}">
  68. <image src="/images/icons/audio-left.png" class="audio-icon-left"></image>
  69. <view class="audio-content">
  70. <view class="audio-wave">
  71. <view class="wave-bar"></view>
  72. <view class="wave-bar"></view>
  73. <view class="wave-bar"></view>
  74. <view class="wave-bar"></view>
  75. <view class="wave-bar"></view>
  76. </view>
  77. <text class="audio-duration">{{item.duration}}''</text>
  78. </view>
  79. </view>
  80. <!-- 文件消息 -->
  81. <view class="message-bubble message-bubble-left message-file" wx:elif="{{item.type === 'file'}}">
  82. <view class="file-icon-box">
  83. <image src="/images/icons/file.png" class="file-icon"></image>
  84. <text class="file-extension">{{item.extension}}</text>
  85. </view>
  86. <view class="file-info">
  87. <text class="file-name">{{item.fileName}}</text>
  88. <text class="file-size">{{formatFileSize(item.fileSize)}}</text>
  89. </view>
  90. <button class="file-download-btn" bindtap="downloadFile" data-url="{{item.content}}">下载</button>
  91. </view>
  92. <text class="message-time">{{formatMessageTime(item.timestamp)}}</text>
  93. </view>
  94. </view>
  95. <!-- 我的消息 -->
  96. <view class="message-item message-right" wx:else>
  97. <view class="message-content-wrapper">
  98. <!-- 消息状态 -->
  99. <view class="message-status">
  100. <image wx:if="{{item.status === 'sending'}}" src="/images/icons/sending.png" class="status-icon"></image>
  101. <image wx:if="{{item.status === 'success'}}" src="/images/icons/success.png" class="status-icon"></image>
  102. <image wx:if="{{item.status === 'error'}}" src="/images/icons/error.png" class="status-icon"></image>
  103. </view>
  104. <!-- 文本消息 -->
  105. <view class="message-bubble message-bubble-right" wx:if="{{item.type === 'text'}}">
  106. <text class="message-text">{{item.content}}</text>
  107. </view>
  108. <!-- 图片消息 -->
  109. <view class="message-bubble message-bubble-right" wx:elif="{{item.type === 'image'}}">
  110. <image src="{{item.content}}" class="message-image" mode="widthFix" bindtap="previewImage" data-url="{{item.content}}"></image>
  111. <view class="upload-progress" wx:if="{{item.status === 'uploading'}}">
  112. <view class="progress-circle">
  113. <view class="progress-fill" style="transform: rotate({{item.progress * 3.6}}deg);"></view>
  114. <text class="progress-text">{{item.progress}}%</text>
  115. </view>
  116. </view>
  117. </view>
  118. <!-- 视频消息 -->
  119. <view class="message-bubble message-bubble-right" wx:elif="{{item.type === 'video'}}">
  120. <video src="{{item.content}}" class="message-video" controls poster="{{item.thumb}}"></video>
  121. <view class="video-play-btn">
  122. <image src="/images/icons/play.png"></image>
  123. </view>
  124. <view class="upload-progress" wx:if="{{item.status === 'uploading'}}">
  125. <view class="progress-circle">
  126. <view class="progress-fill" style="transform: rotate({{item.progress * 3.6}}deg);"></view>
  127. <text class="progress-text">{{item.progress}}%</text>
  128. </view>
  129. </view>
  130. </view>
  131. <!-- 语音消息 -->
  132. <view class="message-bubble message-bubble-right message-audio" wx:elif="{{item.type === 'audio'}}">
  133. <view class="audio-content">
  134. <view class="audio-wave">
  135. <view class="wave-bar"></view>
  136. <view class="wave-bar"></view>
  137. <view class="wave-bar"></view>
  138. <view class="wave-bar"></view>
  139. <view class="wave-bar"></view>
  140. </view>
  141. <text class="audio-duration">{{item.duration}}''</text>
  142. </view>
  143. <image src="/images/icons/audio-right.png" class="audio-icon-right"></image>
  144. </view>
  145. <!-- 文件消息 -->
  146. <view class="message-bubble message-bubble-right message-file" wx:elif="{{item.type === 'file'}}">
  147. <view class="file-icon-box">
  148. <image src="/images/icons/file.png" class="file-icon"></image>
  149. <text class="file-extension">{{item.extension}}</text>
  150. </view>
  151. <view class="file-info">
  152. <text class="file-name">{{item.fileName}}</text>
  153. <text class="file-size">{{formatFileSize(item.fileSize)}}</text>
  154. </view>
  155. <view class="upload-progress" wx:if="{{item.status === 'uploading'}}">
  156. <view class="progress-circle">
  157. <view class="progress-fill" style="transform: rotate({{item.progress * 3.6}}deg);"></view>
  158. <text class="progress-text">{{item.progress}}%</text>
  159. </view>
  160. </view>
  161. </view>
  162. <text class="message-time">{{formatMessageTime(item.timestamp)}}</text>
  163. </view>
  164. <view class="message-avatar">
  165. <image src="{{userInfo.avatar}}"></image>
  166. </view>
  167. </view>
  168. </block>
  169. </scroll-view>
  170. <!-- 输入区域 -->
  171. <view class="input-section">
  172. <!-- 录音面板 -->
  173. <view class="voice-panel" wx:if="{{inputMode === 'voice'}}">
  174. <button class="voice-record-btn" bindtouchstart="startVoiceRecord" bindtouchend="endVoiceRecord">
  175. <image src="/images/icons/mic.png" class="mic-icon"></image>
  176. <text class="voice-tip">按住说话</text>
  177. </button>
  178. </view>
  179. <!-- 正常输入面板 -->
  180. <view class="input-panel" wx:else>
  181. <!-- 语音/键盘切换按钮 -->
  182. <button class="input-mode-btn" bindtap="switchInputMode">
  183. <image src="{{inputMode === 'keyboard' ? '/images/icons/voice.png' : '/images/icons/keyboard.png'}}" class="mode-icon"></image>
  184. </button>
  185. <!-- 输入框 -->
  186. <view class="input-box-wrapper">
  187. <input
  188. type="text"
  189. class="chat-input"
  190. placeholder="{{inputPlaceholder}}"
  191. placeholder-class="placeholder"
  192. value="{{inputValue}}"
  193. bindinput="onInput"
  194. bindconfirm="sendTextMessage"
  195. confirm-type="send"
  196. focus="{{inputFocus}}"
  197. adjust-position="{{false}}"
  198. />
  199. </view>
  200. <!-- 多媒体按钮 -->
  201. <button class="media-btn" bindtap="showMediaActionSheet">
  202. <image src="/images/icons/add.png" class="media-icon"></image>
  203. </button>
  204. <!-- 发送按钮 -->
  205. <button class="send-btn" bindtap="sendTextMessage" wx:if="{{inputValue.trim()}}">
  206. <image src="/images/icons/send.png" class="send-icon"></image>
  207. </button>
  208. </view>
  209. </view>
  210. <!-- 多媒体选择面板 -->
  211. <view class="media-action-sheet" wx:if="{{showMediaSheet}}" catchtap="hideMediaActionSheet">
  212. <view class="media-sheet-content" catchtap="stopPropagation">
  213. <view class="media-sheet-header">
  214. <text class="sheet-title">发送内容</text>
  215. <button class="close-sheet-btn" bindtap="hideMediaActionSheet">
  216. <image src="/images/icons/close.png"></image>
  217. </button>
  218. </view>
  219. <view class="media-options">
  220. <button class="media-option" bindtap="chooseImage">
  221. <view class="option-icon photo-icon">
  222. <image src="/images/icons/photo.png"></image>
  223. </view>
  224. <text class="option-text">照片</text>
  225. </button>
  226. <button class="media-option" bindtap="takePhoto">
  227. <view class="option-icon camera-icon">
  228. <image src="/images/icons/camera.png"></image>
  229. </view>
  230. <text class="option-text">拍摄</text>
  231. </button>
  232. <button class="media-option" bindtap="chooseVideo">
  233. <view class="option-icon video-icon">
  234. <image src="/images/icons/video.png"></image>
  235. </view>
  236. <text class="option-text">视频</text>
  237. </button>
  238. <button class="media-option" bindtap="recordAudio">
  239. <view class="option-icon audio-icon">
  240. <image src="/images/icons/voice.png"></image>
  241. </view>
  242. <text class="option-text">语音</text>
  243. </button>
  244. <button class="media-option" bindtap="chooseFile">
  245. <view class="option-icon file-icon">
  246. <image src="/images/icons/file2.png"></image>
  247. </view>
  248. <text class="option-text">文件</text>
  249. </button>
  250. </view>
  251. </view>
  252. </view>
  253. <!-- 录音提示 -->
  254. <view class="recording-modal" wx:if="{{isRecording}}">
  255. <view class="recording-box">
  256. <view class="recording-wave-box">
  257. <view class="recording-wave"></view>
  258. <image src="/images/icons/mic2.png" class="recording-mic-icon"></image>
  259. </view>
  260. <text class="recording-tip">{{recordingTip}}</text>
  261. <text class="recording-time">{{recordingTime}}s</text>
  262. </view>
  263. </view>
  264. </view>