主要功能:获取服务器端作业,循环输出作业内容,为每条作业实现录音上传

大坑:点击循环列表中的一个按钮,其他按钮也一起激活。。。找了好多资料。综合各个资料。终于解决这个问题(点击组件,获取点击下标。给每个组件赋值为当前下标,判断点击的下标是否等于当前组件的小标,从而判断点击的哪个组件)

先上大家最关心的js代码:

// pages/audio/audio.js
var common = require('../../utils/util.js'); //获取时间
const app = getApp()
const innerAudioContext = wx.createInnerAudioContext();
Page({

  data: {
    isPlayAudio: false, //暂停播放按钮显示切换
    chooseday: "", //选择日期(通过setData默认为今天)
    choosekemu: "", //选择科目 (通过setData默认为语文)
    kemu: ['语文作业', '数学作业', '英语作业', '其他作业'], //科目列表
    hw_audio_area: [], //需要循环的作业内容
    hw_audio_array: [], //需要循环的临时数组
    index: '', //点击循环数组中元素的下标,表示当前点击了哪个元素
    checkid: -1, //点击“开始录音”按钮的下标。设为-1表示默认未点击
    checkidEnd: -1, //点击“结束录音”按钮的下标。设为-1表示默认未点击
    checkidre: -1, //点击“重新录音”按钮的下标。设为-1表示默认未点击
    name: '', //用户名
    serverPath: '', //服务器端本地路径
    httpPath: '', //服务器端http路径
    /*播放器*/
    audiolist: [{
      audiosrc: '',
    }],
    isPlayAudio: false,
    audioSeek: 0,
    audioDuration: 0,
    showTime1: '00:00',
    showTime2: '00:00',
    audioTime: 0
  },
  onLoad: function() {
    //获取系统日期及用户名
    var today = common.formatTime(new Date()); //获取系统日期,今天
    const name = getApp().globalData.name; //获取全局变量,登录用户名
    this.setData({
      name
    })
    this.setData({
      chooseday: today, //设置默认的日期
      choosekemu: '语文作业', //设置默认的科目
    })
    this.hw_request() //服务器请求函数
  },
  /*选择科目 */
  kemuChange: function(e) {
    this.setData({
      chooseday, //重新设置系统日期为选中的日期
      choosekemu: this.data.kemu[e.detail.value]
    })
    this.hw_request()
  },
  /*选择日期 */
  bindDateChange: function(e) {
    this.setData({
      chooseday: e.detail.value,
      choosekemu //重新设置科目为选中的科目
    })
    this.hw_request()
  },
  // 查询作业服务器请求函数
  hw_request() {
    var that = this
    wx.request({
      url: 'https://www.ailaiyun.com/1.php', //服务器地址
      method: 'post',
      data: {
        type: 'hw_get_audio',
        hw_kemu: that.data.choosekemu,
        today: that.data.chooseday,
      },
      header: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      success(res) {
        // console.log(res.data)
        //如果服务器返回的data值为空表示当天这个科目下没有作业
        if (res.data == null) {
          that.setData({
            hw_audio_area: ''
          })
          wx.showToast({
            title: '今日暂无' + that.data.choosekemu + '(录音)',
            icon: 'none'
          })
        } else {
          var hw_audio_array = that.data.hw_audio_array; // 根据服务器返回的数组组合为新的数组
          var hw_audio_area = that.data.hw_audio_area; // 服务器返回的数组
          for (let i = 0; i < res.data.length; i++) {
            hw_audio_array.push(res.data[i].hw_audio) //提取服务器返回的数组中的需要的对象
            that.setData({
              hw_audio_array
            })
            // console.log(hw_audio_array)
          }
          that.removeEmpty(hw_audio_array) //去除数组中的空值
          var str = String(hw_audio_array); //转换为字符串
          var arr = str.split("^"); //去除旧字符串中的'^'并赋值一个新的字符串
          that.removeEmpty(arr) //再次清除数组中的空值
          //把值存到需要要循环的数组中
          that.setData({
            hw_audio_area: arr
          })
          // console.log(that.data.hw_audio_area)
        }
      },
    })
  },
  /**去除数组中的空值 */
  removeEmpty: function(arr) {
    for (var i = 0; i < arr.length; i++) {
      if (arr[i] == "" || typeof(arr[i]) == "undefined" || arr[i] == ",") {
        arr.splice(i, 1);
        i = i - 1; // i - 1 ,因为空元素在数组下标 2 位置,删除空之后,后面的元素要向前补位
      }
    }
    return arr;
  },
  /*开始录音 */
  start: function(e) {
    // console.log(e)
    // console.log(e.currentTarget.dataset.id)
    var checkid = e.currentTarget.dataset.index //点击开始的按钮的下标
    //控制结束按钮显示
    this.setData({
      checkid: checkid,
      checkidre: checkid,
      checkidEnd: -1
    })
    // console.log(this.data.checkid)
    //启动录音功能
    const recorderManager = wx.getRecorderManager()
    recorderManager.onStart(() => {
      console.log('recorder start')
    })
    recorderManager.onStop((res) => {
      console.log('recorder stop', res)
      const {
        tempFilePath
      } = res
    })
    recorderManager.onFrameRecorded((res) => {
      const {
        frameBuffer
      } = res
      console.log('frameBuffer.byteLength', frameBuffer.byteLength)
    })
    const options = {
      duration: 600000,
      sampleRate: 8000,
      numberOfChannels: 1,
      encodeBitRate: 48000,
      format: 'mp3',
      frameSize: 50
    }
    recorderManager.start(options)
  },

  /**结束录音 */
  stop: function(e) {
    var checkidEnd = e.currentTarget.dataset.index //点击结束录音按钮传出的下标
    //是最后一组上传控件显示出来
    this.setData({
      checkidEnd: checkidEnd,
      checkid: -1
    })
    //结束录音功能
    const recorderManager = wx.getRecorderManager()
    recorderManager.onStop((res) => {
      // console.log(res.tempFilePath)
      this.setData({
        'audiolist[0].audiosrc': res.tempFilePath
      })

    })
    recorderManager.onFrameRecorded((res) => {
      const {
        frameBuffer
      } = res
      console.log('frameBuffer.byteLength', frameBuffer.byteLength)
    })
    const options = {
      duration: 10000,
      sampleRate: 44100,
      numberOfChannels: 1,
      encodeBitRate: 192000,
      format: 'aac',
      frameSize: 50
    }
    recorderManager.stop(options)
  },
  /**重新录制 */
  rere: function(e) {
    //控制“开始录音”按钮重新显示出来
    var checkidre = e.currentTarget.dataset.index
    this.setData({
      checkidre: -1,
      checkidEnd: -1
    })
  },
  /*上传录音 */
  upload: function() {
    var user_id = this.data.name //需要上传的用户名
    var pathAudio = this.data.audiolist[0].audiosrc //需要上传的录音文件路径
    var checkidEnd = this.data.checkidEnd //根据点击的ID判断上传那一条录音作业信息
    var hw = this.data.hw_audio_area[checkidEnd]
    var that = this
    wx.showLoading({
      title: '录音上传中',
      mask: true
    })
    wx.uploadFile({
      url: 'https://www.ailaiyun.com/2.php',
      filePath: pathAudio,
      name: 'file',
      formData: {
        user_id: user_id
      },
      success(res) {
        var data = res.data
        var obj = JSON.parse(data) //把服务器返回的值转换成json格式
        // console.log(obj)
        var httpPath = obj.httpPath
        var serverPath = obj.serverPath
        that.setData({
          httpPath,
          serverPath
        })
        // console.log(that.data.serverPath)
        //把作业信息等数据上传到数据库
        if (res.statusCode == "200") {
          wx.request({
            url: 'https://www.ailaiyun.com/3.php',
            method: "post",
            header: {
              "Content-Type": "application/x-www-form-urlencoded"
            },
            data: {
              type: "addAudioPath",
              name: user_id,
              httpPath: that.data.httpPath,
              serverPath: that.data.serverPath,
              date: that.data.chooseday,
              kemu: that.data.choosekemu,
              hw: hw
            },
            success(res) {
              wx.hideLoading()
              console.log(res.data)
            },
          })
          wx.showToast({
            title: '录音上传成功',
            icon: 'success',
          })
        }
      }
    })
  },
  /**播放器 */
  onShow: function(e) {
    // console.log(e)
    this.Initialization();
    this.loadaudio();
  },
  //初始化播放器,获取duration
  Initialization() {
    var t = this;
    if (this.data.audiolist[0].audiosrc.length != 0) {
      //设置src
      innerAudioContext.src = this.data.audiolist[0].audiosrc;
      //运行一次
      innerAudioContext.play();
      innerAudioContext.pause();
      innerAudioContext.onCanplay(() => {
        //初始化duration
        innerAudioContext.duration
        setTimeout(function() {
          //延时获取音频真正的duration
          var duration = innerAudioContext.duration;
          var min = parseInt(duration / 60);
          var sec = parseInt(duration % 60);
          if (min.toString().length == 1) {
            min = `0${min}`;
          }
          if (sec.toString().length == 1) {
            sec = `0${sec}`;
          }
          t.setData({
            audioDuration: innerAudioContext.duration,
            showTime2: `${min}:${sec}`
          });
        }, 1000)
      })
    }
  },
  //拖动进度条事件
  sliderChange(e) {
    var that = this;
    innerAudioContext.src = this.data.audiolist[0].audiosrc;
    //获取进度条百分比
    var value = e.detail.value;
    this.setData({
      audioTime: value
    });
    var duration = this.data.audioDuration;
    //根据进度条百分比及歌曲总时间,计算拖动位置的时间
    value = parseInt(value * duration / 100);
    //更改状态
    this.setData({
      audioSeek: value,
      isPlayAudio: true
    });
    //调用seek方法跳转歌曲时间
    innerAudioContext.seek(value);
    //播放歌曲
    innerAudioContext.play();
  },
  //播放、暂停按钮
  playAudio() {
    //获取播放状态和当前播放时间
    var isPlayAudio = this.data.isPlayAudio;
    var seek = this.data.audioSeek;
    innerAudioContext.pause();
    //更改播放状态
    this.setData({
      isPlayAudio: !isPlayAudio
    })
    if (isPlayAudio) {
      //如果在播放则记录播放的时间seek,暂停
      this.setData({
        audioSeek: innerAudioContext.currentTime
      });
    } else {
      //如果在暂停,获取播放时间并继续播放
      innerAudioContext.src = this.data.audiolist[0].audiosrc;
      if (innerAudioContext.duration != 0) {
        this.setData({
          audioDuration: innerAudioContext.duration
        });
      }
      //跳转到指定时间播放
      innerAudioContext.seek(seek);
      innerAudioContext.play();
    }
  },
  loadaudio() {
    var that = this;
    //设置一个计步器
    this.data.durationIntval = setInterval(function() {
      //当歌曲在播放时执行
      if (that.data.isPlayAudio == true) {
        //获取歌曲的播放时间,进度百分比
        var seek = that.data.audioSeek;
        var duration = innerAudioContext.duration;
        var time = that.data.audioTime;
        time = parseInt(100 * seek / duration);
        //当歌曲在播放时,每隔一秒歌曲播放时间+1,并计算分钟数与秒数
        var min = parseInt((seek + 1) / 60);
        var sec = parseInt((seek + 1) % 60);
        //填充字符串,使3:1这种呈现出 03:01 的样式
        if (min.toString().length == 1) {
          min = `0${min}`;
        }
        if (sec.toString().length == 1) {
          sec = `0${sec}`;
        }
        var min1 = parseInt(duration / 60);
        var sec1 = parseInt(duration % 60);
        if (min1.toString().length == 1) {
          min1 = `0${min1}`;
        }
        if (sec1.toString().length == 1) {
          sec1 = `0${sec1}`;
        }
        //当进度条完成,停止播放,并重设播放时间和进度条
        if (time >= 100) {
          innerAudioContext.stop();
          that.setData({
            audioSeek: 0,
            audioTime: 0,
            audioDuration: duration,
            isPlayAudio: false,
            showTime1: `00:00`
          });
          return false;
        }
        //正常播放,更改进度信息,更改播放时间信息
        that.setData({
          audioSeek: seek + 1,
          audioTime: time,
          audioDuration: duration,
          showTime1: `${min}:${sec}`,
          showTime2: `${min1}:${sec1}`
        });
      }
    }, 1000);
  },
  onUnload: function() {
    //卸载页面,清除计步器
    clearInterval(this.data.durationIntval);
  }
})

