Sfoglia il codice sorgente

添加 cam 相关页面和接口

reghao 2 anni fa
parent
commit
bcd4a9ab49

+ 2 - 2
src/api/article.js

@@ -1,11 +1,11 @@
-import {delete0, get, post} from '@/utils/request'
+import { delete0, get, post } from '@/utils/request'
 
 const articleApi = {
   articlePostApi: '/api/content/post/article',
   updateArticleScopeApi: '/api/content/post/article/update/scope',
   updateArticleContentApi: '/api/content/post/article/update/content',
   articleApi: '/api/content/article',
-  userArticleApi: '/api/content/article/user',
+  userArticleApi: '/api/content/article/user'
 }
 
 export function submitArticle(data) {

+ 46 - 0
src/api/cam.js

@@ -0,0 +1,46 @@
+import { delete0, get, post } from '@/utils/request'
+
+const camApi = {
+  camApi: '/api/content/cam',
+  updateCamNameApi: '/api/content/cam/update/name',
+  camListApi: '/api/content/cam/list/kv',
+  camRecordApi: '/api/content/cam/record/month',
+  camRecordListApi: '/api/content/cam/record/day',
+  camPullUrlApi: '/api/content/cam/stream/rtmp/pull'
+}
+
+export function addCam(data) {
+  return post(camApi.camApi, data)
+}
+
+export function updateCamName(jsonData) {
+  return post(camApi.updateCamNameApi, jsonData)
+}
+
+export function deleteCam(camId) {
+  return delete0(camApi.camApi + '/' + camId)
+}
+
+export function getUserCams(page) {
+  return get(camApi.camApi + '?page=' + page)
+}
+
+export function getCamDetail(camId) {
+  return get(camApi.camApi + '/' + camId)
+}
+
+export function getCamList() {
+  return get(camApi.camListApi)
+}
+
+export function getCamRecordDay(param) {
+  return get(camApi.camRecordApi, param)
+}
+
+export function getCamRecordList(param) {
+  return get(camApi.camRecordListApi, param)
+}
+
+export function getCamPullUrl(camId) {
+  return get(camApi.camPullUrlApi + '/' + camId)
+}

+ 1 - 1
src/api/image.js

@@ -34,7 +34,7 @@ export function deleteAlbumImage(imageFileId) {
 }
 
 export function deleteAlbum(albumId) {
-  return delete0(imageApi.imageAlbumApi, albumId)
+  return delete0(imageApi.imageAlbumApi + '/' + albumId)
 }
 
 export function getUserAlbums(page) {

+ 9 - 17
src/components/LivePlayer.vue

@@ -3,13 +3,12 @@
 </template>
 
 <script>
-import { videoUrl } from '@/api/video'
-
 import flvjs from 'flv.js'
 import DPlayer from 'dplayer'
+import { getCamPullUrl } from '@/api/cam'
 
 export default {
-  name: 'VideoPlayer',
+  name: 'LivePlayer',
   props: {
     videoProp: {
       type: Object,
@@ -20,29 +19,23 @@ export default {
     return {
       flvjs,
       DPlayer,
-      danmaku: {
-        api: '//api.reghao.cn/api/comment/danmaku/',
-        token: 'bili'
-      },
       getUrl: true
     }
   },
   created() {
   },
   mounted() {
-    const videoId = this.videoProp.videoId
-    if (this.getUrl) {
-      const url = 'https://disk.reghao.cn/live/cam1'
-      this.initFlvPlayer(videoId, this.videoProp.coverUrl, url)
-    }
+    const camId = this.videoProp.videoId
+    this.getPullUrl(camId)
   },
   methods: {
-    getVideoUrl(videoId) {
-      videoUrl(videoId).then(resp => {
+    getPullUrl(camId) {
+      getCamPullUrl(camId).then(resp => {
         if (resp.code === 0) {
+          this.initFlvPlayer(resp.data)
         } else {
           this.$notify.error({
-            message: '视频 url 获取失败',
+            message: '获取摄像头拉流地址失败',
             type: 'warning',
             duration: 3000
           })
@@ -55,11 +48,10 @@ export default {
         })
       })
     },
-    initFlvPlayer(videoId, coverUrl, videoUrl) {
+    initFlvPlayer(videoUrl) {
       new DPlayer({
         container: document.getElementById('dplayer'),
         live: true,
-        danmaku: false,
         video: {
           url: videoUrl,
           type: 'customFlv',

+ 17 - 1
src/router/index.js

@@ -46,6 +46,8 @@ const HistoryIndex = () => import('views/my/History')
 // 消息
 const MessageIndex = () => import('views/my/Message')
 
+const CamList = () => import('views/post/CamList')
+
 // 发布稿件
 const PostPublishVideo = () => import('components/upload/PublishVideo')
 const PostPublishAudio = () => import('components/upload/PublishAudio')
@@ -231,6 +233,20 @@ const routes = [
       }
     ]
   },
+  {
+    path: '/my/cam',
+    name: 'MyMessage',
+    component: My,
+    meta: { needAuth: true },
+    children: [
+      {
+        path: '/my/cam/list',
+        name: '摄像头列表',
+        component: CamList,
+        meta: { needAuth: true }
+      }
+    ]
+  },
   // ********************************************************************************************************************
   {
     path: '/admin',
@@ -272,7 +288,7 @@ const routes = [
     meta: { needAuth: true }
   },
   {
-    path: '/live/:id',
+    path: '/live',
     name: 'LivePage',
     component: LivePage,
     meta: { needAuth: true }

+ 1 - 1
src/views/admin/PostList.vue

@@ -87,7 +87,7 @@
           prop="duration"
           label="时长"
         >
-<!--          <span>59:59:59</span>-->
+          <!--          <span>59:59:59</span>-->
         </el-table-column>
         <el-table-column
           prop="direction"

+ 1 - 1
src/views/admin/UserList.vue

@@ -163,7 +163,7 @@ export default {
       // 屏幕宽度, 为了控制分页条的大小
       screenWidth: document.body.clientWidth,
       currentPage: 1,
-      pageSize: 100,
+      pageSize: 20,
       totalSize: 0,
       dataList: [],
       // **********************************************************************

+ 174 - 17
src/views/home/LivePage.vue

@@ -1,6 +1,6 @@
 <template>
   <el-row class="movie-list">
-    <el-col :md="15">
+    <el-col :md="16">
       <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
         <el-card class="box-card">
           <div slot="header" class="clearfix">
@@ -12,10 +12,67 @@
         </el-card>
       </el-row>
     </el-col>
-    <el-col :md="9">
+    <el-col :md="8">
       <el-row>
         <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
-          <user-avatar-card :user-avatar="user" />
+          <el-card class="box-card">
+            <div slot="header" class="clearfix">
+              <el-select v-model="cam" placeholder="选择摄像头" @change="onSelect">
+                <el-option
+                  v-for="item in camList"
+                  :key="item.value"
+                  :label="item.name"
+                  :value="item.value"
+                />
+              </el-select>
+            </div>
+            <div class="text item">
+              <el-calendar v-if="showCalender" v-model="calendarDate">
+                <div
+                  slot="dateCell"
+                  slot-scope="{ date, data }"
+                  @click="handleCellClick(date, data)"
+                >
+                  <p>{{ data.day.split("-").slice(2).join() }}</p>
+                  <p v-if="dateMap.get(data.day) != null">{{ '✔️' }}</p>
+                </div>
+              </el-calendar>
+            </div>
+          </el-card>
+        </el-row>
+        <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
+          <el-card v-if="showRecordList" class="box-card">
+            <div slot="header" class="clearfix">
+              <el-row>
+                <h3>列表</h3>
+              </el-row>
+            </div>
+            <div class="text item">
+              <el-table
+                :data="recordList"
+                :show-header="false"
+                height="480"
+                style="width: 100%"
+              >
+                <el-table-column
+                  prop="title"
+                >
+                  <template slot-scope="scope">
+                    <router-link :to="`/vidlist/${scope.row.videoId}`">
+                      <span>{{ scope.row.title | ellipsis }}</span>
+                    </router-link>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="duration"
+                >
+                  <template slot-scope="scope">
+                    <span>{{ scope.row.duration }}</span>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
+          </el-card>
         </el-row>
       </el-row>
     </el-col>
@@ -23,16 +80,20 @@
 </template>
 
 <script>
+import flvjs from 'flv.js'
+import DPlayer from 'dplayer'
 import LivePlayer from 'components/LivePlayer'
-import UserAvatarCard from '@/components/card/UserAvatarCard'
+import { getCamList, getCamRecordDay, getCamRecordList } from '@/api/cam'
 
 export default {
   name: 'LivePage',
-  components: { LivePlayer, UserAvatarCard },
+  components: { LivePlayer },
   data() {
     return {
+      flvjs,
+      DPlayer,
       video: {
-        videoId: 'jk1024',
+        videoId: 110120119,
         title: '我的直播',
         description: '我的直播',
         view: 10,
@@ -50,24 +111,120 @@ export default {
         autoPlay: false,
         playlist: []
       },
-      similarVideos: [],
-      isCollected: false,
-      showErrorReportDialog: false,
-      errorReportForm: {
-        videoId: null,
-        errorCode: null
-      },
       showPlaylist: false,
-      autoPlay: false
+      autoPlay: false,
+      playList: {
+        current: 0,
+        list: [
+          'eyNXaDnmN3',
+          'WkYNYzDePp',
+          'a8Vx9EGDbA',
+          'a8V3D88NJK',
+          '4m7qMXapp1'
+        ]
+      },
+      calendarDate: new Date(),
+      dateList: [],
+      dateMap: new Map(),
+      showCalender: false,
+      showRecordList: false,
+      camList: [],
+      cam: null,
+      form: {},
+      recordList: []
+    }
+  },
+  watch: {
+    calendarDate: {
+      handler(newValue, oldValue) {
+        const oldMonth = this.getYearMonth(oldValue)
+        const newMonth = this.getYearMonth(newValue)
+        if (oldMonth !== newMonth) {
+          this.showCalender = false
+          this.form.yearMonth = this.getYearMonth(newValue)
+          getCamRecordDay(this.form).then(resp => {
+            if (resp.code === 0) {
+              this.dateMap.clear()
+              for (const item of resp.data) {
+                const date1 = new Date(item)
+                const dayStr = this.getYearMonthDay(date1)
+                this.dateMap.set(dayStr, date1)
+              }
+              this.showCalender = true
+            }
+          })
+        }
+      }
     }
   },
   created() {
+    getCamList().then(resp => {
+      if (resp.code === 0) {
+        this.camList = resp.data
+      }
+    })
   },
   methods: {
-    // 用户点击收藏
-    collection(videoId) {
+    onSelect(value) {
+      this.showCalender = false
+      this.form.camId = value
+      this.form.yearMonth = this.getYearMonth(this.calendarDate)
+      getCamRecordDay(this.form).then(resp => {
+        if (resp.code === 0) {
+          for (const item of resp.data) {
+            const date1 = new Date(item)
+            const dayStr = this.getYearMonthDay(date1)
+            this.dateMap.set(dayStr, date1)
+          }
+          this.showCalender = true
+        }
+      })
+    },
+    handleCellClick(date, data) {
+      this.form.yearMonthDay = this.getYearMonthDay(date)
+      getCamRecordList(this.form).then(resp => {
+        if (resp.code === 0) {
+          this.showRecordList = true
+          this.recordList = resp.data
+        }
+      })
+    },
+    getYearMonth(date) {
+      const year = date.getFullYear().toString().padStart(4, '0')
+      const month = (date.getMonth() + 1).toString().padStart(2, '0')
+      // const day = date.getDate().toString().padStart(2, '0')
+      // const hour = date.getHours().toString().padStart(2, '0')
+      // const minute = date.getMinutes().toString().padStart(2, '0')
+      // const second = date.getSeconds().toString().padStart(2, '0')
+      // 2023-02-16 08:25:05
+      // console.log(`${year}-${month}-${day} ${hour}:${minute}:${second}`)
+      return year + '-' + month
+    },
+    getYearMonthDay(date) {
+      const year = date.getFullYear().toString().padStart(4, '0')
+      const month = (date.getMonth() + 1).toString().padStart(2, '0')
+      const day = date.getDate().toString().padStart(2, '0')
+      return year + '-' + month + '-' + day
     },
-    getDownloadUrl(videoId) {
+    initFlvPlayer(videoId, coverUrl, videoUrl) {
+      new DPlayer({
+        container: document.getElementById('dplayer'),
+        live: true,
+        video: {
+          url: videoUrl,
+          type: 'customFlv',
+          customType: {
+            customFlv: function(video, player) {
+              const flvPlayer = flvjs.createPlayer({
+                type: 'flv',
+                url: video.src
+              })
+              flvPlayer.attachMediaElement(video)
+              flvPlayer.load()
+            }
+          }
+        }
+      })
     }
   }
 }

+ 187 - 0
src/views/home/LivePage1.vue

@@ -0,0 +1,187 @@
+<template>
+  <div class="app-container">
+    <el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
+      <el-form-item label="年份" prop="holidayYear">
+        <el-date-picker
+          v-model="queryParams.holidayYear"
+          type="year"
+          :clearable="false"
+          placeholder="选择年"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <el-row>
+      <div v-for="cal in defaultCals" @click="handleUpdateHoliday(cal)">
+        <el-col :span="6">
+          <el-calendar :value="cal" class="holiday">
+            <template slot="dateCell" slot-scope="{date, data}" class="temp-mt">
+              <div v-show="data.type === 'current-month'" :id="cal.getMonth()+'-'+data.day" class="holiday-cell">
+                {{ data.day.split('-')[2] }}
+              </div>
+            </template>
+          </el-calendar>
+        </el-col>
+      </div>
+    </el-row>
+
+    <el-dialog title="节假日设置" :visible.sync="show" width="40%">
+      <el-calendar :value="currentMonth" class="select-month">
+        <!-- 这里使用的是 2.5 slot 语法,对于新项目请使用 2.6 slot 语法-->
+        <template slot="dateCell" slot-scope="{date, data}" class="temp-mt">
+          <div v-show="data.type === 'current-month'" class="holiday-cell" @click="selectDate(date,data)">
+            <span>{{ data.day.split('-')[2] }}</span>
+            <span :id="data.day">{{ initHolidayDate(data) }}</span>
+          </div>
+        </template>
+      </el-calendar>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="show = false">取 消</el-button>
+        <el-button type="primary" @click="submitHoliday">确 定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: 'Temp',
+  data() {
+    return {
+      queryParams: {
+        holidayYear: new Date()
+      },
+      // 设置的月份
+      defaultCals: [],
+      // 全年已选中的日期
+      holidayDate: [],
+      // 弹框
+      show: false,
+      // 点击修改的月份
+      currentMonth: undefined,
+      // 点击月中已选中的日期
+      currentDate: []
+    }
+  },
+  created() {
+    // 初始化日历
+    const nowYear = new Date().getFullYear()
+    this.initCalendar(nowYear)
+  },
+  methods: {
+    // 初始化日历
+    initCalendar(year) {
+      this.defaultCals = [
+        new Date(year, 0, 1), new Date(year, 1, 1), new Date(year, 2, 1),
+        new Date(year, 3, 1), new Date(year, 4, 1), new Date(year, 5, 1),
+        new Date(year, 6, 1), new Date(year, 7, 1), new Date(year, 8, 1),
+        new Date(year, 9, 1), new Date(year, 10, 1), new Date(year, 11, 1)
+      ]
+
+      // 调接口获取
+      this.holidayDate = [
+        { day: 2, date: '0-' + year + '-01-02' },
+        { day: 2, date: '1-' + year + '-02-02' },
+        { day: 2, date: '2-' + year + '-03-02' }
+      ]
+      this.$nextTick(() => {
+        const holidayCell = document.getElementsByClassName('holiday-cell')
+        for (const i in holidayCell) {
+          if (undefined != holidayCell[i].style) {
+            holidayCell[i].style.backgroundColor = '#FFFFFF'
+          }
+        }
+        // 给已选中的日期加背景色
+        for (const i in this.holidayDate) {
+          const span = document.getElementById(this.holidayDate[i].date)
+          span.style.backgroundColor = '#F56C6C'
+        }
+      })
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      const year = this.queryParams.holidayYear.getFullYear()
+      this.initCalendar(year)
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm('queryForm')
+      this.queryParams.holidayYear = new Date()
+      this.handleQuery()
+    },
+    // 初始化已选中的日期
+    initHolidayDate(data) {
+      for (const i in this.currentDate) {
+        if (data.day === this.currentDate[i].date) {
+          data.isSelected = true
+          return '✔️'
+        }
+      }
+    },
+    // 节假日设置
+    handleUpdateHoliday(cal) {
+      this.show = true
+      this.currentMonth = cal
+      // 调接口获取
+      this.currentDate = [
+        { day: 2, date: cal.getFullYear() + '-01-02' }
+      ]
+    },
+    selectDate(date, data) {
+      const day = date.getDate()
+      const span = document.getElementById(data.day)
+      if (span.innerText) {
+        span.innerText = ''
+        for (const i in this.currentDate) {
+          if (day === this.currentDate[i].day) {
+            this.currentDate.splice(i, 1)
+          }
+        }
+      } else {
+        span.innerText = '✔️'
+        this.currentDate.push({ day: day, date: data.day })
+      }
+    },
+    // 提交
+    submitHoliday() {
+      console.log(this.currentMonth, this.currentDate)
+      this.show = false
+      this.queryParams.holidayYear = this.currentMonth
+      this.handleQuery()
+    }
+  }
+}
+</script>
+
+<style>
+.holiday .el-calendar__button-group{
+  display: none;
+}
+
+.select-month .el-calendar__button-group{
+  display: none;
+}
+
+.holiday .el-calendar-day{
+  padding: 1px;
+  width: 100%;
+  height: 34px;
+}
+
+.select-month .el-calendar-day{
+  padding: 1px;
+  width: 100%;
+}
+
+.holiday-cell{
+  width: 100%;
+  height: 100%;
+  display:flex;
+  justify-content: center;
+  align-items: center;
+}
+</style>

+ 12 - 0
src/views/my/My.vue

@@ -127,6 +127,18 @@
             </el-menu-item>
           </el-menu-item-group>
         </el-submenu>
+        <el-submenu index="/my/cam">
+          <template slot="title">
+            <i class="el-icon-camera" />
+            <span slot="title">我的监控</span>
+          </template>
+          <el-menu-item-group>
+            <el-menu-item index="/my/cam/list">
+              <i class="el-icon-camera" />
+              <span slot="title">摄像头列表</span>
+            </el-menu-item>
+          </el-menu-item-group>
+        </el-submenu>
       </el-menu>
     </el-aside>
     <el-main>

+ 316 - 0
src/views/post/CamList.vue

@@ -0,0 +1,316 @@
+<template>
+  <el-row>
+    <el-row>
+      <el-button
+        size="mini"
+        type="warning"
+        class="el-icon-document-add"
+        @click="handleAdd"
+      >添加</el-button>
+      <el-table
+        :data="dataList"
+        border
+        style="width: 100%"
+      >
+        <el-table-column
+          fixed="left"
+          label="No"
+          type="index"
+        />
+        <el-table-column
+          prop="addAt"
+          label="添加时间"
+          width="150"
+        />
+        <el-table-column
+          prop="camName"
+          label="摄像头名字"
+          width="150"
+        />
+        <el-table-column
+          prop="state"
+          label="状态"
+        >
+          <template slot-scope="scope">
+            <el-tag v-if="scope.row.state === 1" :type="'warning'" disable-transitions>
+              离线
+            </el-tag>
+            <el-tag v-else-if="scope.row.state === 2" :type="'success'" disable-transitions>
+              推流中
+            </el-tag>
+            <el-tag v-else :type="'danger'" disable-transitions>
+              未知状态
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column
+          fixed="right"
+          label="操作"
+          width="320"
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="mini"
+              @click="handleEdit(scope.$index, scope.row)"
+            >修改名字</el-button>
+            <el-button
+              size="mini"
+              @click="handleDetail(scope.$index, scope.row)"
+            >详情</el-button>
+            <el-button
+              size="mini"
+              type="danger"
+              @click="handleDelete(scope.$index, scope.row)"
+            >删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 添加摄像头对话框 -->
+      <el-dialog
+        append-to-body
+        :visible.sync="showEditScopeDialog"
+        width="50%"
+        center
+      >
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <h3>添加摄像头</h3>
+          </div>
+          <div class="text item">
+            <el-form ref="form" :model="addCamForm" label-width="80px">
+              <el-form-item label="名字">
+                <el-input v-model="addCamForm.name" />
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" @click="onAddCam">立即添加</el-button>
+                <el-button>取消</el-button>
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-card>
+      </el-dialog>
+      <!-- 修改摄像头名字对话框 -->
+      <el-dialog
+        append-to-body
+        :visible.sync="showUpdateDialog"
+        width="50%"
+        center
+      >
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <h3>修改摄像头名字</h3>
+          </div>
+          <div class="text item">
+            <el-form ref="form" :model="updateNameForm" label-width="80px">
+              <el-form-item label="新名字">
+                <el-input v-model="updateNameForm.newName" />
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" @click="onUpdateCam">立即修改</el-button>
+                <el-button>取消</el-button>
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-card>
+      </el-dialog>
+      <!-- 摄像头详情对话框 -->
+      <el-dialog
+        append-to-body
+        :visible.sync="showDetailDialog"
+        width="50%"
+        center
+      >
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <h3>摄像头详情</h3>
+          </div>
+          <div class="text item">
+            <el-form v-if="camDetail" :model="camDetail" label-width="100px">
+              <el-form-item label="摄像头名字">
+                <span>{{ camDetail.camName }}</span>
+              </el-form-item>
+              <el-form-item label="推流地址">
+                <span>{{ camDetail.camName }}</span>
+              </el-form-item>
+            </el-form>
+          </div>
+        </el-card>
+      </el-dialog>
+    </el-row>
+    <el-row>
+      <el-pagination
+        background
+        :small="screenWidth <= 768"
+        layout="prev, pager, next"
+        :page-size="pageSize"
+        :current-page="currentPage"
+        :total="totalSize"
+        @current-change="handleCurrentChange"
+        @prev-click="handleCurrentChange"
+        @next-click="handleCurrentChange"
+      />
+    </el-row>
+  </el-row>
+</template>
+
+<script>
+import {
+  getVideoResource
+} from '@/api/video'
+import { addCam, deleteCam, getCamDetail, getUserCams, updateCamName } from '@/api/cam'
+
+export default {
+  name: 'CamList',
+  data() {
+    return {
+      // 屏幕宽度, 为了控制分页条的大小
+      screenWidth: document.body.clientWidth,
+      currentPage: 1,
+      pageSize: 20,
+      totalSize: 0,
+      dataList: [],
+      // **********************************************************************
+      showEditScopeDialog: false,
+      showUpdateDialog: false,
+      showDetailDialog: false,
+      videoResources: [],
+      addCamForm: {
+        name: null
+      },
+      updateNameForm: {
+        camId: null,
+        newName: null
+      },
+      camDetail: null
+    }
+  },
+  created() {
+    document.title = '摄像头列表'
+    this.getData(this.currentPage)
+  },
+  methods: {
+    handleCurrentChange(pageNumber) {
+      this.currentPage = pageNumber
+      this.getData(this.currentPage)
+      // 回到顶部
+      scrollTo(0, 0)
+    },
+    getData() {
+      this.dataList = []
+      getUserCams(this.currentPage).then(resp => {
+        if (resp.code === 0) {
+          this.dataList = resp.data.list
+          this.totalSize = resp.data.totalSize
+        } else {
+          this.$notify({
+            title: '提示',
+            message: resp.msg,
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify({
+          title: '提示',
+          message: error.message,
+          type: 'error',
+          duration: 3000
+        })
+      })
+    },
+    handleVideoResource(index, row) {
+      const videoId = row.videoId
+      getVideoResource(videoId).then(resp => {
+        if (resp.code === 0) {
+          this.videoResources = resp.data
+        }
+      })
+    },
+    handleAdd(index, row) {
+      this.showEditScopeDialog = true
+    },
+    handleEdit(index, row) {
+      this.updateNameForm.camId = row.camId
+      this.showUpdateDialog = true
+    },
+    handleDetail(index, row) {
+      getCamDetail(row.camId).then(resp => {
+        if (resp.code === 0) {
+          this.camDetail = resp.data
+          this.showDetailDialog = true
+        }
+      })
+    },
+    handleDelete(index, row) {
+      this.$confirm('确定要删除 ' + row.title + '?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        deleteCam(row.camId).then(resp => {
+          if (resp.code === 0) {
+            this.$notify({
+              title: '提示',
+              message: '摄像头已删除',
+              type: 'warning',
+              duration: 3000
+            })
+            this.$router.go(0)
+          }
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消'
+        })
+      })
+    },
+    onAddCam() {
+      this.showEditScopeDialog = false
+      addCam(this.addCamForm).then(resp => {
+        if (resp.code === 0) {
+          this.addCamForm = {
+            name: null
+          }
+          this.$notify({
+            title: '提示',
+            message: '摄像头已添加',
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify({
+          title: '提示',
+          message: error.message,
+          type: 'warning',
+          duration: 3000
+        })
+      })
+    },
+    onUpdateCam() {
+      this.showUpdateDialog = false
+      updateCamName(this.updateNameForm).then(resp => {
+        if (resp.code === 0) {
+          this.$notify({
+            title: '提示',
+            message: '摄像头名字已更新',
+            type: 'warning',
+            duration: 3000
+          })
+        }
+      }).catch(error => {
+        this.$notify({
+          title: '提示',
+          message: error.message,
+          type: 'warning',
+          duration: 3000
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style>
+</style>