graceIMInput.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <template name="graceIMMsg">
  2. <view>
  3. <view class="grace-im-footer" :style="{paddingBottom:paddingB}">
  4. <view class="grace-im-menus graceIMFonts icon-voice"
  5. v-if="voiceBtnShow"
  6. @tap="showRec"></view>
  7. <view class="grace-im-menus graceIMFonts icon-photograph" @tap="chooseImg"></view>
  8. <view class="grace-im-input">
  9. <input type="text" v-model="inputMsg" @confirm="sendTextMsg" />
  10. </view>
  11. <view class="grace-items" style="padding:0 8px; margin-right:6px;" @tap="sendTextMsg">发送</view>
  12. </view>
  13. <!-- 语音输入 -->
  14. <view class="grace-im-record" v-if="recShow">
  15. <view class="grace-im-record-txt">
  16. {{recTxt}}<text v-if="recing">已录音 : {{recLength}} s</text>
  17. </view>
  18. <view class="grace-im-record-btn" @tap="rec" :class="[recing ? 'grace-im-recording' : '']"></view>
  19. <view class="grace-im-send-voice" v-if="tmpVoice != ''">
  20. <text @tap="playVoice">{{playTxt}}</text>| <text @tap="sendVoiceMsg">发送语音</text>
  21. </view>
  22. <view class="grace-im-record-close graceIMFonts icon-close" @tap="closeRec" v-if="!recing"></view>
  23. </view>
  24. </view>
  25. </template>
  26. <script>
  27. var bgAudioMannager = {};
  28. export default {
  29. name: "graceIMMsg",
  30. props: {
  31. user : {
  32. type : Object,
  33. default : function(){return {};}
  34. },
  35. token : {
  36. type : String,
  37. default : ""
  38. },
  39. config :{
  40. type : Object,
  41. default : function(){return {};}
  42. }
  43. },
  44. data() {
  45. return {
  46. paddingB : '0',
  47. uploading : false,
  48. recShow : false,
  49. recTxt : "请点击绿色按钮开始录音",
  50. inputMsg : "",
  51. recorderManager : null,
  52. recing : false,
  53. recLength : 1,
  54. recTimer : null,
  55. tmpVoice : '',
  56. voiceLen : 0,
  57. voiceBtnShow : false,
  58. // 播放相关
  59. player : null,
  60. playTxt : "试听语音"
  61. }
  62. },
  63. created : function(){
  64. var _self = this;
  65. // #ifndef H5
  66. this.voiceBtnShow = true;
  67. this.recorderManager = uni.getRecorderManager();
  68. this.recorderManager.onStop((res) => {
  69. _self.tmpVoice = res.tempFilePath;
  70. this.recing = false;
  71. this.recTxt = "... 已录音 "+this.recLength+"s, 点击绿色按钮重新录音 ...";
  72. clearInterval(this.recTimer);
  73. });
  74. this.recorderManager.onError(function () {
  75. uni.showToast({ title: '录音失败', icon: 'none' });
  76. _self.recing = false;
  77. _self.recTxt = "请点击绿色按钮开始录音",
  78. clearInterval(_self.recTimer);
  79. });
  80. // #endif
  81. // #ifdef MP
  82. try {
  83. var res = uni.getSystemInfoSync();
  84. res.model = res.model.replace(' ', '');
  85. res.model = res.model.toLowerCase();
  86. if(res.model.indexOf('iphonex') != -1 || res.model.indexOf('iphone11') != -1){
  87. this.paddingB = uni.upx2px(50)+'px';
  88. }
  89. } catch (e){return null;}
  90. // #endif
  91. },
  92. methods:{
  93. // 录音
  94. rec : function(){
  95. if (this.recing){
  96. this.recorderManager.stop();
  97. this.recing = false;
  98. this.recTxt = "... 已录音 "+this.recLength+"s, 点击绿色按钮重新录音 ...";
  99. clearInterval(this.recTimer);
  100. } else {
  101. this.recorderManager.start({duration:60000, format:'mp3' });
  102. this.recing = true;
  103. this.recTxt = "... 正在录音 ...";
  104. this.recLength = 1;
  105. this.recTimer = setInterval(function(){this.recLength++;}.bind(this), 1000);
  106. }
  107. },
  108. // 播放录音
  109. playVoice : function(){
  110. var _self = this;
  111. if(this.playTxt == '正在播放'){
  112. this.playTxt = '试听语音';
  113. bgAudioMannager.stop();
  114. return ;
  115. }
  116. bgAudioMannager = uni.getBackgroundAudioManager();
  117. this.playTxt = '正在播放';
  118. bgAudioMannager.src = this.tmpVoice;
  119. bgAudioMannager.onEnded(function(){
  120. _self.playTxt = "试听语音";
  121. });
  122. bgAudioMannager.onStop(function(){
  123. _self.playTxt = "试听语音";
  124. });
  125. },
  126. // 发送录音
  127. sendVoiceMsg : function(){
  128. var _self = this;
  129. if (_self.tmpVoice == '') {
  130. uni.showToast({ title: "请先录制一段语音", icon: "none" });
  131. return;
  132. }
  133. // 关闭界面
  134. this.recShow = false;
  135. uni.showLoading({ title:"正在发送" });
  136. const uploadTask = uni.uploadFile({
  137. url : _self.config.serverUrl+'?c=uploadFile&token='+_self.token,
  138. filePath : _self.tmpVoice,
  139. name : 'gChatUploadFile',
  140. success : function (uploadFileRes) {
  141. var res = JSON.parse(uploadFileRes.data);
  142. if(res.status == 'ok'){
  143. var msg = _self.user;
  144. msg.type = 'msg';
  145. msg.contentType = 'voice';
  146. msg.content = res.msg;
  147. msg.length = _self.recLength;
  148. uni.sendSocketMessage({
  149. data : JSON.stringify(msg),
  150. complete:function(){
  151. setTimeout(function(){
  152. _self.uploading = false;
  153. uni.hideLoading();
  154. _self.tmpVoice = '';
  155. }, 500);
  156. },
  157. fail:function(e){
  158. _self.uploading = false;
  159. console.log('消息发送失败');
  160. }
  161. });
  162. }else{
  163. setTimeout(function(){uni.hideLoading();}, 1000);
  164. }
  165. },
  166. fail:function(e){
  167. _self.uploading = false;
  168. console.log(e);
  169. }
  170. });
  171. },
  172. // 展示录音界面
  173. showRec : function(){this.recShow = true;},
  174. // 关闭录音界面
  175. closeRec: function (){this.recShow = false;},
  176. // 发送文本消息
  177. sendTextMsg: function () {
  178. if (this.inputMsg < 1) {return false;}
  179. var msg = this.user;
  180. msg.type = 'msg';
  181. msg.contentType = 'txt';
  182. msg.content = this.inputMsg;
  183. msg.token = this.token;
  184. console.log(msg,33);
  185. uni.sendSocketMessage({
  186. data : JSON.stringify(msg),
  187. fail:function(e){console.log('消息发送失败 ...');}
  188. });
  189. this.inputMsg = '';
  190. },
  191. // 选择图片
  192. chooseImg : function(){
  193. if(this.uploading){ return false;}
  194. var _self = this;
  195. uni.showLoading({title:"选择图片"});
  196. this.uploading = true;
  197. uni.chooseImage({
  198. count: 1,
  199. sizeType: ['compressed'],
  200. sourceType: ['album', 'camera'],
  201. success : function(res){
  202. uni.showLoading({title:"图片发送中"});
  203. const tempFilePaths = res.tempFilePaths;
  204. const uploadTask = uni.uploadFile({
  205. url : _self.config.serverUrl+'?c=uploadFile&token='+_self.token,
  206. filePath : tempFilePaths[0],
  207. name : 'gChatUploadFile',
  208. success : function (uploadFileRes) {
  209. var res = JSON.parse(uploadFileRes.data);
  210. if(res.status == 'ok'){
  211. var msg = _self.user;
  212. msg.type = 'msg';
  213. msg.contentType = 'img';
  214. msg.content = res.msg;
  215. uni.sendSocketMessage({
  216. data : JSON.stringify(msg),
  217. complete:function(){
  218. setTimeout(function(){
  219. _self.uploading = false;
  220. uni.hideLoading();
  221. }, 500);
  222. },
  223. fail:function(e){
  224. _self.uploading = false;
  225. console.log('消息发送失败');
  226. }
  227. });
  228. }else{
  229. setTimeout(function(){uni.hideLoading();}, 500);
  230. }
  231. },
  232. fail:function(e){
  233. _self.uploading = false;
  234. console.log(e);
  235. }
  236. });
  237. },
  238. fail:function(){uni.hideLoading();}
  239. });
  240. }
  241. }
  242. }
  243. </script>
  244. <style scoped>
  245. @font-face {font-family: "graceIMFonts"; src:url('data:font/truetype;charset=utf-8;base64,d09GMgABAAAAAASoAAsAAAAACpAAAARbAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDMgqILIZ4ATYCJAMUCwwABCAFhG0HSxsHCcgOJQUABgUAAMBk8EB6fW8yk/3Z7Cd4BLPXQW6vA9B99wc4f67lvzL5jC8R2YVkAS+XAsN4QPB1pPqF+wfHUj8K/8Hyvu1BXjGyLDq25lGBDagb1ySRuNkEfcvRGr5iXEVcDQGYRBOJS2OXykbwRoFqQYpmTZc48HZYUBEkgaF3BBypENvQMbT12hNgq/b24g35wgANXYLX6jelSITc52EvKqRlDzJKWljFuYDbcSCBTAAFYkGgZxZuhipT05hBv+dOLYCJgYb2POx50vPyFxW2DZaiQzqT/8MDDYlCgHCAGk+KrY0reB4m8aDB8yQeJDwv50HBiwrZtGh0ur0JhAGiEhCdYIisoERHonui2lcmOM2zJHp7m6a+suXpoNZng9tfDG17vkyohugi+3dbns4wdwWyFuTaGyL2DH1o+v/RweMTg2Y6LqngIEk2qXNSr6zPX9naOrilZVBb25D29qFN+/Nh99riT7Z3vdsad6xlyKkr1tWNZ09eGz6kkbRWS7iliav7hBVp1hm64Q4O3rMhcFCzzBa4ywoa3MgWtHtjyNAmVUhYR3kdd6O7DasHDfpeN2jwb7vbQFjoV6Fa7o6VK9v0qChdVrZdRURhRbwW3rqlUHWLS5mMreMeM3nRSDO2TbYUy16uGosg002pTpZwphre5b7iZKa3S1VPqnNboCS+PE4Hmd9c9SJ2Lk+1zG3JjnAsPmH0XBpvDWJl+WX186e6zIWKSG6z0np0qthYRZSdTEQULL34fb9uJZ66RKiru0eP4K4lSXcWecR/xPf20/WbFi0Bz/8qJrcUz0VLHq9jd7SqyEjVyoWKSFZYZV4TL99QQihCuiGEghgP3sLyqYFyCAlv/7hDnEsCyWXFCOnjZkAVINnlhrLtTEJFJEusvRjRsGVZpxpGRH+psDBFlC1MRCRsj0k9bjZvPtcjYrOpiXamCVUROssu7hLWO2VNhdl5+yxFRU/Z8/pcBwNGkpu2yNAKAPaY/CNXAvak/CmXAfaM/CYXH8o/w6M7d+aODar8ZrgUAB2fJ5zRauxBhbTgeNSSWHrgShOOqa8crbp6d0qSt09n10Gh0T6LTOBwDfjzrxh7EEUmBAZBFmh4EAUSg0SkwmaCjotCcGBQAyYZlBzvIgCKG0I5gXTGAAS+nIKGN9dB4ssnUmH/QCeY/+DAV0gwGSICzugiWUw3GxZgjmER8V1IESyTCDvz1YvrsdSmc9Qu18jNmDqVIIrLznUnS7CJaRH7ONuleMYIItQyUDFcD+u6hWxqqVhg0TJjdnpMzpSgJ4oWLAN8aYCC4WBgRBA8XSAUBCxMiLIww9fz+vVgJNrQ4aARXT/8zWAoTpTVI+KIJjYBskRjJuralEon7UjEw2iEgCC3QgsDRDF1YXQes0DYwZupYAQY0cgZIjbpxNDJSFJNdPU6Yx5LT5ueeAZdaEIKJXThwGPGdM60RcRz0WJbUY1TF8sb8IrH8sVdigkAAA==') format('truetype');}
  246. .graceIMFonts {font-family:"graceIMFonts" !important; font-size:15px; font-style:normal; color:#5E5E5E;}
  247. .icon-voice:before{content: "\e63a";}
  248. .icon-photograph:before {content:"\e619";}
  249. .icon-close:before {content:"\e625";}
  250. .icon-kbd{content:"\e73b";}
  251. .grace-im-footer{display:flex; background:#FFFFFF; width:100%; position:fixed; left:0; bottom:0; height:50px; flex-wrap:nowrap; overflow:hidden; box-shadow:1px 1px 6px #888;}
  252. .grace-im-footer .grace-items{width:auto; line-height:50px; flex-shrink:0;}
  253. .grace-im-menus{width:44px; height:50px; flex-shrink:0; line-height:50px; text-align:center; font-size:28px;}
  254. .grace-im-input{width:100%; margin:5px; padding:0 8px; background:#F4F5F6; border-radius:5px; height:40px; flex-wrap:nowrap; margin-left:10px;}
  255. .grace-im-input input{width:100%; background:#F4F5F6; height:20px; margin:8px 0; line-height:20px; border-radius:5px;}
  256. .grace-im-record{width:100%; position:fixed; left:0; bottom:0; background:#FFF; padding:30px 0; padding-bottom:50px; z-index:11; box-shadow:1px 1px 6px #888;}
  257. .grace-im-record-close{width:50px; height:50px; position:absolute; top:0px; right:0px; z-index:100; text-align:center; line-height:50px; color:#ccc; font-size:20px;}
  258. .grace-im-record-txt{text-align:center; line-height:30px; padding-bottom:10px; color:#ccc;}
  259. .grace-im-record-btn{width:60px; height:60px; margin:0 auto; border:5px solid #F1F2F3; border-radius:100%; background:#00B26A;}
  260. .grace-im-recording{background:#FF0000; animation:fade linear 2s infinite;}
  261. @keyframes fade{from{opacity:0.1;} 50%{opacity:1;} to{opacity:0.1;}}
  262. .grace-im-record-txt text{color:#00B26A; padding:0 12px;}
  263. .grace-im-send-voice{margin-top:12px; color:#00BA62; text-align:center;}
  264. .grace-im-send-voice text{margin:0 15px; color:#00BA62;}
  265. </style>