Browse Source

基础

基础
Your Name 2 years ago
commit
4d2e881aa2
61 changed files with 2126 additions and 0 deletions
  1. 31 0
      .eslintrc.js
  2. 1 0
      .gitignore
  3. 15 0
      api/global.js
  4. 20 0
      api/user.js
  5. 12 0
      api/video.js
  6. 77 0
      app.js
  7. 31 0
      app.json
  8. 46 0
      app.wxss
  9. 26 0
      components/empty/index.js
  10. 4 0
      components/empty/index.json
  11. 19 0
      components/empty/index.less
  12. 4 0
      components/empty/index.wxml
  13. 17 0
      components/empty/index.wxss
  14. 54 0
      components/navigationBar/index.js
  15. 5 0
      components/navigationBar/index.json
  16. 95 0
      components/navigationBar/index.less
  17. 37 0
      components/navigationBar/index.wxml
  18. 84 0
      components/navigationBar/index.wxss
  19. 75 0
      components/rewardedVideo/index.js
  20. 4 0
      components/rewardedVideo/index.json
  21. 1 0
      components/rewardedVideo/index.wxml
  22. 1 0
      components/rewardedVideo/index.wxss
  23. 1 0
      miniprogram_npm/mobx-miniprogram-bindings/index.js
  24. 1 0
      miniprogram_npm/mobx-miniprogram/index.js
  25. 58 0
      package-lock.json
  26. 15 0
      package.json
  27. 0 0
      pages/index/index.js
  28. 3 0
      pages/index/index.json
  29. 0 0
      pages/index/index.less
  30. 0 0
      pages/index/index.wxml
  31. 0 0
      pages/index/index.wxss
  32. 18 0
      pages/logs/logs.js
  33. 4 0
      pages/logs/logs.json
  34. 6 0
      pages/logs/logs.wxml
  35. 8 0
      pages/logs/logs.wxss
  36. 182 0
      pages/my/index.js
  37. 8 0
      pages/my/index.json
  38. 313 0
      pages/my/index.less
  39. 143 0
      pages/my/index.wxml
  40. 260 0
      pages/my/index.wxss
  41. 175 0
      pages/userWorks/index.js
  42. 9 0
      pages/userWorks/index.json
  43. 21 0
      pages/userWorks/index.less
  44. 15 0
      pages/userWorks/index.wxml
  45. 18 0
      pages/userWorks/index.wxss
  46. 51 0
      project.config.json
  47. 29 0
      project.private.config.json
  48. 7 0
      sitemap.json
  49. BIN
      static/image/collect.png
  50. BIN
      static/image/concern.png
  51. BIN
      static/image/contact.png
  52. BIN
      static/image/edit_new.png
  53. BIN
      static/image/message.png
  54. BIN
      static/image/task1.png
  55. BIN
      static/image/task2.png
  56. BIN
      static/image/task3.png
  57. BIN
      static/image/work.png
  58. 20 0
      store/index.js
  59. 41 0
      utils/filter.wxs
  60. 42 0
      utils/request.js
  61. 19 0
      utils/util.js

+ 31 - 0
.eslintrc.js

@@ -0,0 +1,31 @@
+/*
+ * Eslint config file
+ * Documentation: https://eslint.org/docs/user-guide/configuring/
+ * Install the Eslint extension before using this feature.
+ */
+module.exports = {
+  env: {
+    es6: true,
+    browser: true,
+    node: true,
+  },
+  ecmaFeatures: {
+    modules: true,
+  },
+  parserOptions: {
+    ecmaVersion: 2018,
+    sourceType: 'module',
+  },
+  globals: {
+    wx: true,
+    App: true,
+    Page: true,
+    getCurrentPages: true,
+    getApp: true,
+    Component: true,
+    requirePlugin: true,
+    requireMiniProgram: true,
+  },
+  // extends: 'eslint:recommended',
+  rules: {},
+}

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+**/node_modules

+ 15 - 0
api/global.js

@@ -0,0 +1,15 @@
+import {
+    request
+} from "../utils/request";
+module.exports = {
+    //获取充值配置信息
+    getProducts: data => request('/v3/product', 'get', data),
+    // 购买vip
+    buyVip: data => request('/order', 'post', data, true),
+    // 购买次数
+    buyNum: data => request('/v3/pay', 'post', data),
+    // 获取任务配置
+    getTasks: data => request('/v3/task', 'get', data),
+    // 提交任务
+    submitTask: data => request('/v3/task', 'post', data),
+}

+ 20 - 0
api/user.js

@@ -0,0 +1,20 @@
+import {
+  request
+} from "../utils/request";
+
+module.exports = {
+  // 用户登录
+  userLogin: data => request('/user/openId', 'get', data),
+  // 获取用户session_key和open_id
+  getUserSO: data => request('/user/openId', 'get', data),
+  //获取用户信息
+  getUserInfo: data => request('/v3/user/my', 'get', data),
+  // 设置用户信息
+  setUserInfo: (data, method = 'post') => request('/user', method, data),
+  //获取是否vip及过期时间
+  getVipInfo: data => request('/auth', 'get', data),
+  //获取自己朗读的作品
+  getSelfRead: data => request('/userRead/my', 'get', data),
+  //获取其他用户朗读的作品
+  getUserRead: data => request('/userRead', 'get', data),
+}

+ 12 - 0
api/video.js

@@ -0,0 +1,12 @@
+import {
+    request
+} from "../utils/request";
+
+module.exports = {
+    //设置视频状态。比如删除。禁用
+    setVideoStatus: data => request('/userRead', 'put', data),
+    // 作品点赞
+    likeVideo: data => request(`/userRead/like/${data}`, 'get'),
+    // 收藏
+    collectVideo: data => request('/favorites', 'post', data)
+}

+ 77 - 0
app.js

@@ -0,0 +1,77 @@
+// app.js
+import {
+  userLogin
+} from '~/api/user'
+import {
+  createStoreBindings
+} from 'mobx-miniprogram-bindings'
+import {
+  store
+} from '~/store/index'
+let storeBindings
+App({
+  onLaunch() {
+    this.checkIsIos()
+    this.getNavbarInfo()
+  },
+  async onShow(options) {
+    let shareUid = options.query.uid
+    this.login(shareUid)
+  },
+  login(shareUid) {
+    this.storeBindings = createStoreBindings(this, {
+      store,
+      fields: ['numA', ],
+      actions: ['updateNumA']
+    })
+    wx.login({
+      success: async (res) => {
+        this.updateNumA(res)
+        if (res.code) {
+          // 获取openid
+          let data = {
+            code: res.code,
+            shareUid
+          }
+          let userRes = await userLogin(data)
+          console.log(userRes);
+          wx.setStorageSync('uid', userRes.data.uid)
+          wx.setStorageSync('user', userRes.data)
+          this.globalData.userInfo = userRes.data
+          if (getApp().callBack) {
+            getApp().callBack(userRes);
+          }
+        }
+      }
+    })
+  },
+  checkIsIos: function () {
+    wx.getSystemInfo({
+      success: (res) => {
+        if (res.system.search('iOS') != -1) {
+          this.globalData.isIOS = true
+        }
+      }
+    })
+  },
+  getNavbarInfo() {
+    // 获取系统信息
+    const systemInfo = wx.getSystemInfoSync();
+    console.log(systemInfo);
+    // 胶囊按钮位置信息
+    const menuButtonInfo = wx.getMenuButtonBoundingClientRect();
+    // 导航栏高度 = 状态栏高度 + 44
+    this.globalData.navBarHeight = systemInfo.statusBarHeight + 44;
+    this.globalData.menuRight = systemInfo.screenWidth - menuButtonInfo.right;
+    this.globalData.menuTop = menuButtonInfo.top;
+    this.globalData.menuHeight = menuButtonInfo.height;
+  },
+  globalData: {
+    userInfo: null,
+    isIOS: false, // 判断设备是否为苹果
+    navBarHeight: 0, // 导航栏高度
+    menuRight: 0, // 胶囊距右方间距(方保持左、右间距一致)
+    menuTop: 0, // 胶囊距底部间距(保持底部间距一致)
+    menuHeight: 0, // 胶囊高度(自定义内容可与胶囊高度保证一致)
+  }
+})

