Explorar o código

feat: 购买短剧

xiansin %!s(int64=2) %!d(string=hai) anos
pai
achega
d3cebbb8f9

+ 8 - 1
mini/api/episode.js

xqd xqd
@@ -50,6 +50,12 @@ export function vipFree(params) {
   )
 }
 
+export function listBuyNum(list_id) {
+  return request.get(
+    `episode/list/${list_id}/buyNum`
+  )
+}
+
 export default {
   recommend,
   news,
@@ -57,5 +63,6 @@ export default {
   detail,
   trace,
   search,
-  vipFree
+  vipFree,
+  listBuyNum
 }

+ 14 - 1
mini/api/user/episode.js

xqd
@@ -23,8 +23,21 @@ export function watched(id, list_id) {
   )
 }
 
+export async function buyRecord(episode_id) {
+  return request.get(
+    `user/episode/buy/${episode_id}/record`
+  )
+}
+
+export async function buyHandle(episode_id, list_id) {
+  return request.post(
+    `user/episode/${episode_id}/${list_id}/buy`
+  )
+}
 export default {
   recent,
   record,
-  watched
+  watched,
+  buyRecord,
+  buyHandle
 }

+ 104 - 10
mini/components/Recharge/index.vue

xqd xqd xqd xqd xqd xqd xqd
@@ -7,12 +7,36 @@
       :close-on-click-overlay="false"
       @close="close"
     >
-      <view class="container">
-        <view class="static-text main-between cross-center">
-          <text>充值金币</text>
-          <u-icon name="close-circle" size="52rpx" color="#BEBDBB" @click="close" />
-        </view>
-        <view class="overage">账户余额:<text>{{ userInfo.info.integral }}金币</text></view>
+      <view class="container" :class="{bottom: mode === 'bottom'}">
+        <template v-if="type === 'play'">
+          <view class="play-container">
+            <view class="header main-between cross-center">
+              <text>感谢您的支持,本集解锁后可继续观看</text>
+              <u-icon name="arrow-down" size="28rpx" @click="close" />
+            </view>
+            <view class="episode main-between cross-center">
+              <view class="detail">
+                <view class="name">{{ episode.name }} 第{{ list.sort }}集</view>
+                <view class="sale-box main-left cross-center">
+                  <view class="sale-price cross-center">专享价{{ list.sale_price }}金币</view>
+                  <view class="origin-price cross-center">原价{{ list.origin_price }}金币</view>
+                </view>
+              </view>
+              <view class="buy-num">{{ buyNum }}人购买</view>
+            </view>
+          </view>
+          <view class="static-text main-between cross-center">
+            <text>充值金币</text>
+            <view class="overage">账户余额:<text>{{ userInfo.info.integral }}金币</text></view>
+          </view>
+        </template>
+        <template v-else>
+          <view class="static-text main-between cross-center">
+            <text>充值金币</text>
+            <u-icon name="close-circle" size="52rpx" color="#BEBDBB" @click="close" />
+          </view>
+          <view class="overage">账户余额:<text>{{ userInfo.info.integral }}金币</text></view>
+        </template>
 
         <view class="recharge-group dir-left-wrap">
           <view