wxml代码:

<!--pages/audio/audio.wxml-->
<view class='choose'>
  <picker mode="selector" range='{{kemu}}' bindchange='kemuChange'>
    <view class='title-ch'>选择科目:{{choosekemu}}</view>
  </picker>
  <picker mode="date" value="{{date}}" start="2019-04-01" end="2029-01-01" bindchange="bindDateChange" value='{{today}}'>
    <view class='now-date'>日期:{{chooseday}}</view>
  </picker>
</view>
<view class='hw'>
  <view class='hw-title'>录音作业</view>
</view>
<scroll-view class='area-content' scroll-y='true'>
  <view wx:for="{{hw_audio_area}}" class="hw_audio_list" wx:key="{{id}}">
    <text class='content'>{{item}}</text>
    <!-- 判断点击的哪个组件 -->
    <block wx:if="{{checkidre == index}}"> 
    </block>
    <block wx:else>
      <view catchtap='start' data-index='{{index}}' class='btn' id='{{index}}'>开始录音</view>
    </block>
    <!-- 判断点击的哪个组件 -->
    <block wx:if="{{checkid == index}}">
      <view catchtap='stop' data-index='{{index}}' class='btn-record' id='{{index}}'><text style='font-size:34rpx'>正在录音</text><text style='color:red;font-weight:bold'>结束录音</text></view>
    </block>
    <block wx:else>
    </block>
    <!-- 判断点击的哪个组件 -->
    <view wx:if='{{checkidEnd == index}}'>
      <view class='last_list'>
        <view catchtap='playAudio' data-id='{{index}}' class='play_the_audio' id='{{index}}'>
        <text wx:if='{{isPlayAudio}}'>暂停</text>
        <text wx:else>播放</text>
        </view>
        <view bindtap='upload' class='upload'>上传</view>
        <view catchtap='rere' data-index='{{index}}' class='rere' id='{{index}}'>重录</view>
      </view>
      <view class='audioControls'>
        <view class='flex'>
          <view class='bottom' catchtap='playAudio' data-id='{{index}}'>
            <!-- 按钮 -->
            <view wx:if="{{isPlayAudio}}">
              <image src='../images/pause.png' />
            </view>
            <view wx:else>
              <image src='../images/play.png' />
            </view>
          </view>
          <view class='slider'>
            <slider bindchange='sliderChange' activeColor='red' block-size="12" value='{{audioTime}}' data-id='{{index}}' />
          </view>
          <view class='time'>
            {{showTime1}}/{{showTime2}}
          </view>
        </view>
      </view>
    </view>
  </view>