+ 31 - 0
app.json

@@ -0,0 +1,31 @@
+{
+  "pages": [
+    "pages/my/index",
+    "pages/logs/logs",
+    "pages/index/index"
+  ],
+  "tabBar": {
+    "list": [{
+      "pagePath": "pages/my/index",
+      "text": "我的"
+    }, {
+      "pagePath": "pages/index/index",
+      "text": "推荐"
+    }, {
+      "pagePath": "pages/logs/logs",
+      "text": "作品"
+    }]
+  },
+  "window": {
+    "backgroundTextStyle": "light",
+    "navigationBarBackgroundColor": "#ededed",
+    "navigationBarTitleText": "小学语文朗读配音",
+    "navigationBarTextStyle": "black",
+    "onReachBottomDistance": 50,
+    "enablePullDownRefresh": true
+  },
+  "resolveAlias": {
+    "~/*": "/*"
+  },
+  "sitemapLocation": "sitemap.json"
+}

+ 46 - 0
app.wxss

@@ -0,0 +1,46 @@
+/**app.wxss**/
+page {
+  width: 100%;
+  /* min-height: 100%; */
+  color: #333;
+  font-family: PingFang SC, Microsoft Yahei, Source Han Sans CN, SimHei;
+  background: #eee;
+}
+
+view {
+  font-family: PingFang SC, Microsoft Yahei, Source Han Sans CN, SimHei;
+}
+
+text {
+  font-family: PingFang SC, Microsoft Yahei, Source Han Sans CN, SimHei;
+}
+.container {
+  height: auto;
+  box-sizing: border-box;
+  font-family: PingFang SC, Microsoft Yahei, Source Han Sans CN, SimHei;
+}
+
+#share {
+  width: 375px;
+  height: 300px;
+  position: absolute;
+  left: -999rpx;
+  top: -9999rpx;
+}
+
+.textOver {
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.resetBtn {
+  padding: 0px;
+  margin: 0;
+  line-height: normal;
+  background-color: transparent;
+}
+
+.resetBtn::after {
+  border: none;
+}

+ 26 - 0
components/empty/index.js

@@ -0,0 +1,26 @@
+// component/empty/index.js
+Component({
+    /**
+     * 组件的属性列表
+     */
+    properties: {
+        message: {
+            type: String,
+            value: "空空如也..."
+        }
+    },
+
+    /**
+     * 组件的初始数据
+     */
+    data: {
+
+    },
+
+    /**
+     * 组件的方法列表
+     */
+    methods: {
+
+    }
+})

+ 4 - 0
components/empty/index.json

@@ -0,0 +1,4 @@
+{
+    "component": true,
+    "usingComponents": {}
+}

+ 19 - 0
components/empty/index.less

@@ -0,0 +1,19 @@
+.empty {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+
+    .nullImg {
+        margin-top: 250rpx;
+        width: 364rpx;
+        height: 280rpx;
+    }
+
+    .message {
+        margin-top: 30rpx;
+        font-size: 32rpx;
+        font-weight: bold;
+        color: #FFB513;
+    }
+}

+ 4 - 0
components/empty/index.wxml

@@ -0,0 +1,4 @@
+<view class="empty">
+    <image src="/static/image/null.png" class="nullImg" mode="" />
+    <view class="message">{{message}}</view>
+</view>

+ 17 - 0
components/empty/index.wxss

@@ -0,0 +1,17 @@
+.empty {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+}
+.empty .nullImg {
+  margin-top: 250rpx;
+  width: 364rpx;
+  height: 280rpx;
+}
+.empty .message {
+  margin-top: 30rpx;
+  font-size: 32rpx;
+  font-weight: bold;
+  color: #FFB513;
+}

+ 54 - 0
components/navigationBar/index.js

@@ -0,0 +1,54 @@
+const app = getApp()
+import {
+  setUserInfo
+} from '~/api/user'
+Component({
+  properties: {
+    title: {
+      type: String,
+      value: '朗读小咖秀',
+    }
+  },
+  data: {
+    navBarHeight: app.globalData.navBarHeight,
+    menuRight: app.globalData.menuRight,
+    menuTop: app.globalData.menuTop,
+    menuHeight: app.globalData.menuHeight,
+    grade: null,
+    isGradeShow: false
+  },
+  attached: function () {
+    // console.log(wx.getStorage(user));
+  },
+  methods: {
+    // 选择年级
+    selectGrade({
+      target
+    }) {
+      let code = target.dataset.code
+      if (!code) {
+        return
+      }
+      this.setData({
+        grade: code
+      })
+    },
+    // 修改年级
+    async changeGrade(e) {
+      const grade = this.data.grade
+      if (!grade) {
+        return wx.showToast({
+          title: '请选择年级',
+          icon: 'none',
+          duration: 2000
+        })
+      }
+      this.setData({
+        isGradeShow: false,
+      })
+      await setUserInfo({
+        grade
+      }, 'put')
+    },
+  }
+})

+ 5 - 0
components/navigationBar/index.json

@@ -0,0 +1,5 @@
+{
+  "component": true,
+  "usingComponents": {},
+  "styleIsolation": "apply-shared"
+}

+ 95 - 0
components/navigationBar/index.less

@@ -0,0 +1,95 @@
+.nav-bar {
+  position: fixed;
+  width: 100%;
+  top: 0;
+  z-index: 9999;
+  color: #fff;
+  background: #30C866;
+
+  .view {
+    padding: 0px 31rpx;
+    width: 100%;
+    color: #fff;
+    position: absolute;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    .selectGrade {
+      position: absolute;
+      left: 22rpx;
+      width: 158rpx;
+      height: 48rpx;
+      line-height: 48rpx;
+      border-radius: 25rpx;
+      background-color: #ffffffa6;
+      color: #333;
+      font-size: 24rpx;
+      text-align: center;
+    }
+
+    .title {
+      text-align: center;
+    }
+  }
+}
+
+.gradeContainer {
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, .7);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 9999;
+
+  .gradeBox {
+    width: 530rpx;
+    padding: 33rpx 40rpx 50rpx;
+    border-radius: 20rpx;
+    background-color: white;
+
+    .title {
+      text-align: center;
+      font-size: 40rpx;
+      font-weight: bold;
+    }
+
+    .content {
+      margin-top: 65rpx;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .grade {
+        padding: 14rpx 64rpx;
+        border-radius: 50rpx;
+        font-size: 36rpx;
+        color: #333;
+        background-color: #E4E4E4;
+      }
+
+      .check {
+        color: white;
+        background-color: #1CCC69;
+      }
+    }
+
+    .submitBox {
+      text-align: center;
+
+      .submit {
+        margin-top: 60rpx;
+        padding: 16rpx 118rpx;
+        display: inline-block;
+        background-color: #F7991B;
+        color: white;
+        font-size: 42rpx;
+        border-radius: 50rpx;
+      }
+    }
+  }
+}

+ 37 - 0
components/navigationBar/index.wxml

