| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590 |
- <template>
- <wrapper
- fill
- margin
- background
- >
- <el-tabs
- v-model="activeName"
- v-loading="videoOption.loading"
- class="c-tabs video"
- @tab-click="handleClick"
- >
- <el-tab-pane
- label="人流量监测"
- name="first"
- >
- <div class="has-padding">
- <div class="l-flex--row c-table__header">
- <div class="l-flex__auto c-sibling-item">
- <button
- v-if="hasEditPermission"
- class="o-button"
- @click="addbtn"
- >
- <i class="o-button__icon el-icon-circle-plus-outline" />新增
- </button>
- </div>
- <search-input
- v-model.trim="searchname"
- class="l-flex__none c-sibling-item"
- placeholder="搜索"
- @search="search"
- />
- <button
- class="l-flex__none c-sibling-item o-button"
- @click="search"
- >
- 搜索
- </button>
- </div>
- <el-row
- v-if="videoOption.list.length"
- :gutter="16"
- class="rowheight"
- >
- <el-col
- v-for="(video, index) in videoOption.list"
- :key="index"
- :span="8"
- class="cameraRow"
- >
- <div
- ref="videoB"
- class="o-video bg-purple"
- :style="{ height: videoheight }"
- @click="toDetail(video)"
- >
- <video
- :ref="video.deviceId"
- style="width: 100%;"
- class="video"
- muted
- autoplay
- :poster="require('@/assets//video-post.png')"
- />
- <div
- v-show="!video.online"
- class="offLine"
- >
- 设备离线
- </div>
- <div class="o-video_buttom l-flex--row">
- <div class="l-flex__auto">{{ video.name }}</div>
- <template v-if="hasEditPermission">
- <img
- class="o-video_edit"
- :src="imgUrl.edit"
- @click.stop="editbtn(video)"
- >
- <img
- class="o-video_delete"
- :src="imgUrl.delete"
- @click.stop="deletebtn(video)"
- >
- </template>
- </div>
- </div>
- </el-col>
- </el-row>
- <div
- v-if="!videoOption.list.length"
- class="empty"
- >无摄像头数据</div>
- <pagination
- :total="videoOption.totalCount"
- :page-sizes="[6]"
- :page.sync="videoOption.params.pageNum"
- :limit.sync="videoOption.params.pageSize"
- @pagination="getCamera"
- />
- </div>
- </el-tab-pane>
- <!-- <el-tab-pane label="视频回传" name="second">
- <div class="has-padding">
- <div class="l-flex--row c-table__header">
- <div class="l-flex__auto c-sibling-item">
- <el-checkbox-group v-model="checkList" @change="chechChange">
- <el-checkbox label="视频回采"></el-checkbox>
- <el-checkbox label="模拟终端"></el-checkbox>
- </el-checkbox-group>
- </div>
- <div class="l-flex__none c-sibling-item">
- <img
- class="c-sibling-item"
- @click="rowChange(24)"
- :src="require('@/assets/icon_one_normal.png')"
- alt=""
- />
- <img
- class="c-sibling-item"
- @click="rowChange(12)"
- :src="require('@/assets/icon_four_normal.png')"
- alt=""
- />
- <img
- class="c-sibling-item"
- @click="rowChange(8)"
- :src="require('@/assets/icon_nine_focus.png')"
- alt=""
- />
- </div>
- <button
- class="l-flex__none c-sibling-item o-button"
- @click="search"
- >
- <i class="o-button__icon el-icon-full-screen" />
- 全屏
- </button>
- </div>
- <el-row :gutter="16" class="rowheight">
- <el-col
- :span="rowNum"
- v-for="(item, index) in returnList.list"
- :key="index"
- class="cameraRow"
- >
- <div class="return_item bg-purple"
- ref="returnB"
- :style="{ height: returnheight }">
- <div class="o-video_buttom l-flex--row">
- <div class="l-flex__auto">{{ item.name }}</div>
- <img
- :src="require('@/assets/icon_address.png')"
- class="o-video_edit"
- />
- <div class="return_local">{{ item.name }}</div>
- </div>
- </div>
- </el-col>
- </el-row>
- </div>
- </el-tab-pane> -->
- </el-tabs>
- <!-- 新增和编辑 -->
- <el-dialog
- :title="dialogTitle"
- :visible.sync="adding"
- custom-class="c-dialog"
- :close-on-click-modal="false"
- >
- <el-form
- ref="cameraForm"
- :model="camera"
- :rules="cameraRules"
- label-width="100px"
- class="c-form"
- >
- <el-form-item
- label="设备名称"
- prop="name"
- >
- <el-input
- v-model.number="camera.name"
- class="c-form__item"
- />
- </el-form-item>
- <el-form-item
- v-if="!isEdit"
- label="ID"
- prop="deviceId"
- >
- <el-input
- v-model.number="camera.deviceId"
- class="c-form__item"
- />
- </el-form-item>
- <el-form-item
- label="用户名"
- prop="username"
- >
- <el-input
- v-model.number="camera.username"
- class="c-form__item"
- />
- </el-form-item>
- <el-form-item
- label="密码"
- prop="password"
- >
- <el-input
- v-model.number="camera.password"
- class="c-form__item"
- />
- </el-form-item>
- <el-form-item
- label="备注"
- prop="remark"
- >
- <el-input
- v-model.number="camera.remark"
- type="textarea"
- maxlength="500"
- class="c-form__item"
- show-word-limit
- />
- </el-form-item>
- </el-form>
- <template #footer>
- <button
- class="o-button"
- @click="add('cameraForm')"
- >
- 确定
- </button>
- <button
- class="o-button cancel"
- @click="handleCloseAddDialog('cameraForm')"
- >
- 取消
- </button>
- </template>
- </el-dialog>
- <el-dialog
- title
- :fullscreen="true"
- :visible="detailing"
- :close-on-click-modal="false"
- class="fulldialog"
- >
- <detail
- v-if="detailing"
- :detailobj="editOption"
- @closeDetail="closeDetail"
- />
- </el-dialog>
- </wrapper>
- </template>
- <script>
- import flvjs from 'flv.js'
- import {
- getCamera,
- addCamera,
- updateCamera,
- deleteCamera,
- getOnline
- } from '@/api/camera'
- import { createListOptions } from '@/utils'
- import Detail from './components/Detail'
- const CAMERA_URL = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${process.env.VUE_APP_GATEWAY || location.host}${process.env.VUE_APP_CAMERA_PROXY}`
- export default {
- name: 'Camera',
- components: {
- Detail
- },
- data () {
- return {
- activeName: 'first',
- searchname: '',
- imgUrl: {
- edit: require('@/assets/icon_edit.png'),
- delete: require('@/assets/icon_delete.png')
- },
- videoOption: createListOptions({
- pageSize: 6
- }),
- dialogTitle: '新增',
- adding: false,
- camera: {
- name: '',
- deviceId: '',
- username: '',
- password: '',
- remark: ''
- },
- cameraRules: {
- name: [{ required: true, message: '请填写设备名称', trigger: 'blur' }],
- deviceId: [{ required: true, message: '请填写ID', trigger: 'blur' }],
- username: [
- { required: true, message: '请填写用户名', trigger: 'blur' }
- ],
- password: [{ required: true, message: '请填写密码', trigger: 'blur' }]
- },
- isEdit: true,
- editOption: {},
- detailing: false,
- videoheight: '',
- playerList: {},
- checkList: [],
- returnList: createListOptions({
- pageSize: 9
- }),
- returnheight: 0,
- rowNum: 8
- }
- },
- created () {
- this.getCamera()
- },
- beforeDestroy () {
- this.destroyPlayer()
- },
- methods: {
- rowChange (num) {
- this.rowNum = num
- this.$nextTick(() => {
- this.returnheight = (this.$refs.returnB[0].clientWidth * 9) / 16 + 'px'
- })
- },
- chechChange (val) {
- console.log(val)
- },
- destroyPlayer () {
- for (const key in this.playerList) {
- if (Object.hasOwnProperty.call(this.playerList, key)) {
- // const element = object[key];
- if (this.playerList[key]) {
- this.playerList[key].pause()
- this.playerList[key].unload()
- this.playerList[key].detachMediaElement()
- this.playerList[key].destroy()
- this.playerList[key] = null
- }
- }
- }
- },
- handleClick () {},
- search () {
- this.getCamera()
- },
- getCamera () {
- const options = this.videoOption
- options.error = false
- options.loading = true
- options.params.name = this.searchname
- getCamera(options.params)
- .then(
- ({ data, totalCount }) => {
- options.totalCount = totalCount
- options.list = data
- // for (let i = 0; i < 34; i++) {
- // data.push({
- // deviceId: Math.random(),
- // })
- // }
- this.$nextTick(() => {
- this.videoheight =
- (this.$refs.videoB[0].clientWidth * 9) / 16 + 'px'
- this.destroyPlayer()
- for (let i = 0; i < data.length; i++) {
- getOnline(options.list[i].deviceId).then(({ data }) => {
- options.list[i].online = data
- if (data) {
- this.getflv(options.list[i].deviceId)
- }
- })
- }
- })
- },
- () => {
- options.error = true
- options.list = []
- }
- )
- .finally(() => {
- options.loading = false
- })
- },
- addCamera () {
- addCamera({
- name: this.camera.name,
- deviceId: this.camera.deviceId,
- username: this.camera.username,
- password: this.camera.password,
- remark: this.camera.remark
- }).then(() => {
- this.handleCloseAddDialog('cameraForm')
- this.getCamera()
- })
- },
- addbtn () {
- this.camera = {
- name: '',
- deviceId: '',
- username: '',
- password: '',
- remark: ''
- }
- this.dialogTitle = '新增'
- this.isEdit = false
- this.adding = true
- },
- add (formName) {
- this.$refs[formName].validate((valid) => {
- if (valid) {
- if (this.isEdit) {
- this.edit(this.editOption)
- } else {
- this.addCamera()
- }
- } else {
- console.log('error submit!!')
- return false
- }
- })
- },
- handleCloseAddDialog (formName) {
- this.adding = false
- this.$refs[formName].resetFields()
- },
- editbtn (item) {
- this.adding = true
- this.isEdit = true
- this.dialogTitle = '编辑'
- this.editOption = item
- this.camera = {
- name: item.name,
- username: item.username,
- remark: item.remark
- }
- },
- edit (item) {
- updateCamera({
- id: item.id,
- name: this.camera.name,
- deviceId: item.deviceId,
- username: this.camera.username,
- password: this.camera.password,
- remark: this.camera.remark
- }).then(() => {
- this.handleCloseAddDialog('cameraForm')
- this.getCamera()
- })
- },
- deletebtn (item) {
- const videoOption = this.videoOption
- deleteCamera({ id: item.id, name: item.name }).then(() => {
- if (videoOption.list.length === 1 && videoOption.params.pageNum > 1) {
- videoOption.params.pageNum -= 1
- }
- this.getCamera()
- })
- },
- getflv (deviceId) {
- if (flvjs.isSupported()) {
- // 创建一个flvjs实例
- this.playerList[deviceId] = flvjs.createPlayer({
- type: 'flv',
- isLive: true,
- hasAudio: false,
- url: `${CAMERA_URL}/${deviceId}?authorization=${this.$keycloak.token}`
- })
- this.playerList[deviceId].on('error', (e) => {
- console.log(e)
- })
- // 将实例挂载到video元素上面
- this.playerList[deviceId].attachMediaElement(this.$refs[deviceId][0])
- // player.currentTime = parseFloat(document.getElementsByName('seekpoint')[0].value);
- try {
- // 开始运行加载 只要流地址正常 就可以在h5页面中播放出画面了
- this.playerList[deviceId].load()
- this.playerList[deviceId].play()
- } catch (error) {
- console.log('连接websocker异常:' + error)
- console.log(error)
- }
- }
- },
- toDetail (item) {
- if (item.online) {
- this.detailing = true
- this.editOption = item
- this.destroyPlayer()
- }
- },
- closeDetail () {
- this.detailing = false
- this.getCamera()
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- //所有控件
- video::-webkit-media-controls-enclosure {
- display: none;
- }
- .has-padding {
- height: 100%;
- }
- .rowheight {
- height: calc(100% - 40px);
- overflow: auto;
- }
- .c-tabs {
- height: 100%;
- }
- .cameraRow {
- margin-bottom: 16px;
- }
- .o-video {
- // height: 190px;
- background-color: #edf0f6;
- position: relative;
- overflow: hidden;
- &_buttom {
- position: absolute;
- bottom: 0px;
- width: 100%;
- height: 58px;
- background-image: linear-gradient(0deg, rgba(6, 11, 18, 0.9), transparent);
- border-radius: 0px 0px 4px 4px;
- color: #fff;
- padding: 0 16px;
- }
- img {
- cursor: pointer;
- }
- &_edit {
- margin-right: 16px;
- }
- .offLine {
- position: absolute;
- left: 50%;
- top: 50%;
- color: #ff0000;
- text-align: center;
- transform: translate(-50%, -50%);
- }
- }
- .return {
- &_item {
- background-color: #aaa;
- width: 100%;
- height: 150px;
- position: relative;
- }
- &_local {
- font-size: 12px;
- }
- }
- .empty {
- color: #aaa;
- text-align: center;
- }
- </style>
- <style lang="scss">
- .fulldialog {
- .el-dialog__header {
- display: none;
- }
- .el-dialog__body {
- padding: 0;
- height: 100%;
- }
- }
- .video {
- .el-tabs__content {
- height: calc(100% - 40px);
- }
- .el-tab-pane {
- height: 100%;
- }
- }
- </style>
|