chatRoom.vue 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. <template>
  2. <div class="chat-room">
  3. <div class="mini-wrap moblie-wrap">
  4. <div class="mini-body">
  5. <div class="box">
  6. <back-bar :title="isPrivate ? group.privateName : group.groupName+'('+group.membersNum+')'"
  7. :url="!isPrivate && group.url ?group.url:''"
  8. >
  9. <span class="group-set-icon el-icon-more" v-if="!isPrivate &&isJoinGroup!=0" @click="$router.push(`/groupSet/${group.groupId}`)"></span>
  10. </back-bar>
  11. <chat-pin v-bind="pinMsg" @pinMsgClose="pinMsgClose" @scrollToView="scrollToView"></chat-pin>
  12. <div class="box-bd" ref="msgBox">
  13. <div ref="scrollWrap"
  14. @scroll.prevent="handleScroll"
  15. class="scroller"
  16. >
  17. <div ref="msgWrap" class="msg-wrap">
  18. <div class="msg-top-more" v-if="lockEnd">
  19. <em>{{ $t('chat.noMore') }}</em>
  20. </div>
  21. <div class="msg-top-load" v-if="lockMore && !lockEnd">
  22. <i class="msg-loading-icon"></i>
  23. </div>
  24. <msg-item v-for="item in group.chatList"
  25. :key="item.hash"
  26. :isMobile="true"
  27. :isAdmin="isAdmin"
  28. v-bind="item"
  29. :msgItem="item"
  30. @quoteMsg="quoteMsg"
  31. @deleteMsg="deleteMsg"
  32. ></msg-item>
  33. </div>
  34. </div>
  35. <at-me :atList="atList" class="mini" @scrollToMsg="scrollToMsg"></at-me>
  36. <div class="msg-unread"
  37. @click="doSetRead"
  38. v-show="unreadNums > 0 && enableScroll && !isBottom">
  39. <em><i class="el-icon-d-arrow-right"></i>{{unreadNums}}{{ $t('chat.unreadMsg') }}</em>
  40. </div>
  41. </div>
  42. <div class="box-ft" v-if="isJoinGroup==0">
  43. <div @click="joinGroup()" class="btn-join">{{ $t('chat.joinGroup') }}</div>
  44. </div>
  45. <div class="box-ft" v-else>
  46. <chat-at
  47. ref="chatAt"
  48. v-if="atShow"
  49. @atperson="atPerson"
  50. :curInd="atInd"
  51. :filterList="filterMembers">
  52. </chat-at>
  53. <div class="input-con">
  54. <div class="more-icon" @click.stop="handleMoreClick"></div>
  55. <form class="input-wrap" @submit="handleSend">
  56. <textarea
  57. @input="handleInput"
  58. @keydown.up.prevent="handleUp"
  59. @keydown.down.prevent="handleDown"
  60. @keydown.left="handleLeft"
  61. @keydown.right="handleRight"
  62. @keydown.delete="handleDel"
  63. @keydown.esc="handleEsc"
  64. cols="1"
  65. ref="chatInput"
  66. rows="1"
  67. @keydown.enter="handleKeyDown"
  68. placeholder="Write a message"
  69. v-model="inputMsg"
  70. @focus="handleFocus"
  71. @blur="handleBlur"
  72. :style="{height:inputHeight}"
  73. />
  74. </form>
  75. <div class="emoji-icon" @click.stop="handleEmojiClick"></div>
  76. <div class="btn-send" @click="handleSend">{{$t('chat.send')}}</div>
  77. </div>
  78. <toolbar ref="toolbar" :toolShow="toolShow" @handleFile="handleFile"></toolbar>
  79. <emoji @addEmoji="addEmoji" :emojiShow="emojiShow" v-show="emojiShow" @closeEmojiList="closeEmojiList"></emoji>
  80. </div>
  81. </div>
  82. <div class="pub-loading" v-show="isLoadingRoom"></div>
  83. </div>
  84. </div>
  85. </div>
  86. </template>
  87. <script>
  88. import backBar from '@/components/backBar'
  89. import msgItem from '@/components/msgItem'
  90. import emoji from '@/components/emoji'
  91. import chatAt from '@/components/chatAt'
  92. import atMe from '@/components/chatAt/atme'
  93. import chatPin from '@/components/chatPin'
  94. import toolbar from '@/components/chatInput/toolbar'
  95. import { chatAtMixin, chatInputMixin } from '@/mixins'
  96. import { chatMixin, inputMixin } from '@/mixins/chat'
  97. export default {
  98. name: 'h5ChatRoom',
  99. mixins: [chatAtMixin, chatInputMixin, chatMixin, inputMixin],
  100. components: {
  101. msgItem,
  102. emoji,
  103. chatAt,
  104. chatPin,
  105. atMe,
  106. backBar,
  107. toolbar
  108. },
  109. data () {
  110. return {
  111. emojiShow: false,
  112. toolShow: false,
  113. inputHeight: 18
  114. }
  115. },
  116. watch: {
  117. inputMsg (val, newval) {
  118. let ele = this.$refs.chatInput
  119. this.inputHeight = 'auto'
  120. this.$nextTick(() => {
  121. this.inputHeight = Math.max(18, Math.min(ele.scrollHeight, 75)) + 'px'
  122. })
  123. }
  124. },
  125. methods: {
  126. handleEmojiClick () {
  127. this.toolShow = false
  128. this.emojiShow = !this.emojiShow
  129. this.checkNeedToBottom()
  130. },
  131. handleMoreClick () {
  132. this.emojiShow = false
  133. this.toolShow = !this.toolShow
  134. this.checkNeedToBottom()
  135. },
  136. checkNeedToBottom () {
  137. if (!this.isBottom) return
  138. this.$nextTick(() => {
  139. this.resizeToBottom()
  140. })
  141. },
  142. /**
  143. * @des 引用某条消息
  144. */
  145. quoteMsg (msg) {
  146. this.inputMsg = msg
  147. }
  148. }
  149. }
  150. </script>
  151. <style lang="scss" scoped>
  152. @charset "UTF-8";
  153. $chatBg: #34363c;
  154. $chatContBg: #eeeeee;
  155. $chatUiFont: #ffffff;
  156. $offsetBottom: 5px;
  157. $offsetRight: 5px;
  158. .group-set-icon{
  159. position: absolute;
  160. right: 0;
  161. top: 0;
  162. height: px2rem(90);
  163. width: px2rem(100);
  164. text-align: center;
  165. font-size: px2rem(42);
  166. line-height: px2rem(90);
  167. color: #333333;
  168. }
  169. .mini-wrap{
  170. z-index: 123456789;
  171. height: 100%;
  172. }
  173. .mini-body{
  174. height: 100%;
  175. box-sizing: border-box;
  176. }
  177. .box{
  178. position: relative;
  179. height: 100%;
  180. display: flex;
  181. flex-direction: column;
  182. }
  183. .chat-room{
  184. position: absolute;
  185. top: 0;
  186. left: 0;
  187. bottom: 0;
  188. width: 100%;
  189. }
  190. .box-bd{
  191. height: 0;
  192. flex: 1;
  193. position: relative;
  194. background: #f2f2f2;
  195. .msg-unread{
  196. position: absolute;
  197. width: 120px;
  198. left: 50%;
  199. bottom: 10px;
  200. border-radius: 20px;
  201. background: rgba(#000000, 0.5);
  202. padding: 0 5px;
  203. text-align: center;
  204. line-height: 32px;
  205. margin-left: -65px;
  206. cursor: pointer;
  207. &:hover{
  208. background: rgba(#000000, 0.3);
  209. }
  210. em{
  211. color: #ffffff;
  212. font-size: 14px;
  213. }
  214. i{
  215. transform: rotate(90deg);
  216. margin-right: 5px;
  217. }
  218. }
  219. }
  220. .scroller{
  221. height: 100%;
  222. overflow-x: hidden;
  223. overflow-y: scroll;
  224. -webkit-overflow-scrolling: touch;
  225. &::-webkit-scrollbar {
  226. width: 8px;
  227. height: 6px;
  228. }
  229. &::-webkit-scrollbar-thumb {
  230. border-radius: 3px;
  231. -moz-border-radius: 3px;
  232. -webkit-border-radius: 3px;
  233. background-color: rgba($color: #8d8a8a, $alpha: 0.2);
  234. }
  235. &::-webkit-scrollbar-track {
  236. background-color: transparent;
  237. }
  238. }
  239. .msg-wrap{
  240. box-sizing: border-box;
  241. height: 100%;
  242. display: flex;
  243. flex-direction: column;
  244. justify-content: flex-end;
  245. padding-bottom: 16px;
  246. overflow: hidden;
  247. }
  248. .box-ft{
  249. position: relative;
  250. background: $chatContBg;
  251. border-top: 1px solid #d6d6d6;
  252. .btn-join{
  253. color: #438aff;
  254. font-size: 16px;
  255. text-align: center;
  256. padding: px2rem(30) 0;
  257. background: #FFF;
  258. }
  259. .input-con{
  260. position: relative;
  261. display: flex;
  262. align-items: flex-end;
  263. background-color: #fafafa;
  264. padding: 6px 0;
  265. }
  266. .input-wrap{
  267. flex: 1;
  268. padding: 10px 0;
  269. background-color: #ffffff;
  270. border-radius: 4px;
  271. }
  272. .more-icon{
  273. width: 38px;
  274. height: 38px;
  275. background: url('../../../assets/more-icon.png') center center no-repeat;
  276. background-size: 22px 22px;
  277. cursor: pointer;
  278. &:hover{
  279. opacity: .6;
  280. }
  281. }
  282. .emoji-icon{
  283. width: 38px;
  284. height: 38px;
  285. background: url('../../../assets/m-face-icon.png') center center no-repeat;
  286. background-size: 22px 22px;
  287. cursor: pointer;
  288. &:hover{
  289. opacity: .6;
  290. }
  291. }
  292. .btn-send{
  293. margin-right: 4px;
  294. font-size: 12px;
  295. color: #ffffff;
  296. padding: 0 10px;
  297. height: 28px;
  298. line-height: 28px;
  299. margin-bottom: 3px;
  300. background: #2b9ff6;
  301. border-radius: 3px;
  302. cursor: pointer;
  303. &:hover{
  304. opacity: 0.8;
  305. }
  306. }
  307. form{
  308. @include flex(1);
  309. }
  310. textarea {
  311. display: block;
  312. width: 100%;
  313. height: 18px;
  314. max-height: 175px;
  315. font-size: 14px;
  316. color: #000000;
  317. line-height: 16px;
  318. padding: 1px;
  319. padding-left: 8px;
  320. margin: 0;
  321. border: none;
  322. outline: none;
  323. background: none;
  324. box-sizing: border-box;
  325. resize: none;
  326. }
  327. .emoji-wrap{
  328. background: #f2f2f2;
  329. box-shadow: 1px 1px 50px rgba(0,0,0,.3);
  330. z-index: 10;
  331. }
  332. .input-ctrl{
  333. span{
  334. width: 120px;
  335. margin: 4px auto;
  336. height: 30px;
  337. line-height: 30px;
  338. color: #ffffff;
  339. font-size: 12px;
  340. text-align: center;
  341. display: block;
  342. background-image: -webkit-linear-gradient( 90deg, rgb(25,145,235) 0%, rgb(46,161,248) 100%);
  343. border-radius: 3px;
  344. &.enable{
  345. cursor: pointer;
  346. &:hover{
  347. opacity: 0.7;
  348. }
  349. }
  350. }
  351. }
  352. }
  353. .msg-top-more{
  354. margin-top: 10px;
  355. text-align: center;
  356. i{
  357. font-size: 30px;
  358. }
  359. em{
  360. font-size: 12px;
  361. line-height: 20px;
  362. color: #999999;
  363. }
  364. }
  365. .msg-loading-icon{
  366. display: block;
  367. background: url('../../../assets/loading-icon.png') no-repeat;
  368. background-size: 100%;
  369. width: 16px;
  370. height: 16px;
  371. margin: 12px auto;
  372. animation: rotate 2s linear infinite;
  373. }
  374. // 手机端适配
  375. .moblie-wrap{
  376. .box-hd{
  377. height: 30px;
  378. }
  379. .box-ft{
  380. @media #{$iphonex} {
  381. padding-bottom: 34px;
  382. background-color: #fafafa;
  383. }
  384. .emoji-wrap{
  385. bottom: 54px;
  386. }
  387. .btn-send{
  388. height: 36px;
  389. line-height: 36px;
  390. padding: 0 10px;
  391. font-size: 16px;
  392. margin-bottom: 0;
  393. }
  394. .input-ctrl span {
  395. height: 40px;
  396. line-height: 40px;
  397. font-size: 16px;
  398. }
  399. .input-con{
  400. padding: 8px 0;
  401. align-items: center;
  402. }
  403. .input-wrap{
  404. padding: 10px 0;
  405. margin: 0 6px;
  406. .textarea{
  407. height: 26px;
  408. line-height: 20px;
  409. }
  410. }
  411. .more-icon{
  412. background-size: 30px 30px;
  413. }
  414. .emoji-icon{
  415. background-size: 30px 30px;
  416. margin-right: 4px;
  417. }
  418. }
  419. }
  420. </style>