@@ -0,0 +1,37 @@
+<!-- 自定义顶部栏 -->
+<view class="nav-bar" style="height:{{navBarHeight}}px;">
+  <view class="view" style="height:{{menuHeight}}px;top:{{menuTop}}px;">
+    <view class="selectGrade">一年级</view>
+    <view class="title">{{title}}</view>
+  </view>
+</view>
+
+<!-- 
+  内容区域:
+  自定义顶部栏用的fixed定位,会遮盖到下面内容,注意设置好间距
+-->
+<view class="content" style="margin-top:{{navBarHeight}}px;"></view>
+
+<view class="gradeContainer" catchtouchmove='true' style="margin-top:{{navBarHeight}}px;">
+  <view class="gradeBox" bindtap="selectGrade">
+    <view class="title">年级选择</view>
+    <view class="content">
+      <view class="grade {{temporaryGrade=='PRESCHOOL'?'check':''}}" data-code="PRESCHOOL">学前班</view>
+      <view class="grade {{temporaryGrade=='PRIMARY_FIRST_GRADE'?'check':''}}" data-code="PRIMARY_FIRST_GRADE">一年级
+      </view>
+    </view>
+    <view class="content">
+      <view class="grade {{temporaryGrade=='PRIMARY_SECOND_GRADE'?'check':''}}" data-code="PRIMARY_SECOND_GRADE">二年级
+      </view>
+      <view class="grade {{temporaryGrade=='PRIMARY_THREE_GRADE'?'check':''}}" data-code="PRIMARY_THREE_GRADE">三年级
+      </view>
+    </view>
+    <view class="content">
+      <view class="grade {{temporaryGrade=='PRIMARY_SENIOR_GRADE'?'check':''}}" data-code="PRIMARY_SENIOR_GRADE">四年级
+      </view>
+    </view>
+    <view class="submitBox">
+      <button class="resetBtn submit" bindtap="changeGrade">登录</button>
+    </view>
+  </view>
+</view>

+ 84 - 0
components/navigationBar/index.wxss

@@ -0,0 +1,84 @@
+.nav-bar {
+  position: fixed;
+  width: 100%;
+  top: 0;
+  z-index: 9999;
+  color: #fff;
+  background: #30C866;
+}
+.nav-bar .view {
+  padding: 0px 31rpx;
+  width: 100%;
+  color: #fff;
+  position: absolute;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.nav-bar .view .selectGrade {
+  position: absolute;
+  left: 22rpx;
+  width: 158rpx;
+  height: 48rpx;
+  line-height: 48rpx;
+  border-radius: 25rpx;
+  background-color: #ffffffa6;
+  color: #333;
+  font-size: 24rpx;
+  text-align: center;
+}
+.nav-bar .view .title {
+  text-align: center;
+}
+.gradeContainer {
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.7);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 9999;
+}
+.gradeContainer .gradeBox {
+  width: 530rpx;
+  padding: 33rpx 40rpx 50rpx;
+  border-radius: 20rpx;
+  background-color: white;
+}
+.gradeContainer .gradeBox .title {
+  text-align: center;
+  font-size: 40rpx;
+  font-weight: bold;
+}
+.gradeContainer .gradeBox .content {
+  margin-top: 65rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.gradeContainer .gradeBox .content .grade {
+  padding: 14rpx 64rpx;
+  border-radius: 50rpx;
+  font-size: 36rpx;
+  color: #333;
+  background-color: #E4E4E4;
+}
+.gradeContainer .gradeBox .content .check {
+  color: white;
+  background-color: #1CCC69;
+}
+.gradeContainer .gradeBox .submitBox {
+  text-align: center;
+}
+.gradeContainer .gradeBox .submitBox .submit {
+  margin-top: 60rpx;
+  padding: 16rpx 118rpx;
+  display: inline-block;
+  background-color: #F7991B;
+  color: white;
+  font-size: 42rpx;
+  border-radius: 50rpx;
+}

+ 75 - 0
components/rewardedVideo/index.js

@@ -0,0 +1,75 @@
+import {
+    submitTask
+} from '~/api/global'
+var videoAd = null;
+Component({
+    /**
+     * 组件的属性列表
+     */
+    properties: {
+
+    },
+    lifetimes: {
+        attached() {
+            this.createVideo()
+        }
+    },
+    /**
+     * 组件的初始数据
+     */
+    data: {
+
+    },
+
+    /**
+     * 组件的方法列表
+     */
+    methods: {
+        rewardedVideo() {
+            if (!videoAd) {
+                this.createVideo()
+            }
+            videoAd.show().catch(err => {
+                // 失败重试
+                videoAd.load()
+                    .then(() => videoAd.show())
+            })
+        },
+        // 创建广告对象并监听
+        createVideo() {
+            if (wx.createRewardedVideoAd) {
+                // 加载激励视频广告
+                videoAd = wx.createRewardedVideoAd({
+                    adUnitId: 'adunit-77f46b2dc73da123'
+                })
+                //捕捉错误
+                videoAd.onError(err => {
+                    console.log(err);
+                })
+                // 监听关闭
+                videoAd.onClose((status) => {
+                    videoAd.offClose()
+                    videoAd = null
+                    if (status && status.isEnded || status === undefined) {
+                        // 正常播放结束,下发奖励
+                        submitTask({
+                            id: 3
+                        }).then(res => {
+                            wx.showToast({
+                                icon: 'none',
+                                title: '观看成功!',
+                            })
+                            this.triggerEvent('taskOver')
+                        })
+                    } else {
+                        // 播放中途退出,进行提示
+                        wx.showToast({
+                            icon: 'none',
+                            title: '取消观看',
+                        })
+                    }
+                })
+            }
+        }
+    }
+})

+ 4 - 0
components/rewardedVideo/index.json

@@ -0,0 +1,4 @@
+{
+    "component": true,
+    "usingComponents": {}
+}

+ 1 - 0
components/rewardedVideo/index.wxml

@@ -0,0 +1 @@
+<view></view>

+ 1 - 0
components/rewardedVideo/index.wxss

@@ -0,0 +1 @@
+/* component/rewardedVideo/index.wxss */

File diff suppressed because it is too large
+ 1 - 0
miniprogram_npm/mobx-miniprogram-bindings/index.js


File diff suppressed because it is too large
+ 1 - 0
miniprogram_npm/mobx-miniprogram/index.js


+ 58 - 0
package-lock.json

@@ -0,0 +1,58 @@
+{
+  "name": "ldxkx",
+  "version": "1.0.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "ldxkx",
+      "version": "1.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "mobx-miniprogram": "^4.13.2",
+        "mobx-miniprogram-bindings": "^2.1.5"
+      }
+    },
+    "node_modules/@types/wechat-miniprogram": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/@types/wechat-miniprogram/-/wechat-miniprogram-3.4.1.tgz",
+      "integrity": "sha512-szbuYR32VotxNQNQ4YyQ6Ob3ya0tLY0zpf/xvi6DF8Oqb+0Y+5CL5BpxS+4wBSJvlu3VfSXhjxZ0ze1a3l16Pw=="
+    },
+    "node_modules/mobx-miniprogram": {
+      "version": "4.13.2",
+      "resolved": "https://registry.npmjs.org/mobx-miniprogram/-/mobx-miniprogram-4.13.2.tgz",
+      "integrity": "sha512-C3HtkqHCLKp35N2gXA80yFD6PNfSqwioPFmnjTQpBLrEqYm1F6yiWZ57CW+8FqgmR306mw6ZfsM5q7hSTHw8BQ=="
+    },
+    "node_modules/mobx-miniprogram-bindings": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/mobx-miniprogram-bindings/-/mobx-miniprogram-bindings-2.1.5.tgz",
+      "integrity": "sha512-2HuiQL5FPgoYJ8XIMdw5iD6XT61LtsujaGyizbN845iZcsLmrKZiF0dKd4jQTSuC/6rGozqqhcy0sDc7qcpjYQ==",
+      "dependencies": {
+        "@types/wechat-miniprogram": "^3.4.0"
+      },
+      "peerDependencies": {
+        "mobx-miniprogram": "^4.0.0"
+      }
+    }
+  },
+  "dependencies": {
+    "@types/wechat-miniprogram": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/@types/wechat-miniprogram/-/wechat-miniprogram-3.4.1.tgz",
+      "integrity": "sha512-szbuYR32VotxNQNQ4YyQ6Ob3ya0tLY0zpf/xvi6DF8Oqb+0Y+5CL5BpxS+4wBSJvlu3VfSXhjxZ0ze1a3l16Pw=="
+    },
+    "mobx-miniprogram": {
+      "version": "4.13.2",
+      "resolved": "https://registry.npmjs.org/mobx-miniprogram/-/mobx-miniprogram-4.13.2.tgz",
+      "integrity": "sha512-C3HtkqHCLKp35N2gXA80yFD6PNfSqwioPFmnjTQpBLrEqYm1F6yiWZ57CW+8FqgmR306mw6ZfsM5q7hSTHw8BQ=="
+    },
+    "mobx-miniprogram-bindings": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/mobx-miniprogram-bindings/-/mobx-miniprogram-bindings-2.1.5.tgz",
+      "integrity": "sha512-2HuiQL5FPgoYJ8XIMdw5iD6XT61LtsujaGyizbN845iZcsLmrKZiF0dKd4jQTSuC/6rGozqqhcy0sDc7qcpjYQ==",
+      "requires": {
+        "@types/wechat-miniprogram": "^3.4.0"
+      }
+    }
+  }
+}

