jinji.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. <template>
  2. <view class="jinji">
  3. <view class="text-center" style="padding-top: 80rpx;font-weight: bold;font-size: 40rpx;color: #222222;">
  4. <view class="datt">严重危害生命财产安全 </view>
  5. <view class="datt margin-top-sm">求助专属通道</view>
  6. <view style="margin-top: 28rpx;font-size: 28rpx;">平台将为您,保留录音证据,实时位置,通知平台联系人</view>
  7. </view>
  8. <!-- <view style="background: #fff;width: 200rpx;text-align: center;margin: 30rpx auto;padding: 20rpx 0;"
  9. @touchstart.stop.prevent="voiceBegin" @touchmove.stop.prevent="voiceIng" @touchend.stop.prevent="voiceEnd"
  10. @touchcancel.stop.prevent="voiceCancel">开始录音</view> -->
  11. <view class="text-center" style="margin-top: 152rpx;" v-if="checkLuYin != '否'" @touchstart.stop.prevent="voiceBegin"
  12. @touchmove.stop.prevent="voiceIng" @touchend.stop.prevent="voiceEnd"
  13. @touchcancel.stop.prevent="voiceCancel">
  14. <image src="/static/images/index/yuyin.png" style="width: 252rpx;height: 252rpx;pointer-events: none;"></image>
  15. </view>
  16. <view class="text-center" style="margin-top: 120rpx;" v-if="checkLuYin === '否'" @tap="setChatSave">
  17. <image src="/static/images/index/yuyin.png" style="width: 252rpx;height: 252rpx;pointer-events: none;"></image>
  18. </view>
  19. <!-- 录音UI效果 -->
  20. <view class="record" :class="recording?'':'hidden'">
  21. <view class="ing" :class="willStop?'hidden':''">
  22. <view class="icon luyin2"></view>
  23. </view>
  24. <view class="cancel" :class="willStop?'':'hidden'">
  25. <view class="icon chehui"></view>
  26. </view>
  27. <view class="tis" :class="willStop?'change':''">{{recordTis}}</view>
  28. </view>
  29. <view class="text-center" style="margin-top:238rpx;" @touchstart.stop.prevent="voiceBegin" v-if="checkLuYin != '否'"
  30. @touchmove.stop.prevent="voiceIng" @touchend.stop.prevent="voiceEnd"
  31. @touchcancel.stop.prevent="voiceCancel">
  32. <image src="/static/images/index/sos.png" style="width: 200rpx;height: 200rpx;pointer-events: none;"></image>
  33. </view>
  34. <view class="text-center" style="margin-top:238rpx;" v-if="checkLuYin === '否'" @tap="setChatSave">
  35. <image src="/static/images/index/sos.png" style="width: 200rpx;height: 200rpx;pointer-events: none;"></image>
  36. </view>
  37. </view>
  38. </template>
  39. <script>
  40. import configdata from '@/common/config.js';
  41. var innerAudioContext; //播放
  42. // #ifdef H5
  43. var recorder; // 定义一个MediaRecorder对象
  44. var stream; //定义一个音频流的对象
  45. var chunks = []; // 定义一个用于存储音频数据片段的数组
  46. // #endif
  47. export default {
  48. data() {
  49. return {
  50. checkLuYin: this.$queue.getData('checkLuYin'),
  51. latitude: '',
  52. longitude: '',
  53. content: '',
  54. //录音相关参数
  55. //H5不能录音
  56. RECORDER: uni.getRecorderManager(),
  57. isVoice: false,
  58. voiceTis: '按住 说话',
  59. recordTis: "手指上滑 取消发送",
  60. recording: false,
  61. willStop: false,
  62. initPoint: {
  63. identifier: 0,
  64. Y: 0
  65. },
  66. recordTimer: null,
  67. recordLength: 0,
  68. //播放语音相关参数
  69. AUDIO: uni.createInnerAudioContext(),
  70. playMsgid: null,
  71. VoiceTimer: null,
  72. blobData: '',
  73. voicePaths: '',
  74. voicePath: '',
  75. }
  76. },
  77. onLoad: function(option) {
  78. // #ifndef H5
  79. //录音开始事件
  80. this.RECORDER.onStart((e) => {
  81. this.recordBegin(e);
  82. })
  83. //录音结束事件
  84. this.RECORDER.onStop((e) => {
  85. this.recordEnd(e);
  86. })
  87. // #endif
  88. let that = this;
  89. uni.getLocation({
  90. type: 'wgs84',
  91. success: function(res) {
  92. console.log('当前位置的经度:' + res.longitude);
  93. console.log('当前位置的纬度:' + res.latitude);
  94. that.latitude = res.latitude
  95. that.longitude = res.longitude
  96. }
  97. });
  98. },
  99. onBackPress() {
  100. this.AUDIO.stop();
  101. },
  102. onHide() {
  103. this.AUDIO.stop();
  104. },
  105. mounted() {
  106. innerAudioContext = uni.createInnerAudioContext(); //播放
  107. let _this = this;
  108. // #ifndef H5
  109. //录音停止事件
  110. // recorderManager.onStop(function(res) {
  111. // console.log('recorder stop' + res.tempFilePath);
  112. // // _this.recordEnd(res);
  113. // _this.voicePath = res.tempFilePath;
  114. // });
  115. // #endif
  116. },
  117. beforeDestroy() {
  118. innerAudioContext.destroy();
  119. // var recorder; // 定义一个MediaRecorder对象
  120. // chunks = [];
  121. },
  122. methods: {
  123. // 切换语音/文字输入
  124. switchVoice() {
  125. this.isVoice = this.isVoice ? false : true;
  126. },
  127. setChatSave() {
  128. let userId = this.$queue.getData('userId');
  129. let userName = this.$queue.getData('nickName');
  130. let data = {
  131. image: this.content,
  132. state: 9,
  133. typeId: this.longitude,
  134. typeName: this.latitude,
  135. userId: userId,
  136. userName: userName
  137. }
  138. this.$Request.postJson('/app/message/insertMessage', data).then(
  139. res => {
  140. if (res.code == 0) {
  141. this.$queue.showToast('求助成功!');
  142. } else {
  143. this.$queue.showToast(res.msg);
  144. }
  145. });
  146. },
  147. // 录音开始
  148. voiceBegin(e) {
  149. // #ifdef H5
  150. if (stream) {
  151. stream.getTracks().forEach((track) => track.stop())
  152. stream = null
  153. }
  154. if (recorder) {
  155. recorder = null
  156. }
  157. this.recordLength = 0
  158. this.voicePaths = '';
  159. this.voicePath = '';
  160. this.startRecord()
  161. // #endif
  162. if (e.touches.length > 1) {
  163. return;
  164. }
  165. this.initPoint.Y = e.touches[0].clientY;
  166. this.initPoint.identifier = e.touches[0].identifier;
  167. // #ifndef H5
  168. this.RECORDER.start({
  169. format: "mp3"
  170. }); //录音开始,
  171. // #endif
  172. },
  173. //开始录音
  174. startRecord: async function() {
  175. let _this = this
  176. // 获取麦克风音频数据流
  177. stream = await navigator.mediaDevices.getUserMedia({
  178. audio: true
  179. })
  180. // 初始化MediaRecorder对象
  181. recorder = new MediaRecorder(stream);
  182. console.log('asdsad___' + recorder)
  183. // alert('asdsad___' + recorder)
  184. // 将 stream 转成 blob 来存放
  185. recorder.ondataavailable = (blobEvent) => {
  186. chunks.push(blobEvent.data);
  187. }
  188. // 停止时生成预览的 blob url
  189. recorder.onstop = () => {
  190. const blob = new Blob(chunks, {
  191. type: 'audio/mp3'
  192. })
  193. // const mediaUrl = URL.createObjectURL(blob);
  194. _this.voicePaths = blob;
  195. _this.blobData = blob;
  196. // that.voicePath = mediaUrl;
  197. // const newbold = new File([recordPath]),{type:'audio/mp3'}
  198. // alert(that.voicePaths,URL.createObjectURL(blob))
  199. }
  200. recorder.start();
  201. _this.recordBegin()
  202. },
  203. //录音开始UI效果
  204. recordBegin(e) {
  205. this.recording = true;
  206. this.voiceTis = '松开 结束';
  207. this.recordLength = 0;
  208. this.recordTimer = setInterval(() => {
  209. this.recordLength++;
  210. }, 1000)
  211. },
  212. // 录音被打断
  213. voiceCancel() {
  214. this.recording = false;
  215. this.voiceTis = '按住 说话';
  216. this.recordTis = '手指上滑 取消发送'
  217. this.willStop = true; //不发送录音
  218. this.RECORDER.stop(); //录音结束
  219. },
  220. // 录音中(判断是否触发上滑取消发送)
  221. voiceIng(e) {
  222. // // #ifdef H5
  223. // this.startRecord()
  224. // // #endif
  225. if (!this.recording) {
  226. return;
  227. }
  228. let touche = e.touches[0];
  229. //上滑一个导航栏的高度触发上滑取消发送
  230. if (this.initPoint.Y - touche.clientY >= uni.upx2px(100)) {
  231. this.willStop = true;
  232. this.recordTis = '松开手指 取消发送'
  233. } else {
  234. this.willStop = false;
  235. this.recordTis = '手指上滑 取消发送'
  236. }
  237. },
  238. // 结束录音
  239. voiceEnd(e) {
  240. if (!this.recording) {
  241. return;
  242. }
  243. this.recording = false;
  244. this.voiceTis = '按住 说话';
  245. this.recordTis = '手指上滑 取消发送'
  246. //原生录音停止
  247. // #ifdef H5
  248. //停止录音
  249. if (recorder.state != "inactive") {
  250. recorder.stop();
  251. }
  252. //把音频流也停止掉
  253. stream.getTracks().forEach((track) => track.stop())
  254. this.uplodMp3(this.voicePaths);
  255. // #endif
  256. // #ifndef H5
  257. this.RECORDER.stop(); //录音结束
  258. // #endif
  259. },
  260. //录音结束(回调文件)
  261. recordEnd(e) {
  262. let that = this
  263. clearInterval(this.recordTimer);
  264. if (!this.willStop) {
  265. this.$queue.showLoading('发送中...')
  266. console.log("e: " + JSON.stringify(e));
  267. let msg = {
  268. length: 0,
  269. url: e.tempFilePath
  270. }
  271. let min = parseInt(this.recordLength / 60);
  272. let sec = this.recordLength % 60;
  273. min = min < 10 ? '0' + min : min;
  274. sec = sec < 10 ? '0' + sec : sec;
  275. if (this.recordLength % 60 > 1) {
  276. msg.length = min + ':' + sec;
  277. console.log('msg.length___:' + msg.length)
  278. uni.uploadFile({ // 上传接口
  279. url: that.config("APIHOST1") + '/alioss/upload', //真实的接口地址
  280. filePath: e.tempFilePath,
  281. name: 'file',
  282. success: (uploadFileRes) => {
  283. uni.hideLoading();
  284. this.content = JSON.parse(uploadFileRes.data).data;
  285. console.log("语音:" + this.content)
  286. this.setChatSave();
  287. uni.hideLoading();
  288. }
  289. });
  290. } else {
  291. this.$queue.showToast('语音要大于一秒才可以发送!')
  292. }
  293. } else {
  294. console.log('取消发送录音');
  295. }
  296. this.willStop = false;
  297. },
  298. //上传mp3格式的音频
  299. uplodMp3(recordPath) {
  300. let _this = this;
  301. // var newbold = new File([recordPath],{type:'audio/mp3'})
  302. clearInterval(_this.recordTimer);
  303. if (!_this.willStop) {
  304. // that.$queue.showLoading('发送中...')
  305. uni.showLoading({
  306. title: '录音上传中...'
  307. })
  308. let msg = {
  309. length: 0,
  310. url: recordPath
  311. }
  312. let min = parseInt(_this.recordLength / 60);
  313. let sec = _this.recordLength % 60;
  314. min = min < 10 ? '0' + min : min;
  315. sec = sec < 10 ? '0' + sec : sec;
  316. if (_this.recordLength % 60 > 1) {
  317. msg.length = min + ':' + sec;
  318. // console.log('msg.length___:' + msg.length)
  319. setTimeout(function() {
  320. uni.uploadFile({ // 上传接口
  321. url: _this.config("APIHOST1") + '/alioss/upload', //真实的接口地址
  322. file: _this.blobData,
  323. // file: recordPath,
  324. name: 'file',
  325. success: (uploadFileRes) => {
  326. console.error('uploadFileRes------' + uploadFileRes)
  327. uni.hideLoading();
  328. _this.content = JSON.parse(uploadFileRes.data).data;
  329. // console.log("语音:" + that.content)
  330. _this.setChatSave();
  331. uni.hideLoading();
  332. }
  333. });
  334. }, 1000)
  335. } else {
  336. _this.$queue.showToast('语音要大于一秒才可以发送!')
  337. }
  338. } else {
  339. console.log('取消发送录音');
  340. }
  341. _this.willStop = false;
  342. },
  343. config: function(name) {
  344. var info = null;
  345. if (name) {
  346. var name2 = name.split("."); //字符分割
  347. if (name2.length > 1) {
  348. info = configdata[name2[0]][name2[1]] || null;
  349. } else {
  350. info = configdata[name] || null;
  351. }
  352. if (info == null) {
  353. let web_config = cache.get("web_config");
  354. if (web_config) {
  355. if (name2.length > 1) {
  356. info = web_config[name2[0]][name2[1]] || null;
  357. } else {
  358. info = web_config[name] || null;
  359. }
  360. }
  361. }
  362. }
  363. return info;
  364. },
  365. }
  366. }
  367. </script>
  368. <style lang="scss">
  369. @import "./css/style.scss";
  370. .jinji {
  371. height: 100vh;
  372. background: linear-gradient( 180deg, #90FFD6 0%, #E6FFF6 28%, #FFFFFF 47%, #E5FFF5 100%);
  373. }
  374. </style>