</scroll-view>

wxss代码:

/* pages/audio/audio.wxss */

page {
  background-image: url("https://www.ailaiyun.com/xxxxx.jpg");
}

.choose {
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  height: 100rpx;
  margin-top: 30rpx;
}

.title-ch, .now-date {
  background-color: #14a1fd;
  font-size: 30rpx;
  text-align: center;
  height: 50rpx;
  line-height: 40rpx;
  border: 1rpx solid #14a1fd;
  width: 320rpx;
  border-radius: 15rpx;
}

.hw {
  display: flex;
  justify-content: center;
}
.hw-title{
  font-weight: bold;
}
.area-content {
  display: flex;
  width: 95%;
  justify-content: center;
  flex-direction: column;
  margin: 0 auto;
  height: 950rpx;
}

.hw_audio_list {
  margin-top: 20rpx;
  width: 98%;
  display: flex;
  justify-content: center;
  flex-direction: column;
  border: 5rpx solid #14a1fd;
  border-radius: 15rpx;
}

.content {
  color: blue;
  margin: 0 auto;
}

.btn {
  margin: 10rpx auto;
  background-color: #14a1fd;
  width: 200rpx;
  height: 50rpx;
  border: 1rpx solid #14a1fd;
  border-radius: 15rpx;
  text-align: center;
}
.btn-record{
    margin: 10rpx auto;
  background-color: #14a1fd;
  width: 160rpx;
  height: 100rpx;
  border: 1rpx solid #14a1fd;
  border-radius: 15rpx;
  text-align: center;
}
.last_list {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items:center;
}