@@ -46,6 +70,22 @@ export default {
     mode: {
       type: String,
       default: 'center'
+    },
+    type: {
+      type: String,
+      default: 'normal'
+    },
+    episode: {
+      type: Object,
+      default() {
+        return {}
+      }
+    },
+    list: {
+      type: Object,
+      default() {
+        return {}
+      }
     }
   },
   data() {
@@ -53,8 +93,9 @@ export default {
       modal: {
         show: false
       },
-      combos: [1, 2, 3, 4],
-      rechargeActive: 1
+      combos: [],
+      rechargeActive: 1,
+      buyNum: 0
     }
   },
   computed: {
@@ -69,6 +110,7 @@ export default {
   },
   created() {
     this.getCombo()
+    this.getBuyNum()
   },
   methods: {
     getCombo() {
@@ -78,6 +120,13 @@ export default {
     },
     close() {
       this.$emit('update:show', false)
+    },
+    getBuyNum() {
+      if (this.type === 'play') {
+        this.$api.episode.listBuyNum(this.list.id).then(res => {
+          this.buyNum = res.data
+        })
+      }
     }
   }
 }
@@ -89,11 +138,19 @@ export default {
       .container{
         width: 700rpx;
         border: 2rpx solid;
-        padding: 30rpx 40rpx;
+        padding: 30rpx;
+        &.bottom{
+          width: 750rpx;
+          border: unset;
+        }
         .static-text{
-          font-size: 38rpx;
+          font-size: 36rpx;
           font-weight: 600;
           margin-bottom: 40rpx;
+          .overage{
+            font-size: 28rpx;
+            color: $info-color;
+          }
         }
         .overage{
           color: $info-color;
@@ -101,6 +158,43 @@ export default {
             color: #FB3651 ;
           }
         }
+        // 播放充值
+        .play-container{
+          .episode{
+            margin: 40rpx 0 ;
+            background: linear-gradient(270deg, #6EEBE8, #FF74B9);
+            border-radius: 20rpx;
+            height: 180rpx;
+            padding: 20rpx;
+            .detail{
+              .name{
+                color: $default-color;
+                font-weight: 600;
+              }
+              .sale-box{
+                margin-top: 40rpx;
+                .sale-price{
+                  color: $primary-color;
+                  font-size: 28rpx;
+                }
+                .origin-price{
+                  color: $default-color;
+                  font-size: 24rpx;
+                  margin-left: 20rpx;
+                  text-decoration: line-through;
+                  opacity: .6;
+                  margin-top: 6rpx;
+                }
+              }
+            }
+            .buy-num{
+              color: $default-color;
+              min-width: 80px;
+              text-align: center;
+            }
+          }
+        }
+        // 充值套餐
         .recharge-group{
           margin-top: 30rpx;
           .recharge-item{

+ 0 - 7
mini/pages.json

xqd
@@ -54,13 +54,6 @@
         "enablePullDownRefresh": false
       }
     },
-    {
-      "path": "pages/trace/trace",
-      "style": {
-        "navigationBarTitleText": "我的追剧",
-        "enablePullDownRefresh": false
-      }
-    },
     {
       "path": "pages/my/consume",
       "style": {

+ 139 - 37
mini/pages/episode/play.vue

xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd xqd
@@ -14,6 +14,7 @@
       </view>
       <!--按钮-->
       <view class="status-bar dir-top-wrap main-center">
+        <!--喜欢-->
         <view
           class="item fav dir-top-wrap main-center cross-center"
           :class="{active: isFav}"
@@ -22,6 +23,7 @@
           <u-icon name="heart-fill" size="58rpx" :color="isFav?$colors.primaryColor:$colors.defaultColor" />
           <text>{{ episode.user_favorite_count }}</text>
         </view>
+        <!--收藏-->
         <view
           class="item collect dir-top-wrap main-center cross-center"
           :class="{active: isCollect}"
@@ -30,7 +32,7 @@
           <u-icon name="star-fill" size="58rpx" :color="isCollect?$colors.primaryColor:$colors.defaultColor" />
           <text>{{ episode.user_collect_count }}</text>
         </view>
-
+        <!--分享-->
         <view class="item share dir-top-wrap main-center cross-center">
           <button open-type="share" />
           <u-icon name="share-fill" size="58rpx" :color="$colors.defaultColor" />
@@ -49,16 +51,16 @@
         <view v-if="isPlaying" class="progress-container">
           <view class="progress" :style="{width: progress+'%'}" />
         </view>
+        <!--视频容器-->
         <video
           id="video"
-          :show-play-btn="playBtn"
-          :show-fullscreen-btn="fullscreenBtn"
-          :controls="controls"
+          :show-play-btn="video.playBtn"
+          :show-fullscreen-btn="video.fullscreenBtn"
+          :controls="video.controls"
           object-fit="contain"
           style="width: 100%;height: 100%;"
           :poster="episode.cover_img"
           :src="src"
-          @binderror="binderror"
           @timeupdate="timeupdate"
         />
       </view>
@@ -75,6 +77,7 @@
           </view>
         </view>
         <view class="episode-container dir-top-wrap">
+          <!--分集 横向滚动-->
           <scroll-view
             class="header-box dir-left-nowrap cross-center"
             scroll-x
@@ -88,6 +91,7 @@
               @click="episodesIndex=index"
             >{{ item.title }}</view>
           </scroll-view>
+          <!--几集选择-->
           <view class="content dir-left-wrap main-left">
             <view
               v-for="(item, index) in episodes[episodesIndex].lists"
@@ -97,63 +101,92 @@
             >
               <image :src="episode.cover_img" />
               <text>第{{ item.sort }}集</text>
-              <view v-if="activeIndex === item.index" class="playing" />
-              <view v-if="!item.is_free" class="lock main-center cross-center">
+              <view v-if="activeIndex === item.index && isPlaying" class="playing" />
+              <view v-if="!item.is_free && buyRecord.indexOf(item.id) === -1" class="lock main-center cross-center">
                 <u-icon name="lock-fill" :color="$colors.defaultColor" size="46rpx" />
               </view>
             </view>
           </view>
         </view>
       </view>
-    </template>
-    <!--toast-->
-    <view
-      v-if="toast.show"
-      class="toast dir-top-wrap main-center cross-center"
-      :class="toast.status"
-    >
-      <u-icon
-        :name="toast.status === 'success' ? 'checkmark-circle' : 'close-circle'"
-        :color="toast.status === 'success' ? $colors.primaryColor : $colors.defaultColor"
-        size="80rpx"
+      <!--toast-->
+      <view
+        v-if="toast.show"
+        class="toast dir-top-wrap main-center cross-center"
+        :class="toast.status"
+      >
+        <u-icon
+          :name="toast.status === 'success' ? 'checkmark-circle' : 'close-circle'"
+          :color="toast.status === 'success' ? $colors.primaryColor : $colors.defaultColor"
+          size="80rpx"
+        />
+        <text>{{ toast.text }}</text>
+      </view>
+      <!--购买弹窗-->
+      <u-modal
+        :show="modal.show"
+        :content="`确定购买【第${modal.item.sort}集】?`"
+        show-cancel-button
+        @confirm="handleBuy"
+        @cancel="modal.show = false"
+      />
+      <!--充值-->
+      <recharge
+        :show.sync="rechargeShow"
+        type="play"
+        mode="bottom"
+        :episode="episode"
+        :list="modal.item"
       />
-      <text>{{ toast.text }}</text>
-    </view>
+    </template>
   </view>
 </template>
 
 <script>
+import { mapState } from 'vuex'
+import Recharge from '../../components/Recharge/index'
 export default {
   name: 'Play',
+  components: { Recharge },
   data() {
     return {
       id: null,
       listId: null,
       isPlaying: false,
       videoContext: null,
-      controls: false,
-      fullscreenBtn: false,
-      playBtn: false,
       progress: 0,
       episode: null,
       activeIndex: 0,
       loading: true,
       isCollect: false,
       isFav: false,
+      video: {
+        controls: false,
+        fullscreenBtn: false,
+        playBtn: false
+      },
       toast: {
         status: 'success',
         text: '收藏成功',
         show: false
       },
       footerShow: false,
-      episodesIndex: 0
+      episodesIndex: 0,
+      buyRecord: [],
+      modal: {
+        show: false,
+        item: {}
+      },
+      rechargeShow: false
     }
   },
   computed: {
+    ...mapState({
+      userInfo: seate => seate.user.info
+    }),
     src() {
-      if (this.episode) {
-        return this.episode.lists[this.activeIndex].url
-      }
+      if (!this.episode) return ''
+      return this.episode.lists[this.activeIndex].url
     },
     episodes() {
       const list = []
@@ -183,18 +216,52 @@ export default {
     }
   },
   methods: {
+    // 播放进度
     timeupdate({ detail }) {
       // currentTime, duration
       if (detail.duration) {
         this.progress = (detail.currentTime / detail.duration * 100).toFixed(2)
       }
     },
+    // 播放
     handlePlay() {
+      const item = this.episode.lists[this.activeIndex]
+      this.modal.item = item
+      // 检查是否购买
+      if (!this.checkBeforePlay(item)) {
+        // 余额是否购买
+        if (!this.checkOverage(item)) {
+          this.rechargeShow = true
+          return
+        }
+        this.modal.show = true
+        this.footerShow = true
+        return
+      }
       this.isPlaying = true
       this.videoContext.play()
       this.watched(this.id, this.listId)
     },
+    // 暂停
+    handlePause() {
+      if (!this.isPlaying) return
+      this.isPlaying = false
+      this.videoContext.pause()
+    },
+    // 选择剧集
     handleSelectEpisode(index) {
+      const item = this.episode.lists[index]
+      this.modal.item = item
+      // 检查是否购买
+      if (!this.checkBeforePlay(item)) {
+        // 余额是否购买
+        if (!this.checkOverage(item)) {
+          this.rechargeShow = true
+          return
+        }
+        this.modal.show = true
+        return
+      }
       this.activeIndex = index
       this.footerShow = false
       this.$loading()
@@ -205,22 +272,16 @@ export default {
         this.watched(this.id, this.episode.lists[this.activeIndex].id)
       }, 1000)
     },
-    handlePause() {
-      if (!this.isPlaying) return
-      this.isPlaying = false
-      this.videoContext.pause()
-    },
+    // 获取剧集详情
     getEpisode() {
       this.loading = true
       this.$api.episode.detail(this.id).then(res => {
         this.loading = false
         this.episode = res.data
-        console.log('-->data', this.listId)
         if (this.listId) {
           this.episode.lists.forEach((obj, index) => {
             if (parseInt(this.listId) === parseInt(obj.id)) {
               this.activeIndex = index
-              console.log('-->data', this.activeIndex)
             }
           })
         } else {
@@ -228,11 +289,13 @@ export default {
         }
       })
     },
+    // 检查是否收藏当前剧集
     checkCollect() {
       this.$api.user.collect.check(this.id).then(res => {
         this.isCollect = res.data
       })
     },
+    // 收藏相关 处理
     handleCollect() {
       const method = this.isCollect ? 'destroy' : 'add'
       const num = this.isCollect ? -1 : 1
@@ -246,11 +309,13 @@ export default {
         }
       })
     },
+    // 检查是否喜欢当前短剧
     checkFavorite() {
       this.$api.user.favorite.check(this.id).then(res => {
         this.isFav = res.data
       })
     },
+    // 喜欢剧集 处理
     handleFavorite() {
       const method = this.isFav ? 'destroy' : 'add'
       const num = this.isFav ? -1 : 1
@@ -264,25 +329,62 @@ export default {
         }
       })
     },
+    // 观看记录
     watched(id, list_id) {
       this.$api.user.episode.watched(id, list_id).then(res => {
 
       })
     },
+    // 分享
     shared(id, list_id) {
       this.$api.episode.shared(id, list_id).then(res => {
         this.episode.share_count += 1
       })
+    },
+    // 当前剧集购买记录
+    async getBuyRecord() {
+      await this.$api.user.episode.buyRecord(this.id).then(res => {
+        this.buyRecord = res.data
+      })
+    },
+    // 购买
+    handleBuy() {
+      this.$loading('购买中...')
+      this.$api.user.episode.buyHandle(this.id, this.modal.item.id).then(res => {
+        this.$hideLoading()
+        if (typeof res.overage !== 'undefined') {
+          this.rechargeShow = true
+        } else {
+          this.$u.toast('购买成功')
+          this.modal.show = false
+          this.getBuyRecord()
+          this.$api.user.info().then(res => {
+            this.$store.dispatch('user/info', res.data)
+          })
+        }
+      }).catch(() => {
+        this.$hideLoading()
+      })
+    },
+    // 播放前检查是否购买/免费
+    checkBeforePlay(item) {
+      return item.is_free || (!item.is_free && this.buyRecord.indexOf(item.id) !== -1)
+    },
+    // 检查余额是否足够支付
+    checkOverage(item) {
+      return this.userInfo.info.integral >= item.sale_price
     }
   },
-  onLoad(options) {
+  async onLoad(options) {
     this.videoContext = uni.createVideoContext('video', this)
     this.id = options.id
     this.listId = options?.list_id
+    await this.getBuyRecord()
     this.getEpisode()
     this.checkCollect()
     this.checkFavorite()
   },
+  // 分享
   onShareAppMessage(res) {
     if (res.from === 'button') { // 来自页面内分享按钮
       console.log(res.target)
@@ -297,8 +399,8 @@ export default {
         path: `/pages/episode/play?id=${this.id}`,
         imageUrl: this.episode.cover_img,
         desc: this.episode.name,
-        success() {
-
+        success: res => {
+          this.shared(this.id, this.listId)
         }
       }
     }

+ 4 - 0
mini/pages/trace/index.vue

xqd xqd
@@ -82,6 +82,9 @@ export default {
   onLoad() {
     this.getCollect()
     this.getTrace()
+  },
+  onShow() {
+    this.getCollect()
   }
 }
 </script>
@@ -118,6 +121,7 @@ export default {
         }
         .content{
           margin-top: 20rpx;
+          min-height: 200rpx;
           .collect-item{
             .cover-image{
               image{

+ 0 - 18
mini/pages/trace/trace.vue

xqd
@@ -1,18 +0,0 @@
-<template>
-  <view class="trace" />
-</template>
-
-<script>
-export default {
-  data() {
-    return {}
-  },
-  computed: {},
-  methods: {}
-}
-</script>
-
-<style lang="scss" scoped>
-  .trace {
-  }
-</style>

+ 8 - 8
mini/utils/request/responseInterceptors.js

xqd xqd
@@ -15,7 +15,7 @@ module.exports = vm => {
       if (data.code !== 0) {
         uni.showModal({
           title: '提示',
-          content: data.message,
+          content: data.msg,
           showCancel: false
         })
         // 401 登录超时 402 需要登录
@@ -24,17 +24,17 @@ module.exports = vm => {
             url: 'pages/index/index'
           })*/
         }
-        return Promise.reject(data.message)
+        return Promise.reject(data.msg)
       }
 
       return data
     }, (error) => {
-      console.error('-->error', error)
-      // uni.showModal({
-      //   title: '提示',
-      //   content: error.message,
-      //   showCancel: false
-      // })
+      console.error('-->error', error.data)
+      uni.showModal({
+        title: '提示',
+        content: error.data.message,
+        showCancel: false
+      })
       return Promise.reject(error)
     })
 }

+ 4 - 1
server/app/Admin/Actions/Form/BatchEditEpisodeListForm.php

xqd xqd
@@ -26,12 +26,14 @@ class BatchEditEpisodeListForm extends Form implements LazyRenderable
         }
 
         $isFree = $input['is_free']??null;
-        $salePrice = $input['sale_price']??null;
+        $salePrice = $input['sale_price']??0;
+        $originPrice = $input['origin_price']??0;
 
         foreach ($ids as $id){
             EpisodesList::where('id' , $id)->update([
                 'is_free' => $isFree,
                 'sale_price' => $salePrice,
+                'origin_price' => $originPrice,
             ]);
         }
 
@@ -43,6 +45,7 @@ class BatchEditEpisodeListForm extends Form implements LazyRenderable
         $this->radio('is_free')
             ->options(config('global.episode_free'))
             ->when(0, function (Form $form) {
+                $form->number('origin_price')->min(1);
                 $form->number('sale_price')->min(1);
             })->default(1);
 

+ 1 - 0
server/app/Admin/Controllers/Episode/EpisodesListController.php

xqd
@@ -81,6 +81,7 @@ class EpisodesListController extends AdminController
             $grid->column('is_free')
                 ->using(config('global.episode_free'))
                 ->label(['success', 'primary'])->sortable();
+            $grid->column('origin_price')->editable();
             $grid->column('sale_price')->editable();
             $grid->column('url')->display(function (){
                 return '<a href="'.$this->url.'">视频链接</a>';

+ 8 - 1
server/app/Http/Controllers/V1/EpisodeController.php

xqd xqd xqd
@@ -6,6 +6,7 @@ use App\Models\EpisodesCategory;
 use App\Models\NavBar;
 use App\Models\Tabbar;
 use App\Models\User;
+use App\Models\UserEpisodesRecord;
 use App\Models\UserWatchRecord;
 use Carbon\Carbon;
 use Illuminate\Database\Eloquent\Builder;
@@ -209,7 +210,7 @@ class EpisodeController extends Controller
     public function detail($id)
     {
         $episodes = Episode::withCount(['userWatchRecord','userCollect','userFavorite','lists'])
-            ->with(['category:id,name','lists:id,episodes_id,sort,url,is_free,sale_price'])
+            ->with(['category:id,name','lists:id,episodes_id,sort,url,is_free,origin_price,sale_price'])
             ->where('is_opend', 1)
             ->where('id', $id)
             ->where('platform', \user()->info->platform)
@@ -217,6 +218,12 @@ class EpisodeController extends Controller
         return $this->success($episodes);
     }
 
+    public function listBuyNum($listId)
+    {
+        $count = UserEpisodesRecord::where('list_id',$listId)->count();
+        return $this->success($count);
+    }
+
     // 分享
     public function shared($id)
     {

+ 79 - 0
server/app/Http/Controllers/V1/User/EpisodeController.php

xqd
@@ -0,0 +1,79 @@
+<?php
+namespace App\Http\Controllers\V1\User;
+
+use App\Http\Controllers\V1\Controller;
+use App\Models\Episode;
+use App\Models\EpisodesList;
+use App\Models\UserConsumeRecord;
+use App\Models\UserEpisodesRecord;
+use App\Models\UserInfo;
+use Illuminate\Database\QueryException;
+
+class EpisodeController extends Controller
+{
+    public function buyRecord($episode)
+    {
+        $lists = UserEpisodesRecord::filterUser()
+            ->select(['episodes_id','list_id'])
+            ->where('episodes_id',$episode)
+            ->get()
+            ->pluck('list_id');
+
+        return $this->success($lists);
+    }
+
+    public function buy($episode,$list)
+    {
+        try {
+            \DB::beginTransaction();
+
+            $episode = Episode::find($episode);
+            $list = EpisodesList::find($list);
+            $user = UserInfo::find(\user()->id);
+
+
+            $count = UserEpisodesRecord::filterUser()->where('list_id',$list->id)->count();
+            if($count){
+                return $this->error('请勿重复购买');
+            }
+
+            if($user->integral < $list->sale_price){
+                return $this->success([
+                    'overage' => 0
+                ],0,'余额不足');
+            }
+
+            // 购买记录
+            $record = new UserEpisodesRecord();
+            $record->user_id =\user()->id;
+            $record->episodes_id = $episode->id;
+            $record->list_id = $list->id;
+            $record->price = $list->sale_price;
+            $record->status = 1;
+            $record->save();
+
+            // 记录日志
+            $record = new UserConsumeRecord();
+            $record->user_id = \user()->id;
+            $record->type = 2; // 消费
+            $record->before = $user->integral;
+            $record->change = -$list->sale_price;
+            $record->current = $user->integral - $list->sale_price;
+            $record->remark = "购买短剧 {$episode->name} 第{$list->sort}集";
+            $record->save();
+
+            // 扣除金币
+            $user->integral = $user->integral - $list->sale_price;
+            $user->save();
+
+            \DB::commit();
+            return $this->success(['episode_id' => $episode, 'list_id' => $list]);
+        }catch (QueryException $e){
+            \DB::rollBack();
+            return $this->error('购买失败');
+        }catch (\Exception $ex){
+            \DB::rollBack();
+            return $this->error('购买失败');
+        }
+    }
+}

+ 1 - 1
server/app/Http/Controllers/V1/User/SignController.php

xqd
@@ -44,7 +44,7 @@ class SignController extends Controller
 
             $user = UserInfo::find(\user()->id);
 
-            // 记录日
+            // 记录日
             $record = new UserConsumeRecord();
             $record->user_id = \user()->id;
             $record->type = 3; // 签到

+ 7 - 0
server/app/Models/EpisodesList.php

xqd xqd
@@ -32,6 +32,12 @@ use Illuminate\Database\Eloquent\Model;
  * @method static \Illuminate\Database\Query\Builder|EpisodesList withoutTrashed()
  * @mixin \Eloquent
  * @property-read \App\Models\Episode|null $episode
+ * @property int $is_free 是否免费
+ * @property string|null $origin_price 原价
+ * @property int $sale_price 价格
+ * @method static \Illuminate\Database\Eloquent\Builder|EpisodesList whereIsFree($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|EpisodesList whereOriginPrice($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|EpisodesList whereSalePrice($value)
  */
 class EpisodesList extends Model
 {
@@ -46,6 +52,7 @@ class EpisodesList extends Model
 
     protected $casts = [
         'sale_price' => 'integer',
+        'origin_price' => 'integer',
         'url' =>  HttpToHttps::class,
     ];
 

+ 1 - 1
server/app/Models/UserEpisodesRecord.php

xqd
@@ -31,7 +31,7 @@ use Illuminate\Database\Eloquent\Model;
  * @method static \Illuminate\Database\Eloquent\Builder|UserEpisodesRecord whereUpdatedAt($value)
  * @method static \Illuminate\Database\Eloquent\Builder|UserEpisodesRecord whereUserId($value)
  * @mixin \Eloquent
- * @property int $statust 状态
+ * @property int $status 状态
  * @property-read \App\Models\User|null $user
  * @method static \Illuminate\Database\Eloquent\Builder|UserEpisodesRecord whereStatust($value)
  * @property-read \App\Models\Episode|null $episodes

+ 1 - 0
server/resources/lang/zh/episodes-list.php

xqd
@@ -10,6 +10,7 @@ return [
         'episodes_id' => '短剧ID',
         'sort' => '第几集',
         'is_free' => '是否免费',
+        'origin_price' => '原价',
         'sale_price' => '价格',
         'url' => '视频链接',
     ],

+ 8 - 0
server/routes/api.php

xqd xqd
@@ -121,6 +121,13 @@ $api->version('v1', ['namespace' => 'App\Http\Controllers\V1'], function ($api)
                     $api->get('setting', 'SignController@setting');
                     $api->post('handle', 'SignController@handle');
                 });
+
+                // 用户剧集
+                $api->group(['prefix' => 'episode'], function ($api){
+                    /* @var Dingo\Api\Routing\Router $api*/
+                    $api->get('buy/{episode}/record', 'EpisodeController@buyRecord');
+                    $api->post('{episode}/{list}/buy', 'EpisodeController@buy');
+                });
             });
         });
 
@@ -144,6 +151,7 @@ $api->version('v1', ['namespace' => 'App\Http\Controllers\V1'], function ($api)
             $api->get('search', 'EpisodeController@search'); // 搜索
             $api->get('vip/free', 'EpisodeController@vipFree'); // banner
             $api->get('{id}/detail', 'EpisodeController@detail'); // 详情
+            $api->get('/list/{listId}/buyNum', 'EpisodeController@listBuyNum'); // 详情
         });
 
     });