|
|
@@ -0,0 +1,558 @@
|
|
|
+<template>
|
|
|
+ <basic-container>
|
|
|
+ <avue-crud v-if="!showDeviceChannelCrud"
|
|
|
+ :option="deviceOption"
|
|
|
+ :table-loading="loading"
|
|
|
+ :data="data"
|
|
|
+ :page.sync="page"
|
|
|
+ :permission="permissionList"
|
|
|
+ :before-open="beforeOpen"
|
|
|
+ v-model="form"
|
|
|
+ ref="crud"
|
|
|
+ @row-update="rowUpdate"
|
|
|
+ @row-save="rowSave"
|
|
|
+ @row-del="rowDel"
|
|
|
+ @search-change="searchChange"
|
|
|
+ @search-reset="searchReset"
|
|
|
+ @selection-change="selectionChange"
|
|
|
+ @current-change="currentChange"
|
|
|
+ @size-change="sizeChange"
|
|
|
+ @refresh-change="refreshChange"
|
|
|
+ @on-load="onLoad">
|
|
|
+ <template slot="menuLeft">
|
|
|
+ <el-button type="danger"
|
|
|
+ size="small"
|
|
|
+ icon="el-icon-delete"
|
|
|
+ plain
|
|
|
+ v-if="permission.gbdevice_delete"
|
|
|
+ @click="handleDelete">删 除
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ <template slot="online" slot-scope="{row}">
|
|
|
+ <el-tag v-if="row.online === 1" type="success">在线</el-tag>
|
|
|
+ <el-tag v-if="row.online === 0" type="info">离线</el-tag>
|
|
|
+ </template>
|
|
|
+ <template slot="hostAddress" slot-scope="{row}">
|
|
|
+ <el-tag type="primary">{{row.hostAddress}}</el-tag>
|
|
|
+ </template>
|
|
|
+ <template slot="menu" slot-scope="{row}">
|
|
|
+ <el-button type="text" size="mini" icon="el-icon-setting">
|
|
|
+ <el-dropdown>
|
|
|
+ <span class="el-dropdown-link">
|
|
|
+ 操作<i class="el-icon-arrow-down el-icon--right"></i>
|
|
|
+ </span>
|
|
|
+ <el-dropdown-menu slot="dropdown">
|
|
|
+ <el-dropdown-item style="color: orange" v-if="permission.gbdevice_bind" @click.native="bindDevice(row)" icon="el-icon-paperclip">绑定</el-dropdown-item>
|
|
|
+ <el-dropdown-item style="color: limegreen" @click.native="handleSync(row, row.$index)" icon="el-icon-refresh">刷新</el-dropdown-item>
|
|
|
+ <el-dropdown-item style="color: #0087ff" @click.native="handleChannel(row.deviceId)" icon="el-icon-video-camera-solid">通道</el-dropdown-item>
|
|
|
+ </el-dropdown-menu>
|
|
|
+ </el-dropdown>
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </avue-crud>
|
|
|
+ <avue-crud v-if="showDeviceChannelCrud" :option="deviceChannelOption" :table-loading="loading" :data="data" :page="page" :permission="permissionList"
|
|
|
+ :before-open="beforeOpen" v-model="form" ref="crud" @row-update="rowUpdate" @row-save="rowSave" @row-del="rowDel"
|
|
|
+ @search-change="channelSearchChange" @search-reset="searchReset" @selection-change="selectionChange" @current-change="currentChange"
|
|
|
+ @size-change="sizeChange" @refresh-change="refreshChannelChange" @on-load="onLoadChannel">
|
|
|
+ <template slot-scope="{row}" slot="channelTypeSearch">
|
|
|
+ <el-select size="mini" style="margin-right: 1rem;" v-model="row.channelType" placeholder="请选择" default-first-option>
|
|
|
+ <el-option label="全部" value=""></el-option>
|
|
|
+ <el-option label="设备" value="false"></el-option>
|
|
|
+ <el-option label="子目录" value="true"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ <template slot-scope="{row}" slot="online">
|
|
|
+ <el-select size="mini" style="margin-right: 1rem;" v-model="row.online" placeholder="请选择" default-first-option>
|
|
|
+ <el-option label="全部" value=""></el-option>
|
|
|
+ <el-option label="在线" value="true"></el-option>
|
|
|
+ <el-option label="离线" value="false"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ <template slot="menuLeft">
|
|
|
+ <el-button type="primary" size="mini" icon="el-icon-arrow-left" @click="backToDeviceList">返 回</el-button>
|
|
|
+ </template>
|
|
|
+ <template slot="hasAudio" slot-scope="{row}">
|
|
|
+ <el-switch @change="updateChannel(scope.row)" v-model="row.hasAudio" active-color="#409EFF">
|
|
|
+ </el-switch>
|
|
|
+ </template>
|
|
|
+ <template slot="status" slot-scope="{row}">
|
|
|
+ <el-tag size="medium" v-if="row.status == 1">开启</el-tag>
|
|
|
+ <el-tag size="medium" v-else="row.status == 0">关闭</el-tag>
|
|
|
+ </template>
|
|
|
+ <template slot="menu" slot-scope="{row}">
|
|
|
+ <el-button size="mini" icon="el-icon-video-play" v-if="permission.gbdevicechannel_play" @click="devicePlay(row)">播放</el-button>
|
|
|
+ <el-button size="mini" icon="el-icon-switch-button" type="danger" :loading="stopBtnLoading" v-if="permission.gbdevicechannel_stop && !!row.streamId" @click="deviceStopPlay(row)">停止</el-button>
|
|
|
+<!-- <el-button size="mini" type="primary" icon="el-icon-video-camera" v-if="permission.wvpvideodevice_record" @click="deviceRecord(row)">设备录像</el-button>-->
|
|
|
+ </template>
|
|
|
+ </avue-crud>
|
|
|
+ <devicePlayer ref="devicePlayer"></devicePlayer>
|
|
|
+ <el-dialog :modal-append-tobody="false" append-to-body :visible.sync="bindVisible" title="设备绑定" width="60%">
|
|
|
+ <select-dialog-residential :id="form.residentialId" :name="form.residentialName" :callback="selectCallback" v-if="bindVisible"></select-dialog-residential>
|
|
|
+ </el-dialog>
|
|
|
+ </basic-container>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ import {getList, getDetail, add, update, remove, bind, sync} from "@/api/device/gb/gbdevice";
|
|
|
+ import {getList as getChannelList, startPlay, stopPlay} from "@/api/device/gb/gbdevicechannel";
|
|
|
+ import {mapGetters} from "vuex";
|
|
|
+ import SelectDialogResidential from "../../../components/select-dialog/select-dialog-residential";
|
|
|
+ import devicePlayer from "../videodevice/devicePlayer";
|
|
|
+
|
|
|
+ export default {
|
|
|
+ components: {devicePlayer, SelectDialogResidential},
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ form: {},
|
|
|
+ query: {},
|
|
|
+ loading: true,
|
|
|
+ page: {
|
|
|
+ pageSize: 10,
|
|
|
+ currentPage: 1,
|
|
|
+ total: 0
|
|
|
+ },
|
|
|
+ bindVisible: false,
|
|
|
+ showDeviceChannelCrud: false,
|
|
|
+ deviceId: null,
|
|
|
+ stopBtnLoading: false,
|
|
|
+ selectionList: [],
|
|
|
+ deviceOption: {
|
|
|
+ height:'auto',
|
|
|
+ calcHeight: 30,
|
|
|
+ tip: false,
|
|
|
+ searchShow: true,
|
|
|
+ searchMenuSpan: 6,
|
|
|
+ border: true,
|
|
|
+ index: true,
|
|
|
+ viewBtn: true,
|
|
|
+ selection: true,
|
|
|
+ dialogClickModal: false,
|
|
|
+ column: [
|
|
|
+ {
|
|
|
+ label: "设备编号",
|
|
|
+ prop: "deviceId",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "设备名称",
|
|
|
+ prop: "name",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "厂商名称",
|
|
|
+ prop: "manufacturer",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "型号",
|
|
|
+ prop: "model",
|
|
|
+ hide:true,
|
|
|
+ disabled: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "传输协议",
|
|
|
+ prop: "transport",
|
|
|
+ hide:true,
|
|
|
+ disabled: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "流传输模式",
|
|
|
+ prop: "streamMode",
|
|
|
+ hide:true,
|
|
|
+ disabled: true,
|
|
|
+ type: "select",
|
|
|
+ dicData:[
|
|
|
+ {
|
|
|
+ label: "udp传输",
|
|
|
+ value: "UDP"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "tcp主动模式",
|
|
|
+ value: "TCP-ACTIVE"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "tcp被动模式",
|
|
|
+ value: "TCP-PASSIVE"
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "在线状态",
|
|
|
+ prop: "online",
|
|
|
+ slot:true,
|
|
|
+ search: true,
|
|
|
+ type: "select",
|
|
|
+ width: 100,
|
|
|
+ align: "center",
|
|
|
+ dicData:[
|
|
|
+ {
|
|
|
+ label: "在线",
|
|
|
+ value: 1
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "离线",
|
|
|
+ value: 0
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "注册时间",
|
|
|
+ prop: "registerTime",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "心跳时间",
|
|
|
+ prop: "keepaliveTime",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "wan地址",
|
|
|
+ prop: "hostAddress",
|
|
|
+ slot: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "所属园区",
|
|
|
+ prop: "agencyName",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "所属区域",
|
|
|
+ prop: "residentialName",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "所属园区",
|
|
|
+ prop: "agencyId",
|
|
|
+ hide: true,
|
|
|
+ search: true,
|
|
|
+ filterable: true,
|
|
|
+ cascaderItem: ['residentialId'],
|
|
|
+ type: "select",
|
|
|
+ remote: true,
|
|
|
+ dicUrl: "/api/cyzh-community/agency/list?size=10&name={{key}}",
|
|
|
+ dicFormatter:(res)=>{
|
|
|
+ return res.data.records;//返回字典的层级结构
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ label: "name",
|
|
|
+ value: "id"
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "所属区域",
|
|
|
+ prop: "residentialId",
|
|
|
+ hide: true,
|
|
|
+ slot: true,
|
|
|
+ type: "select",
|
|
|
+ search: true,
|
|
|
+ dicUrl: "/api/cyzh-community/residential/list?agencyId={{key}}",
|
|
|
+ dicFormatter:(res)=>{
|
|
|
+ return res.data.records;//返回字典的层级结构
|
|
|
+ },
|
|
|
+ filterable: true,
|
|
|
+ props: {
|
|
|
+ label: "name",
|
|
|
+ value: "id"
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ deviceChannelOption: {
|
|
|
+ menu: true,
|
|
|
+ menuWidth: 300,
|
|
|
+ height: 'auto',
|
|
|
+ calcHeight: 30,
|
|
|
+ tip: false,
|
|
|
+ searchShow: true,
|
|
|
+ searchMenuSpan: 6,
|
|
|
+ labelWidth: 150,
|
|
|
+ border: true,
|
|
|
+ index: true,
|
|
|
+ viewBtn: false,
|
|
|
+ editBtn: false,
|
|
|
+ delBtn: false,
|
|
|
+ selection: true,
|
|
|
+ dialogClickModal: false,
|
|
|
+ addBtn:false,
|
|
|
+ column: [
|
|
|
+ {
|
|
|
+ label: "通道编号",
|
|
|
+ prop: "channelId",
|
|
|
+ span: 12,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "设备编号",
|
|
|
+ prop: "deviceId",
|
|
|
+ span: 12,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "通道名称",
|
|
|
+ prop: "name",
|
|
|
+ span: 12,
|
|
|
+ width: 100,
|
|
|
+ search: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "开启音频",
|
|
|
+ prop: "hasAudio",
|
|
|
+ span: 12,
|
|
|
+ width: 80,
|
|
|
+ slot: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "状态",
|
|
|
+ prop: "status",
|
|
|
+ span: 12,
|
|
|
+ width:80,
|
|
|
+ slot: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "云台类型",
|
|
|
+ prop: "ptzType",
|
|
|
+ span: 12,
|
|
|
+ type: "select",
|
|
|
+ dicData:[
|
|
|
+ {
|
|
|
+ label: "未知",
|
|
|
+ value: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "球机",
|
|
|
+ value: 1
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "半球",
|
|
|
+ value: 2
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "固定枪机",
|
|
|
+ value: 3
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "遥控枪机",
|
|
|
+ value: 4
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ data: []
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapGetters(["permission"]),
|
|
|
+ permissionList() {
|
|
|
+ return {
|
|
|
+ addBtn: this.vaildData(this.permission.gbdevice_add, false),
|
|
|
+ viewBtn: this.vaildData(this.permission.gbdevice_view, false),
|
|
|
+ delBtn: this.vaildData(this.permission.gbdevice_delete, false),
|
|
|
+ editBtn: this.vaildData(this.permission.gbdevice_edit, false)
|
|
|
+ };
|
|
|
+ },
|
|
|
+ ids() {
|
|
|
+ let ids = [];
|
|
|
+ this.selectionList.forEach(ele => {
|
|
|
+ ids.push(ele.id);
|
|
|
+ });
|
|
|
+ return ids.join(",");
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ devicePlay(row){
|
|
|
+ let deviceId = row.deviceId;
|
|
|
+ let channelId = row.channelId;
|
|
|
+ let that = this;
|
|
|
+ startPlay(deviceId, channelId).then(res => {
|
|
|
+ if (res.data.code == 200) {
|
|
|
+ that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
|
|
|
+ streamInfo: res.data.data,
|
|
|
+ hasAudio: row.hasAudio
|
|
|
+ });
|
|
|
+ that.onLoadChannel(that.page);
|
|
|
+ }else {
|
|
|
+ that.$message.error(res.data.msg);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ deviceStopPlay(row) {
|
|
|
+ let that = this;
|
|
|
+ let deviceId = row.deviceId;
|
|
|
+ let channelId = row.channelId;
|
|
|
+ this.stopBtnLoading = true;
|
|
|
+ stopPlay(deviceId, channelId).then(res => {
|
|
|
+ console.log(JSON.stringify(res));
|
|
|
+ that.onLoadChannel(that.page);
|
|
|
+ this.stopBtnLoading = false;
|
|
|
+ }).catch(err => {
|
|
|
+ if (err.response.status === 402) { // 已经停止过
|
|
|
+ that.onLoadChannel(that.page);
|
|
|
+ }else {
|
|
|
+ console.log(err)
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ channelSearchChange(params, done){
|
|
|
+ this.query = params;
|
|
|
+ this.page.currentPage = 1;
|
|
|
+ params.deviceId = this.deviceId;
|
|
|
+ this.onLoadChannel(this.page, params);
|
|
|
+ done();
|
|
|
+ },
|
|
|
+ handleSync(row, index){
|
|
|
+ sync(row).then(res => {
|
|
|
+ let result = res.data.data;
|
|
|
+ this.$set(this.data, index, result)
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: "操作成功!"
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onLoadChannel(page, params = {}) {
|
|
|
+ this.loading = true;
|
|
|
+ getChannelList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
|
|
+ const data = res.data.data;
|
|
|
+ this.page.total = data.total;
|
|
|
+ this.data = data.records;
|
|
|
+ this.loading = false;
|
|
|
+ this.selectionClear();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ backToDeviceList(){
|
|
|
+ this.showDeviceChannelCrud = false;
|
|
|
+ this.deviceId = null;
|
|
|
+ },
|
|
|
+ handleChannel(deviceId){
|
|
|
+ this.showDeviceChannelCrud = true;
|
|
|
+ this.deviceId = deviceId;
|
|
|
+ this.page.currentPage = 1;
|
|
|
+ this.onLoadChannel(this.page, {"deviceId": deviceId});
|
|
|
+ },
|
|
|
+ bindDevice(row){
|
|
|
+ this.bindVisible = true;
|
|
|
+ this.deviceId = row.deviceId;
|
|
|
+ },
|
|
|
+ refreshChannelChange() {
|
|
|
+ this.onLoadChannel(this.page, this.query);
|
|
|
+ },
|
|
|
+ selectCallback(row){
|
|
|
+ this.form.residentialId = row.id;
|
|
|
+ this.form.agencyId = row.agencyId;
|
|
|
+ this.form.deviceId = this.deviceId;
|
|
|
+ bind(this.form).then(() =>{
|
|
|
+ this.onLoad(this.page);
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: "操作成功!"
|
|
|
+ });
|
|
|
+ });
|
|
|
+ this.bindVisible = false;
|
|
|
+ },
|
|
|
+ rowSave(row, done, loading) {
|
|
|
+ add(row).then(() => {
|
|
|
+ this.onLoad(this.page);
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: "操作成功!"
|
|
|
+ });
|
|
|
+ done();
|
|
|
+ }, error => {
|
|
|
+ loading();
|
|
|
+ window.console.log(error);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ rowUpdate(row, index, done, loading) {
|
|
|
+ update(row).then(() => {
|
|
|
+ this.onLoad(this.page);
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: "操作成功!"
|
|
|
+ });
|
|
|
+ done();
|
|
|
+ }, error => {
|
|
|
+ loading();
|
|
|
+ console.log(error);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ rowDel(row) {
|
|
|
+ this.$confirm("确定将选择数据删除?", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ return remove(row.id);
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ this.onLoad(this.page);
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: "操作成功!"
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ handleDelete() {
|
|
|
+ if (this.selectionList.length === 0) {
|
|
|
+ this.$message.warning("请选择至少一条数据");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.$confirm("确定将选择数据删除?", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ return remove(this.ids);
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ this.onLoad(this.page);
|
|
|
+ this.$message({
|
|
|
+ type: "success",
|
|
|
+ message: "操作成功!"
|
|
|
+ });
|
|
|
+ this.$refs.crud.toggleSelection();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ beforeOpen(done, type) {
|
|
|
+ if (["edit", "view"].includes(type)) {
|
|
|
+ getDetail(this.form.id).then(res => {
|
|
|
+ this.form = res.data.data;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ done();
|
|
|
+ },
|
|
|
+ searchReset() {
|
|
|
+ this.query = {};
|
|
|
+ this.onLoad(this.page);
|
|
|
+ },
|
|
|
+ searchChange(params, done) {
|
|
|
+ this.query = params;
|
|
|
+ this.page.currentPage = 1;
|
|
|
+ this.onLoad(this.page, params);
|
|
|
+ done();
|
|
|
+ },
|
|
|
+ selectionChange(list) {
|
|
|
+ this.selectionList = list;
|
|
|
+ },
|
|
|
+ selectionClear() {
|
|
|
+ this.selectionList = [];
|
|
|
+ this.$refs.crud.toggleSelection();
|
|
|
+ },
|
|
|
+ currentChange(currentPage){
|
|
|
+ this.page.currentPage = currentPage;
|
|
|
+ },
|
|
|
+ sizeChange(pageSize){
|
|
|
+ this.page.pageSize = pageSize;
|
|
|
+ },
|
|
|
+ refreshChange() {
|
|
|
+ this.onLoad(this.page, this.query);
|
|
|
+ },
|
|
|
+ onLoad(page, params = {}) {
|
|
|
+ this.loading = true;
|
|
|
+ getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
|
|
|
+ const data = res.data.data;
|
|
|
+ this.page.total = data.total;
|
|
|
+ this.data = data.records;
|
|
|
+ this.loading = false;
|
|
|
+ this.selectionClear();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+</script>
|
|
|
+
|
|
|
+<style>
|
|
|
+</style>
|