chat.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <template>
  2. <view class="page" ref="page">
  3. <view style="display: none;position: fixed;left: 50%;top: 50%;">{{ $store.state.hackUpdate }}</view>
  4. <load-more status="loading" v-if="initializing" />
  5. <!-- 消息记录 -->
  6. <chat-panel :storeKey="storeKey" :sending="sending" :sendingdata="sendingdata" @click-avatar="openProfile"
  7. @setSending="setSending" :boardheight="boardheight" @chooseQuote="setQuote" ref="panel" />
  8. <!-- 底部 -->
  9. <v-sender v-if="!initializing" v-model="message" ref="sender" @send="sendTextMessage" @face="sendVoice"
  10. @sendImage="sendImg" @sendVedio="sendVedio" @emoji="sendEmoji" @input="inputMessage"
  11. @handleEmotion="handleEmotion" @senderheight="set_sheight" @keyboardheight="keyboardheight"
  12. :showboard="showboard" :sendtype="type" :isgroup="0" :groupid="friend.id" :quote="quoteItem" />
  13. </view>
  14. </template>
  15. <script>
  16. import {
  17. mapState,
  18. mapGetters
  19. } from 'vuex';
  20. import ChatPanel from '../../components/chat-panel.vue';
  21. import api from '../../library/index.js';
  22. import http from '../../library/http.js';
  23. import config from '../../config.js';
  24. export default {
  25. components: {
  26. ChatPanel
  27. },
  28. data() {
  29. return {
  30. quoteItem: {},
  31. friend: {},
  32. message: '',
  33. initializing: false,
  34. getPick: false,
  35. showPickMoney: '',
  36. pickMsg: '',
  37. pickId: '',
  38. pickSender: {},
  39. pickTitle: '',
  40. pickErrorText: '',
  41. storeKey: '',
  42. redpackInfo: {},
  43. sending: false,
  44. sendingdata: [],
  45. senderheight: 120,
  46. sender: [],
  47. receiver: [],
  48. inpuvalue: '',
  49. boardheight: 0,
  50. showboard: false,
  51. type: '',
  52. user: uni.getStorageSync('userInfo'),
  53. system: uni.getStorageSync('system'),
  54. list: [
  55. ['微笑', '撇嘴', '色', '发呆', '得意', '流泪', '害羞', '闭嘴'],
  56. ['睡', '大哭', '尴尬', '发怒', '调皮', '呲牙', '惊讶', '难过'],
  57. ['酷', '冷汗', '抓狂', '吐', '偷笑', '可爱', '白眼', '傲慢'],
  58. ['饥饿', '困', '惊恐', '流汗', '憨笑', '大兵', '奋斗', '咒骂'],
  59. ['疑问', '嘘', '晕', '折磨', '衰', '骷髅', '敲打', '再见'],
  60. ['擦汗', '抠鼻', '鼓掌', '糗大了', '坏笑', '左哼哼', '右哼哼', '哈欠'],
  61. ['鄙视', '委屈', '快哭了', '阴险', '亲亲', '吓', '可怜', '菜刀'],
  62. ['西瓜', '啤酒', '篮球', '乒乓', '咖啡', '饭', '猪头', '玫瑰', ],
  63. ['凋谢', '示爱', '爱心', '心碎', '蛋糕', '闪电', '炸弹', '刀'],
  64. ['足球', '瓢虫', '便便', '月亮', '太阳', '礼物', '拥抱', '强'],
  65. ['弱', '握手', '胜利', '抱拳', '勾引', '拳头', '差劲', '爱你'],
  66. ['NO', 'OK', '爱情', '飞吻', '跳跳', '发抖', '怄火', '转圈'],
  67. ['磕头', '回头', '跳绳', '挥手', '激动', '闭嘴', '笑哭', '吐舌'],
  68. ['耶', '跳舞', '恐惧', '失望', '脸红', '无语', '奸笑', '嘿哈'],
  69. ['鬼混', '福', '合十', '强壮', '红包', '发财', '庆祝', '礼物']
  70. ],
  71. reg: /\S{1,3}/gi,
  72. lists: [],
  73. listss: []
  74. };
  75. },
  76. onShow(event) {
  77. uni.setNavigationBarTitle({
  78. title: decodeURI(this.friend.nickname)
  79. });
  80. var value = '';
  81. this.list = this.list.map((line, index) => {
  82. this.listss = [];
  83. line = line.map((item, idx) => {
  84. value = item;
  85. item = item.replace(/\S{1,3}/gi, this.getemotion(item));
  86. this.listss.push({
  87. "name": item,
  88. "index": index,
  89. "value": value,
  90. "idx": idx
  91. })
  92. return item;
  93. })
  94. this.lists.push(this.listss);
  95. return line;
  96. })
  97. },
  98. onLoad(opts) {
  99. uni.setNavigationBarTitle({
  100. title: decodeURI(opts.nickname)
  101. });
  102. // #ifdef APP-PLUS
  103. let currentWebview = this.$mp.page.$getAppWebview();
  104. currentWebview.setStyle({
  105. titleNView: {
  106. titleText: ''
  107. },
  108. })
  109. // #endif
  110. this.friend = opts;
  111. this.storeKey = 'U' + this.friend.id;
  112. uni.setStorageSync('cache_key', this.storeKey);
  113. this.getUserInfo(this.friend.id);
  114. this.sender = this.user;
  115. this.receiver = this.friend;
  116. },
  117. onUnload() {
  118. uni.setStorageSync('cache_key', '');
  119. },
  120. methods: {
  121. getemotion(res) {
  122. let word = res.replace(/\[|\]/gi, '')
  123. const list = ['微笑', '撇嘴', '色', '发呆', '得意', '流泪', '害羞', '闭嘴', '睡', '大哭', '尴尬', '发怒', '调皮', '呲牙', '惊讶',
  124. '难过', '酷', '冷汗', '抓狂', '吐', '偷笑', '可爱', '白眼', '傲慢', '饥饿', '困', '惊恐', '流汗', '憨笑', '大兵', '奋斗',
  125. '咒骂', '疑问', '嘘', '晕', '折磨', '衰', '骷髅', '敲打', '再见', '擦汗', '抠鼻', '鼓掌', '糗大了', '坏笑', '左哼哼', '右哼哼',
  126. '哈欠', '鄙视', '委屈', '快哭了', '阴险', '亲亲', '吓', '可怜', '菜刀', '西瓜', '啤酒', '篮球', '乒乓', '咖啡', '饭', '猪头',
  127. '玫瑰', '凋谢', '示爱', '爱心', '心碎', '蛋糕', '闪电', '炸弹', '刀', '足球', '瓢虫', '便便', '月亮', '太阳', '礼物', '拥抱',
  128. '强', '弱', '握手', '胜利', '抱拳', '勾引', '拳头', '差劲', '爱你', 'NO', 'OK', '爱情', '飞吻', '跳跳', '发抖', '怄火',
  129. '转圈', '磕头', '回头', '跳绳', '挥手', '激动',
  130. '闭嘴', '笑哭', '吐舌', '耶', '跳舞', '恐惧', '失望', '脸红', '无语', '奸笑', '嘿哈', '鬼混', '福', '合十', '强壮', '红包',
  131. '发财', '庆祝', '礼物'
  132. ]
  133. let index = list.indexOf(word);
  134. var index1 = index + 100;
  135. return '^' + index1 + '^';
  136. },
  137. // 选择引用的聊天记录
  138. setQuote(item) {
  139. if (item.message.type == 'text') {
  140. if (!item.message.content.type) {
  141. item.ttype = 'text'
  142. // 空格替换回车
  143. item.message.qute = item.message.content.replace(/<br>/g, " ").replace(/&nbsp;/g, ' ')
  144. } else if (item.message.content.type == "remind") {
  145. // 去除html 标签 && 去除 回车替换成空格
  146. if(item.message.content.remind && item.message.content.remind.nickname) {
  147. item.message.qute = item.message.content.content.replace(/<span.*?>.*?<\/span>/g, '@' + item.message.content.remind.nickname).replace(
  148. /<br>/g, " ").replace(/&nbsp;/g, ' ')
  149. }else {
  150. item.message.qute = item.message.content.content.replace(/<span.*?>|<\/span>/g, '@' + '').replace(
  151. /<br>/g, " ").replace(/&nbsp;/g, ' ')
  152. }
  153. item.ttype = 'remind'
  154. }
  155. }
  156. if (item.message.type == 'emotion') {
  157. item.ttype = 'emotion'
  158. console.log(item.message.content,'item.message.content');
  159. item.message.qute = item.message.content.content.replace(/<br>/g, " ")
  160. var content = item.message.qute.replace(/\[\S{1,3}\]/gi, this.getemotion).split('^');
  161. var imgs = [];
  162. for (var i = 0; i < content.length; i++) {
  163. if (content[i] >= 100 && content[i] <= 222) {
  164. imgs.push({
  165. 'type': 'img',
  166. 'content': "/static/emoji/" + content[i] + '.gif'
  167. })
  168. } else {
  169. imgs.push({
  170. 'type': 'text',
  171. 'content': content[i]
  172. })
  173. }
  174. }
  175. item.message.face = imgs;
  176. console.log('content', content);
  177. }
  178. if(item.message.type == 'image') {
  179. console.log('引用图片');
  180. item.ttype = 'image'
  181. item.message.qute = item.message.content
  182. }
  183. this.$refs.sender.setQute(item)
  184. this.quoteItem = item
  185. console.log("设置item", item);
  186. },
  187. // 检测输入值
  188. inputMessage(e) {
  189. // console.log(e);
  190. this.emotion = e;
  191. },
  192. getUserInfo(id) {
  193. if (id > 0) {
  194. id = parseInt(id);
  195. http.setWait(false).get('user.php?act=userdetail', {
  196. id: id,
  197. group_id: 0,
  198. userid: this.user.id
  199. }).then(res => {
  200. this.friend = res.data;
  201. uni.setNavigationBarTitle({
  202. title: decodeURI(this.friend.nickname)
  203. });
  204. })
  205. } else {
  206. var avatar = this.system.admin_logo;
  207. if (avatar.indexOf('http') <= -1) avatar = config.imgUri + avatar;
  208. this.friend = {
  209. id: 0,
  210. nickname: this.system.admin_nickname,
  211. avatar: avatar
  212. };
  213. }
  214. },
  215. toHtml(str) {
  216. str = str.replace(/ /g, "&nbsp;");
  217. str = str.replace(/\n/g, "<br>");
  218. return str;
  219. },
  220. set_sheight(e) {
  221. this.$refs.panel.setAutoHeight(e);
  222. },
  223. keyboardheight(e) {
  224. this.boardheight = e;
  225. this.$refs.panel.setAutoHeight(0);
  226. },
  227. // 选择表情
  228. handleEmotion(value) {
  229. // console.log(value);
  230. this.emotion = value;
  231. this.type = 'emotion';
  232. },
  233. sendEmoji(e) {
  234. this.commitMessage('face', e);
  235. },
  236. sendImg(e) {
  237. this.commitMessage('image', e);
  238. },
  239. sendVedio(e) {
  240. this.commitMessage('vedio', e);
  241. },
  242. // 发送文本消息
  243. sendTextMessage() {
  244. // this.commitMessage('text',this.message);
  245. let that = this;
  246. let addStr = '';
  247. console.log(that.quoteItem,'发送that.quoteItem');
  248. if (this.quoteItem && this.quoteItem.id) {
  249. addStr += '-qute-nickname=' + that.quoteItem.sender.nickname + 'q&qcontent=' + that.quoteItem
  250. .message
  251. .qute + 'q&qttype=' + that.quoteItem.ttype
  252. }
  253. if (this.type == "emotion") {
  254. this.emotionInfo = {
  255. "type": "emotion",
  256. "value": this.emotion + addStr,
  257. "content": this.emotion + addStr
  258. }
  259. console.log('-------------表情---------------', this.emotionInfo);
  260. this.commitMessage('emotion', this.emotionInfo);
  261. } else {
  262. var msg = this.toHtml(this.message) + addStr;
  263. console.log('---------文本发送---------', msg);
  264. this.commitMessage('text', msg,1);
  265. }
  266. this.quoteItem = {}
  267. this.$refs.sender.clearQute()
  268. },
  269. setSending(e) {
  270. this.sending = e;
  271. },
  272. commitMessage(type, sendData) {
  273. this.message = '';
  274. // this.showboard=true
  275. if (type == 'image') {
  276. var mid = sendData.mid;
  277. sendData = sendData.src;
  278. } else if (type == 'vedio') {
  279. var mid = sendData.mid;
  280. // sendData=sendData.src;
  281. } else if (type == 'voice') {
  282. var mid = sendData.mid;
  283. } else {
  284. var mid =
  285. 'm' +
  286. Math.random()
  287. .toString(36)
  288. .substring(2);
  289. }
  290. let data = {
  291. userid: this.user.id,
  292. friend_uid: this.friend.id,
  293. type: 'chat',
  294. msgtype: type,
  295. content: sendData,
  296. mid: mid
  297. };
  298. // console.log(data);
  299. var sendlocal = 0;
  300. if ((type == 'image' && sendData.indexOf('http') <= -1) || (type == 'vedio' && sendData.src.indexOf(
  301. 'http') <= -1) || (type == 'voice' && sendData.url.indexOf('http') <= -1)) {
  302. //本地图片不发到服务器
  303. // console.log(sendData);
  304. sendlocal = 1;
  305. } else {
  306. this.$socket.send(data);
  307. }
  308. if (type !== 'image' && type !== 'voice') sendlocal = 1;
  309. // uni.showLoading({
  310. // title: '发送中'
  311. // });
  312. var that = this;
  313. if (sendlocal == 1) {
  314. var arr = {};
  315. arr.id = that.receiver.id;
  316. arr.cache_key = 'U' + arr.id;
  317. arr['self'] = 1;
  318. arr['isloading'] = 1;
  319. arr['receiver_id'] = arr['id'];
  320. arr['sender_id'] = that.sender.id;
  321. arr['group_id'] = 0;
  322. arr['timestamp'] = parseInt(new Date().getTime() / 1000);
  323. arr['time'] = '';
  324. arr['message'] = {
  325. type: type,
  326. content: sendData
  327. };
  328. arr['sender'] = that.sender;
  329. arr['receiver'] = that.receiver;
  330. arr['nickname'] = that.sender.nickname;
  331. arr['avatar'] = that.sender.avatar;
  332. arr['msg_id'] = '';
  333. arr['_mid'] = mid;
  334. that.sendingdata = arr;
  335. that.sending = true;
  336. this.type = 'text';
  337. //that.sendmsg(arr);
  338. // console.log(sendlocal);
  339. }
  340. //that.sending=true;
  341. },
  342. sendVoice(e) {
  343. this.commitMessage('voice', e);
  344. },
  345. openProfile(e) {
  346. // console.log(JSON.stringify(e));
  347. let params = {
  348. id: e.id,
  349. status: 'friend'
  350. };
  351. return this.$jump('friend.detail', params);
  352. }
  353. },
  354. onNavigationBarButtonTap(e) {
  355. let params = {
  356. ...this.friend,
  357. status: 'friend'
  358. };
  359. return this.$jump('friend.userset', params);
  360. }
  361. };
  362. </script>
  363. <style lang="scss">
  364. $avatar-width: 80upx;
  365. $control-height: 100upx;
  366. $control-input-height: $control-height - $uni-spacing-col-base * 2;
  367. .placeholder {
  368. width: 750upx;
  369. height: 1upx;
  370. }
  371. .message {
  372. &-time {
  373. color: #999;
  374. font-size: 24upx;
  375. text-align: center;
  376. }
  377. &-info {
  378. display: flex;
  379. flex-direction: row;
  380. justify-content: flex-start;
  381. align-items: flex-start;
  382. padding: $uni-spacing-col-lg $uni-spacing-row-lg;
  383. .spacing {
  384. width: $uni-spacing-row-lg;
  385. height: $avatar-width;
  386. position: relative;
  387. display: flex;
  388. flex-direction: column;
  389. align-items: center;
  390. justify-content: center;
  391. flex-shrink: 0;
  392. &::before {
  393. display: block;
  394. content: '';
  395. border: $uni-spacing-row-lg/2 solid transparent;
  396. border-right-color: #fff;
  397. }
  398. }
  399. }
  400. &.right &-info {
  401. flex-direction: row-reverse;
  402. padding-left: $uni-spacing-row-lg;
  403. padding-right: $uni-spacing-row-lg * 2 + $avatar-width;
  404. .spacing::before {
  405. border-right-color: transparent;
  406. border-left-color: $uni-color-primary;
  407. }
  408. }
  409. &.right &-info {
  410. padding-left: $uni-spacing-row-lg * 2 + $avatar-width;
  411. padding-right: $uni-spacing-row-lg;
  412. }
  413. &-avatar {
  414. width: $avatar-width;
  415. height: $avatar-width;
  416. vertical-align: middle;
  417. border-radius: $uni-border-radius-base;
  418. flex-shrink: 0;
  419. }
  420. &-content {
  421. font-size: 32upx;
  422. background: rgba(255, 255, 255, 1);
  423. border-radius: $uni-border-radius-base;
  424. }
  425. &.right &-content {
  426. color: white;
  427. background-color: $uni-color-primary;
  428. }
  429. &--text &-content {
  430. padding: 20upx $uni-spacing-row-base;
  431. }
  432. &-failed {
  433. width: 30upx;
  434. height: 30upx;
  435. background-color: $uni-color-error;
  436. border-radius: 50%;
  437. margin: ($avatar-width - 30upx)/2 $uni-spacing-row-base 0;
  438. }
  439. }
  440. </style>