+ 15 - 0
package.json

@@ -0,0 +1,15 @@
+{
+  "name": "ldxkx",
+  "version": "1.0.0",
+  "description": "",
+  "main": ".eslintrc.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "mobx-miniprogram": "^4.13.2",
+    "mobx-miniprogram-bindings": "^2.1.5"
+  }
+}

+ 0 - 0
pages/index/index.js


+ 3 - 0
pages/index/index.json

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

+ 0 - 0
pages/index/index.less


+ 0 - 0
pages/index/index.wxml


+ 0 - 0
pages/index/index.wxss


+ 18 - 0
pages/logs/logs.js

@@ -0,0 +1,18 @@
+// logs.js
+const util = require('../../utils/util.js')
+
+Page({
+  data: {
+    logs: []
+  },
+  onLoad() {
+    this.setData({
+      logs: (wx.getStorageSync('logs') || []).map(log => {
+        return {
+          date: util.formatTime(new Date(log)),
+          timeStamp: log
+        }
+      })
+    })
+  }
+})

+ 4 - 0
pages/logs/logs.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "查看启动日志",
+  "usingComponents": {}
+}

+ 6 - 0
pages/logs/logs.wxml

@@ -0,0 +1,6 @@
+<!--logs.wxml-->
+<view class="container log-list">
+  <block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log">
+    <text class="log-item">{{index + 1}}. {{log.date}}</text>
+  </block>
+</view>

+ 8 - 0
pages/logs/logs.wxss

@@ -0,0 +1,8 @@
+.log-list {
+  display: flex;
+  flex-direction: column;
+  padding: 40rpx;
+}
+.log-item {
+  margin: 10rpx;
+}

+ 182 - 0
pages/my/index.js

@@ -0,0 +1,182 @@
+import {
+  getUserInfo,
+  getVipInfo
+} from '~/api/user'
+import {
+  getProducts,
+  getTasks,
+  buyVip,
+  buyNum,
+  submitTask
+} from '~/api/global'
+const app = getApp()
+Page({
+  data: {
+    userInfo: {},
+    vipTime: '',
+    tasks: [],
+    isIos: app.globalData.isIOS,
+    productNum: {},
+    productVip: {}
+  },
+  onLoad() {
+    this.getProducts()
+  },
+  async onShow() {
+    let uid = wx.getStorageSync('uid') || ''
+    if (!uid) {
+      getApp().callBack = (res) => {
+        this.setUserInfo()
+      }
+    } else {
+      this.setUserInfo()
+    }
+  },
+  // 设置用户信息及vip状态和任务完成情况
+  async setUserInfo() {
+    let userInfo = await getUserInfo()
+    console.log(userInfo, '4222');
+    let vipTime = await getVipInfo()
+    this.getTasks()
+    this.setData({
+      userInfo,
+      vipTime,
+    })
+  },
+  async getTasks() {
+    let tasks = await getTasks()
+    this.setData({
+      tasks
+    })
+  },
+  async getProducts() {
+    let products = await getProducts()
+    console.log(products);
+    let productVip = products.find(item => {
+      return item.type == 1
+    })
+    let productNum = products.find(item => {
+      return item.type == 2
+    })
+    this.setData({
+      productNum,
+      productVip
+    })
+  },
+  //购买vip和购买次数不是一个接口 type 1001是vip,1010是次数
+  async toBuy({
+    currentTarget
+  }) {
+    let productId = currentTarget.dataset.type
+    wx.showLoading({
+      title: '提交中',
+      mask: true
+    })
+    let res = ''
+    if (productId == '1001') {
+      res = await buyVip({
+        productId
+      }).finally(() => {
+        wx.hideLoading()
+      })
+    } else if (productId == '1010') {
+      res = await buyNum({
+        productId
+      }).finally(() => {
+        wx.hideLoading()
+      })
+    } else {
+      wx.hideLoading()
+      wx.showToast({
+        title: "支付失败,请重试",
+        icon: "none"
+      })
+    }
+    let {
+      timeStamp,
+      nonceStr,
+      signType,
+      paySign
+    } = res
+    // package保留字
+    wx.requestPayment({
+      timeStamp,
+      nonceStr,
+      package: res.package,
+      signType,
+      paySign,
+      success(res) {
+        wx.showToast({
+          title: "支付成功",
+          duration: 2500
+        })
+        setTimeout(() => {
+          this.setUserInfo()
+        }, 1500)
+
+      },
+      fail(res) {
+        wx.showToast({
+          title: "支付失败",
+          icon: "none"
+        })
+      }
+    })
+  },
+  // 提交任务
+  async submitTask({
+    currentTarget
+  }) {
+    let id = currentTarget.dataset.type
+    await submitTask({
+      id
+    })
+    wx.showToast({
+      title: id == '1' ? '签到成功!' : id == 3 ? "观看成功!" : "",
+      icon: "none"
+    })
+    this.setUserInfo()
+  },
+  jump({
+    currentTarget
+  }) {
+    let url = currentTarget.dataset.url
+    wx.navigateTo({
+      url: url
+    });
+  },
+  // 调起广告
+  rewardedVideo() {
+    if (this.data.tasks.length != 3 || this.data.tasks[2].completed) {
+      return
+    }
+    this.selectComponent('#advert').rewardedVideo();
+  },
+  clipboar() {
+    wx.setClipboardData({
+      data: this.data.userInfo.user.eid,
+      success: function (res) { //成功回调函数
+        wx.showToast({
+          title: '已复制',
+          icon: "none"
+        })
+      }
+    })
+  },
+  // 分享配置
+  onShareAppMessage: function (res) {
+    const user = wx.getStorageSync('user');
+    return {
+      title: '课文朗读,从未如此有趣。',
+      path: `/pages/index/index?uid=${user.uid}`,
+      imageUrl: 'http://reader-wx.ai160.com/images/reader/v3/shareContent.png'
+    }
+  },
+  onShareTimeline: function () {
+    return {
+      title: '终于找到适合孩子的朗读神器了!动画配音,边玩边学!',
+      query: `uid=${wx.getStorageSync('uid')}`,
+      imageUrl: 'http://reader-wx.ai160.com/images/reader/v3/yuwen.jpg'
+    }
+  },
+})

+ 8 - 0
pages/my/index.json

