addVoice.vue 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. <template>
  2. <view class="add-voice-page">
  3. <van-field
  4. :value="form.title"
  5. placeholder="请输入语音标题"
  6. :border="false"
  7. clearable
  8. @change="inputChange"
  9. label="语音标题"
  10. />
  11. <van-field
  12. :value="form.variety_name"
  13. placeholder="请选择品种"
  14. :border="false"
  15. readonly
  16. is-link
  17. label="品种"
  18. @click-input="showFilter=true"
  19. @click-icon="showFilter=true"
  20. />
  21. <van-field
  22. :value="form.section_name"
  23. placeholder="请选择板块名称"
  24. :border="false"
  25. readonly
  26. is-link
  27. label="板块名称"
  28. @click-input="showFilter=true"
  29. @click-icon="showFilter=true"
  30. />
  31. <van-field
  32. :value="form.central_arguments"
  33. placeholder="请输入文字"
  34. :border="false"
  35. clearable
  36. @change="inputChangeArgument"
  37. type="textarea"
  38. label="核心观点"
  39. :autosize="{minHeight:50,maxHeight:100}"
  40. />
  41. <!-- 上传图片部分 -->
  42. <view
  43. class="flex upload-img-box"
  44. v-if="recorderStatus!=='doing'&&recorderStatus!=='pause'"
  45. :style="[{'border-bottom':recorderStatus==='stop'?'1px solid #E6E6E6':''}]"
  46. >
  47. <view class="item" v-for="(item,index) in imgList" :key="item" @click="handlePreViewImg(item)">
  48. <image :src="item" mode="aspectFill"/>
  49. <view class="del-btn" @click.stop="handleDelImg(index)">
  50. <van-icon name="cross" size="12" style="position: absolute;left:16rpx;top:8rpx" color="#ffffff"/>
  51. </view>
  52. </view>
  53. <view class="item add-btn" @click="handleUploadImg" v-if="imgList.length<5">
  54. <image src="./static/camera.png" mode="aspectFill" />
  55. </view>
  56. </view>
  57. <view class="flex audio-box" v-if="recorderStatus==='stop'">
  58. <image
  59. :src="temAudio.paused?'../../../static/voice/pause.png':'../../../static/voice/playing.png'"
  60. mode="aspectFill"
  61. @click="handlePlayAudio"
  62. />
  63. <slider
  64. activeColor="#E6B77D"
  65. :max="temAudio.duration"
  66. :value="temAudio.curTime"
  67. @change="handleAudioSliderChange($event)"
  68. block-size="12"
  69. class="slider"
  70. />
  71. <text class="left-time">{{temAudio.curTime|formatTime}}</text>
  72. <text class="right-time">{{temAudio.duration|formatTime}}</text>
  73. <view class="del-btn" @click="handleDelRecord">
  74. <image src="./static/del.png" mode="aspectFill" />
  75. <text>删除</text>
  76. </view>
  77. <view class="pre_publish_time" v-if="voiceId!=0">定时发布时间:{{pre_publish_time}}</view>
  78. </view>
  79. <!-- <view class="empty-voice-box" v-if="recorderStatus==='start'">
  80. <image src="./static/record.png" mode="aspectFill" />
  81. <view>无录音(录音时长超过十分钟自动结束)</view>
  82. </view> -->
  83. <view class="animat-box" v-if="recorderStatus==='doing'||recorderStatus==='pause'">
  84. <view class="con-box">
  85. <image :class="['img move1',recorderStatus==='doing'?'animat-run':'animat-pause']" src="./static/record-img.png" mode="widthFix" />
  86. <image :class="['img move2',recorderStatus==='doing'?'animat-run':'animat-pause']" src="./static/record-img.png" mode="widthFix" />
  87. <image :class="['img move3',recorderStatus==='doing'?'animat-run':'animat-pause']" src="./static/record-img.png" mode="widthFix" />
  88. </view>
  89. <view class="bot-text">{{time|formatTime}}</view>
  90. </view>
  91. <view class="sound-record-wrap" v-if="recorderStatus!=='stop'">
  92. <view class="top-text" v-show="recorderStatus=='start'">点击开始录音</view>
  93. <image class="btn" :src="btnImg" mode="aspectFill" @click="handleClickBtn" />
  94. <view
  95. class="del-btn"
  96. :style="{color:recorderStatus==='doing'&&'#999'}"
  97. v-if="recorderStatus!=='start'"
  98. @click="handleResetRecorder"
  99. >删除</view>
  100. <view
  101. class="done-btn"
  102. v-if="recorderStatus!=='start'"
  103. @click="handleEndRecorder"
  104. >完成</view>
  105. <view style="text-align:center;color:#999;margin-top:44rpx" v-if="recorderStatus==='start'">无录音(录音时长超过十分钟自动结束)</view>
  106. </view>
  107. <view class="publish-btn" v-if="recorderStatus==='stop'">
  108. <text @click="handlePublish('time')">定时发布</text>
  109. <text @click="handlePublish">立即发布</text>
  110. </view>
  111. <!-- 筛选弹窗 -->
  112. <van-popup
  113. :show="showFilter"
  114. position="bottom"
  115. :close-on-click-overlay="true"
  116. @close="showFilter = false"
  117. round
  118. >
  119. <view class="fliter-wrap-list">
  120. <view class="flex top">
  121. <text style="color:#000">全部选项</text>
  122. <text style="color:#E3B377" @click="showFilter=false">取消</text>
  123. </view>
  124. <van-tree-select
  125. :items="options"
  126. :main-active-index="mainActiveIndex"
  127. :active-id="activeId"
  128. @click-nav="onClickNav"
  129. @click-item="onClickItem"
  130. main-active-class="main-active-class"
  131. content-active-class="content-active-class"
  132. />
  133. </view>
  134. </van-popup>
  135. <!-- 选择时间弹窗 -->
  136. <van-popup
  137. :show="showTime"
  138. position="bottom"
  139. :close-on-click-overlay="true"
  140. @close="showTime = false"
  141. round
  142. >
  143. <van-datetime-picker
  144. title="设置发布时间"
  145. type="datetime"
  146. :value="selectTime"
  147. :min-date="minDate"
  148. @confirm="handleConfirmTime"
  149. @cancel="showTime = false"
  150. />
  151. </van-popup>
  152. <!-- <van-dialog id="van-dialog" /> -->
  153. <!-- 发布弹窗 -->
  154. <van-dialog
  155. use-slot
  156. :show="showPublish"
  157. confirm-button-text="发布且推送"
  158. cancel-button-text="仅发布"
  159. show-cancel-button
  160. @confirm="handleConfirmPublish(1)"
  161. @cancel="handleConfirmPublish(0)"
  162. @close="showPublish=false"
  163. >
  164. <view style="padding:40px 20px 20px;text-align:center;position: relative;">
  165. 发布后将推送模板消息和客群,确认发布吗?
  166. <van-icon name="cross" size="20" style="position: absolute;right:10px;top:10px" color="#6666" @click="showPublish=false"/>
  167. </view>
  168. </van-dialog>
  169. <!-- 定时发布提示弹窗 -->
  170. <van-dialog
  171. use-slot
  172. :show="showTimeAttention"
  173. confirm-button-text="知道了"
  174. confirm-button-color="#E3B377"
  175. @confirm="showTime=true"
  176. @close="showTimeAttention=false,showTime=true"
  177. >
  178. <view style="padding:40px 20px 20px;text-align:center;position: relative;">
  179. 设置定时发布后,会在设定的时间发布语音播报并推送模板消息
  180. <van-icon name="cross" size="20" style="position: absolute;right:10px;top:10px" color="#666" @click="showTimeAttention=false,showTime=true"/>
  181. </view>
  182. </van-dialog>
  183. </view>
  184. </template>
  185. <script>
  186. import {apiVoiceSectionList,apiVoiceSendMsg,apiVoiceAdd,apiVoiceEdit,apiVoicePublish,apiVoiceDetail} from '@/api/voice'
  187. import {baseApiUrl} from '@/utils/config.js'
  188. import {apiGetSceneToParams} from '@/api/common'
  189. import CryptoJS from '@/utils/crypto.js'
  190. import uniAsync from "@/utils/uni-async.js"; // uni api async 化
  191. import {uploadImg,commonUploadAudio} from '@/utils/upload'
  192. const dayjs=require('@/utils/dayjs.min')
  193. const recorderManager = wx.getRecorderManager();//录音实例
  194. let innerAudioContext = uni.createInnerAudioContext();//播放音频实例
  195. let TIMER=null//计时器
  196. export default {
  197. filters:{
  198. formatTime(e){
  199. let m=parseInt(e/60)
  200. let s=parseInt(e%60)
  201. return `${m>9?m:'0'+m}:${s>9?s:'0'+s}`
  202. }
  203. },
  204. computed:{
  205. btnImg(){
  206. if(this.recorderStatus==='start'){
  207. return './static/voice-start.png'
  208. }else if(this.recorderStatus==='doing'){
  209. return './static/voice-doing.png'
  210. }else if(this.recorderStatus==='stop'){
  211. return './static/voice-pause.png'
  212. }else if(this.recorderStatus==='pause'){
  213. return './static/voice-pause.png'
  214. }
  215. }
  216. },
  217. data() {
  218. return {
  219. form:{
  220. title:'',//语音标题
  221. variety_name:'',
  222. variety_id:'',
  223. section_id:'',
  224. section_name:'',
  225. img_url:'',//分享时的底图
  226. central_arguments:'',//核心观点
  227. },
  228. voiceId:0,
  229. voiceUrl:'',//编辑音频地址
  230. pre_publish_time:'',
  231. recorderStatus:'start',//当前录音状态 start开始 doing正在录音 stop停止录音 pause录音暂停
  232. time:0,
  233. isReset:false,//是否点击了重置
  234. temAudio:{
  235. url:'',//音频地址
  236. duration:'',//时长
  237. size:'',//大小
  238. curTime:0,//播放时当前播放的时间
  239. paused:true,
  240. },//临时音频文件信息
  241. showFilter:false,
  242. options:[],
  243. mainActiveIndex:0,
  244. activeId:0,//选择的板块id
  245. showPublish:false,
  246. imgList:[],
  247. showTime:false,
  248. showTimeAttention:false,
  249. selectTime:new Date().getTime(),
  250. minDate:new Date().getTime()+600000,
  251. }
  252. },
  253. onLoad(options){
  254. // 调取用户授权使用麦克风
  255. uni.authorize({
  256. scope: 'scope.record',
  257. success() {}
  258. })
  259. this.listenVoice()
  260. this.getOptionsList()
  261. this.init(options)
  262. },
  263. onShow(){
  264. innerAudioContext = uni.createInnerAudioContext()
  265. this.listenAudio()
  266. },
  267. onHide(){
  268. innerAudioContext.destroy()
  269. this.temAudio.paused=true
  270. },
  271. onUnload(){
  272. innerAudioContext.destroy()
  273. clearInterval(TIMER)
  274. },
  275. methods: {
  276. async init(options){
  277. if(options.scene){
  278. const res=await apiGetSceneToParams({scene_key:options.scene})
  279. if(res.code===200){
  280. const obj=JSON.parse(res.data)
  281. this.voiceId=Number(obj.voiceId)
  282. this.getVoiceDetail()
  283. }
  284. }else if(options.voiceId){
  285. this.voiceId=Number(options.voiceId)
  286. this.getVoiceDetail()
  287. }
  288. },
  289. //语音详情
  290. async getVoiceDetail(){
  291. uni.setNavigationBarTitle({ title: '编辑语音' })
  292. const res=await apiVoiceDetail({broadcast_id:Number(this.voiceId)})
  293. if(res.code===200){
  294. this.form.title=res.data.BroadcastName
  295. this.form.variety_name=res.data.VarietyName
  296. this.form.variety_id=res.data.VarietyId
  297. this.form.section_id=res.data.SectionId
  298. this.form.section_name=res.data.SectionName
  299. this.voiceUrl=res.data.VoiceUrl
  300. this.temAudio.url=res.data.VoiceUrl
  301. this.temAudio.duration=res.data.VoicePlaySeconds
  302. this.temAudio.size=res.data.VoiceSize
  303. this.activeId=res.data.SectionId
  304. this.imgList=res.data.Imgs||[]
  305. this.pre_publish_time=dayjs(res.data.PrePublishTime).format('YYYY-MM-DD HH:mm')
  306. this.selectTime=dayjs(res.data.PrePublishTime).valueOf()
  307. this.recorderStatus='stop'
  308. this.form.central_arguments=res.data.CentralArguments
  309. }
  310. },
  311. //录音事件
  312. listenVoice(){
  313. recorderManager.onStart(()=>{
  314. //录音开始监听事件
  315. console.log('开始录音');
  316. this.recorderStatus='doing'
  317. this.isReset=false
  318. if(!TIMER){
  319. TIMER=setInterval(() => {
  320. this.time++
  321. }, 1000);
  322. }
  323. })
  324. recorderManager.onPause(()=>{
  325. //录音暂停监听事件
  326. console.log('录音暂停');
  327. this.recorderStatus='pause'
  328. clearInterval(TIMER)
  329. TIMER=null
  330. })
  331. recorderManager.onResume(()=>{
  332. //录音继续监听事件
  333. console.log('录音继续');
  334. this.recorderStatus='doing'
  335. if(!TIMER){
  336. TIMER=setInterval(() => {
  337. this.time++
  338. }, 1000);
  339. }
  340. })
  341. recorderManager.onStop((e)=>{
  342. //录音结束监听事件
  343. console.log('录音结束',e);
  344. // 如果是点击重置(删除按钮)的 则不做结束处理
  345. if(!this.isReset){
  346. this.recorderStatus='stop'
  347. this.temAudio.url=e.tempFilePath
  348. this.temAudio.size=e.fileSize
  349. this.temAudio.duration=parseInt(e.duration/1000)
  350. }
  351. clearInterval(TIMER)
  352. TIMER=null
  353. })
  354. recorderManager.onError((e)=>{
  355. //录音事件错误监听
  356. console.log('录音错误哦',e);
  357. })
  358. },
  359. //点击录音操作按钮
  360. async handleClickBtn(){
  361. const setRes=await uniAsync.getSetting()
  362. console.log(setRes.authSetting['scope.record']);
  363. if(!setRes.authSetting['scope.record']){
  364. uni.showToast({
  365. title:'请打开麦克风交流',
  366. icon:'none'
  367. })
  368. uni.openSetting()
  369. return
  370. }
  371. if(this.recorderStatus==='start'){
  372. recorderManager.start({
  373. duration:600000,
  374. format:'mp3'
  375. })
  376. }
  377. if(this.recorderStatus==='doing'){
  378. recorderManager.pause()//暂停录音
  379. }
  380. if(this.recorderStatus==='pause'){
  381. recorderManager.resume()//继续录音
  382. }
  383. },
  384. //点击重置录音状态
  385. handleResetRecorder(){
  386. if(this.recorderStatus==='doing') return
  387. this.isReset=true
  388. recorderManager.stop()
  389. this.recorderStatus='start'
  390. this.handleDelRecord()
  391. },
  392. //点击完成录音
  393. handleEndRecorder(){
  394. //点击完成时还不是已结束录音状态
  395. this.isReset=false
  396. recorderManager.stop()
  397. },
  398. //拖动音频播放进度条
  399. handleAudioSliderChange(e){
  400. const value=e.detail.value
  401. innerAudioContext.seek(value)
  402. },
  403. //点击播放\暂停音频
  404. handlePlayAudio(){
  405. innerAudioContext.src=this.temAudio.url
  406. innerAudioContext.obeyMuteSwitch=false
  407. if(this.temAudio.paused){
  408. innerAudioContext.play()
  409. }else{
  410. innerAudioContext.pause()
  411. }
  412. },
  413. //音频播放事件
  414. listenAudio(){
  415. innerAudioContext.onPlay(()=>{
  416. console.log('开始播放录音');
  417. this.temAudio.paused=false
  418. })
  419. innerAudioContext.onPause(()=>{
  420. console.log('录音播放暂停');
  421. this.temAudio.paused=true
  422. })
  423. // innerAudioContext.onStop(()=>{
  424. // console.log('录音播放停止');
  425. // this.temAudio.paused=true
  426. // innerAudioContext.src=''
  427. // })
  428. innerAudioContext.onEnded(()=>{
  429. console.log('录音播放自然结束');
  430. this.temAudio.curTime=this.temAudio.duration
  431. setTimeout(() => {
  432. this.temAudio.paused=true
  433. innerAudioContext.src=''
  434. this.temAudio.curTime=0
  435. }, 300);
  436. })
  437. innerAudioContext.onTimeUpdate(()=>{
  438. this.temAudio.curTime=parseInt(innerAudioContext.currentTime)
  439. })
  440. },
  441. //删除录音记录
  442. handleDelRecord(){
  443. this.recorderStatus='start'
  444. this.isReset=true
  445. this.temAudio.url=''
  446. this.temAudio.duration=''
  447. this.temAudio.curTime=0
  448. this.temAudio.paused=true
  449. this.time=0
  450. innerAudioContext.stop()
  451. TIMER=null
  452. },
  453. //获取选项数据
  454. async getOptionsList(){
  455. const res=await apiVoiceSectionList()
  456. if(!res.code===200) return
  457. const arr=res.data||[]
  458. this.options=arr.filter(item=>{
  459. item.text=item.VarietyName
  460. item.children=item.Children.filter(_item=>{
  461. if(_item.Status===1){
  462. _item.text=_item.SectionName
  463. _item.id=_item.SectionId
  464. return _item
  465. }
  466. })
  467. if(item.children.length>0){
  468. delete item.Children
  469. return item
  470. }
  471. })
  472. },
  473. onClickNav({detail}){
  474. console.log(detail);
  475. this.mainActiveIndex=detail.index
  476. },
  477. onClickItem({detail}){
  478. console.log(detail);
  479. this.activeId=detail.id
  480. this.form.section_id=detail.SectionId
  481. this.form.section_name=detail.SectionName
  482. this.form.variety_name=this.options[this.mainActiveIndex].VarietyName
  483. this.form.variety_id=this.options[this.mainActiveIndex].VarietyId
  484. this.form.img_url=detail.ImgUrl
  485. this.showFilter=false
  486. },
  487. inputChange(event) {
  488. this.form.title=event.detail
  489. },
  490. inputChangeArgument(event){
  491. this.form.central_arguments=event.detail
  492. },
  493. // 发布
  494. async handlePublish(type){
  495. if(!this.form.title||!this.form.variety_id){
  496. uni.showToast({
  497. title:'请将内容填写完整',
  498. icon:'none'
  499. })
  500. return
  501. }
  502. if(type==='time'){//定时发布
  503. this.showTimeAttention=true
  504. }else{
  505. this.showPublish=true
  506. }
  507. },
  508. //确认发布 publishType 发布类型: 0-仅发布 1-发布并推送 2-定时发布
  509. async handleConfirmPublish(publishType){
  510. //上传音频
  511. if(this.temAudio.url!=this.voiceUrl){
  512. const voiceRes=await commonUploadAudio(this.temAudio.url)
  513. if(voiceRes.code===200){
  514. this.temAudio.url=voiceRes.data.audio_url
  515. }
  516. }
  517. //新增、编辑语音
  518. let params={
  519. broadcast_name:this.form.title,
  520. section_id:Number(this.form.section_id),
  521. section_name:this.form.section_name,
  522. variety_id:Number(this.form.variety_id),
  523. variety_name:this.form.variety_name,
  524. author_id:Number(this.$store.state.user.userInfo.user_id),
  525. author:this.$store.state.user.userInfo.real_name,
  526. imgs:this.imgList.join(','),
  527. voice_seconds:this.temAudio.duration.toString(),
  528. voice_size:this.temAudio.size.toString(),
  529. voice_url:this.temAudio.url,
  530. central_arguments:this.form.central_arguments
  531. }
  532. wx.showLoading({
  533. title: '发布中...',
  534. mask: true,
  535. success: (result) => {},
  536. fail: () => {},
  537. complete: () => {}
  538. });
  539. let addRes=null
  540. if(this.voiceId!=0){//编辑语音
  541. params.broadcast_id=this.voiceId
  542. addRes=await apiVoiceEdit(params)
  543. }else{
  544. addRes=await apiVoiceAdd(params)
  545. }
  546. if(addRes.code===200){
  547. let par={
  548. broadcast_id:addRes.data.BroadcastId,
  549. }
  550. if(publishType===2){//定时发布
  551. par.publish_type=2
  552. par.pre_publish_time=dayjs(this.selectTime).format('YYYY-MM-DD HH:mm:ss')
  553. }else{
  554. par.publish_type=1
  555. }
  556. //发布语音
  557. const publishRes=await apiVoicePublish(par)
  558. wx.hideLoading();
  559. if(publishRes.code===200){
  560. if(publishType==0){//仅发布
  561. uni.showToast({
  562. title:'发布成功',
  563. icon:'success'
  564. })
  565. setTimeout(() => {
  566. uni.$emit('addVoiceSuccess')
  567. uni.navigateBack()
  568. }, 1000);
  569. }else if(publishType==1){//发布并推送
  570. this.handleSendMsg(addRes.data.BroadcastId)
  571. }else{////定时发布
  572. uni.showToast({
  573. title:'定时发布成功',
  574. icon:'success'
  575. })
  576. setTimeout(() => {
  577. uni.$emit('addVoiceSuccess')
  578. uni.navigateBack()
  579. }, 1000);
  580. }
  581. }else{
  582. uni.showToast({
  583. title:publishRes.msg,
  584. icon:'none'
  585. })
  586. }
  587. }else{
  588. wx.hideLoading();
  589. uni.showToast({
  590. title:addRes.msg,
  591. icon:'none'
  592. })
  593. }
  594. },
  595. //推送消息
  596. handleSendMsg(id){
  597. apiVoiceSendMsg({broadcast_id:id}).then(res=>{
  598. if(res.code===200){
  599. uni.showToast({
  600. title:"发布&推送成功",
  601. icon:'success'
  602. })
  603. setTimeout(() => {
  604. uni.$emit('addVoiceSuccess')
  605. uni.navigateBack()
  606. }, 1000);
  607. }
  608. })
  609. },
  610. //图片上传
  611. handleUploadImg(e){
  612. uploadImg({count:5-this.imgList.length}).then(res=>{
  613. this.imgList=[...this.imgList,...res]
  614. }).catch(err=>{
  615. console.log(err);
  616. if(err.errMsg=='chooseImage:fail cancel') return
  617. uni.showToast({
  618. title:'上传失败,请重试!',
  619. icon:'none'
  620. })
  621. })
  622. },
  623. //预览图片
  624. handlePreViewImg(item){
  625. wx.previewImage({
  626. urls:this.imgList,
  627. current:item
  628. })
  629. },
  630. //删除图片
  631. handleDelImg(index){
  632. this.imgList.splice(index,1)
  633. },
  634. //选择时间
  635. handleConfirmTime(e){
  636. this.selectTime=e.detail
  637. this.showTime=false
  638. this.handleConfirmPublish(2)
  639. },
  640. },
  641. }
  642. </script>
  643. <style lang="scss">
  644. .add-voice-page .van-cell{
  645. border-bottom: 1px solid #e5e5e5;
  646. }
  647. .add-voice-page .van-field__label{
  648. font-size: 32rpx;
  649. color: #333;
  650. }
  651. /* .add-voice-page .van-cell__title{
  652. max-width: 6.2em;
  653. min-width: 6.2em;
  654. margin-right: 12px;
  655. font-size: 32rpx;
  656. color: #333;
  657. } */
  658. .add-voice-page .van-cell__value{
  659. text-align: left;
  660. font-size: 32rpx;
  661. }
  662. .add-voice-page{
  663. .fliter-wrap-list{
  664. background-color: #fff;
  665. padding-top: 53rpx;
  666. .top{
  667. font-size: 32rpx;
  668. justify-content: space-between;
  669. margin-bottom: 40rpx;
  670. padding: 0 34rpx;
  671. }
  672. .van-sidebar{
  673. flex-shrink: 0;
  674. }
  675. .van-tree-select__content{
  676. overflow-x: hidden;
  677. }
  678. .main-active-class{
  679. border-color: #E3B377;
  680. }
  681. .content-active-class{
  682. color: #E3B377;
  683. }
  684. }
  685. }
  686. page{
  687. padding-bottom:constant(safe-area-inset-bottom);
  688. padding-bottom:env(safe-area-inset-bottom);
  689. }
  690. </style>
  691. <style lang="scss" scoped>
  692. .add-voice-page{
  693. .empty-voice-box{
  694. height: 36vh;
  695. padding-top: 150rpx;
  696. image{
  697. width: 140rpx;
  698. height: 140rpx;
  699. margin-bottom: 20rpx;
  700. }
  701. text-align: center;
  702. color: #999999;
  703. }
  704. .sound-record-wrap{
  705. border-top: 1px solid #E6E6E6;
  706. padding-top: 126rpx;
  707. position: relative;
  708. .top-text{
  709. text-align: center;
  710. color: #EE3636;
  711. position: absolute;
  712. top: 50rpx;
  713. left: 50%;
  714. transform: translateX(-50%);
  715. }
  716. .btn{
  717. width: 118rpx;
  718. height: 118rpx;
  719. display: block;
  720. margin-left: auto;
  721. margin-right: auto;
  722. }
  723. .del-btn{
  724. position: absolute;
  725. left: 122rpx;
  726. bottom: 40rpx;
  727. font-size: 32rpx;
  728. color: #EE3636;
  729. }
  730. .done-btn{
  731. position: absolute;
  732. right: 122rpx;
  733. bottom: 40rpx;
  734. font-size: 32rpx;
  735. color: #EE3636;
  736. }
  737. }
  738. .audio-box{
  739. background-color: #FDF8F2;
  740. height: 123rpx;
  741. align-items: center;
  742. margin-left: 34rpx;
  743. margin-right: 34rpx;
  744. margin-top: 60rpx;
  745. margin-bottom: 180rpx;
  746. padding: 0 30rpx;
  747. position: relative;
  748. border-radius: 16rpx;
  749. .left-time{
  750. position: absolute;
  751. bottom: 20rpx;
  752. left: 100rpx;
  753. color: #999999;
  754. font-size: 20rpx;
  755. }
  756. .right-time{
  757. position: absolute;
  758. bottom: 20rpx;
  759. right: 40rpx;
  760. color: #999999;
  761. font-size: 20rpx;
  762. }
  763. image{
  764. width: 40rpx;
  765. height: 48rpx;
  766. flex-shrink: 0;
  767. margin-right: 30rpx;
  768. }
  769. .slider{
  770. flex: 1;
  771. margin: 0 10rpx;
  772. }
  773. .del-btn{
  774. display: flex;
  775. align-items: center;
  776. color: #999999;
  777. font-size: 28rpx;
  778. position: absolute;
  779. bottom: -50rpx;
  780. right: 0;
  781. image{
  782. width: 32rpx;
  783. height: 35rpx;
  784. margin-right: 10rpx;
  785. }
  786. }
  787. .pre_publish_time{
  788. position: absolute;
  789. bottom: -50rpx;
  790. left: 0;
  791. color: #999999;
  792. }
  793. }
  794. .publish-btn{
  795. // width: 390rpx;
  796. // height: 80rpx;
  797. // text-align: center;
  798. // line-height: 80rpx;
  799. // color: #fff;
  800. // background: #E6B77D;
  801. // font-size: 32rpx;
  802. // border-radius: 40px;
  803. // margin-left: auto;
  804. // margin-right: auto;
  805. text-align: center;
  806. text{
  807. width: 300rpx;
  808. height: 80rpx;
  809. text-align: center;
  810. line-height: 80rpx;
  811. display: inline-block;
  812. font-size: 32rpx;
  813. margin: 0 15rpx;
  814. border-radius: 40rpx;
  815. }
  816. text:first-child{
  817. border: 1px solid #E6B77D;
  818. color: #E6B77D;
  819. }
  820. text:last-child{
  821. background-color: #E6B77D;
  822. color: #fff;
  823. }
  824. }
  825. .upload-img-box{
  826. padding: 34rpx 4rpx 34rpx 34rpx;
  827. flex-wrap: wrap;
  828. // height: 50vh;
  829. align-content: flex-start;
  830. .item{
  831. width: 200rpx;
  832. height: 200rpx;
  833. margin-right: 30rpx;
  834. margin-bottom: 30rpx;
  835. flex-shrink: 0;
  836. position: relative;
  837. image{
  838. width: 100%;
  839. height: 100%;
  840. }
  841. .del-btn{
  842. position: absolute;
  843. right: 0;
  844. top: 0;
  845. width: 48rpx;
  846. height: 48rpx;
  847. background-color: rgba(0, 0, 0, 0.7);
  848. border-radius: 0 0 0 48rpx;
  849. }
  850. }
  851. .add-btn{
  852. background-color: #f7f7f7;
  853. image{
  854. width: 80rpx;
  855. height: 80rpx;
  856. position: absolute;
  857. left: 60rpx;
  858. top: 60rpx;
  859. }
  860. }
  861. }
  862. }
  863. .animat-box{
  864. height: 30vh;
  865. width:100vw;
  866. overflow-x: hidden;
  867. .con-box{
  868. height: 70%;
  869. background-color: #FAFAFA;
  870. position: relative;
  871. }
  872. .bot-text{
  873. font-size: 60rpx;
  874. padding-top: 36rpx;
  875. text-align: center;
  876. }
  877. .img{
  878. position: absolute;
  879. width: 100vw;
  880. top: 27%;
  881. transform: translateX(100vw);
  882. }
  883. .move1{
  884. animation: move 30s linear infinite;
  885. }
  886. .move2{
  887. animation: move 30s 10s linear infinite;
  888. }
  889. .move3{
  890. animation: move 30s 20s linear infinite;
  891. }
  892. .animat-pause{
  893. animation-play-state: paused;
  894. }
  895. .animat-run{
  896. animation-play-state: running;
  897. }
  898. @keyframes move {
  899. 0%{
  900. transform: translateX(100vw);
  901. }
  902. 100%{
  903. transform: translateX(-200vw);
  904. }
  905. }
  906. }
  907. </style>