.play_the_audio {
  margin: 10rpx auto;
  background-color:green;
  width: 140rpx;
  height: 50rpx;
  border: 1rpx solid green;
  border-radius: 15rpx;
  text-align: center;
}

.rere {
  margin: 10rpx auto;
  background-color: orange;
  width: 140rpx;
  height: 50rpx;
  border: 1rpx solid orange;
  border-radius: 15rpx;
  text-align: center;
}

.upload-content {
  width: 100%;
  position: fixed;
  bottom: 50rpx;
  display: flex;
  justify-content: center;
  margin: 0 auto;
}

.upload {
  width: 100rpx;
  background: #14a1fd;
  color: #fff;
  border-radius: 50%;
  height: 100rpx;
  text-align: center;
  line-height: 100rpx;
}

/*音频播放器*/

.flex {
  display: flex;
}

.audioControls {
  margin: 20rpx auto;
  width: 100%;
  height: 80rpx;
  background: green;
  opacity: 0.8;
  bottom: 0;
  color: white;
  font-size: 6pt;
  line-height: 80rpx;
  text-align: center;
}

.audioControls .bottom {
  width: 60rpx;
  height: 100%;
}

.audioControls .bottom image {
  margin-top: 30%;
  margin-left: 30%;
  width: 40rpx;
  height: 40rpx;
}

