Browse Source

开发朗读页,评分页

bayi 2 years ago
parent
commit
02676316d6

+ 1 - 0
app.json

@@ -1,6 +1,7 @@
 {
     "pages": [
         "pages/index/index",
+        "pages/score/index",
         "pages/reading/index",
         "pages/pkPage/index",
         "pages/userWorks/index",

+ 169 - 169
components/videoPreview/index.js

@@ -1,185 +1,185 @@
 import {
-    setVideoStatus,
-    likeVideo,
-    collectVideo,
+  setVideoStatus,
+  likeVideo,
+  collectVideo,
 } from '~/api/video'
 import {
-    setFans
+  setFans
 } from '~/api/user'
 Component({
-    /**
-     * 组件的属性列表
-     */
-    properties: {
-        videoInfo: {
-            type: Object,
-            value: {},
-            observer(newVal) {
-                this.setData({
-                    videoInfoCopy: newVal
-                })
-            }
-        },
-        videoType: {
-            type: String,
-            // value 为public时是默认公共样式,为my时为“我的”样式,展示下载删除是否公开,pk为pk的样式文案
-            value: 'public'
-        },
-        currentId: {
-            type: Number,
-        }
+  /**
+   * 组件的属性列表
+   */
+  properties: {
+    videoInfo: {
+      type: Object,
+      value: {},
+      observer(newVal) {
+        this.setData({
+          videoInfoCopy: newVal
+        })
+      }
     },
-    data: {
-        selfUid: wx.getStorageSync('uid'),
-        videoInfoCopy: {}
+    videoType: {
+      type: String,
+      // value 为public时是默认公共样式,为my时为“我的”样式,展示下载删除是否公开,pk为pk的样式文案
+      value: 'public'
     },
-    methods: {
-        // 播放视频
-        playVideo() {
-            this.triggerEvent('playVideo', this.properties.videoInfo.userRead.id)
-        },
-        // 设置视频公开还是隐私
-        async setVideoPublic() {
-            let info = this.properties.videoInfo.userRead
-            let data = {
-                id: info.id,
-                status: info.status === 'NORMAL' ? 'DISABLE' : 'NORMAL'
-            }
-            let res = await setVideoStatus(data)
-            if (res.status == 'DISABLE') {
+    currentId: {
+      type: Number,
+    }
+  },
+  data: {
+    selfUid: wx.getStorageSync('uid'),
+    videoInfoCopy: {}
+  },
+  methods: {
+    // 播放视频
+    playVideo() {
+      this.triggerEvent('playVideo', this.properties.videoInfo.userRead.id)
+    },
+    // 设置视频公开还是隐私
+    async setVideoPublic() {
+      let info = this.properties.videoInfo.userRead
+      let data = {
+        id: info.id,
+        status: info.status === 'NORMAL' ? 'DISABLE' : 'NORMAL'
+      }
+      let res = await setVideoStatus(data)
+      if (res.status == 'DISABLE') {
+        wx.showToast({
+          title: '该作品仅自己可见',
+          icon: 'none',
+          duration: 2000
+        })
+      }
+      this.setData({
+        ['videoInfoCopy.userRead.status']: info.status === 'NORMAL' ? 'DISABLE' : 'NORMAL'
+      })
+    },
+    // 点赞
+    async likeVideo() {
+      let {
+        id
+      } = this.properties.videoInfo.userRead
+      if (this.properties.videoInfo.isLike) {
+        return
+      }
+      await likeVideo(id)
+      this.setData({
+        ['videoInfoCopy.isLike']: true,
+        ['videoInfoCopy.userRead.likeAmount']: this.data.videoInfoCopy.userRead.likeAmount + 1
+      })
+    },
+    // 下载视频
+    download() {
+      wx.showLoading({
+        title: '保存到本地',
+        mask: true
+      })
+      const url = this.properties.videoInfo.userRead.markPath || ''
+      wx.downloadFile({
+        url,
+        success(res) {
+          if (res.statusCode === 200) {
+            wx.saveVideoToPhotosAlbum({
+              filePath: res.tempFilePath,
+              success(res) {
+                wx.hideLoading()
                 wx.showToast({
-                    title: '该作品仅自己可见',
-                    icon: 'none',
-                    duration: 2000
+                  title: '成功保存到相册!',
+                  duration: 3000,
+                  icon: 'success',
+                  mask: true
                 })
-            }
-            this.setData({
-                ['videoInfoCopy.userRead.status']: info.status === 'NORMAL' ? 'DISABLE' : 'NORMAL'
-            })
-        },
-        // 点赞
-        async likeVideo() {
-            let {
-                id
-            } = this.properties.videoInfo.userRead
-            if (this.properties.videoInfo.isLike) {
-                return
-            }
-            await likeVideo(id)
-            this.setData({
-                ['videoInfoCopy.isLike']: true,
-                ['videoInfoCopy.userRead.likeAmount']: this.data.videoInfoCopy.userRead.likeAmount + 1
-            })
-        },
-        // 下载视频
-        download() {
-            wx.showLoading({
-                title: '保存到本地',
-                mask: true
-            })
-            const url = this.properties.videoInfo.userRead.markPath || ''
-            wx.downloadFile({
-                url,
-                success(res) {
-                    if (res.statusCode === 200) {
-                        wx.saveVideoToPhotosAlbum({
-                            filePath: res.tempFilePath,
-                            success(res) {
-                                wx.hideLoading()
-                                wx.showToast({
-                                    title: '成功保存到相册!',
-                                    duration: 3000,
-                                    icon: 'success',
-                                    mask: true
-                                })
-                            },
-                            fail() {
-                                wx.hideLoading()
-                                wx.showToast({
-                                    title: '网络不给力',
-                                    icon: 'error',
-                                    duration: 3000,
-                                    mask: true
-                                })
-                            }
-                        })
-                    }
-                },
-                fail() {
-                    wx.hideLoading()
-                    wx.showToast({
-                        title: '网络不给力',
-                        icon: 'error',
-                        duration: 3000,
-                        mask: true
-                    })
-                }
-            })
-        },
-        //评论
-        openComment() {
-            this.triggerEvent('openComment', this.properties.videoInfo.userRead.id)
-        },
-        // 删除
-        delete() {
-            let {
-                id
-            } = this.properties.videoInfo.userRead
-            wx.showModal({
-                title: '确认删除吗?',
-                content: '作品将被永久删除,无法找回。',
-                confirmText: '确认',
-                cancelText: '取消',
-                success: async (res) => {
-                    if (res.confirm) {
-                        let data = {
-                            id,
-                            status: 'DEL'
-                        }
-                        await setVideoStatus(data)
-                        wx.showToast({
-                            title: '删除成功!',
-                            icon: "none"
-                        })
-                        this.triggerEvent('getList')
-                    }
-                }
-            })
-        },
-        // 收藏课程
-        async collect() {
-            let {
-                id,
-                type,
-                uid
-            } = this.properties.videoInfo.userRead
-            if (wx.getStorageSync('uid') == uid) {
-                return
-            }
-            await collectVideo({
-                targetCode: id,
-                favoritesType: type
-            })
-            this.setData({
-                ['videoInfoCopy.isFavorites']: !this.data.videoInfoCopy.isFavorites
+              },
+              fail() {
+                wx.hideLoading()
+                wx.showToast({
+                  title: '网络不给力',
+                  icon: 'error',
+                  duration: 3000,
+                  mask: true
+                })
+              }
             })
+          }
         },
-        // 关注
-        async setFans() {
-            if (this.properties.videoInfo.isFans) {
-                return
+        fail() {
+          wx.hideLoading()
+          wx.showToast({
+            title: '网络不给力',
+            icon: 'error',
+            duration: 3000,
+            mask: true
+          })
+        }
+      })
+    },
+    //评论
+    openComment() {
+      this.triggerEvent('openComment', this.properties.videoInfo.userRead.id)
+    },
+    // 删除
+    delete() {
+      let {
+        id
+      } = this.properties.videoInfo.userRead
+      wx.showModal({
+        title: '确认删除吗?',
+        content: '作品将被永久删除,无法找回。',
+        confirmText: '确认',
+        cancelText: '取消',
+        success: async (res) => {
+          if (res.confirm) {
+            let data = {
+              id,
+              status: 'DEL'
             }
-            await setFans({
-                uid: this.properties.videoInfo.user.uid
-            })
-            this.triggerEvent('setListFans', this.properties.videoInfo.user.uid)
-        },
-        toPkPage() {
-            let readId = this.data.videoInfoCopy.userRead.id
-            let url = this.properties.videoType == 'public' ? `/pages/pkPage/index?videoId=${readId}` : `/pages/reading/index?videoId=${readId}`
-            wx.navigateTo({
-                url
+            await setVideoStatus(data)
+            wx.showToast({
+              title: '删除成功!',
+              icon: "none"
             })
+            this.triggerEvent('getList')
+          }
         }
+      })
+    },
+    // 收藏课程
+    async collect() {
+      let {
+        id,
+        type,
+        uid
+      } = this.properties.videoInfo.userRead
+      if (wx.getStorageSync('uid') == uid) {
+        return
+      }
+      await collectVideo({
+        targetCode: id,
+        favoritesType: type
+      })
+      this.setData({
+        ['videoInfoCopy.isFavorites']: !this.data.videoInfoCopy.isFavorites
+      })
+    },
+    // 关注
+    async setFans() {
+      if (this.properties.videoInfo.isFans) {
+        return
+      }
+      await setFans({
+        uid: this.properties.videoInfo.user.uid
+      })
+      this.triggerEvent('setListFans', this.properties.videoInfo.user.uid)
+    },
+    toPkPage() {
+      let readId = this.data.videoInfoCopy.userRead.id
+      let url = this.properties.videoType == 'public' ? `/pages/pkPage/index?videoId=${readId}` : `/pages/reading/index?videoId=${this.data.videoInfoCopy.userRead.exampleId}`
+      wx.navigateTo({
+        url
+      })
     }
+  }
 })

+ 73 - 75
components/videoPreview/index.wxml

@@ -1,83 +1,81 @@
 <wxs src="../../utils/filter.wxs" module="filters" />
 <view class="work">
-    <view class="workHead">
-        <view class="wH-left">
-            <image src="{{videoInfoCopy.user.avatar}}" class="avatar" mode="" />
-            <view class="wH-left-user">
-                <view class="nickname textOver">{{videoInfoCopy.user.nickName||videoInfoCopy.user.eid}}</view>
-                <view class="time">{{videoInfoCopy.userRead.day}}</view>
-            </view>
-        </view>
-        <view class="wH-right" wx:if="{{videoType=='my'}}">
-            <view class="wH-right-btn" bindtap="download">
-                <image class="img" src="/static/down.png" mode="" />
-                <view class="text">下载</view>
-            </view>
-            <view class="wH-right-btn" bindtap="delete">
-                <image class=" img" style="width:24rpx" src="/static/delete.png" mode="" />
-                <view class="text">删除</view>
-            </view>
-            <view class="wH-right-btn" bindtap="setVideoPublic">
-                <image class="img" style="width:30rpx"
-                    src="{{videoInfoCopy.userRead.status==='NORMAL'? '/static/unlock.png': '/static/lock.png'}}" />
-                <view class="text">
-                    {{videoInfoCopy.userRead.status==='NORMAL'? '公开': '私密'}}
-                </view>
-            </view>
-        </view>
-        <view class="wH-right" wx:elif="{{videoType=='public'&&selfUid!=videoInfoCopy.user.uid}}">
-            <view class="follow {{videoInfoCopy.isFans?'isFans':''}}" bindtap="setFans">
-                <image src="{{videoInfoCopy.isFans?'/static/follow_2.png':'/static/follow_1.png'}}" class="character"
-                    mode="" />
-                <text class="text">{{videoInfoCopy.isFans?'已关注':'关注'}}</text>
-            </view>
-        </view>
-        <view class="wH-right" wx:elif="{{videoType=='pk'}}">
-            <view class="pkNum">
-                {{videoInfoCopy.userRead.score||'暂无评'}}分
-            </view>
-        </view>
+  <view class="workHead">
+    <view class="wH-left">
+      <image src="{{videoInfoCopy.user.avatar}}" class="avatar" mode="" />
+      <view class="wH-left-user">
+        <view class="nickname textOver">{{videoInfoCopy.user.nickName||videoInfoCopy.user.eid}}</view>
+        <view class="time">{{videoInfoCopy.userRead.day}}</view>
+      </view>
     </view>
-    <view class="workContent">
-        <!-- 审核中遮罩 -->
-        <view class="videoBox" wx:if="{{videoInfoCopy.userRead.status=='CHECK'&&videoInfoCopy.userRead.id!=currentId}}">
-            <view class="maskBg"></view>
-            <image class="maskImg" src="/static/checking.png" />
-            <image class="cover" src="{{videoInfoCopy.userRead.coverImg}}" />
+    <view class="wH-right" wx:if="{{videoType=='my'}}">
+      <view class="wH-right-btn" bindtap="download">
+        <image class="img" src="/static/down.png" mode="" />
+        <view class="text">下载</view>
+      </view>
+      <view class="wH-right-btn" bindtap="delete">
+        <image class=" img" style="width:24rpx" src="/static/delete.png" mode="" />
+        <view class="text">删除</view>
+      </view>
+      <view class="wH-right-btn" bindtap="setVideoPublic">
+        <image class="img" style="width:30rpx"
+          src="{{videoInfoCopy.userRead.status==='NORMAL'? '/static/unlock.png': '/static/lock.png'}}" />
+        <view class="text">
+          {{videoInfoCopy.userRead.status==='NORMAL'? '公开': '私密'}}
         </view>
-        <!--未播放-->
-        <view class="videoBox" wx:if="{{videoInfoCopy.userRead.status!='CHECK'&&videoInfoCopy.userRead.id!=currentId}}"
-            bindtap="playVideo">
-            <image class="play" src="/static/play-btn.png" />
-            <image class="cover" src="{{videoInfoCopy.userRead.coverImg}}" />
-        </view>
-        <!-- 播放时渲染的video -->
-        <video class="video" id="myVideo" wx:if="{{videoInfoCopy.userRead.id==currentId}}"
-            src="{{videoInfoCopy.userRead.videoPath}}" autoplay="true" object-fit="contain">
-        </video>
+      </view>
     </view>
-    <view class="workFooter">
-        <button class="resetBtn mangeL-box" open-type="share" data-info='{{videoInfo}}'>
-            <image src="/static/share.png" mode="" class="icon" />
-            <view class="icon-name">分享</view>
-        </button>
-        <view class="mangeL-box" bindtap="collect">
-            <image src="{{videoInfoCopy.isFavorites ? '/static/star_colored.png' : '/static/star.png'}}" mode=""
-                class="icon" />
-            <view class="icon-name">{{videoInfoCopy.isFavorites?'已收藏':'收藏'}}</view>
-        </view>
-        <view class="mangeL-box" bindtap="openComment">
-            <image src="/static/comment.png" mode="" class="icon" />
-            <view class="icon-name">{{filters.numFilter(videoInfoCopy.userRead.commentAmount)}}</view>
-        </view>
-        <view class="mangeL-box" bindtap="likeVideo">
-            <image src="{{videoInfoCopy.isLike ? '/static/heart_colored.png' : '/static/heart.png'}}" mode=""
-                class="icon" />
-            <view class="icon-name">{{filters.numFilter(videoInfoCopy.userRead.likeAmount)}}</view>
-        </view>
+    <view class="wH-right" wx:elif="{{videoType=='public'&&selfUid!=videoInfoCopy.user.uid}}">
+      <view class="follow {{videoInfoCopy.isFans?'isFans':''}}" bindtap="setFans">
+        <image src="{{videoInfoCopy.isFans?'/static/follow_2.png':'/static/follow_1.png'}}" class="character" mode="" />
+        <text class="text">{{videoInfoCopy.isFans?'已关注':'关注'}}</text>
+      </view>
+    </view>
+    <view class="wH-right" wx:elif="{{videoType=='pk'}}">
+      <view class="pkNum">
+        {{videoInfoCopy.userRead.score||'暂无评'}}分
+      </view>
+    </view>
+  </view>
+  <view class="workContent">
+    <!-- 审核中遮罩 -->
+    <view class="videoBox" wx:if="{{videoInfoCopy.userRead.status=='CHECK'&&videoInfoCopy.userRead.id!=currentId}}">
+      <view class="maskBg"></view>
+      <image class="maskImg" src="/static/checking.png" />
+      <image class="cover" src="{{videoInfoCopy.userRead.coverImg}}" />
+    </view>
+    <!--未播放-->
+    <view class="videoBox" wx:if="{{videoInfoCopy.userRead.status!='CHECK'&&videoInfoCopy.userRead.id!=currentId}}"
+      bindtap="playVideo">
+      <image class="play" src="/static/play-btn.png" />
+      <image class="cover" src="{{videoInfoCopy.userRead.coverImg}}" />
+    </view>
+    <!-- 播放时渲染的video -->
+    <video class="video" id="myVideo" wx:if="{{videoInfoCopy.userRead.id==currentId}}"
+      src="{{videoInfoCopy.userRead.videoPath}}" autoplay="true" object-fit="contain">
+    </video>
+  </view>
+  <view class="workFooter">
+    <button class="resetBtn mangeL-box" open-type="share" data-info='{{videoInfo}}'>
+      <image src="/static/share.png" mode="" class="icon" />
+      <view class="icon-name">分享</view>
+    </button>
+    <view class="mangeL-box" bindtap="collect">
+      <image src="{{videoInfoCopy.isFavorites ? '/static/star_colored.png' : '/static/star.png'}}" mode=""
+        class="icon" />
+      <view class="icon-name">{{videoInfoCopy.isFavorites?'已收藏':'收藏'}}</view>
+    </view>
+    <view class="mangeL-box" bindtap="openComment">
+      <image src="/static/comment.png" mode="" class="icon" />
+      <view class="icon-name">{{filters.numFilter(videoInfoCopy.userRead.commentAmount)}}</view>
     </view>
-    <view class="toReading" bindtap="toPkPage" wx:if="{{videoType!='my'}}">
-        <image src="/static/reading.png" class="reading" mode="" />
-        <view class="reading-text">挑战PK</view>
+    <view class="mangeL-box" bindtap="likeVideo">
+      <image src="{{videoInfoCopy.isLike ? '/static/heart_colored.png' : '/static/heart.png'}}" mode="" class="icon" />
+      <view class="icon-name">{{filters.numFilter(videoInfoCopy.userRead.likeAmount)}}</view>
     </view>
+  </view>
+  <view class="toReading" bindtap="toPkPage" wx:if="{{videoType!='my'}}">
+    <image src="/static/reading.png" class="reading" mode="" />
+    <view class="reading-text">挑战PK</view>
+  </view>
 </view>

+ 126 - 129
pages/pkPage/index.js

@@ -1,141 +1,138 @@
 import behavior from '~/mixins/video'
 import {
-    getreadInfo
+  getreadInfo
 } from '~/api/video'
 Page({
-    behaviors: [behavior],
-    data: {
-        videoInfo: {}
-    },
+  behaviors: [behavior],
+  data: {
+    videoInfo: {}
+  },
 
-    /**
-     * 生命周期函数--监听页面加载
-     */
-    onLoad(options) {
-        let videoId = options.videoId
-        this.getreadInfo(videoId)
-    },
-    async getreadInfo(videoId) {
-        let videoInfo = await getreadInfo(videoId)
-        console.log(videoInfo);
-        wx.setNavigationBarTitle({
-            title: videoInfo.userRead.title
-        })
-        this.setData({
-            videoInfo
-        })
-    },
-    /**
-     * 生命周期函数--监听页面显示
-     */
-    onShow() {
-
-    },
-
-    /**
-     * 页面上拉触底事件的处理函数
-     */
-    onReachBottom() {
+  /**
+   * 生命周期函数--监听页面加载
+   */
+  onLoad(options) {
+    console.log('销毁了');
+    let videoId = options.videoId
+    this.getreadInfo(videoId)
+  },
+  async getreadInfo(videoId) {
+    let videoInfo = await getreadInfo(videoId)
+    wx.setNavigationBarTitle({
+      title: videoInfo.userRead.title
+    })
+    this.setData({
+      videoInfo
+    })
+  },
+  /**
+   * 页面上拉触底事件的处理函数
+   */
+  onReachBottom() {
 
-    },
-    creatShare(video) {
-        return new Promise((resolve, reject) => {
-            let context = wx.createSelectorQuery();
-            context
-                .select('#share')
-                .fields({
-                    node: true,
-                    size: true
-                }).exec((res) => {
-                    const canvas = res[0].node;
-                    const ctx = canvas.getContext('2d');
-                    const dpr = wx.getSystemInfoSync().pixelRatio;
-                    canvas.width = res[0].width * dpr;
-                    canvas.height = res[0].height * dpr;
-                    ctx.scale(dpr, dpr);
-                    ctx.font = '14px PingFang';
-                    let pic = canvas.createImage();
-                    pic.src = video.userRead.coverImg; //可以是本地,也可以是网络图片
-                    pic.onload = () => {
-                        ctx.drawImage(pic, 0, 0, 375, 211);
-                    }
-                    let peiyin = canvas.createImage();
-                    peiyin.src = '/static/peiyin.jpg';
-                    peiyin.onload = () => {
-                        ctx.drawImage(peiyin, 0, 211, 375, 89);
-                        // 收藏,一个一个渲染
-                        let sc = canvas.createImage();
-                        sc.src = '/static/star.png'
-                        sc.onload = () => {
-                            ctx.drawImage(sc, 12, 220, 20, 20)
-                            ctx.fillText('收藏', 36, 238)
-                            //分享
-                            let fx = canvas.createImage();
-                            fx.src = '/static/share.png'
-                            fx.onload = () => {
-                                ctx.drawImage(fx, 78, 220, 22, 22)
-                                ctx.fillText('分享', 104, 238)
-                                //点赞
-                                let dz = canvas.createImage();
-                                dz.src = video.isLike ? '/static/heart_colored.png' : '/static/heart.png'
-                                dz.onload = () => {
-                                    ctx.drawImage(dz, 258, 222, 22, 22)
-                                    ctx.fillText(video.userRead.likeAmount, 284, 238)
-                                    //评论
-                                    let pl = canvas.createImage();
-                                    pl.src = '/static/comment.png'
-                                    pl.onload = () => {
-                                        ctx.drawImage(pl, 318, 222, 22, 22)
-                                        ctx.fillText(video.userRead.commentAmount, 340, 238)
-                                        setTimeout(() => {
-                                            wx.canvasToTempFilePath({
-                                                canvas: canvas,
-                                                success(res) {
-                                                    resolve({
-                                                        title: '请欣赏我的课文朗读作品,点赞+评论。',
-                                                        path: `/pages/index/index?readId=${video.userRead.id}&uid=${wx.getStorageSync('uid')}`,
-                                                        imageUrl: res.tempFilePath
-                                                    })
-                                                },
-                                                fail(res) {
-                                                    reject()
-                                                }
-                                            }, this)
-                                        }, 500)
-                                    }
-                                }
-                            }
+  },
+  creatShare(video) {
+    return new Promise((resolve, reject) => {
+      let context = wx.createSelectorQuery();
+      context
+        .select('#share')
+        .fields({
+          node: true,
+          size: true
+        }).exec((res) => {
+          const canvas = res[0].node;
+          const ctx = canvas.getContext('2d');
+          const dpr = wx.getSystemInfoSync().pixelRatio;
+          canvas.width = res[0].width * dpr;
+          canvas.height = res[0].height * dpr;
+          ctx.scale(dpr, dpr);
+          ctx.font = '14px PingFang';
+          let pic = canvas.createImage();
+          pic.src = video.userRead.coverImg; //可以是本地,也可以是网络图片
+          pic.onload = () => {
+            ctx.drawImage(pic, 0, 0, 375, 211);
+          }
+          let peiyin = canvas.createImage();
+          peiyin.src = '/static/peiyin.jpg';
+          peiyin.onload = () => {
+            ctx.drawImage(peiyin, 0, 211, 375, 89);
+            // 收藏,一个一个渲染
+            let sc = canvas.createImage();
+            sc.src = '/static/star.png'
+            sc.onload = () => {
+              ctx.drawImage(sc, 12, 220, 20, 20)
+              ctx.fillText('收藏', 36, 238)
+              //分享
+              let fx = canvas.createImage();
+              fx.src = '/static/share.png'
+              fx.onload = () => {
+                ctx.drawImage(fx, 78, 220, 22, 22)
+                ctx.fillText('分享', 104, 238)
+                //点赞
+                let dz = canvas.createImage();
+                dz.src = video.isLike ? '/static/heart_colored.png' : '/static/heart.png'
+                dz.onload = () => {
+                  ctx.drawImage(dz, 258, 222, 22, 22)
+                  ctx.fillText(video.userRead.likeAmount, 284, 238)
+                  //评论
+                  let pl = canvas.createImage();
+                  pl.src = '/static/comment.png'
+                  pl.onload = () => {
+                    ctx.drawImage(pl, 318, 222, 22, 22)
+                    ctx.fillText(video.userRead.commentAmount, 340, 238)
+                    setTimeout(() => {
+                      wx.canvasToTempFilePath({
+                        canvas: canvas,
+                        success(res) {
+                          resolve({
+                            title: '请欣赏我的课文朗读作品,点赞+评论。',
+                            path: `/pages/index/index?readId=${video.userRead.id}&uid=${wx.getStorageSync('uid')}`,
+                            imageUrl: res.tempFilePath
+                          })
+                        },
+                        fail(res) {
+                          reject()
                         }
-                    }
+                      }, this)
+                    }, 500)
+                  }
+                }
+              }
+            }
+          }
 
-                })
         })
+    })
 
-    },
-    onShareAppMessage({
-        from,
-        target
-    }) {
-        if (from == 'button') {
-            let video = this.data.videoInfo
-            const promise = new Promise(resolve => {
-                this.creatShare(video).then(res => {
-                    resolve(res)
-                })
-            })
-            console.log(video);
-            return {
-                title: '请欣赏我的课文朗读作品,点赞+评论。',
-                path: `/pages/index/index?readId=${video.userRead.id}&uid=${wx.getStorageSync('uid')}`,
-                imageUrl: video.userRead.coverImg,
-                promise
-            }
-        } else {
-            return {
-                title: '课文朗读,从未如此有趣。',
-                path: `/pages/index/index?&uid=${wx.getStorageSync('uid')}`,
-                imageUrl: 'http://reader-wx.ai160.com/images/reader/v3/shareContent.png'
-            }
-        }
+  },
+  onShareAppMessage({
+    from,
+    target
+  }) {
+    if (from == 'button') {
+      let video = this.data.videoInfo
+      const promise = new Promise(resolve => {
+        this.creatShare(video).then(res => {
+          resolve(res)
+        })
+      })
+      return {
+        title: '请欣赏我的课文朗读作品,点赞+评论。',
+        path: `/pages/index/index?readId=${video.userRead.id}&uid=${wx.getStorageSync('uid')}`,
+        imageUrl: video.userRead.coverImg,
+        promise
+      }
+    } else {
+      return {
+        title: '课文朗读,从未如此有趣。',
+        path: `/pages/index/index?&uid=${wx.getStorageSync('uid')}`,
+        imageUrl: 'http://reader-wx.ai160.com/images/reader/v3/shareContent.png'
+      }
     }
+  },
+  onHide() {
+    this.setData({
+      currentId: ''
+    })
+  }
 })

+ 302 - 148
pages/reading/index.js

@@ -1,167 +1,321 @@
 import {
-    getreadInfo
+  getreadInfo
 } from '~/api/video'
+const aiengine = require('~/utils/ChivoxAiEngine')
+const sha1 = require('~/utils/sha1');
 let rowHeight = 0
 let videoContext = null
 let stl = null
 let setTimeoutObj = null
+/*创建基础引擎*/
+let wsEngine = aiengine.createWsEngine({});
+/*微信录音*/
+let recorderManager = wx.getRecorderManager();
 Page({
-    data: {
-        videoInfo: {},
-        currentRow: null,
-        state: false,
-        countDown: {
-            state: false,
-            num: 3,
-        },
-        scrollTop: 0,
-        article: [{
-            id: 1,
-            text: '传说在很久很久以前,',
-            time: '0'
-        }, {
-            id: 2,
-            text: '天和地还没有分开,',
-            time: '4010'
-        }, {
-            id: 3,
-            text: '整个宇宙混沌一团,',
-            time: '7080'
-        }, {
-            id: 4,
-            text: '像个大鸡蛋。',
-            time: '10150'
-        }, {
-            id: 5,
-            text: '有个叫盘古的大神,',
-            time: '13150'
-        }, {
-            id: 6,
-            text: '昏睡了一万八千年。',
-            time: '16190'
-        }, {
-            id: 7,
-            text: '一天,大神醒来,睁眼一看,',
-            time: '20030'
-        }, {
-            id: 8,
-            text: '周围黑乎乎一片,',
-            time: '24210'
-        }, {
-            id: 9,
-            text: '什么也看不见。',
-            time: '27300'
-        }, {
-            id: 10,
-            text: '他一使劲翻身坐了起来,',
-            time: '29210'
-        }, {
-            id: 11,
-            text: '只听“咔嚓”一声,',
-            time: '32700'
-        }, {
-            id: 12,
-            text: '“大鸡蛋”裂开了一条缝,',
-            time: '35320'
-        }, {
-            id: 13,
-            text: '一丝微光透了进来。',
-            time: '38270'
-        }, ]
+  data: {
+    videoInfo: {},
+    currentRow: null,
+    state: false,
+    countDown: {
+      state: false,
+      num: 3,
     },
-    onLoad(options) {
-        let videoId = options.videoId
-        this.getreadInfo(videoId)
-        let data = this.data.article
-        data = data.map((item, index) => {
-            item.readTime = data[index + 1] ? data[index + 1].time - item.time : ''
-            return item
-        })
+    scrollTop: 0,
+    article: [{
+      id: 1,
+      text: '传说在很久很久以前,',
+      time: '0'
+    }, {
+      id: 2,
+      text: '天和地还没有分开,',
+      time: '4010'
+    }, {
+      id: 3,
+      text: '整个宇宙混沌一团,',
+      time: '7080'
+    }, {
+      id: 4,
+      text: '像个大鸡蛋。',
+      time: '10150'
+    }, {
+      id: 5,
+      text: '有个叫盘古的大神,',
+      time: '13150'
+    }, {
+      id: 6,
+      text: '昏睡了一万八千年。',
+      time: '16190'
+    }, {
+      id: 7,
+      text: '一天,大神醒来,睁眼一看,',
+      time: '20030'
+    }, {
+      id: 8,
+      text: '周围黑乎乎一片,',
+      time: '24210'
+    }, {
+      id: 9,
+      text: '什么也看不见。',
+      time: '27300'
+    }, {
+      id: 10,
+      text: '他一使劲翻身坐了起来,',
+      time: '29210'
+    }, {
+      id: 11,
+      text: '只听“咔嚓”一声,',
+      time: '32700'
+    }, {
+      id: 12,
+      text: '“大鸡蛋”裂开了一条缝,',
+      time: '35320'
+    }, {
+      id: 13,
+      text: '一丝微光透了进来。',
+      time: '38270'
+    }, ]
+  },
+  onLoad(options) {
+    let videoId = options.videoId
+    this.getreadInfo(videoId)
+    let data = this.data.article
+    data = data.map((item, index) => {
+      item.readTime = data[index + 1] ? data[index + 1].time - item.time : ''
+      return item
+    })
+    this.setData({
+      article: data
+    })
+    var query = wx.createSelectorQuery();
+    query.select('.row').boundingClientRect((rect) => {
+      this.rowHeight = rect.height
+    }).exec()
+    this.videoContext = wx.createVideoContext('myVideo')
+    // 录音授权
+    wx.getSetting({
+      success(res) {
+        if (!res.authSetting['scope.record']) {
+          wx.authorize({
+            scope: 'scope.record',
+            success() {
+              // 用户已经同意小程序使用录音功能,后续调用接口不会弹窗询问
+              wx.getRecorderManager()
+            }
+          })
+        }
+      }
+    })
+    /*监听评测结果:必须在基础引擎创建后,调用任何评测接口前设置监听,否则有可能收不到相关事件。*/
+    wsEngine.onResult((res) => {
+      this.getRecordScore(res)
+    });
+    wsEngine.onErrorResult((res) => {
+      console.log("===收到错误结果=============", res)
+    });
+  },
+  async getreadInfo(videoId) {
+    let videoInfo = await getreadInfo(videoId)
+    wx.setNavigationBarTitle({
+      title: videoInfo.userRead.title
+    })
+    this.setData({
+      videoInfo
+    })
+  },
+  // 开始录制
+  setCountDown() {
+    if (this.data.state) {
+      this.finishRecord()
+      return
+    }
+    this.setData({
+      'countDown.state': true
+    })
+    this.stl = setInterval(() => {
+      if (this.data.countDown.num == 0) {
+        clearInterval(this.stl)
         this.setData({
-            article: data
-        })
-        var query = wx.createSelectorQuery();
-        query.select('.row').boundingClientRect((rect) => {
-            this.rowHeight = rect.height
-            console.log(rect);
-        }).exec()
-        this.videoContext = wx.createVideoContext('myVideo')
-    },
-    async getreadInfo(videoId) {
-        let videoInfo = await getreadInfo(videoId)
-        console.log(videoInfo);
-        wx.setNavigationBarTitle({
-            title: videoInfo.userRead.title
+          state: true,
+          countDown: {
+            state: false,
+            num: 3
+          }
         })
+        this.soundRecording()
+        this.videoContext.play()
+        this.startRecording()
+      } else {
         this.setData({
-            videoInfo
+          'countDown.num': --this.data.countDown.num
         })
-    },
-    // 开始录制
-    setCountDown() {
-        if (this.data.state) {
-            return
+      }
+    }, 1000)
+  },
+  // 录音
+  soundRecording() {
+    /*调用微信开始录音接口,并启动语音评测*/
+    let timeStamp = new Date().getTime()
+    let sig = sha1(`16075689600000da${timeStamp}caa8e60da6042731c230fe431ac9c7fd`)
+    let app = {
+      applicationId: '16075689600000da',
+      sig, //签名字符串 
+      alg: 'sha1',
+      timestamp: timeStamp + '',
+      userId: wx.getStorageSync('uid')
+    }
+    let lessonText = this.data.videoInfo.userRead.lessonText;
+    wsEngine.start({
+      request: {
+        coreType: "cn.pred.raw",
+        refText: lessonText,
+        rank: 100,
+        attachAudioUrl: 1,
+        result: {
+          details: {
+            gop_adjust: 1
+          }
         }
+      },
+      app,
+      audio: {
+        audioType: "mp3",
+        channel: 1,
+        sampleBytes: 2,
+        sampleRate: 16000
+      },
+      success: (res) => {
+        /*引擎启动成功,可以启动录音机开始录音,并将音频片传给引擎*/
+        const options = {
+          sampleRate: 44100, //采样率
+          numberOfChannels: 1, //录音通道数
+          encodeBitRate: 192000, //编码码率
+          format: 'mp3', //音频格式,有效值aac/mp3
+          frameSize: 50 //指定帧大小,单位 KB
+        };
+        //开始录音,在开始录音回调中feed音频片
+        recorderManager.start(options);
+      },
+      fail: (res) => {
+        console.log("fail=============  " + res);
+      },
+    });
+    //监听录音开始事件
+    recorderManager.onStart(() => {});
+    //监听录音结束事件
+    recorderManager.onStop((res) => {
+      console.log('录音结束', res);
+      this.setData({
+        tempFilePath: res.tempFilePath,
+      });
+      //录音机结束后,驰声引擎执行结束操作,等待评测返回结果
+      wsEngine.stop({
+        success: () => {
+          console.log('====== wsEngine stop success ======');
+        },
+        fail: (res) => {
+          console.log('录音结束报错', res);
+        },
+      });
+    });
+    //监听已录制完指定帧大小的文件事件。如果设置了 frameSize,则会回调此事件。
+    recorderManager.onFrameRecorded((res) => {
+      const {
+        frameBuffer
+      } = res
+      //TODO 调用feed接口传递音频片给驰声评测引擎
+      wsEngine.feed({
+        data: frameBuffer, // frameBuffer为微信录音机回调的音频数据
+        success: () => {
+          console.log('feed success.监听已录制完指定帧大小的文件事件')
+        },
+        fail: (res) => {
+          console.log('监听已录制完指定帧大小报错', res)
+        },
+      });
+    });
+  },
+  // 结束录制
+  finishRecord() {
+    recorderManager.stop();
+    this.videoContext.stop()
+    this.videoContext.seek(0)
+    clearTimeout(this.setTimeoutObj)
+    clearInterval(this.stl)
+    this.setData({
+      state: false,
+      currentRow: null,
+      scrollTop: 0
+    })
+  },
+  // 倒计时
+  startRecording() {
+    if (this.data.currentRow == null) {
+      this.setData({
+        currentRow: 0
+      })
+    }
+    let row = this.data.article[this.data.currentRow]
+    if (!row.readTime) {
+      return
+    }
+    this.setTimeoutObj = setTimeout(() => {
         this.setData({
-            'countDown.state': true
+          currentRow: ++this.data.currentRow
         })
-        this.stl = setInterval(() => {
-            if (this.data.countDown.num == 0) {
-                clearInterval(this.stl)
-                this.setData({
-                    state: true,
-                    countDown: {
-                        state: false,
-                        num: 3
-                    }
-                })
-                this.videoContext.play()
-                this.startRecording()
-            } else {
-                this.setData({
-                    'countDown.num': --this.data.countDown.num
-                })
-            }
-        }, 1000)
-    },
-    startRecording() {
-        console.log('递归');
-        if (this.data.currentRow == null) {
-            this.setData({
-                currentRow: 0
-            })
-        }
-        let row = this.data.article[this.data.currentRow]
-        if (!row.readTime) {
-            return
-        }
-        this.setTimeoutObj = setTimeout(() => {
-                this.setData({
-                    currentRow: ++this.data.currentRow
-                })
-                this.setData({
-                    scrollTop: this.rowHeight * this.data.currentRow
-                })
-                this.startRecording()
-            },
-            row.readTime);
-    },
-    // 视频播放结束
-    videoEnd() {
         this.setData({
-            currentRow: null,
-            state: false,
-            scrollTop: 0,
+          scrollTop: this.rowHeight * this.data.currentRow
         })
-    },
-    /**
-     * 生命周期函数--监听页面卸载
-     */
-    onUnload() {
-        clearTimeout(this.setTimeoutObj)
-        clearInterval(this.stl)
-    },
-    onShareAppMessage() {
-
+        this.startRecording()
+      },
+      row.readTime);
+  },
+  // 视频播放结束
+  videoEnd() {
+    this.finishRecord()
+  },
+  // 获取测评结果
+  getRecordScore(res) {
+    var res = {
+      result: {
+        rank: 100,
+        res: "chn.pred.G4.D4.0.3",
+        tone: 50,
+        integrity: 12,
+        forceout: 0,
+        pron: 7,
+        overall: 8,
+        fluency: {
+          pause: 1,
+          overall: 0,
+          speed: 73
+        },
+      }
     }
+    const result = res.result;
+    const integrity = result.integrity; //完成度
+    const tone = result.tone; // 语调声调
+    const accuracy = result.overall; // 准确度 发音分
+    const fluency = result.fluency.overall; //流利度
+    let myOverall = integrity * 0.3 + accuracy * 0.5 + fluency * 0.1 + tone * 0.1;
+    let detail = JSON.stringify({
+      integrity,
+      tone,
+      accuracy,
+      fluency,
+      myOverall
+    })
+    wx.redirectTo({
+      url: `/pages/score/index?detail=${detail}`,
+    })
+  },
+  /**
+   * 生命周期函数--监听页面卸载
+   */
+  onUnload() {
+    clearTimeout(this.setTimeoutObj)
+    clearInterval(this.stl)
+  },
+  onShareAppMessage() {
+
+  }
 })

+ 127 - 119
pages/reading/index.less

@@ -1,130 +1,138 @@
 .readingBox {
+  position: relative;
+  height: 100vh;
+  width: 100vw;
+  display: flex;
+  flex-direction: column;
+  background-color: white;
+
+  .poster {
+    top: 0px;
+    left: 0px;
+    position: absolute;
+    width: 100%;
+    height: 422rpx;
+    z-index: 99;
+  }
+
+  #myVideo {
+    width: 100%;
+    height: 422rpx;
+  }
+
+
+
+  .contentBox {
+    flex: 1;
+    width: 100%;
+    overflow: hidden;
     position: relative;
-    height: 100vh;
-    width: 100vw;
-    display: flex;
-    flex-direction: column;
-    background-color: white;
 
-
-    #myVideo {
-        width: 100%;
-        height: 422rpx;
+    .articleMask {
+      position: absolute;
+      top: 0rpx;
+      width: 100%;
+      height: 80rpx;
+      z-index: 10;
+      background: linear-gradient(to bottom, rgb(255, 255, 255), rgba(255, 255, 255, 0.4))
     }
 
-
-
-    .contentBox {
-        flex: 1;
-        width: 100%;
-        overflow: hidden;
-        position: relative;
-
-        .articleMask {
-            position: absolute;
-            top: 0rpx;
-            width: 100%;
-            height: 80rpx;
-            z-index: 10;
-            background: linear-gradient(to bottom, rgb(255, 255, 255), rgba(255, 255, 255, 0.4))
-        }
-
-        .content {
-            width: 100%;
-            height: 100%;
-            padding: 0rpx 30rpx;
-            padding-bottom: calc(170rpx + env(safe-area-inset-bottom));
-            text-align: center;
-            box-sizing: border-box;
-
-            .row {
-                padding: 18rpx 0rpx;
-                font-size: 40rpx;
-            }
-
-            .currentRow {
-                font-weight: bold;
-                color: #019e45;
-            }
-
-            .article {
-                height: 2000rpx;
-                background-color: red;
-            }
-        }
+    .content {
+      width: 100%;
+      height: 100%;
+      padding: 0rpx 30rpx;
+      padding-bottom: calc(170rpx + env(safe-area-inset-bottom));
+      text-align: center;
+      box-sizing: border-box;
+
+      .row {
+        padding: 18rpx 0rpx;
+        font-size: 40rpx;
+      }
+
+      .currentRow {
+        font-weight: bold;
+        color: #019e45;
+      }
+
+      .article {
+        height: 2000rpx;
+        background-color: red;
+      }
     }
-
-    .controller {
-        width: 100%;
-        height: 110rpx;
-        position: absolute;
-        bottom: 0px;
-        left: 0px;
-        display: flex;
-        align-items: center;
-        flex-direction: column;
-        padding-bottom: env(safe-area-inset-bottom);
-        box-shadow: rgba(14, 30, 37, 0.12) 0px 2rpx 4rpx 0px, rgba(14, 30, 37, 0.32) 0px 2rpx 16rpx 0px;
-        background-color: white;
-        z-index: 10;
-
-        .playImg {
-            position: absolute;
-            top: -62rpx;
-            border-radius: 50%;
-            width: 114rpx;
-            height: 114rpx;
-            box-shadow: #4EC4FF 0px 0rpx 14rpx;
-            background-color: #4EC4FF;
-        }
-
-        .text {
-            position: absolute;
-            top: 60rpx;
-            font-size: 28rpx;
-        }
+  }
+
+  .controller {
+    width: 100%;
+    height: 110rpx;
+    position: absolute;
+    bottom: 0px;
+    left: 0px;
+    display: flex;
+    align-items: center;
+    flex-direction: column;
+    padding-bottom: env(safe-area-inset-bottom);
+    box-shadow: rgba(14, 30, 37, 0.12) 0px 2rpx 4rpx 0px, rgba(14, 30, 37, 0.32) 0px 2rpx 16rpx 0px;
+    background-color: white;
+    z-index: 10;
+
+    .playImg {
+      position: absolute;
+      top: -62rpx;
+      border-radius: 50%;
+      width: 114rpx;
+      height: 114rpx;
+      box-shadow: #4EC4FF 0px 0rpx 14rpx;
+      background-color: #4EC4FF;
     }
 
-    .playImgBg {
-        position: absolute;
-        width: 134rpx;
-        height: 124rpx;
-        z-index: 1;
-        left: -1rpx;
-        right: 0px;
-        margin: auto;
-        bottom: calc(56rpx + env(safe-area-inset-bottom));
-        background-color: white;
-        box-shadow: rgba(14, 30, 37, 0.12) 0px 2rpx 4rpx 0px, rgba(14, 30, 37, 0.32) 0px 2rpx 16rpx 0px;
-        border-radius: 50%;
+    .text {
+      position: absolute;
+      top: 60rpx;
+      font-size: 28rpx;
     }
-
-    .countDownBox {
-        position: fixed;
-        width: 100%;
-        height: 100%;
-        background-color: rgba(255, 255, 255, 0);
-        z-index: 999;
-
-        .countDown {
-            position: absolute;
-            left: 0rpx;
-            right: 0rpx;
-            top: 30%;
-            margin: auto;
-            width: 293rpx;
-            height: 293rpx;
-            border-radius: 30rpx;
-            color: white;
-            background-color: rgba(0, 0, 0, 0.8);
-            text-align: center;
-            padding: 30rpx 0rpx;
-            box-sizing: border-box;
-
-            .number {
-                font-size: 124rpx;
-                margin-bottom: 6rpx;
-            }
-        }
+  }
+
+  .playImgBg {
+    position: absolute;
+    width: 134rpx;
+    height: 124rpx;
+    z-index: 1;
+    left: -1rpx;
+    right: 0px;
+    margin: auto;
+    bottom: calc(56rpx + env(safe-area-inset-bottom));
+    background-color: white;
+    box-shadow: rgba(14, 30, 37, 0.12) 0px 2rpx 4rpx 0px, rgba(14, 30, 37, 0.32) 0px 2rpx 16rpx 0px;
+    border-radius: 50%;
+  }
+
+  .countDownBox {
+    position: fixed;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(255, 255, 255, 0);
+    z-index: 999;
+
+    .countDown {
+      position: absolute;
+      left: 0rpx;
+      right: 0rpx;
+      top: 30%;
+      margin: auto;
+      width: 293rpx;
+      height: 293rpx;
+      border-radius: 30rpx;
+      color: white;
+      background-color: rgba(0, 0, 0, 0.8);
+      text-align: center;
+      padding: 30rpx 0rpx;
+      box-sizing: border-box;
+
+      .number {
+        font-size: 124rpx;
+        margin-bottom: 6rpx;
+      }
     }
+  }
 }

+ 23 - 22
pages/reading/index.wxml

@@ -1,25 +1,26 @@
 <view class="readingBox">
-    <video id="myVideo" src="{{videoInfo.userRead.videoPath}}" bindended='videoEnd' controls="{{false}}" 
-        show-center-play-btn="{{false}}"></video>
-    <view class="contentBox">
-        <view class="articleMask"></view>
-        <scroll-view class="content" scroll-y enhanced show-scrollbar="{{false}}" scroll-top="{{scrollTop}}"
-            scroll-with-animation>
-            <view style="height: 60rpx;"></view>
-            <view class="row {{currentRow==index?'currentRow':''}}" wx:for="{{article}}" wx:key="id">{{item.text}}
-            </view>
-        </scroll-view>
-    </view>
-    <view class="controller">
-        <image src="{{state?'/static/readingNow.gif':'/static/work.png'}}" class="playImg" bindtap="setCountDown" />
-        <view class="text">{{state?'完成录制':'开始挑战'}}</view>
-    </view>
-    <view class="playImgBg"></view>
-    <!-- 倒计时 -->
-    <view class="countDownBox" wx:if="{{countDown.state}}">
-        <view class="countDown">
-            <view class="number">{{countDown.num}}</view>
-            <view class="tips">秒后开始</view>
-        </view>
+  <image src="{{videoInfo.userRead.coverImg}}" class='poster' wx:if="{{!state}}" />
+  <video id="myVideo" src="{{videoInfo.userRead.videoPath}}" bindended='videoEnd' controls="{{false}}"
+    show-center-play-btn="{{false}}" poster="{{videoInfoCopy.userRead.coverImg}}"></video>
+  <view class="contentBox">
+    <view class="articleMask"></view>
+    <scroll-view class="content" scroll-y enhanced show-scrollbar="{{false}}" scroll-top="{{scrollTop}}"
+      scroll-with-animation>
+      <view style="height: 60rpx;"></view>
+      <view class="row {{currentRow==index?'currentRow':''}}" wx:for="{{article}}" wx:key="id">{{item.text}}
+      </view>
+    </scroll-view>
+  </view>
+  <view class="controller">
+    <image src="{{state?'/static/readingNow.gif':'/static/work.png'}}" class="playImg" bindtap="getRecordScore" />
+    <view class="text">{{state?'完成录制':'开始挑战'}}</view>
+  </view>
+  <view class="playImgBg"></view>
+  <!-- 倒计时 -->
+  <view class="countDownBox" wx:if="{{countDown.state}}">
+    <view class="countDown">
+      <view class="number">{{countDown.num}}</view>
+      <view class="tips">秒后开始</view>
     </view>
+  </view>
 </view>

+ 8 - 0
pages/reading/index.wxss

@@ -6,6 +6,14 @@
   flex-direction: column;
   background-color: white;
 }
+.readingBox .poster {
+  top: 0px;
+  left: 0px;
+  position: absolute;
+  width: 100%;
+  height: 422rpx;
+  z-index: 99;
+}
 .readingBox #myVideo {
   width: 100%;
   height: 422rpx;

+ 69 - 0
pages/score/index.js

@@ -0,0 +1,69 @@
+// pages/score/index.js
+Page({
+
+  /**
+   * 页面的初始数据
+   */
+  data: {
+    score: {}
+  },
+
+  /**
+   * 生命周期函数--监听页面加载
+   */
+  onLoad(options) {
+    let score = JSON.parse(options.detail)
+    this.setData({
+      score
+    })
+  },
+
+  /**
+   * 生命周期函数--监听页面初次渲染完成
+   */
+  onReady() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面显示
+   */
+  onShow() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面隐藏
+   */
+  onHide() {
+
+  },
+
+  /**
+   * 生命周期函数--监听页面卸载
+   */
+  onUnload() {
+
+  },
+
+  /**
+   * 页面相关事件处理函数--监听用户下拉动作
+   */
+  onPullDownRefresh() {
+
+  },
+
+  /**
+   * 页面上拉触底事件的处理函数
+   */
+  onReachBottom() {
+
+  },
+
+  /**
+   * 用户点击右上角分享
+   */
+  onShareAppMessage() {
+
+  }
+})

+ 3 - 0
pages/score/index.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 2 - 0
pages/score/index.wxml

@@ -0,0 +1,2 @@
+<!--pages/score/index.wxml-->
+<text>pages/score/index.wxml</text>

+ 1 - 0
pages/score/index.wxss

@@ -0,0 +1 @@
+/* pages/score/index.wxss */

+ 8 - 1
project.private.config.json

@@ -12,7 +12,7 @@
         {
           "name": "",
           "pathName": "pages/reading/index",
-          "query": "videoId=1671442175069193",
+          "query": "videoId=10312700101",
           "launchMode": "default",
           "scene": null
         },
@@ -22,6 +22,13 @@
           "query": "uid=123",
           "launchMode": "default",
           "scene": null
+        },
+        {
+          "name": "",
+          "pathName": "pages/score/index",
+          "query": "detail={\"integrity\":12,\"tone\":50,\"accuracy\":8,\"fluency\":0,\"myOverall\":12.6}",
+          "launchMode": "default",
+          "scene": null
         }
       ]
     }

BIN
static/defeated.png


BIN
static/light.png


BIN
static/start-1.png


BIN
static/start-2.png


BIN
static/victory.png


BIN
static/编组备份 2.png


File diff suppressed because it is too large
+ 2069 - 0
utils/ChivoxAiEngine.js


+ 372 - 0
utils/sha1.js

@@ -0,0 +1,372 @@
+  
+/*
+ * [js-sha1]{@link https://github.com/emn178/js-sha1}
+ *
+ * @version 0.6.0
+ * @author Chen, Yi-Cyuan [emn178@gmail.com]
+ * @copyright Chen, Yi-Cyuan 2014-2017
+ * @license MIT
+ */
+/*jslint bitwise: true */
+(function() {
+    'use strict';
+  
+    var root = typeof window === 'object' ? window : {};
+    var NODE_JS = !root.JS_SHA1_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
+    if (NODE_JS) {
+      root = global;
+    }
+    var COMMON_JS = !root.JS_SHA1_NO_COMMON_JS && typeof module === 'object' && module.exports;
+    var AMD = typeof define === 'function' && define.amd;
+    var HEX_CHARS = '0123456789abcdef'.split('');
+    var EXTRA = [-2147483648, 8388608, 32768, 128];
+    var SHIFT = [24, 16, 8, 0];
+    var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];
+  
+    var blocks = [];
+  
+    var createOutputMethod = function (outputType) {
+      return function (message) {
+        return new Sha1(true).update(message)[outputType]();
+      };
+    };
+  
+    var createMethod = function () {
+      var method = createOutputMethod('hex');
+      if (NODE_JS) {
+        method = nodeWrap(method);
+      }
+      method.create = function () {
+        return new Sha1();
+      };
+      method.update = function (message) {
+        return method.create().update(message);
+      };
+      for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
+        var type = OUTPUT_TYPES[i];
+        method[type] = createOutputMethod(type);
+      }
+      return method;
+    };
+  
+    var nodeWrap = function (method) {
+      var crypto = eval("require('crypto')");
+      var Buffer = eval("require('buffer').Buffer");
+      var nodeMethod = function (message) {
+        if (typeof message === 'string') {
+          return crypto.createHash('sha1').update(message, 'utf8').digest('hex');
+        } else if (message.constructor === ArrayBuffer) {
+          message = new Uint8Array(message);
+        } else if (message.length === undefined) {
+          return method(message);
+        }
+        return crypto.createHash('sha1').update(new Buffer(message)).digest('hex');
+      };
+      return nodeMethod;
+    };
+  
+    function Sha1(sharedMemory) {
+      if (sharedMemory) {
+        blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+        this.blocks = blocks;
+      } else {
+        this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+      }
+  
+      this.h0 = 0x67452301;
+      this.h1 = 0xEFCDAB89;
+      this.h2 = 0x98BADCFE;
+      this.h3 = 0x10325476;
+      this.h4 = 0xC3D2E1F0;
+  
+      this.block = this.start = this.bytes = this.hBytes = 0;
+      this.finalized = this.hashed = false;
+      this.first = true;
+    }
+  
+    Sha1.prototype.update = function (message) {
+      if (this.finalized) {
+        return;
+      }
+      var notString = typeof(message) !== 'string';
+      if (notString && message.constructor === root.ArrayBuffer) {
+        message = new Uint8Array(message);
+      }
+      var code, index = 0, i, length = message.length || 0, blocks = this.blocks;
+  
+      while (index < length) {
+        if (this.hashed) {
+          this.hashed = false;
+          blocks[0] = this.block;
+          blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+          blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+          blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+          blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+        }
+  
+        if(notString) {
+          for (i = this.start; index < length && i < 64; ++index) {
+            blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
+          }
+        } else {
+          for (i = this.start; index < length && i < 64; ++index) {
+            code = message.charCodeAt(index);
+            if (code < 0x80) {
+              blocks[i >> 2] |= code << SHIFT[i++ & 3];
+            } else if (code < 0x800) {
+              blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            } else if (code < 0xd800 || code >= 0xe000) {
+              blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            } else {
+              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
+              blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            }
+          }
+        }
+  
+        this.lastByteIndex = i;
+        this.bytes += i - this.start;
+        if (i >= 64) {
+          this.block = blocks[16];
+          this.start = i - 64;
+          this.hash();
+          this.hashed = true;
+        } else {
+          this.start = i;
+        }
+      }
+      if (this.bytes > 4294967295) {
+        this.hBytes += this.bytes / 4294967296 << 0;
+        this.bytes = this.bytes % 4294967296;
+      }
+      return this;
+    };
+  
+    Sha1.prototype.finalize = function () {
+      if (this.finalized) {
+        return;
+      }
+      this.finalized = true;
+      var blocks = this.blocks, i = this.lastByteIndex;
+      blocks[16] = this.block;
+      blocks[i >> 2] |= EXTRA[i & 3];
+      this.block = blocks[16];
+      if (i >= 56) {
+        if (!this.hashed) {
+          this.hash();
+        }
+        blocks[0] = this.block;
+        blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+      }
+      blocks[14] = this.hBytes << 3 | this.bytes >>> 29;
+      blocks[15] = this.bytes << 3;
+      this.hash();
+    };
+  
+    Sha1.prototype.hash = function () {
+      var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4;
+      var f, j, t, blocks = this.blocks;
+  
+      for(j = 16; j < 80; ++j) {
+        t = blocks[j - 3] ^ blocks[j - 8] ^ blocks[j - 14] ^ blocks[j - 16];
+        blocks[j] =  (t << 1) | (t >>> 31);
+      }
+  
+      for(j = 0; j < 20; j += 5) {
+        f = (b & c) | ((~b) & d);
+        t = (a << 5) | (a >>> 27);
+        e = t + f + e + 1518500249 + blocks[j] << 0;
+        b = (b << 30) | (b >>> 2);
+  
+        f = (a & b) | ((~a) & c);
+        t = (e << 5) | (e >>> 27);
+        d = t + f + d + 1518500249 + blocks[j + 1] << 0;
+        a = (a << 30) | (a >>> 2);
+  
+        f = (e & a) | ((~e) & b);
+        t = (d << 5) | (d >>> 27);
+        c = t + f + c + 1518500249 + blocks[j + 2] << 0;
+        e = (e << 30) | (e >>> 2);
+  
+        f = (d & e) | ((~d) & a);
+        t = (c << 5) | (c >>> 27);
+        b = t + f + b + 1518500249 + blocks[j + 3] << 0;
+        d = (d << 30) | (d >>> 2);
+  
+        f = (c & d) | ((~c) & e);
+        t = (b << 5) | (b >>> 27);
+        a = t + f + a + 1518500249 + blocks[j + 4] << 0;
+        c = (c << 30) | (c >>> 2);
+      }
+  
+      for(; j < 40; j += 5) {
+        f = b ^ c ^ d;
+        t = (a << 5) | (a >>> 27);
+        e = t + f + e + 1859775393 + blocks[j] << 0;
+        b = (b << 30) | (b >>> 2);
+  
+        f = a ^ b ^ c;
+        t = (e << 5) | (e >>> 27);
+        d = t + f + d + 1859775393 + blocks[j + 1] << 0;
+        a = (a << 30) | (a >>> 2);
+  
+        f = e ^ a ^ b;
+        t = (d << 5) | (d >>> 27);
+        c = t + f + c + 1859775393 + blocks[j + 2] << 0;
+        e = (e << 30) | (e >>> 2);
+  
+        f = d ^ e ^ a;
+        t = (c << 5) | (c >>> 27);
+        b = t + f + b + 1859775393 + blocks[j + 3] << 0;
+        d = (d << 30) | (d >>> 2);
+  
+        f = c ^ d ^ e;
+        t = (b << 5) | (b >>> 27);
+        a = t + f + a + 1859775393 + blocks[j + 4] << 0;
+        c = (c << 30) | (c >>> 2);
+      }
+  
+      for(; j < 60; j += 5) {
+        f = (b & c) | (b & d) | (c & d);
+        t = (a << 5) | (a >>> 27);
+        e = t + f + e - 1894007588 + blocks[j] << 0;
+        b = (b << 30) | (b >>> 2);
+  
+        f = (a & b) | (a & c) | (b & c);
+        t = (e << 5) | (e >>> 27);
+        d = t + f + d - 1894007588 + blocks[j + 1] << 0;
+        a = (a << 30) | (a >>> 2);
+  
+        f = (e & a) | (e & b) | (a & b);
+        t = (d << 5) | (d >>> 27);
+        c = t + f + c - 1894007588 + blocks[j + 2] << 0;
+        e = (e << 30) | (e >>> 2);
+  
+        f = (d & e) | (d & a) | (e & a);
+        t = (c << 5) | (c >>> 27);
+        b = t + f + b - 1894007588 + blocks[j + 3] << 0;
+        d = (d << 30) | (d >>> 2);
+  
+        f = (c & d) | (c & e) | (d & e);
+        t = (b << 5) | (b >>> 27);
+        a = t + f + a - 1894007588 + blocks[j + 4] << 0;
+        c = (c << 30) | (c >>> 2);
+      }
+  
+      for(; j < 80; j += 5) {
+        f = b ^ c ^ d;
+        t = (a << 5) | (a >>> 27);
+        e = t + f + e - 899497514 + blocks[j] << 0;
+        b = (b << 30) | (b >>> 2);
+  
+        f = a ^ b ^ c;
+        t = (e << 5) | (e >>> 27);
+        d = t + f + d - 899497514 + blocks[j + 1] << 0;
+        a = (a << 30) | (a >>> 2);
+  
+        f = e ^ a ^ b;
+        t = (d << 5) | (d >>> 27);
+        c = t + f + c - 899497514 + blocks[j + 2] << 0;
+        e = (e << 30) | (e >>> 2);
+  
+        f = d ^ e ^ a;
+        t = (c << 5) | (c >>> 27);
+        b = t + f + b - 899497514 + blocks[j + 3] << 0;
+        d = (d << 30) | (d >>> 2);
+  
+        f = c ^ d ^ e;
+        t = (b << 5) | (b >>> 27);
+        a = t + f + a - 899497514 + blocks[j + 4] << 0;
+        c = (c << 30) | (c >>> 2);
+      }
+  
+      this.h0 = this.h0 + a << 0;
+      this.h1 = this.h1 + b << 0;
+      this.h2 = this.h2 + c << 0;
+      this.h3 = this.h3 + d << 0;
+      this.h4 = this.h4 + e << 0;
+    };
+  
+    Sha1.prototype.hex = function () {
+      this.finalize();
+  
+      var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4;
+  
+      return HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
+             HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
+             HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
+             HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
+             HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
+             HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
+             HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
+             HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
+             HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
+             HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
+             HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
+             HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
+             HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] +
+             HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
+             HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
+             HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
+             HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] +
+             HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] +
+             HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] +
+             HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F];
+    };
+  
+    Sha1.prototype.toString = Sha1.prototype.hex;
+  
+    Sha1.prototype.digest = function () {
+      this.finalize();
+  
+      var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4;
+  
+      return [
+        (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF,
+        (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF,
+        (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF,
+        (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF,
+        (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF
+      ];
+    };
+  
+    Sha1.prototype.array = Sha1.prototype.digest;
+  
+    Sha1.prototype.arrayBuffer = function () {
+      this.finalize();
+  
+      var buffer = new ArrayBuffer(20);
+      var dataView = new DataView(buffer);
+      dataView.setUint32(0, this.h0);
+      dataView.setUint32(4, this.h1);
+      dataView.setUint32(8, this.h2);
+      dataView.setUint32(12, this.h3);
+      dataView.setUint32(16, this.h4);
+      return buffer;
+    };
+  
+    var exports = createMethod();
+  
+    if (COMMON_JS) {
+      module.exports = exports;
+    } else {
+      root.sha1 = exports;
+      if (AMD) {
+        define(function () {
+          return exports;
+        });
+      }
+    }
+  })();