@@ -0,0 +1,8 @@
+{
+  "usingComponents": {
+    "rewardedVideo": "/components/rewardedVideo/index",
+    "navigationBar":"/components/navigationBar/index"
+  },
+  "navigationStyle": "custom",
+  "enablePullDownRefresh": false
+}

+ 313 - 0
pages/my/index.less

@@ -0,0 +1,313 @@
+.container {
+  padding: 30rpx 20rpx;
+
+  .userBox {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    background-color: white;
+    padding: 20rpx 12rpx 0rpx;
+    border-radius: 20rpx;
+
+    .avatar {
+      width: 152rpx;
+      height: 152rpx;
+      border-radius: 50%;
+      position: relative;
+    }
+
+    .userRight {
+      flex: 1;
+      margin-left: 30rpx;
+      padding: 0px 10rpx;
+
+      .uRtop {
+        display: flex;
+        justify-content: space-between;
+
+        .uRtopleft {
+          .nickName {
+            max-width: 340rpx;
+            color: #333;
+            font-size: 32rpx;
+          }
+
+          .gradeText {
+            margin: 18rpx 0rpx 12rpx;
+            font-size: 24rpx;
+            color: #989A9C;
+          }
+        }
+
+        .uRtopRight {
+          display: flex;
+          align-items: center;
+
+          .edit {
+            width: 22rpx;
+            height: 28rpx;
+          }
+
+          text {
+            margin: 0px 10rpx;
+            font-size: 24rpx;
+            color: #666;
+          }
+        }
+      }
+
+      .uRBtm {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        border-top: 1px solid rgba(0, 0, 0, 0.1);
+        padding: 18rpx 0rpx;
+
+        .count {
+          width: 33%;
+          font-size: 28rpx;
+          color: rgba(0, 0, 0, 0.6);
+          border-right: 1px solid rgba(51, 51, 51, 0.3);
+          text-align: center;
+
+          .countNum {
+            margin-left: 10rpx;
+          }
+        }
+
+        .countFirst {
+          text-align: left;
+        }
+
+        .countEnd {
+          text-align: right;
+          border: none;
+        }
+      }
+    }
+  }
+
+  .iosVip {
+    margin: 4rpx 0px 0px 6rpx;
+    font-size: 20rpx;
+    color: #333;
+  }
+
+  .sectionBoxs {
+    margin-top: 20rpx;
+    padding: 20rpx 30rpx;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    background-color: white;
+    border-radius: 20rpx;
+
+    .sBox {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+
+      .img {
+        width: 69rpx;
+        height: 69rpx;
+      }
+
+      .title {
+        margin-top: 8rpx;
+        font-size: 24rpx;
+        color: #333;
+      }
+    }
+
+    .contactBtn {
+      border: none;
+      padding: 0rpx;
+      line-height: normal;
+      margin: 0;
+    }
+  }
+
+  .payBox {
+    margin-top: 20rpx;
+    padding: 13rpx 30rpx;
+    background-color: white;
+    border-radius: 20rpx;
+
+    .title {
+      font-size: 30rpx;
+      font-weight: bold;
+      color: #000;
+    }
+
+    .pay {
+      margin: 20rpx 0rpx;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0rpx 30rpx;
+      border-radius: 22rpx;
+      overflow: hidden;
+
+      .payLeft {
+        .pLTitle {
+          font-size: 36rpx;
+          font-weight: bold;
+        }
+
+        .pLcontent {
+          font-size: 22rpx;
+        }
+      }
+
+      .payRight {
+        margin: 24rpx 0rpx;
+        padding: 12rpx 28rpx;
+        border-radius: 40rpx;
+        font-size: 24rpx;
+        font-weight: bold;
+      }
+    }
+
+    .vipPay {
+      background: url('http://reader-wx.ai160.com/images/reader/v3/year.png') no-repeat;
+      background-size: cover;
+
+      .vipTitle {
+        color: #FFE6B9;
+      }
+
+      .vipContent {
+        margin-top: 4rpx;
+        color: #FFE6B9;
+      }
+
+      .vipBtn {
+        background-image: linear-gradient(to bottom, #F4E7A8, #F9EDCF);
+        color: #211501;
+      }
+    }
+
+    .buyPay {
+      background: url('http://reader-wx.ai160.com/images/reader/v3/10yuan.png') no-repeat;
+      background-size: cover;
+
+      .payLeft {
+        color: #7D320A;
+        font-size: 36rpx;
+        font-weight: bold;
+      }
+
+      .buyBtn {
+        border: 1rpx solid white;
+        color: white;
+        background-color: #7D320A;
+      }
+    }
+  }
+
+  .surplus {
+    margin-top: 20rpx;
+    padding: 22rpx 30rpx;
+    background-color: white;
+    border-radius: 20rpx;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-size: 32rpx;
+
+    .title {
+      font-size: 30rpx;
+      font-weight: bold;
+      color: #000;
+    }
+
+    .num {
+      color: #F97419;
+      font-weight: bold;
+      margin-right: 10rpx;
+    }
+  }
+
+  .taskBox {
+    margin-top: 20rpx;
+    padding: 20rpx 10rpx 0rpx;
+    background-color: white;
+    border-radius: 20rpx;
+
+    .title {
+      padding: 0rpx 20rpx;
+      font-size: 30rpx;
+      font-weight: bold;
+      color: #000;
+    }
+
+    .task {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 30rpx 22rpx;
+      border-bottom: 1px solid #EAEAEA;
+
+      .taskLeft {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+
+        .img {
+          width: 76rpx;
+          height: 76rpx;
+          border-radius: 50%;
+        }
+
+        .taskContent {
+          margin-left: 40rpx;
+
+          .tcTitle {
+            font-size: 30rpx;
+            font-weight: bold;
+            color: #333;
+          }
+
+          .tcNum {
+            color: #FF6259;
+            font-size: 26rpx;
+          }
+        }
+      }
+
+      .taskRightBox {
+        display: flex;
+        flex-direction: column;
+        align-items: flex-end;
+        /*  */
+      }
+
+      .taskRight {
+        width: 138rpx;
+        text-align: center;
+        padding: 10rpx 0rpx;
+        border-radius: 40rpx;
+        color: white;
+        background-color: #FC614E;
+        font-size: 30rpx;
+      }
+
+      .taskRight-close {
+        color: #6C6C6C;
+        background: #D0D0D0;
+        box-shadow: 0 2px 2px 0 #AEABAB;
+      }
+
+      .taskSurplus {
+        text-align: center;
+        margin-top: 4rpx;
+        color: #686868;
+        font-size: 20rpx;
+      }
+    }
+
+    .advert {
+      border: none;
+    }
+  }
+}

+ 143 - 0
pages/my/index.wxml

@@ -0,0 +1,143 @@
+<wxs src="../../utils/filter.wxs" module="filters" />
+<navigationBar title="我的"></navigationBar>
+<view class="container">
+  <!-- 用户信息 -->
+  <view class="userBox">
+    <image class='avatar' src='{{ userInfo.user.avatar}}'></image>
+    <view class="userRight">
+      <view class="uRtop" bindtap="jump" data-url="/pages/user/myEdit/myEdit">
+        <view class="uRtopleft">
+          <view class="nickName textOver">昵称:{{userInfo.user.nickName||userInfo.user.eid }}</view>
+          <view class="gradeText textOver">学号:{{userInfo.user.eid}}</view>
+        </view>
+        <view class="uRtopRight">
+          <image class="edit" src="/static/image/edit_new.png" mode="" />
+          <text>编辑</text>
+        </view>
+      </view>
+      <view class="uRBtm">
+        <view class="count countFirst">
+          作品<text class="countNum textOver">{{filters.numFilter(userInfo.readAmount)|| 0}}</text>
+        </view>
+        <view class="count">
+          粉丝<text class="countNum textOver">{{filters.numFilter(userInfo.fansAmount)|| '0'}}</text>
+        </view>
+        <view class="count countEnd">
+          播放<text class="countNum textOver">{{filters.numFilter(userInfo.playAmount) || 0}}</text>
+        </view>
+      </view>
+    </view>
+  </view>
+  <!-- ios会员展示到期时间 -->
+  <view class="iosVip" wx:if="{{isIos&&vipTime}}">
+    会员至:{{filters.formatDate(vipTime)}}
+  </view>
+  <!-- 跳转菜单 -->
+  <view class="sectionBoxs">
+    <view class="sBox" bindtap='jump' data-url="/pages/userWorks/index">
+      <image class="img" src="/static/image/work.png" mode="" />
+      <text class="title">我的作品</text>
+    </view>
+    <view class="sBox" bindtap='jump' data-url="/pages/myconcern/myconcern?title=我的关注">
+      <image class="img" src="/static/image/concern.png" mode="" />
+      <text class="title">我的关注</text>
+    </view>
+    <view class="sBox" bindtap='jump' data-url="/pages/mycollection/mycollection?title=我的收藏">
+      <image class="img" src="/static/image/collect.png" mode="" />
+      <text class="title">我的收藏</text>
+    </view>
+    <view class="sBox" bindtap='jump' data-url="/pages/social/insideMessage/insideMessage">
+      <image class="img" src="/static/image/message.png" mode="" />
+      <text class="title">消息通知</text>
+    </view>
+    <button class="resetBtn contactBtn" bindtap="goToService" open-type="contact" plain="true">
+      <view class="sBox">
+        <image class="img" src="/static/image/contact.png" mode="" />
+        <text class="title">联系客服</text>
+      </view>
+    </button>
+  </view>
+  <!-- 支付 -->
+  <!-- <view class="payBox" wx:if="{{!isIos}}"> -->
+  <view class="payBox">
+    <view class="title">
+      付费购
+    </view>
+    <view class="pay vipPay">
+      <view class="payLeft">
+        <view class="pLTitle vipTitle">
+          {{productVip.title}}
+        </view>
+        <view class="pLcontent vipContent">
+          {{vipTime?filters.formatDate(vipTime)+'过期':'购买VIP会员,即可有权使用全部资源'}}
+        </view>
+      </view>
+      <view class="payRight vipBtn" bindtap="toBuy" data-type="{{productVip.id}}">
+        {{vipTime?'立即续费':'立即开通'}}
+      </view>
+    </view>
+    <view class="pay buyPay">
+      <view class="payLeft">
+        {{productNum.title}}
+      </view>
+      <view class="payRight buyBtn" bindtap="toBuy" data-type="{{productNum.id}}">
+        立即购买
+      </view>
+    </view>
+  </view>
+  <!-- 剩余使用次数 -->
+  <view class="surplus">
+    <view class="title">剩余使用次数:</view>
+    <view class="num">{{userInfo.experienceAmount}}次</view>
+  </view>
+  <!-- 任务活动 -->
+  <view class="taskBox">
+    <view class="title">免费获取</view>
+    <view class="task">
+      <view class="taskLeft">
+        <image class="img" src="/static/image/task1.png" alt="" mode="" />
+        <view class="taskContent">
+          <view class="tcTitle">
+            {{tasks[0].title}}
+          </view>
+          <view class="tcNum">+{{tasks[0].award}}次</view>
+        </view>
+      </view>
+      <view class="taskRight {{tasks[0].completed?'taskRight-close':''}}" bindtap="submitTask"
+        data-type='{{tasks[0].id}}'>
+        {{tasks[0].completed?'已签到':'签到'}}</view>
+    </view>
+    <view class="task">
+      <view class="taskLeft">
+        <image class="img" src="/static/image/task2.png" alt="" mode="" />
+        <view class="taskContent">
+          <view class="tcTitle">
+            {{tasks[1].title}}
+          </view>
+          <view class="tcNum">+{{tasks[1].award}}次/每位</view>
+        </view>
+      </view>
+      <button open-type="share" class="resetBtn taskRight">去邀请</button>
+    </view>
+    <view class="task advert">
+      <view class="taskLeft">
+        <image class="img" src="/static/image/task3.png" alt="" mode="" />
+        <view class="taskContent">
+          <view class="tcTitle">
+            {{tasks[2].title}}
+          </view>
+          <view class="tcNum">+{{tasks[2].award}}次/每条</view>
+        </view>
+      </view>
+      <view class="taskRightBox">
+        <view class="taskRight {{tasks[2].completed?'taskRight-close':''}}" bindtap="rewardedVideo">去观看
+        </view>
+        <view class="taskSurplus">
+          今日剩余{{tasks[2].num-tasks[2].completedNum}}次
+        </view>
+      </view>
+    </view>
+  </view>
+</view>
+<!-- 广告组件 -->
+<rewardedVideo id='advert' bind:taskOver="setUserInfo" />

+ 260 - 0
pages/my/index.wxss

@@ -0,0 +1,260 @@
+.container {
+  padding: 30rpx 20rpx;
+}
+.container .userBox {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  background-color: white;
+  padding: 20rpx 12rpx 0rpx;
+  border-radius: 20rpx;
+}
+.container .userBox .avatar {
+  width: 152rpx;
+  height: 152rpx;
+  border-radius: 50%;
+  position: relative;
+}
+.container .userBox .userRight {
+  flex: 1;
+  margin-left: 30rpx;
+  padding: 0px 10rpx;
+}
+.container .userBox .userRight .uRtop {
+  display: flex;
+  justify-content: space-between;
+}
+.container .userBox .userRight .uRtop .uRtopleft .nickName {
+  max-width: 340rpx;
+  color: #333;
+  font-size: 32rpx;
+}
+.container .userBox .userRight .uRtop .uRtopleft .gradeText {
+  margin: 18rpx 0rpx 12rpx;
+  font-size: 24rpx;
+  color: #989A9C;
+}
+.container .userBox .userRight .uRtop .uRtopRight {
+  display: flex;
+  align-items: center;
+}
+.container .userBox .userRight .uRtop .uRtopRight .edit {
+  width: 22rpx;
+  height: 28rpx;
+}
+.container .userBox .userRight .uRtop .uRtopRight text {
+  margin: 0px 10rpx;
+  font-size: 24rpx;
+  color: #666;
+}
+.container .userBox .userRight .uRBtm {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  border-top: 1px solid rgba(0, 0, 0, 0.1);
+  padding: 18rpx 0rpx;
+}
+.container .userBox .userRight .uRBtm .count {
+  width: 33%;
+  font-size: 28rpx;
+  color: rgba(0, 0, 0, 0.6);
+  border-right: 1px solid rgba(51, 51, 51, 0.3);
+  text-align: center;
+}
+.container .userBox .userRight .uRBtm .count .countNum {
+  margin-left: 10rpx;
+}
+.container .userBox .userRight .uRBtm .countFirst {
+  text-align: left;
+}
+.container .userBox .userRight .uRBtm .countEnd {
+  text-align: right;
+  border: none;
+}
+.container .iosVip {
+  margin: 4rpx 0px 0px 6rpx;
+  font-size: 20rpx;
+  color: #333;
+}
+.container .sectionBoxs {
+  margin-top: 20rpx;
+  padding: 20rpx 30rpx;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  background-color: white;
+  border-radius: 20rpx;
+}
+.container .sectionBoxs .sBox {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.container .sectionBoxs .sBox .img {
+  width: 69rpx;
+  height: 69rpx;
+}
+.container .sectionBoxs .sBox .title {
+  margin-top: 8rpx;
+  font-size: 24rpx;
+  color: #333;
+}
+.container .sectionBoxs .contactBtn {
+  border: none;
+  padding: 0rpx;
+  line-height: normal;
+  margin: 0;
+}
+.container .payBox {
+  margin-top: 20rpx;
+  padding: 13rpx 30rpx;
+  background-color: white;
+  border-radius: 20rpx;
+}
+.container .payBox .title {
+  font-size: 30rpx;
+  font-weight: bold;
+  color: #000;
+}
+.container .payBox .pay {
+  margin: 20rpx 0rpx;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0rpx 30rpx;
+  border-radius: 22rpx;
+  overflow: hidden;
+}
+.container .payBox .pay .payLeft .pLTitle {
+  font-size: 36rpx;
+  font-weight: bold;
+}
+.container .payBox .pay .payLeft .pLcontent {
+  font-size: 22rpx;
+}
+.container .payBox .pay .payRight {
+  margin: 24rpx 0rpx;
+  padding: 12rpx 28rpx;
+  border-radius: 40rpx;
+  font-size: 24rpx;
+  font-weight: bold;
+}
+.container .payBox .vipPay {
+  background: url('http://reader-wx.ai160.com/images/reader/v3/year.png') no-repeat;
+  background-size: cover;
+}
+.container .payBox .vipPay .vipTitle {
+  color: #FFE6B9;
+}
+.container .payBox .vipPay .vipContent {
+  margin-top: 4rpx;
+  color: #FFE6B9;
+}
+.container .payBox .vipPay .vipBtn {
+  background-image: linear-gradient(to bottom, #F4E7A8, #F9EDCF);
+  color: #211501;
+}
+.container .payBox .buyPay {
+  background: url('http://reader-wx.ai160.com/images/reader/v3/10yuan.png') no-repeat;
+  background-size: cover;
+}
+.container .payBox .buyPay .payLeft {
+  color: #7D320A;
+  font-size: 36rpx;
+  font-weight: bold;
+}
+.container .payBox .buyPay .buyBtn {
+  border: 1rpx solid white;
+  color: white;
+  background-color: #7D320A;
+}
+.container .surplus {
+  margin-top: 20rpx;
+  padding: 22rpx 30rpx;
+  background-color: white;
+  border-radius: 20rpx;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 32rpx;
+}
+.container .surplus .title {
+  font-size: 30rpx;
+  font-weight: bold;
+  color: #000;
+}
+.container .surplus .num {
+  color: #F97419;
+  font-weight: bold;
+  margin-right: 10rpx;
+}
+.container .taskBox {
+  margin-top: 20rpx;
+  padding: 20rpx 10rpx 0rpx;
+  background-color: white;
+  border-radius: 20rpx;
+}
+.container .taskBox .title {
+  padding: 0rpx 20rpx;
+  font-size: 30rpx;
+  font-weight: bold;
+  color: #000;
+}
+.container .taskBox .task {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 30rpx 22rpx;
+  border-bottom: 1px solid #EAEAEA;
+}
+.container .taskBox .task .taskLeft {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.container .taskBox .task .taskLeft .img {
+  width: 76rpx;
+  height: 76rpx;
+  border-radius: 50%;
+}
+.container .taskBox .task .taskLeft .taskContent {
+  margin-left: 40rpx;
+}
+.container .taskBox .task .taskLeft .taskContent .tcTitle {
+  font-size: 30rpx;
+  font-weight: bold;
+  color: #333;
+}
+.container .taskBox .task .taskLeft .taskContent .tcNum {
+  color: #FF6259;
+  font-size: 26rpx;
+}
+.container .taskBox .task .taskRightBox {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+  /*  */
+}
+.container .taskBox .task .taskRight {
+  width: 138rpx;
+  text-align: center;
+  padding: 10rpx 0rpx;
+  border-radius: 40rpx;
+  color: white;
+  background-color: #FC614E;
+  font-size: 30rpx;
+}
+.container .taskBox .task .taskRight-close {
+  color: #6C6C6C;
+  background: #D0D0D0;
+  box-shadow: 0 2px 2px 0 #AEABAB;
+}
+.container .taskBox .task .taskSurplus {
+  text-align: center;
+  margin-top: 4rpx;
+  color: #686868;
+  font-size: 20rpx;
+}
+.container .taskBox .advert {
+  border: none;
+}

+ 175 - 0
pages/userWorks/index.js

@@ -0,0 +1,175 @@
+import {
+    getSelfRead
+} from '~/api/user'
+let videoContext = null
+Page({
+
+    /**
+     * 页面的初始数据
+     */
+    data: {
+        list: null,
+        currentId: '',
+        videoState: true,
+        commentShow: false,
+        canvasHidden: false, //设置画板的显示与隐藏
+        shareImgPath: '' //用于储存canvas生成的图片
+    },
+    onLoad(options) {
+        this.getSelfRead()
+    },
+    // 打开评论
+    openComment({
+        target
+    }) {
+        this.setData({
+            commentShow: true,
+            commentId: target.dataset.id,
+        });
+    },
+    // 评论区点击
+    commentTap: function(e) {
+        if (e.target.dataset.type === 'blank') {
+            this.setData({
+                commentShow: false
+            })
+        }
+    },
+    //获取自己作品列表
+    async getSelfRead() {
+        let list = await getSelfRead()
+        console.log(list);
+        this.setData({
+            list
+        })
+    },
+    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/image/peiyin.jpg';
+                    peiyin.onload = () => {
+                        ctx.drawImage(peiyin, 0, 211, 375, 89);
+                        // 收藏,一个一个渲染
+                        let sc = canvas.createImage();
+                        sc.src = '/static/image/no_collect.png'
+                        sc.onload = () => {
+                            ctx.drawImage(sc, 12, 220, 20, 20)
+                            ctx.fillText('收藏', 36, 238)
+                                //分享
+                            let fx = canvas.createImage();
+                            fx.src = '/static/index/share.png'
+                            fx.onload = () => {
+                                ctx.drawImage(fx, 78, 220, 22, 22)
+                                ctx.fillText('分享', 104, 238)
+                                    //点赞
+                                let dz = canvas.createImage();
+                                dz.src = video.isLike ? '/static/index/heart_colored.png' : '/static/index/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/index/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)
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                })
+        })
+
+    },
+    // 改变视频状态
+    changStatus({
+        detail
+    }) {
+        this.setData(detail)
+    },
+    // 开始播放
+    playVideo({
+        currentTarget
+    }) {
+        this.setData({
+            videoState: true,
+            currentId: currentTarget.dataset.id
+        })
+    },
+    /* 改变视频播放状态 ,暂时先不用*/
+    changeVideoState() {
+        this.videoContext = wx.createVideoContext('myVideo')
+        let videoState = this.data.videoState
+        if (videoState) {
+            this.videoContext.pause()
+        } else {
+            this.videoContext.play()
+        }
+        this.setData({
+            videoState: !videoState
+        })
+    },
+
+    onShareAppMessage({
+        from,
+        target
+    }) {
+        if (from == 'button') {
+            let video = target.dataset.info
+            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'
+            }
+        }
+    }
+})

+ 9 - 0
pages/userWorks/index.json

@@ -0,0 +1,9 @@
+{
+  "navigationStyle": "custom",
+  "usingComponents": {
+    "videoPreview": "/components/videoPreview/index",
+    "emptyBg": "/components/empty/index",
+    "Comment": "/components/comment/comment"
+  },
+  "enablePullDownRefresh": false
+}

+ 21 - 0
pages/userWorks/index.less

@@ -0,0 +1,21 @@
+.worksBox {
+    .comment_section {
+        position: fixed;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        z-index: 9999;
+        background: rgba(0, 0, 0, .3);
+        overflow: hidden;
+    }
+
+    .comment_close {
+        position: absolute;
+        bottom: 760rpx;
+        right: 10rpx;
+        font-size: 60rpx;
+        padding: 20rpx;
+        z-index: 999;
+    }
+}

+ 15 - 0
pages/userWorks/index.wxml

@@ -0,0 +1,15 @@
+<view class="worksBox">
+    <!-- 作品列表 -->
+    <canvas id='share' type="2d"> </canvas>
+    <block wx:if="{{list.length>0}}">
+        <videoPreview wx:for="{{list}}" wx:key="index" videoInfo="{{item}}" index='{{index}}' currentId="{{currentId}}" data-id="{{item.userRead.id}}" bind:playVideo="playVideo" bind:changStatus="changStatus" bind:getList="getSelfRead" bind:openComment="openComment">
+        </videoPreview>
+    </block>
+    <emptyBg wx:if="{{list.length==0}}" message='您还没有作品哦,赶快去发表吧!'></emptyBg>
+    <view class="comment_section" catchtouchmove="touchMove" catchtap="commentTap" data-type="blank" wx:if="{{commentShow}}">
+        <view class="comment_close" data-type='blank'>
+            ×
+        </view>
+        <Comment commentId="{{commentId}}" bindsendReply="sendReply" />
+    </view>
+</view>

+ 18 - 0
pages/userWorks/index.wxss

@@ -0,0 +1,18 @@
+.worksBox .comment_section {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 9999;
+  background: rgba(0, 0, 0, 0.3);
+  overflow: hidden;
+}
+.worksBox .comment_close {
+  position: absolute;
+  bottom: 760rpx;
+  right: 10rpx;
+  font-size: 60rpx;
+  padding: 20rpx;
+  z-index: 999;
+}

+ 51 - 0
project.config.json

@@ -0,0 +1,51 @@
+{
+  "description": "项目配置文件",
+  "packOptions": {
+    "ignore": [],
+    "include": []
+  },
+  "setting": {
+    "bundle": false,
+    "userConfirmedBundleSwitch": false,
+    "urlCheck": true,
+    "scopeDataCheck": false,
+    "coverView": true,
+    "es6": true,
+    "postcss": true,
+    "compileHotReLoad": false,
+    "lazyloadPlaceholderEnable": false,
+    "preloadBackgroundData": false,
+    "minified": true,
+    "autoAudits": false,
+    "newFeature": false,
+    "uglifyFileName": false,
+    "uploadWithSourceMap": true,
+    "useIsolateContext": true,
+    "nodeModules": false,
+    "enhance": true,
+    "useMultiFrameRuntime": true,
+    "useApiHook": true,
+    "useApiHostProcess": true,
+    "showShadowRootInWxmlPanel": true,
+    "packNpmManually": false,
+    "enableEngineNative": false,
+    "packNpmRelationList": [],
+    "minifyWXSS": true,
+    "showES6CompileOption": false,
+    "minifyWXML": true,
+    "babelSetting": {
+      "ignore": [],
+      "disablePlugins": [],
+      "outputPath": ""
+    }
+  },
+  "compileType": "miniprogram",
+  "libVersion": "2.19.4",
+  "appid": "wx8961a3e5512f307c",
+  "projectname": "miniprogram-92",
+  "condition": {},
+  "editorSetting": {
+    "tabIndent": "insertSpaces",
+    "tabSize": 2
+  }
+}

+ 29 - 0
project.private.config.json

@@ -0,0 +1,29 @@
+{
+  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
+  "projectname": "%E6%9C%97%E8%AF%BB%E5%B0%8F%E5%92%96%E7%A7%80",
+  "setting": {
+    "compileHotReLoad": true,
+    "urlCheck": false
+  },
+  "libVersion": "2.28.1",
+  "condition": {
+    "miniprogram": {
+      "list": [
+        {
+          "name": "",
+          "pathName": "pages/index/index",
+          "query": "shareUid=123",
+          "launchMode": "default",
+          "scene": null
+        },
+        {
+          "name": "",
+          "pathName": "pages/index/index",
+          "query": "uid=123",
+          "launchMode": "default",
+          "scene": null
+        }
+      ]
+    }
+  }
+}

+ 7 - 0
sitemap.json

@@ -0,0 +1,7 @@
+{
+  "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
+  "rules": [{
+  "action": "allow",
+  "page": "*"
+  }]
+}

BIN
static/image/collect.png


BIN
static/image/concern.png


BIN
static/image/contact.png


BIN
static/image/edit_new.png


BIN
static/image/message.png


BIN
static/image/task1.png


BIN
static/image/task2.png


BIN
static/image/task3.png


BIN
static/image/work.png


+ 20 - 0
store/index.js

@@ -0,0 +1,20 @@
+// 该文件用于创建store实例
+import {
+  action,
+  observable
+} from 'mobx-miniprogram'
+
+export const store = observable({
+  // 数据字段
+  numA: 1,
+  numB: 2,
+  // 计算属性
+  get sum() {
+    return this.numA + this.numB
+  },
+  // actions
+  updateNumA: action(function (step) {
+    console.log(step, '触发');
+    this.numA += step
+  })
+})

+ 41 - 0
utils/filter.wxs

@@ -0,0 +1,41 @@
+var formatNumber = function (n) {
+    n = n.toString()
+    return n[1] ? n : '0' + n
+}
+/**
+ * 将时间戳(1570550400)格式转为 yyyy-MM-dd格式
+ */
+var formatDate = function (datetime) {
+    var time = datetime * 1
+    var date = getDate(time);
+    var year = date.getFullYear();
+    var month = date.getMonth() + 1;
+    var day = date.getDate();
+    return year + '年' + month + '月' + day + '日';
+}
+
+function gradeFilter(grade) {
+    if (!grade) {
+        return '暂无'
+    }
+    var gradeObj = {
+        "PRIMARY_FIRST_GRADE": "一年级",
+        "PRIMARY_SECOND_GRADE": "二年级",
+        "PRIMARY_THREE_GRADE": "三年级",
+        "PRIMARY_SENIOR_GRADE": "四年级",
+        "PRESCHOOL": "学前班",
+    }
+    return gradeObj[grade]
+}
+// 数字满万补w
+function numFilter(num) {
+    if (!num || num < 10000) {
+        return num
+    }
+    return Math.floor(num / 100) / 100 + 'w'
+}
+module.exports = {
+    formatDate: formatDate,
+    gradeFilter: gradeFilter,
+    numFilter: numFilter
+}

+ 42 - 0
utils/request.js

@@ -0,0 +1,42 @@
+let baseUrl = 'https://reader-api.ai160.com/wx'
+let oldUrl = 'https://reader-api.ai160.com'
+
+
+function request(url, method, data, oldBaseUrl = false) {
+  let header = {
+    'uid': wx.getStorageSync('uid') || ''
+  }
+
+  return new Promise((reslove, reject) => {
+    wx.request({
+      url: oldBaseUrl ? oldUrl + url : baseUrl + url,
+      method: method,
+      data: data,
+      header: header,
+      success: (result) => {
+        let {
+          data: {
+            code,
+            data = {},
+            message
+          }
+        } = result
+        if (code == '200') {
+          reslove(data)
+        } else if (code == '1102' || code == '1204') {
+          wx.clearStorage()
+        } else {
+          console.log(message);
+          // reject(message)
+        }
+      },
+      fail: (res) => {
+        console.error(res)
+        reject(res)
+      },
+    })
+  })
+}
+module.exports = {
+  request,
+}

+ 19 - 0
utils/util.js

@@ -0,0 +1,19 @@
+const formatTime = date => {
+  const year = date.getFullYear()
+  const month = date.getMonth() + 1
+  const day = date.getDate()
+  const hour = date.getHours()
+  const minute = date.getMinutes()
+  const second = date.getSeconds()
+
+  return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`
+}
+
+const formatNumber = n => {
+  n = n.toString()
+  return n[1] ? n : `0${n}`
+}
+
+module.exports = {
+  formatTime
+}