.audioControls .slider {
  width: 520rpx;
  height: 100%;
}

.slider slider {
  width: 95%;
  margin-left: 4%;
  margin-right: 0;
}

.audioControls .time {
  width: 120rpx;
  height: 100%;
}

PHP后端代码

1.php

//学生查询音频作业
elseif ($type=="hw_get_audio") {
	$post_kemu =$_POST['hw_kemu'];
	$post_today =$_POST['today'];
	$con = mysqli_connect("localhost","xxxxx","xxxxx") or die("数据库连接失败");//连接数据库
	mysqli_query($con,"set names utf8");
	mysqli_select_db($con,"stu") or die("数据库选择失败");
	$sql_search="SELECT hw_audio from hw_text where hw_kemu = '$post_kemu' and hw_date = '$post_today'";
	$result_search = mysqli_query($con,$sql_search);
	while ($row = mysqli_fetch_array($result_search)) {
		$res[] = $row;
	}
		echo json_encode($res);
}

2.php

<?php
 date_default_timezone_set("Asia/Shanghai"); //设置时区
$code = $_FILES['file'];//获取小程序传来的图片
if(is_uploaded_file($_FILES['file']['tmp_name'])) {  
    //把文件转存到你希望的目录(不要使用copy函数)  
    $uploaded_file=$_FILES['file']['tmp_name'];  
    $username = $_POST["user_id"];
    //我们给每个用户动态的创建一个文件夹  
    $user_path=$_SERVER['DOCUMENT_ROOT']."uploadaudio/".$username; 
    //判断该用户文件夹是否已经有这个文件夹  
    if(!file_exists($user_path)) {  
        mkdir($user_path);  
    }  
    $file_true_name=$_FILES['file']['name']; 
    $random = uniqid();
    $move_to_file=$user_path."/".date("Y-m-d")."-".time().$random.substr($file_true_name,strrpos($file_true_name,"."));
    if(move_uploaded_file($uploaded_file,iconv("utf-8","gb2312",$move_to_file))) {  
        $arr=array('httpPath' => "https://".$_SERVER['SERVER_NAME']."/uploadaudio/".$username."/".date("Y-m-d")."-".time().$random.substr($file_true_name,strrpos($file_true_name,".")),'serverPath' => $move_to_file);
        echo json_encode($arr,JSON_UNESCAPED_SLASHES);
    } 
} 
?>

3.php

//上传录音作业
elseif($type == "addAudioPath"){
	function res(){
		$post_name = $_POST["name"];
		$post_date = $_POST["date"];
		$post_kemu = $_POST["kemu"];
		$post_serverPath = $_POST["serverPath"];
		$post_httpPath = $_POST["httpPath"];
		$post_hw = $_POST["hw"];		
		$con = mysqli_connect("localhost","xxxx","xxxx") or die("数据库连接失败");//连接数据库
		mysqli_query($con,"set names utf8");
		mysqli_select_db($con,"stu") or die("数据库选择失败");
		$sql_insert="INSERT INTO hw_audio (id,name,post_date,kemu,serverPath,httpPath,hw) VALUES (null,'$post_name','$post_date','$post_kemu','$post_serverPath','$post_httpPath','$post_hw')";
		$result_insert = mysqli_query($con,$sql_insert);
		echo "数据库上传成功";
	}
	res();
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注