answerDetail.vue 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. <template>
  2. <view class="answerdetail-page flex-column">
  3. <template v-if="questionItem&&hasAuth">
  4. <template>
  5. <view class="question-wrap">
  6. <view class="question-item">
  7. <view class="question-info">
  8. <view style="flex: 1" class="question-title">
  9. <text class="item-label">{{
  10. questionItem.variety_tag_name
  11. }}</text>
  12. {{ questionItem.question_content }}
  13. </view>
  14. <view class="item-answer" v-if="questionItem.reply_status === 3&&!isUserResearcher">
  15. <view class="answer" @click.stop="handlePlayAudioByBg(questionItem)">
  16. <!-- 改为背景音频播放 -->
  17. <image class="music-img" :src="questionItem.community_question_id==curVoiceId&&!curAudioPaused?playImgSrc:pauseImgSrc" mode="widthFix"/>
  18. <text>{{ formatAudioTime(questionItem.audio_list[0].audio_play_seconds*1000) }}</text>
  19. <!-- <template v-if="!questionItem.loading">
  20. <image
  21. class="music-img"
  22. :src="questionItem.answer.isplay ? playImgSrc : pauseImgSrc"
  23. mode="widthFix"
  24. />
  25. <template
  26. v-if="
  27. questionItem.answer.isplay || questionItem.answer.ispause
  28. "
  29. >
  30. <text>{{
  31. questionItem.answer.audioTime -
  32. currentAudioMsg.audioCurrentTime >
  33. 0
  34. ? dayjs(
  35. (questionItem.answer.audioTime -
  36. currentAudioMsg.audioCurrentTime) *
  37. 1000
  38. ).format("mm:ss")
  39. : "00:00"
  40. }}</text>
  41. </template>
  42. <template v-else>
  43. <text>{{
  44. dayjs(questionItem.answer.audioTime * 1000).format(
  45. "mm:ss"
  46. )
  47. }}</text>
  48. </template>
  49. </template>
  50. <template v-else>
  51. <image
  52. class="load-img"
  53. src="../static/loading.png"
  54. mode="aspectFill"
  55. />
  56. <text>{{
  57. dayjs(questionItem.answer.audioTime).format("mm:ss")
  58. }}</text>
  59. </template> -->
  60. </view>
  61. <!-- 普通用户进入的音频悬浮 -->
  62. <audioBox v-if="showAudioPop"/>
  63. </view>
  64. </view>
  65. <text class="item-time">提问时间:{{ questionItem.create_time }}</text>
  66. </view>
  67. </view>
  68. <view
  69. class="record-wrap flex-column"
  70. v-if="questionItem.reply_status === 2&&isUserResearcher"
  71. >
  72. <view class="record flex-column" v-if="questionItem.recordStatus !== 4">
  73. <view class="no-record" v-if="questionItem.recordStatus === 1">
  74. <image
  75. src="./static/record.png"
  76. mode="widthFix"
  77. style="width: 90rpx; height: 180rpx"
  78. />
  79. <view>无录音(录音时长超过三分钟自动结束)</view>
  80. <view class="black-btn" style="margin-top:100rpx" @click.stop="showRemoveQ=true">转移问题</view>
  81. <view class="black-btn" style="margin-top:50rpx" @click.stop="stopQuestion.show=true">终止问答</view>
  82. </view>
  83. <!-- <view class="record-time" v-else>{{ audioTime }}</view> -->
  84. <view class="recode-image" v-else>
  85. <scroll-view scroll-x style="height: 100rpx" class="scroll-view" :scroll-left="scrollTop" @scrolltolower="handleScrolltolower" :show-scrollbar="false">
  86. <view style="width:100%;height:100rpx;display:inline-block;"></view>
  87. <image
  88. src="./static/record-img.png"
  89. mode="scaleToFill"
  90. />
  91. <image
  92. src="./static/record-img.png"
  93. mode="scaleToFill"
  94. />
  95. <image
  96. src="./static/record-img.png"
  97. mode="scaleToFill"
  98. />
  99. </scroll-view>
  100. </view>
  101. </view>
  102. <view
  103. class="record-tool flex-column"
  104. v-if="questionItem.recordStatus !== 4"
  105. >
  106. <view class="hint" v-if="questionItem.recordStatus === 1"
  107. >点击开始录音</view
  108. >
  109. <view class="record-time" v-else>{{ audioTime }}</view>
  110. <view
  111. class="record-btn-wrap center"
  112. v-if="questionItem.recordStatus === 1"
  113. >
  114. <view class="switch" @click="changeRecodeStatus"> </view>
  115. </view>
  116. <view class="record-btn-wrap" v-else>
  117. <text
  118. @click="questionItem.recordStatus === 3 && handleRecode('delete')"
  119. v-if="questionItem.recordStatus >= 2"
  120. :class="{ active: questionItem.recordStatus === 3 }"
  121. >删除</text
  122. >
  123. <view class="switch" @click="changeRecodeStatus">
  124. <image
  125. v-if="questionItem.recordStatus >= 2"
  126. :src="
  127. questionItem.recordStatus === 2 ? playImgSrc : pauseImgSrc
  128. "
  129. :key="playIconKey"
  130. :style="{
  131. 'margin-left': questionItem.recordStatus !== 2 ? '7rpx' : 0,
  132. width: '36rpx',
  133. height: '44rpx',
  134. }"
  135. mode="widthFix"
  136. />
  137. </view>
  138. <text
  139. @click="handleRecode('finish')"
  140. v-if="questionItem.recordStatus >= 2"
  141. :class="{ active: questionItem.recordStatus >= 2 }"
  142. >完成</text
  143. >
  144. </view>
  145. </view>
  146. <view class="record-play" v-if="questionItem.recordStatus === 4">
  147. <view class="audio-wrap">
  148. <view v-if="pageLoading">音频生成中...</view>
  149. <view class="play" v-else>
  150. <van-icon
  151. :name="isplay ? 'pause' : 'play'"
  152. @click="handleAudioByReplay"
  153. color="#E6B77DFF"
  154. size="64rpx"
  155. style="align-items: flex-start; margin-left: -20rpx"
  156. />
  157. <!-- 进度条 -->
  158. <view class="slider-box">
  159. <slider
  160. :value="currentAudioMsg.audioCurrentTime"
  161. :max="currentAudioMsg.audioTime"
  162. @change="sliderChange($event)"
  163. @changing="sliderChanging"
  164. activeColor="#E6B77DFF"
  165. backgroundColor="#EBEBEBFF"
  166. block-color="#E6B77DFF"
  167. block-size="12"
  168. />
  169. <view class="slider-time">
  170. <text>{{
  171. formatAudioTime(currentAudioMsg.audioCurrentTime * 1000)
  172. }}</text>
  173. <text>{{
  174. formatAudioTime(currentAudioMsg.audioTime * 1000)
  175. }}</text>
  176. </view>
  177. </view>
  178. </view>
  179. </view>
  180. <view class="audio-delete" @click="handleRecode('delete')">
  181. <image
  182. src="./static/delerecord.png"
  183. mode="heightFix"
  184. style="width: 32rpx; height: 35rpx"
  185. />
  186. <text>删除</text></view
  187. >
  188. <view class="audio-pub" @click="handleRecode('pub')">发布</view>
  189. </view>
  190. </view>
  191. <view class="record-wrap flex-column" v-if="questionItem.reply_status===3&&isUserResearcher">
  192. <view class="record-play" v-if="questionItem.recordStatus === 4">
  193. <view class="audio-wrap">
  194. <view class="play">
  195. <van-icon
  196. :name="questionItem.community_question_id==curVoiceId&&!curAudioPaused ? 'pause' : 'play'"
  197. @click="handlePlayAudioByBg(questionItem)"
  198. color="#E6B77DFF"
  199. size="64rpx"
  200. style="align-items: flex-start; margin-left: -20rpx"
  201. />
  202. <!-- 进度条 -->
  203. <view class="slider-box">
  204. <slider
  205. :value="curTime"
  206. :max="currentAudioMsg.audioTime"
  207. @change="bgAudiosliderChange($event)"
  208. @changing="sliderChanging"
  209. activeColor="#E6B77DFF"
  210. backgroundColor="#EBEBEBFF"
  211. block-color="#E6B77DFF"
  212. block-size="12"
  213. />
  214. <view class="slider-time">
  215. <text>{{
  216. formatAudioTime(curTime*1000)
  217. }}</text>
  218. <text>{{
  219. formatAudioTime(questionItem.answer.audioTime * 1000)
  220. }}</text>
  221. </view>
  222. </view>
  223. </view>
  224. </view>
  225. <view class="audio-pub disable">已发布</view>
  226. <!-- 音频悬浮 -->
  227. <view v-show="false">
  228. <audioBox v-if="showAudioPop"/>
  229. </view>
  230. </view>
  231. </view>
  232. </template>
  233. </template>
  234. <!-- 没有该问题权限 -->
  235. <template v-else-if="!hasAuth">
  236. <view class="noAuth-wrap">
  237. <image class="img" :src="globalImgUrls.activityNoAuth" mode="widthFix"></image>
  238. <view class="auth-text">您暂无权限查看问答社区</view>
  239. <view class="auth-text" v-if="noAuthInfo.type==='contact'">若想查看可以联系对口销售</view>
  240. <view class="auth-text" v-else>若想查看可以申请开通</view>
  241. <view class="auth-text" v-if="noAuthInfo.type==='contact'">
  242. {{noAuthInfo.name||''}}:<text @click="handleCallPhone(noAuthInfo.mobile+'')">{{noAuthInfo.mobile||''}}</text>
  243. </view>
  244. <view class="global-btn-yellow-change btn" @click="handleGoApply" v-else>立即申请</view>
  245. </view>
  246. </template>
  247. <!-- 终止问答弹窗 -->
  248. <van-dialog
  249. use-slot
  250. title="终止问答"
  251. :show="stopQuestion.show"
  252. show-cancel-button
  253. confirm-button-open-type="getUserInfo"
  254. @close="stopQuestion.show=false;stopQuestion.reason=''"
  255. @confirm="handleConfirmStopQuestion"
  256. >
  257. <view style="padding:48rpx">
  258. <textarea
  259. style="background: #F7F8FA;border-radius: 8px;padding: 20rpx;display:block;box-sizing:border-box;width:100%"
  260. maxlength="-1"
  261. cols="30"
  262. rows="10"
  263. placeholder="请输入终止理由"
  264. v-model="stopQuestion.reason"
  265. ></textarea>
  266. </view>
  267. </van-dialog>
  268. <!-- 转移问答弹窗 -->
  269. <removeQuestionDig :show="showRemoveQ" :qid="qid" @close="showRemoveQ=false" ></removeQuestionDig>
  270. </view>
  271. </template>
  272. <script>
  273. import mixin from "../mixin/questionMixin";
  274. import { apiReplayAsk, apiGetQuestion, apiSetRead,apiCountAudioClick,apiQuestionStop } from "@/api/question";
  275. import { apiApplyPermission} from '@/api/user';
  276. import {apiGetSceneToParams} from "../api/common.js"
  277. import { uploadAudioToServer } from "@/utils/upload";
  278. import audioBox from '@/components/audioBox/audioBox.vue'
  279. import removeQuestionDig from './components/removeQuestionDig.vue'
  280. export default {
  281. mixins: [mixin],
  282. components:{
  283. audioBox,
  284. removeQuestionDig
  285. },
  286. computed:{
  287. showAudioPop(){//是否显示音频弹窗
  288. return this.$store.state.audio.show
  289. },
  290. showAudioBigPop(){
  291. return this.$store.state.audio.showBig
  292. },
  293. curVoiceId(){//当前正在播放的音频id
  294. return this.$store.state.audio.questionId
  295. },
  296. curAudioPaused(){//当前音频是否暂停状态
  297. return this.$store.state.audio.paused
  298. },
  299. curTime(){
  300. let t=0
  301. if(this.questionItem?.community_question_id==this.$store.state.audio.questionId){
  302. t=this.$store.state.audio.curTime
  303. }
  304. return t
  305. }
  306. },
  307. data() {
  308. return {
  309. qid:0,
  310. questionItem: null /* {
  311. recordStatus: 1, //1:未录音;2:正在录音;3:已暂停;4:完成录音
  312. permission_info:{
  313. type:'',
  314. name:'梁娜',
  315. mobile:'123456',
  316. customer_info:{
  317. has_apply:false,
  318. company_name:'',
  319. name:'',
  320. status:'流失',
  321. }
  322. }
  323. }, */,
  324. pauseImgSrc: "../static/question/recordplay.png",
  325. playImgSrc: "../static/question/recordpause.png",
  326. innerAudio: null, //该页面的音频
  327. audioCount: 0, //录音计时,毫秒
  328. audioSrc:'',//tempSrc
  329. audioTime: "00:00", //录音时间(格式化后):string
  330. timer: null,
  331. audioItem: null,
  332. pageLoading: false,
  333. playIconKey: 0,
  334. isplay: false,
  335. isSlider: false,
  336. scrollTop:0,
  337. isStart:false,//判断录音是否开始
  338. //globalRecorder:uni.getRecorderManager(),
  339. /* userInfo:{
  340. is_inner:1,//0:外部客户;1内部员工
  341. status:'正式',
  342. is_suspend:1,
  343. is_researcher:0,
  344. }, *///mock用户信息
  345. stopQuestion:{
  346. show:false,
  347. reason:'',
  348. },//终止问答
  349. showRemoveQ:false,//展示转移问题弹窗
  350. };
  351. },
  352. async onLoad(options) {
  353. this.initAudio();
  354. let obj={}
  355. if(options.scene){
  356. // 小程序码进来的
  357. let res = await apiGetSceneToParams({scene_key:options.scene})
  358. if(res.code==200){
  359. obj=JSON.parse(res.data)
  360. }
  361. }
  362. this.qid=obj.id || options.id
  363. this.getQuestionItem(obj.id || options.id);
  364. },
  365. onShow(){
  366. uni.authorize({
  367. scope: 'scope.record',
  368. success() {
  369. },
  370. fail(e){
  371. console.log('fail',e);
  372. }
  373. })
  374. },
  375. onUnload() {
  376. this.resetAudio();
  377. this.destroyAudio();
  378. //录音时误操作退出页面的情况
  379. if(this.questionItem.recordStatus!==4&&this.questionItem.recordStatus!==1){
  380. this.globalRecorder.stop()
  381. }
  382. },
  383. //转发分享
  384. onShareAppMessage(){
  385. const {community_question_id} = this.questionItem
  386. return{
  387. title:'问答详情',
  388. path:`/pages-question/answerDetail?id=${community_question_id}`
  389. }
  390. },
  391. methods: {
  392. //初始化audio,onShow执行
  393. initAudio() {
  394. this.innerAudio = uni.createInnerAudioContext();
  395. this.handleAudioFun();
  396. this.handleRecorderFun();
  397. //录音完成后,切出其他页面再切回来
  398. if(this.questionItem?.recordStatus===4){
  399. console.log('count',this.audioCount,'src',this.audioSrc)
  400. this.setAudio(this.audioSrc,this.audioCount)
  401. }
  402. },
  403. //录音完成or从其他app切回本页面时,初始化音频
  404. setAudio(src,audioCount){
  405. this.innerAudio.stop();
  406. this.isplay = false;
  407. this.innerAudio.src = src;
  408. console.log('秒数',audioCount)
  409. this.changeCurrentAudio({
  410. id: "",
  411. answer: {
  412. source: src,
  413. audioTime: audioCount/1000,
  414. },
  415. });
  416. },
  417. //麦克风被占用,初始化录音相关变量 其他状态->未录音状态
  418. setRecorder(){
  419. this.questionItem.recordStatus = 1;
  420. this.innerAudio.stop();
  421. this.isplay = false;
  422. this.audioItem = null;
  423. this.audioCount = 0;
  424. this.scrollTop = 0;
  425. this.audioTime = this.formatAudioTime(this.audioCount * 1000)
  426. },
  427. //onHide触发
  428. resetAudio(){
  429. this.innerAudio.stop();
  430. this.isplay = false;
  431. this.changeCurrentAudio({
  432. id: '',
  433. answer: {
  434. source: '',
  435. audioTime: 0
  436. }
  437. })
  438. },
  439. //audio事件
  440. handleAudioFun() {
  441. this.innerAudio.onPlay(() => {
  442. this.isplay = true;
  443. console.log("播放录音了");
  444. this.questionItem.loading = false;
  445. });
  446. this.innerAudio.onTimeUpdate(() => {
  447. //console.log("时间更新", this.innerAudio.currentTime);
  448. /* this.currentAudioMsg.audioCurrentTime = parseInt(
  449. this.innerAudio.currentTime
  450. ); */
  451. this.currentAudioMsg.audioCurrentTime = this.innerAudio.currentTime;
  452. });
  453. this.innerAudio.onSeeked(() => {
  454. //取this.innerAudio.currentTime为0
  455. console.log("seek完成");
  456. this.isSlider = false;
  457. });
  458. this.innerAudio.onPause(() => {
  459. this.isplay = false;
  460. console.log("暂停");
  461. console.log(this.innerAudio.paused);
  462. });
  463. this.innerAudio.onEnded(() => {
  464. console.log("音频播放完毕");
  465. this.questionItem.answer.isplay = false;
  466. this.questionItem.answer.ispause = false;
  467. /* this.changeCurrentAudio({
  468. id: "",
  469. answer: {
  470. source: "",
  471. audioTime: 0,
  472. },
  473. }); */
  474. this.currentAudioMsg.audioCurrentTime = 0;
  475. this.isplay = false;
  476. });
  477. },
  478. //录音事件
  479. handleRecorderFun() {
  480. this.globalRecorder.onStart(() => {
  481. console.log("开始录音");
  482. if(this.questionItem.recordStatus===1){
  483. this.questionItem.recordStatus=2
  484. }
  485. uni.hideToast();
  486. this.clockTime();
  487. });
  488. this.globalRecorder.onPause(() => {
  489. console.log("暂停录音");
  490. if(this.questionItem.recordStatus===2){
  491. this.questionItem.recordStatus = 3
  492. }
  493. this.cleanTime();
  494. });
  495. this.globalRecorder.onStop((res) => {
  496. console.log("录音完成");
  497. //录音自动结束 和 暂停时点击删除 的情况
  498. if (this.questionItem.recordStatus === 2) {
  499. this.questionItem.recordStatus = 4;
  500. }
  501. console.log('status',this.questionItem.recordStatus)
  502. console.log("res", JSON.stringify(res));
  503. this.cleanTime();
  504. //初始化音频播放
  505. this.audioSrc = res.tempFilePath
  506. this.setAudio(this.audioSrc ,this.audioCount)
  507. this.pageLoading = false;
  508. });
  509. this.globalRecorder.onError((res) => {
  510. console.log('err',res)
  511. console.log('errMsg',res.errMsg)
  512. /* uni.showToast({
  513. title:res.errMsg,
  514. icon:'none'
  515. }) */
  516. //开始录音失败
  517. if(res.errMsg.includes('start')){
  518. this.questionItem.recordStatus = 1;
  519. }
  520. //麦克风被占用的情况
  521. if(res.errCode===1){
  522. uni.showToast({
  523. title:'麦克风被占用,已停止录音',
  524. icon:'none'
  525. })
  526. this.globalRecorder.stop();
  527. this.setRecorder()
  528. }
  529. });
  530. /* this.globalRecorder.onFrameRecorded((res) => {
  531. console.log("?", res);
  532. }); */
  533. },
  534. async getQuestionItem(id) {
  535. const res = await apiGetQuestion({
  536. question_id: id,
  537. });
  538. if (res.code === 200) {
  539. this.questionItem = {...res.data,recordStatus:1};
  540. const { audio_list } = res.data;
  541. let temp = {};
  542. if (audio_list.length > 0) {
  543. temp = {
  544. source: res.data.audio_list[0].audio_url,
  545. audioTime: parseInt(res.data.audio_list[0].audio_play_seconds)||0,
  546. isplay: false,
  547. ispause: false,
  548. };
  549. } else {
  550. temp = {
  551. source: "",
  552. audioTime: 0,
  553. isplay: false,
  554. ispause: false,
  555. };
  556. }
  557. let readKey = "";
  558. //const { is_inner } = this.userInfo;
  559. if (this.isUserResearcher) {
  560. readKey = "replier_is_read";
  561. } else {
  562. readKey = "is_read";
  563. }
  564. console.log('readKey',readKey)
  565. this.questionItem[readKey] !== 1 &&
  566. (await apiSetRead({
  567. question_ids: this.questionItem.community_question_id + "",
  568. }));
  569. this.questionItem.id = res.data.community_question_id;
  570. this.questionItem.answer = temp;
  571. this.questionItem.loading = false;
  572. this.questionItem.recordStatus = res.data.reply_status === 3 ? 4 : 1;
  573. //研究员查看已回复的问题,初始化音频
  574. if(res.data.reply_status===3&&this.isUserResearcher){
  575. this.innerAudio.src = res.data.audio_list[0].audio_url
  576. this.audioSrc = res.data.audio_list[0].audio_url
  577. this.audioCount = parseInt(res.data.audio_list[0].audio_play_seconds)*1000
  578. this.changeCurrentAudio({
  579. id: "",
  580. answer: {
  581. source: res.data.audio_list[0].audio_url,
  582. audioTime: parseInt(res.data.audio_list[0].audio_play_seconds)||0,
  583. },
  584. });
  585. }
  586. }else if(res.code===403){
  587. this.hasAuth=false
  588. this.noAuthInfo = res.data
  589. }else{
  590. //问题被删除的情况,返回小程序首页
  591. setTimeout(()=>{
  592. uni.switchTab({ url:'/pages/report/report' });
  593. },1000)
  594. }
  595. },
  596. changeRecodeStatus() {
  597. console.log('a',this.questionItem.recordStatus)
  598. //根据questionItem.recordStatus
  599. if (this.questionItem.recordStatus === 1) {
  600. const that = this
  601. //检查是否有权限
  602. uni.getSetting({
  603. success(res){
  604. console.log('res',res)
  605. if(res.authSetting['scope.record']){
  606. that.startRecord()
  607. }else{
  608. that.getRecordAuth()
  609. }
  610. }
  611. });
  612. } else if (this.questionItem.recordStatus === 2) {
  613. //暂停录音
  614. this.globalRecorder.pause();
  615. this.questionItem.recordStatus = 3;
  616. } else if (this.questionItem.recordStatus === 3) {
  617. //继续录音
  618. this.globalRecorder.resume();
  619. this.clockTime();
  620. this.questionItem.recordStatus = 2;
  621. } else {
  622. //结束录音
  623. this.globalRecorder.stop();
  624. //this.cleanTime();
  625. }
  626. },
  627. //获取录音授权
  628. getRecordAuth(){
  629. const {community_question_id} = this.questionItem
  630. uni.openSetting({
  631. success(res){
  632. //刷新页面
  633. if(res.authSetting['scope.record']){
  634. uni.redirectTo({url: `/pages-question/answerDetail?id=${community_question_id}`})
  635. }
  636. }
  637. })
  638. //this.questionItem.recordStatus = 1
  639. },
  640. //开启录音
  641. startRecord(){
  642. console.log(this.globalRecorder)
  643. this.globalRecorder.start({ duration: 180000, format: "mp3" });
  644. uni.showToast({
  645. title:'加载中',
  646. icon:'loading'
  647. })
  648. this.questionItem.recordStatus = 2;
  649. },
  650. //上传音频
  651. async uploadAudio() {
  652. const res = await uploadAudioToServer(this.innerAudio.src);
  653. if (res.code === 200) {
  654. this.audioItem = res.data;
  655. } else {
  656. //重新录
  657. this.setRecorder()
  658. }
  659. },
  660. //录音操作:完成/删除/发布
  661. async handleRecode(type) {
  662. if (type==='finish') {
  663. this.questionItem.recordStatus = 4;
  664. this.changeRecodeStatus();
  665. }
  666. if (type === "finish") {
  667. //生成音频,更改页面布局
  668. this.pageLoading = true;
  669. } else if (type === "delete") {
  670. //重新录
  671. if(this.questionItem.recordStatus===3)this.globalRecorder.stop();
  672. this.setRecorder()
  673. } else {
  674. //发布
  675. if (!this.audioItem) {
  676. await this.uploadAudio();
  677. }
  678. //如果上传音频成功
  679. if (this.questionItem.recordStatus === 4) {
  680. //发布回答
  681. const res = await apiReplayAsk({
  682. question_id: this.questionItem.community_question_id,
  683. audio_list: [{ ...this.audioItem, sort: 1 }],
  684. });
  685. if (res.code === 200) {
  686. uni.showToast({
  687. title: "发布成功",
  688. icon: "success",
  689. duration: 500,
  690. });
  691. setTimeout(() => {
  692. //关闭当前页面,跳转到我的回答
  693. // 返回失败 从公众号模板消息过来的,导航至我的问答
  694. uni.navigateBack({
  695. delta: 1 ,
  696. fail:()=>{
  697. uni.redirectTo({
  698. url: '/pages-question/answerList'
  699. })
  700. }
  701. });
  702. }, 500);
  703. }
  704. }
  705. }
  706. },
  707. //(提问者)问题已被回答,点击回答音频
  708. handleAudio(item) {
  709. const { source, isplay, ispause } = item.answer;
  710. if (isplay) {
  711. //说明是播放->暂停
  712. this.innerAudio.pause();
  713. this.questionItem.answer.isplay = false;
  714. this.questionItem.answer.ispause = true;
  715. } else if (ispause) {
  716. //说明是暂停->播放
  717. this.innerAudio.play();
  718. this.questionItem.answer.isplay = true;
  719. this.questionItem.answer.ispause = false;
  720. } else {
  721. //console.log("aaa", source, this.innerAudio.src);
  722. //说明是第一次播放或播放完
  723. this.changeCurrentAudio(item);
  724. this.innerAudio.stop();
  725. this.innerAudio.src = source;
  726. this.handleAudioPlay();
  727. this.questionItem.answer.isplay = true;
  728. //音频点击次数+1
  729. const audio_id = this.questionItem.audio_list[0].community_question_audio_id
  730. apiCountAudioClick({
  731. community_question_audio_id:audio_id,
  732. source_agent:1
  733. }).then((res)=>{
  734. if(res.code===200){
  735. console.log('音频id为'+audio_id+'点击次数+1')
  736. }
  737. })
  738. }
  739. },
  740. //(回答者)问题被回答,点击回答音频
  741. handleAudioByReplay() {
  742. this.isplay = !this.isplay;
  743. if (this.innerAudio.paused) {
  744. this.innerAudio.play();
  745. } else {
  746. this.innerAudio.pause();
  747. }
  748. this.playIconKey++; //更新音频播放图标
  749. },
  750. //拖动音频进度条
  751. sliderChange(e) {
  752. console.log("拖动完成?");
  753. //this.innerAudio.pause();
  754. const value = e.detail.value;
  755. this.innerAudio.seek(value);
  756. this.currentAudioMsg.audioCurrentTime = value;
  757. },
  758. sliderChanging() {
  759. this.isSlider = true;
  760. },
  761. // 背景音频播放的拖动
  762. bgAudiosliderChange(e){
  763. const value=e.detail.value
  764. this.globalBgMusic.seek(value)
  765. },
  766. //切换当前播放音频
  767. changeCurrentAudio(item) {
  768. const { id } = item;
  769. const { source, audioTime } = item.answer;
  770. this.currentAudioMsg = {
  771. id: id,
  772. audioCurrentTime: 0 * 1000,
  773. audioTime: audioTime,
  774. audioCurrentUrl: source,
  775. };
  776. if (id) {
  777. this.questionItem.loading = true;
  778. }
  779. },
  780. //录音计时
  781. clockTime() {
  782. console.log("开始录音计时");
  783. if(this.timer) return
  784. this.timer = setInterval(() => {
  785. if (this.timer) {
  786. this.audioCount += 30;
  787. this.audioTime = this.formatAudioTime(this.audioCount)
  788. this.scrollTop+=1;
  789. }
  790. }, 30);
  791. },
  792. //清除录音计时
  793. cleanTime() {
  794. console.log("结束录音计时");
  795. clearInterval(this.timer);
  796. this.timer=null
  797. this.playIconKey++; //更新录音暂停播放图标
  798. //this.audioTime = this.dayjs(this.audioCount).format("mm:ss.SS");
  799. },
  800. //scroll-view滑动到最右
  801. handleScrolltolower(){
  802. console.log('a',this.scrollTop)
  803. this.scrollTop-=150;
  804. },
  805. //权限相关
  806. handleContact(mobile){
  807. uni.makePhoneCall({
  808. phoneNumber: mobile+''
  809. });
  810. },
  811. async handleGoApply(){
  812. const {customer_info} = this.questionItem.permission_info
  813. const {community_question_id} = this.questionItem
  814. if (customer_info.has_apply) { //已经申请过
  815. uni.showToast({
  816. title:'您已提交过申请,请耐心等待',
  817. icon:'none'
  818. })
  819. } else {
  820. if (!customer_info.status || customer_info.status != '流失'|| customer_info.status != '关闭') {
  821. uni.navigateTo({
  822. url: "/pages-applyPermission/applyPermission?source=5&form_page=问答社区"
  823. })
  824. } else { //主动调一次申请权限接口
  825. const res = await apiApplyPermission({
  826. company_name: customer_info.company_name,
  827. real_name: customer_info.name,
  828. source: 5,
  829. from_page: '问答社区'
  830. })
  831. if (res.code === 200) {
  832. uni.showToast({
  833. title:'您已提交过申请,请耐心等待',
  834. icon:'none'
  835. })
  836. uni.redirectTo({url: `/pages-question/answerDetail?id=${community_question_id}`})
  837. }
  838. }
  839. }
  840. },
  841. // 终止问答
  842. async handleConfirmStopQuestion(){
  843. console.log('stop question');
  844. if(!this.stopQuestion.reason){
  845. uni.showToast({
  846. title:"请填写终止理由",
  847. icon:"none"
  848. })
  849. return
  850. }
  851. const res=await apiQuestionStop({
  852. community_question_id:this.questionItem.community_question_id,
  853. reason:this.stopQuestion.reason
  854. })
  855. if(res.code===200){
  856. uni.showToast({
  857. title:"成功终止",
  858. icon:"success"
  859. })
  860. setTimeout(() => {
  861. uni.navigateBack({
  862. delta:1,
  863. fail(){
  864. uni.switchTab({
  865. url: '/pages/question/question'
  866. })
  867. }
  868. })
  869. }, 1500);
  870. }
  871. }
  872. },
  873. };
  874. </script>
  875. <style scoped lang="scss">
  876. .flex-column {
  877. display: flex;
  878. flex-direction: column;
  879. }
  880. .answerdetail-page {
  881. padding: 50rpx 30rpx 0 30rpx;
  882. height: calc(100vh - calc(50px + env(safe-area-inset-bottom)));
  883. box-sizing: border-box;
  884. .question-wrap {
  885. .question-item::after {
  886. height: 0;
  887. }
  888. }
  889. .record-wrap {
  890. margin: 0 -30rpx;
  891. flex: 1;
  892. .record {
  893. flex: 1;
  894. justify-content: center;
  895. align-items: center;
  896. .no-record {
  897. text-align: center;
  898. color: #999999ff;
  899. font-size: 28rpx;
  900. // height:130rpx;
  901. image {
  902. width: 94rpx;
  903. }
  904. .black-btn{
  905. width: 100%;
  906. height: 80rpx;
  907. line-height: 80rpx;
  908. background: #333333;
  909. box-shadow: 0px 4rpx 20rpx rgba(160, 126, 84, 0.25);
  910. border-radius: 40rpx;
  911. color: #E3B377;
  912. text-align: center;
  913. font-size: 32rpx;
  914. }
  915. }
  916. /* .record-time {
  917. justify-self: flex-end;
  918. font-size: 60rpx;
  919. } */
  920. .recode-image {
  921. width: 100%;
  922. height: 100%;
  923. background-color: #fafafaff;
  924. display: flex;
  925. align-items: center;
  926. .scroll-view {
  927. width: 100%;
  928. white-space: nowrap;
  929. ::-webkit-scrollbar{
  930. width:0;
  931. height:0;
  932. display:none;
  933. color:transparent;
  934. }
  935. image {
  936. width: 421rpx;
  937. height: 100rpx;
  938. margin-right: 6rpx;
  939. }
  940. }
  941. }
  942. }
  943. .record-tool {
  944. justify-content: center;
  945. align-items: center;
  946. border-top: 1rpx solid #e6e6e6ff;
  947. height: 400rpx;
  948. position: relative;
  949. .hint {
  950. color: #ee3636ff;
  951. font-size: 28rpx;
  952. position: absolute;
  953. top: 50rpx;
  954. }
  955. .record-time{
  956. font-size: 60rpx;
  957. }
  958. .record-btn-wrap {
  959. margin-top: 38rpx;
  960. display: flex;
  961. width: 100%;
  962. justify-content: space-around;
  963. align-items: center;
  964. &.center {
  965. justify-content: center;
  966. }
  967. text {
  968. color: #999999ff;
  969. font-size: 32rpx;
  970. &.active {
  971. color: #ee3636ff;
  972. }
  973. }
  974. .switch {
  975. width: 118rpx;
  976. height: 118rpx;
  977. padding: 12rpx;
  978. box-sizing: border-box;
  979. border-radius: 50%;
  980. border: 1rpx solid #ee3636ff;
  981. /* background-color: rgb(68, 46, 46); */
  982. position: relative;
  983. display: flex;
  984. align-items: center;
  985. justify-content: center;
  986. image {
  987. position: absolute;
  988. width: 36rpx;
  989. z-index: 5;
  990. }
  991. &::after {
  992. content: "";
  993. display: inline-block;
  994. width: 100%;
  995. height: 100%;
  996. border-radius: 50%;
  997. background-color: #ee3636ff;
  998. }
  999. }
  1000. }
  1001. }
  1002. .record-play {
  1003. margin: 20rpx 30rpx;
  1004. .audio-wrap {
  1005. background-color: #fdf8f2ff;
  1006. padding: 30rpx;
  1007. border-radius: 16rpx;
  1008. }
  1009. .play {
  1010. display: flex;
  1011. justify-content: space-between;
  1012. .slider-box {
  1013. margin-left: 15rpx;
  1014. flex: 1;
  1015. slider {
  1016. margin: 15rpx 0 0 0;
  1017. }
  1018. .slider-time {
  1019. display: flex;
  1020. justify-content: space-between;
  1021. text {
  1022. color: #999999ff;
  1023. font-size: 22rpx;
  1024. }
  1025. }
  1026. }
  1027. }
  1028. .audio-delete {
  1029. margin-top: 20rpx;
  1030. width: 100%;
  1031. height: 40rpx;
  1032. display: flex;
  1033. justify-content: flex-end;
  1034. align-items: center;
  1035. image {
  1036. height: 40rpx;
  1037. }
  1038. text {
  1039. margin-left: 10rpx;
  1040. color: #999999ff;
  1041. font-size: 28rpx;
  1042. }
  1043. }
  1044. .audio-pub {
  1045. margin-top: 120rpx;
  1046. background-color: #e6b77dff;
  1047. color: #fff;
  1048. height: 80rpx;
  1049. line-height: 80rpx;
  1050. border-radius: 40rpx;
  1051. text-align: center;
  1052. position: relative;
  1053. width: 390rpx;
  1054. left: 50%;
  1055. margin-left: -170rpx;
  1056. &.disable{
  1057. background-color:#999999ff;
  1058. color: #fff;
  1059. }
  1060. }
  1061. }
  1062. }
  1063. }
  1064. </style>