首页 新闻 会员 周边 捐助

海康WebSDK封装成Vue组件后,PTZ无法控制,后来PTZ请求httpCode 404

0
悬赏园豆:20 [已解决问题] 解决于 2024-07-29 16:25

1. nginx配置

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '

    access_log  logs/access.log  main;
    #access_log      off;
    client_max_body_size 50m;
    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       12345;
        server_name  192.168.1.141;

        #charset koi8-r;

        access_log  logs/host.access.log  main;
        #websocket相关配置
		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
    	proxy_set_header Connection "upgrade";
    	proxy_set_header X-real-ip $remote_addr;
		proxy_set_header X-Forwarded-For $remote_addr;

        location / {
            # root   "../webs";
			root	"E:\HcSDK\dist";
            index  index.html index.htm;
        }

		location ~ /ISAPI|SDK/ {
			if ($http_cookie ~ "webVideoCtrlProxy=(.+)") {
			proxy_pass http://$cookie_webVideoCtrlProxy;
			break;
			}
		}
		location ^~ /webSocketVideoCtrlProxy {
			#web socket
			proxy_http_version 1.1;
			proxy_set_header Upgrade $http_upgrade;
			proxy_set_header Connection "upgrade";
			proxy_set_header Host $host;

			if ($http_cookie ~ "webVideoCtrlProxyWs=(.+)") {
				proxy_pass http://$cookie_webVideoCtrlProxyWs/$cookie_webVideoCtrlProxyWsChannel?$args;
				break;
			}
			if ($http_cookie ~ "webVideoCtrlProxyWss=(.+)") {
				proxy_pass http://$cookie_webVideoCtrlProxyWss/$cookie_webVideoCtrlProxyWsChannel?$args;
				break;
			}
		}
    }
}

2. Vue 组件和js

<template>
  <div class="HcNet">
    <div class="window-title">
      <div>相机名称</div>
      <div class="close-div" @click="handleClose">X</div>
    </div>
    <div class="content">
      <div id="video-window" ref="video"></div>
      <div class="opt-panel">
        <div class="opt-pan">
          <!-- // 8个方向移动 -->
          <div class="row-btn">
            <div class="pan" @mousedown.left="handlePTZOption(5, false)" @mouseup.left="handlePTZOption(5, true)">↖</div>
            <div class="pan" @mousedown.left="handlePTZOption(1, false)" @mouseup.left="handlePTZOption(1, true)">↑</div>
            <div class="pan" @mousedown.left="handlePTZOption(6, false)" @mouseup.left="handlePTZOption(6, true)">↗</div>
          </div>
          <div class="row-btn">
            <div class="pan" @mousedown.left="handlePTZOption(3, false)" @mouseup.left="handlePTZOption(3, true)">←</div>
            <div class="pan" @mousedown.left="handlePTZOption(5, false)" @mouseup.left="handlePTZOption(5, true)"></div>
            <div class="pan" @mousedown.left="handlePTZOption(4, false)" @mouseup.left="handlePTZOption(4, true)">→</div>
          </div>
          <div class="row-btn">
            <div class="pan" @mousedown.left="handlePTZOption(7, false)" @mouseup.left="handlePTZOption(7, true)">↙</div>
            <div class="pan" @mousedown.left="handlePTZOption(2, false)" @mouseup.left="handlePTZOption(2, true)">↓</div>
            <div class="pan" @mousedown.left="handlePTZOption(8, false)" @mouseup.left="handlePTZOption(8, true)">↘</div>
          </div>
        </div>
        <div class="opt-zoom row-btn">
          <!-- // 缩放 -->
          <div class="pan" @mousedown.left="handlePTZOption(10, false)" @mouseup.left="handlePTZOption(10, true)">+</div>
          <div class="pan">缩放</div>
          <div class="pan" @mousedown.left="handlePTZOption(11, false)" @mouseup.left="handlePTZOption(11, true)">-</div>
        </div>
        <div class="opt-aperture row-btn">
          <!-- // 光圈 -->
          <div class="pan" @mousedown.left="handlePTZOption(14, false)" @mouseup.left="handlePTZOption(14, true)">+</div>
          <div class="pan">光圈</div>
          <div class="pan" @mousedown.left="handlePTZOption(15, false)" @mouseup.left="handlePTZOption(15, true)">-</div>
        </div>
        <div class="opt-aperture row-btn">
          <div class="pan" @click="toggleRealPlay">{{isRealPlay ? '停止预览':'开始预览'}}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
  import Vue from "vue";
  import { init, login, realPlayStart, realPlayStop, operationPTZ } from "@/api/hcnet/HcNet";

  export default Vue.extend({
    name: "HcNet",
    props: {
      isVisible: {
        type: Boolean,
        default: false,
        required: true,
      },
    },
    data() {
      return {
        visible: false,
        cameraData: {
          ip: "10.0.1.12",
          port: "80",
          user: "admin",
          passwd: "",
        },
        isRealPlay: false
      };
    },
    beforeMount() {
      this.visible = this.isVisible;
    },
    mounted() {
      const rect = this.$refs.video.getBoundingClientRect();
      const style = window.getComputedStyle(this.$refs.video);

      const paddingLeft = parseFloat(style.paddingLeft);
      const paddingRight = parseFloat(style.paddingRight);
      const paddingTop = parseFloat(style.paddingTop);
      const paddingBottom = parseFloat(style.paddingBottom);

      const borderLeft = parseFloat(style.borderLeftWidth);
      const borderRight = parseFloat(style.borderRightWidth);
      const borderTop = parseFloat(style.borderTopWidth);
      const borderBottom = parseFloat(style.borderBottomWidth);

      const width = rect.width - paddingLeft - paddingRight - borderLeft - borderRight;
      const height = rect.height - paddingTop - paddingBottom - borderTop - borderBottom;
      const result = init("video-window", width, height, this.messageSDK);
      console.log("🚀 ~ mounted ~ result:", result)
      setTimeout(() => {
        login("10.195.200.24", 1 ,80, 'admin', '08A301301', this.messageSDK)
      }, 2000);
    },
    methods: {
      handleClose() {
        this.$emit("close", false);
      },
      messageSDK(result){
        if(!result.isSuccess){
          console.error(result.message)
        }else{
          console.info(result.message)
        }
      },
      toggleRealPlay(){
        this.isRealPlay = !this.isRealPlay
        const id = this.cameraData.ip + '_' + this.cameraData.port
        if(this.isRealPlay){
          realPlayStart(id, this.messageSDK)
        }else{
          realPlayStop(this.messageSDK)
        }
      },
      handlePTZOption(type, isStop){
        operationPTZ(type, isStop, this.messageSDK)
      }
    },
  });
</script>

<style scoped>
  .HcNet {
    user-select: none;
    width: 50vw;
    height: 40vh;
    display: flex;
    flex-direction: column;
    background-color: #808080;
  }
  .window-title {
    color: #c9c9c9;
    width: 100%;
    height: 2rem;
    font-size: medium;
    font-weight: 600;
    display: flex;
    flex-direction: row;
    align-items: center;
  }
  .close-div {
    user-select: none;
    width: 2rem;
    height: 100%;

    display: flex;
    justify-content: center;
    align-items: center;

    color: #c9c9c9;
    background-color: brown;
    margin-left: auto;
  }
  .close-div:hover {
    color: #e2e2e2;
    background-color: red;
  }
  .close-div:active {
    color: #e2e2e2;
    background-color: brown;
  }

  .content {
    width: 100%;
    height: calc(100% - 2rem);
    display: flex;
    flex-direction: row;
    padding: 5px;
  }
  #video-window {
    width: 80%;
    max-width: calc(100% - 150px);
    height: 100%;
    background-color: black;
    overflow: auto;
  }

  .opt-panel {
    min-width: 150px;
    width: 20%;
    height: 100%;
    display: flex;
    flex-direction: column;
    padding: 5px
  }

  .opt-pan {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    width: 100%;
    height: 150px;
  }

  .pan {
    width: 25%;
    height: 25%;
    min-width: 2rem;
    min-height: 2rem;
    color: #c9c9c9;
    background-color: #333333;
    border: 1px solid #333333;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 5px;
  }
  .pan:hover {
    color: #e2e2e2;
    background-color: #676767;
    border-color: #909090;
  }
  .pan:active {
    color: #ffffff;
    background-color: #232323;
  }

  .opt-pan > .row-btn:nth-child(2)> .pan:nth-child(2) {
    visibility: hidden;
    pointer-events: none;
  }

  .opt-zoom,
  .opt-aperture {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    width: 100%;
    height: 50px;
    margin: 10px 0 0 0;
  }
  .opt-zoom > .pan:nth-child(2),
  .opt-aperture>.pan:nth-child(2) {
    pointer-events: none;
    background-color: transparent;
    border: none;
    color: #ffffff;
  }

  .row-btn{
    width: 100%;
    height: auto;
    margin: 5px 0;
    display: flex;
    flex-direction: row;
    justify-content: space-around
  }
</style>
class Result{
  isSuccess = true
  message = ''
  data = null

  constructor(isSuccess, message, data) {
    this.isSuccess = isSuccess
    this.message = message
    this.data = data
  }
}

/**
 * 初始化SDK,并将SDK视频播放插件插入Dom文档
 * @param {String} containerID 放视频组件的div ID
 * @param {Number} width div的宽
 * @param {Number} height div的高
 * @param {Function} callback callback 操作成功或者失败的回调,默认入参为 Result 对象。如果自定义了options对象的成功/失败回调函数,需要根据自定义的返回参数来修改入参
 * @param {Object | null} options 配置对象,可选,表示采用默认配置对象
 * @param {String} options.szColorProperty 插件的背景颜色。表示插件的背景颜色,子窗口的背景颜色,子窗口的边框颜色,子窗框选中的边框颜色。插件中有一套自己的默认颜色。
 * @param {String} options.szOcxClassId ocx插件的 ID,OEM 时可以修改对应 ID 来实现开发包绑定不同的插件,默认为海康 WEB3.0 插件(无插件不支持该参数)
 * @param {String} options.szMimeTypes 非IE插件的MIMETYPE,OEM 时可以修改对应 ID 来实现开发包绑定不同的插件,默认为海康 WEB3.0 插件
 * @param {Number} options.iWndowType 分屏类型:1- 1*1,2- 2*2,3- 3*3,4- 4*4,默认值为 1,单画面
 * @param {String} options.bWndFull 是否支持单窗口双击全屏,默认支持 true:支持 false:不支持
 * @param {String} options.iPlayMode 播放模式,默认值为 2,正常播放模式。暂不支持其它模式。
 * @param {String} options.bDebugMode 控制台打印调试信息,true(开启),false(关闭)
 * @param {String} options.bNoPlugin 文档里没有该参数含义,推测为是否是无插件模式
 * @param {String} options.iPackageType 封装格式,2-PS 格式 11-MP4 格式。(无插件不支持该参数)
 * @param {Function} options.cbSelWnd 窗口选中事件回调函数,只包含一个字符串参数,里面的值是 XML,如果不需要该事件回调可以不定义
 * @param {Function} options.cbEvent  插件事件回调函数,有三个参数,第一个参数是事件类型,第二参数是窗口号(无插件不支持该回调),第三个参数文档没讲
 * @param {Function} options.cbDoubleClickWnd 窗口双击回调函数,有两个参数,第一个参数是窗口号,第二个参数是是否全屏(无插件不支持该回调),如果不需要该事件回调可以不定义
 * @param {Function} options.cbRemoteConfig 远程配置库关闭回调(无插件不支持该回调),如果不需要该事件回调可以不定义
 * @param {Function} options.cbInitPluginComplete 插件初始化完成回调,必须要定义,在该事件中,将SDK视频插件插入Dom文档
 * @returns 
 */
export function init(containerID, width = 500, height = 300, callback, options = null ) {
  const webViewCtrl = window.WebVideoCtrl
  const isSupportNoPlugin = webViewCtrl.I_SupportNoPlugin()
  if (!isSupportNoPlugin /*&& pluginCheckRes == -1*/) {
    typeof callback === 'function' && callback(new Result(false, "浏览器不支持无插件模式,请使用最新版Chrome或者Edge"))
    return 
  }
  const optionDefault = {
    szColorProperty: "plugin-background:000000; sub-background:000000; sub-border:0000; sub-border-select:000000",
    iWndowType: 1,
    bWndFull: false,
    bDebugMode: false,
    bNoPlugin: true,
    iPackageType: 2,
    cbSelWnd: function (xmlDoc) {
      // const g_iWndIndex = parseInt($(xmlDoc).find("SelectWnd").eq(0).text(), 10);
      // const szInfo = "当前选择的窗口编号:" + g_iWndIndex;
      console.log("🚀 ~ init ~ szInfo:", xmlDoc)
    },
    cbEvent: function (iEventType, iParam1, iParam2) {
      console.log("🚀 ~ init ~ optionDefault.iEventType, iParam1, iParam2:", optionDefault.iEventType, iParam1, iParam2)
      
    },
    cbDoubleClickWnd: function (windowNumer, isFullScreen) {
      console.log("🚀 ~ init ~ optionDefault.windowNumer, isFullScreen:", optionDefault.windowNumer, isFullScreen)
      
    },
    cbRemoteConfig: function () {
      
    },
    cbInitPluginComplete: function () {
      const result = webViewCtrl.I_InsertOBJECTPlugin(containerID)
      if (result != 0) { // 成功返回0 ,失败返回-1
        typeof callback === 'function' && callback(new Result(false, "SDK组件插入网页元素失败"))
        return
      }
      // 检查插件是否最新
      if (-1 == webViewCtrl.I_CheckPluginVersion()) {
        typeof callback === 'function' && callback(new Result(true, "插件有新版本的了"))
        return; 
      }
      typeof callback === 'function' && callback(new Result(true, "SDK初始化成功"))
    }
  }
  options = options || optionDefault
  webViewCtrl.I_InitPlugin(width, height, options)
}

/**
 * 登录
 * @param {String} ip 设备IP
 * @param {Number} protocol http 协议,1 表示 http 协议 2 表示 https 协议
 * @param {Number} port 设备登录的http/https端口号
 * @param {String} username 登录用户名
 * @param {String} passwd 密码
 * @param {Function} callback 操作成功或者失败的回调,默认入参为 Result对象。如果自定义了options对象的成功/失败回调函数,需要根据自定义的返回参数来修改入参
 * @param {Object | null} options 配置对象,可选,表示采用默认配置对象
 * @param {Boolean} options.async http 交互方式,可选,true 表示异步,false 表示同步,有默认值,但是未指明
 * @param {Number} options.cgi  CGI 协议选择,可选,1 表示 ISAPI,2 表示 PSIA,如果不传这个参数,会自动选择一种设备支持的协议
 * @param {Function} options.success 成功回调函数,有一个参数,表示返回的 XML 内容。
 * @param {Function} options.error 失败回调函数,有两个参数,第一个是 http 状态码,第二个是设备返回的 XML(可能为空)
 */
export function login(ip, protocol = 1, port, username, passwd, callback, options = null) {
  const webViewCtrl = window.WebVideoCtrl
  const defaultOption = {
    // async: true // http 交互方式,true 表示异步,false 表示同步
    // cgi: 1 // CGI 协议选择,1 表示 ISAPI,2 表示 PSIA,如果不传这个参数,会自动选择一种设备支持的协议
    success: function (xmlDoc) {
      console.log("🚀 ~ login ~ xmlDoc:", xmlDoc)
      typeof callback === 'function' &&  callback(new Result(true, "登录成功"))
    },
    error: function (httpCode, xmlDoc) {
      console.log("🚀 ~ login ~ httpCode, xmlDoc:", httpCode, xmlDoc)
      typeof callback === 'function' &&  callback(new Result(false, "登录失败"))
    }
  }

  const option = options || defaultOption
  webViewCtrl.I_Login(ip, protocol, port, username, passwd, option)
}

/**
 * 登出设备
 * @param {String} ip_port 设备标识(ip_port)
 * @returns @classdesc Result对象:包含操作结果,操作信息,数据(可能为空)
 */
export function logout(ip_port) {
  const webViewCtrl = window.WebVideoCtrl
  if (!ip_port) return new Result(false, "登出时ip不能为空")
  const result = webViewCtrl.I_Logout(ip_port);
  if (result !== 0) {
    return new Result(false, "登出返回失败")
  }
  return new Result(true, "退出成功")
}

/**
 * 获取模拟通道
 * @param {String} ip_port 设备标识(IP_Port)
 * @param {Function} callback 操作成功或者失败的回调,默认入参为 @classdesc Result。如果自定义了options对象的成功/失败回调函数,需要根据自定义的返回参数来修改
 * @param {Object | null} options 配置对象,可选,不传该参数表示使用默认配置对象
 * @param {Boolean} options.async http 交互方式,可选,true 表示异步,false 表示同步,默认值不清楚,但是有默认值
 * @param {Function} options.success 成功回调函数,有一个参数,表示返回的 XML 内容。
 * @param {Function} options.error 失败回调函数,有两个参数,第一个是 http 状态码,第二个是设备返回的 XML(可能为空)
 */
export function getAnalogChannel(ip_port, callback,options = null) {
  const webViewCtrl = window.WebVideoCtrl
  const defaultOption = {
    // async: true, // demo没有写明,不清楚默认值
    success: function (xmlDoc) {
      console.log("🚀 ~ getAnalogChannel ~ xmlDoc:", xmlDoc)
      
      // TODO 处理xml内容以获取有用的信息
      typeof callback === 'function' && callback(new Result(true, "获取模拟通道成功"))
    },
    error: function (httpCode, xmlDoc) { // 此处xmlDoc 可能为null
      console.log("🚀 ~ getAnalogChannel ~ httpCode, xmlDoc:", httpCode, xmlDoc)
      
      typeof callback === 'function' && callback(new Result(false, "获取模拟通道失败"))
    }
  }

  const option = options || defaultOption
  webViewCtrl.I_GetAnalogChannelInfo(ip_port, option);
}

/**
 * 获取数字通道
 * @param {String} ip_port 设备标识(IP_Port)
 * @param {Function} callback 操作成功或者失败的回调,默认入参为 @classdesc Result。如果自定义了options对象的成功/失败回调函数,需要根据自定义的回调来处理
 * @param {Object | null} options 配置对象,可选,不传该参数表示使用默认配置对象
 * @param {Boolean} options.async http 交互方式,可选,true 表示异步,false 表示同步,默认值不清楚,但是有默认值
 * @param {Function} options.success 成功回调函数,有一个参数,表示返回的 XML 内容。
 * @param {Function} options.error 失败回调函数,有两个参数,第一个是 http 状态码,第二个是设备返回的 XML(可能为空)
 */
export function getDigtalChannel(ip_port, callback, options = null) {
  const webViewCtrl = window.WebVideoCtrl
  const defaultOption = {
    // async: true, // demo没有写明,不清楚默认值
    success: function (xmlDoc) {
      console.log("🚀 ~ getDigtalChannel ~ xmlDoc:", xmlDoc)
      
      // TODO 处理xml内容以获取有用的信息
      typeof callback === 'function' && callback(new Result(true, "获取数字通道成功"))
    },
    error: function (httpCode, xmlDoc) { // 此处xmlDoc 可能为null
      console.log("🚀 ~ getDigtalChannel ~ httpCode, xmlDoc:", httpCode, xmlDoc)
      
      typeof callback === 'function' && callback(new Result(false, "获取数字通道失败"))
    }
  }
  const option = options || defaultOption
  webViewCtrl.I_GetDigitalChannelInfo(ip_port, option);
}

/**
 * 获取零通道
 * @param {String} ip_port 设备标识(IP_Port)
 * @param {Function} callback 操作成功或者失败的回调,默认入参为 @classdesc Result。如果自定义了options对象的成功/失败回调函数,需要根据自定义的回调来处理
 * @param {Object | null} options 配置对象,可选,不传该参数表示使用默认配置对象
 * @param {Boolean} options.async http 交互方式,可选,true 表示异步,false 表示同步,默认值不清楚,但是有默认值
 * @param {Function} options.success 成功回调函数,有一个参数,表示返回的 XML 内容。
 * @param {Function} options.error 失败回调函数,有两个参数,第一个是 http 状态码,第二个是设备返回的 XML(可能为空)
 */
export function getZeroChannel(ip_port, callback, options = null) {
  const webViewCtrl = window.WebVideoCtrl
  const defaultOption = {
    success: function (xmlDoc) {
      // TODO 处理xml内容以获取有用的信息
      typeof callback === 'function' && callback(new Result(true, "获取零通道成功"))
      console.log("🚀 ~ getZeroChannel ~ defaultOption.xmlDoc:", xmlDoc)
    },
    error: function (httpCode, xmlDoc) { // 此处xmlDoc 可能为null
      console.log("🚀 ~ getZeroChannel ~ defaultOption.httpCode, xmlDoc:", httpCode, xmlDoc)
      typeof callback === 'function' && callback(new Result(false, "获取零通道失败"))
    }
  }
  const option = options || defaultOption
  webViewCtrl.I_GetZeroChannelInfo(ip_port, option);
}

/**
 * 开始实时预览
 * @param {String} ip_port 设备标识(IP_Port)
 * @param {Function} callback 操作成功或者失败的回调,默认入参为 @classdesc Result。如果自定义了options对象的成功/失败回调函数,需要根据自定义的回调来处理
 * @param {Object | null} options 配置对象,可选,不传入该值,表示使用默认配置对象
 * @param {Number} options.iWndIndex 播放窗口,可选,如果不传,则默认使用当前选择窗口播放(默认选中窗口 0)
 * @param {Number} options.iStreamType 码流类型,可选,1-主码流,2-子码流,默认使用主码流预览
 * @param {Number} options.iChannelID 播放通道号,可选,默认通道1
 * @param {Number} options.bZeroChannel 是否播放零通道,可选,默认为 false
 * @param {Number} options.iPort RTSP 端口号,可选,如果不传,开发包会自动判断设备的 RTSP 端口
 * @param {Function} options.success 操作成功后的回调函数
 * @param {Function} options.error 操作失败后的回调函数,有两个参数,第一个是 http 状态码,第二个是设备返回的 XML(可能为空)
 */
export function realPlayStart(ip_port, callback, options = null) {
  const webViewCtrl = window.WebVideoCtrl
  const defaultOption = {
    success: function (sss) { // 似乎没有入参
      console.log("🚀 ~ realPlayStart ~ defaultOption.sss:", sss)
      
      typeof callback === 'function' && callback(new Result(true, "预览成功"))
    },
    error: function (httpCode, xmlDoc) { // 似乎没有入参
      console.log("🚀 ~ realPlayStart ~ defaultOption.xmlDoc:", xmlDoc)
      if (httpCode === 403) {
        typeof callback === 'function' && callback(new Result(false, "设备不支持Websocket取流!"))
      }else
        typeof callback === 'function' && callback(new Result(false, "预览失败"))
    }
  }

  const option = options || defaultOption
  webViewCtrl.I_StartRealPlay(ip_port, option)
}

/**
 * 实时预览停止
 * @param {Function} callback 操作成功或者失败的回调,默认入参为 @classdesc Result。如果自定义了options对象的成功/失败回调函数,需要根据自定义的回调来处理
 * @param {Object | null} options 设置对象,可选
 * @param {Number} options.iWndIndex 窗口号,可选,默认为当前选中窗口
 * @param {Function} options.success 操作成功后的回调函数
 * @param {Function} options.error 操作失败后的回调函数
 */
export function realPlayStop(callback, options = null) {
  stopPlay(callback, options)
}

/**
 * 停止播放:停止预览和停止回放统一使用该函数
 * @param {Function} callback 操作成功或者失败的回调,默认入参为 @classdesc Result。如果自定义了options对象的成功/失败回调函数,需要根据自定义的回调来处理
 * @param {Object | null} options 设置对象,可选
 * @param {Number} options.iWndIndex 窗口号,可选,默认为当前选中窗口
 * @param {Function} options.success 操作成功后的回调函数
 * @param {Function} options.error 操作失败后的回调函数
 */
function stopPlay(callback, options) {
  const webViewCtrl = window.WebVideoCtrl
  const defaultOption = {
    // iWndIndex: 0,
    success: function () {
        typeof callback === 'function' && callback(new Result(true, "停止播放成功"))
    },
    error: function () {
        typeof callback === 'function' && callback(new Result(false, "停止播放成功"))
    }
  }

  const option = options || defaultOption
  webViewCtrl.I_Stop(option)
}

/**
 * 云台操作
 * @param {Number} operationType 操作类型(1-上,2-下,3-左,4-右,5-左上,6-左下,7-右上,8-右下,9-自转,10-变倍+, 11-变倍-, 12-F 聚焦+, 13-聚焦-, 14-光圈+, 15-光圈-)
 * @param {Boolean} isStop 是否停止:false-执行,true-停止
 * @param {Object | null} options 设置对象,可选
 * @param {Number} options.iWndIndex 窗口号,可选,默认为当前选中窗口
 * @param {Number} options.iPTZSpeed  云台速度,可选,默认为 4
 */
export function operationPTZ(operationType, isStop, callback, options = null) {
  console.log("🚀 ~ operationPTZ ~ operationType, isStop:", operationType, isStop)
  const webViewCtrl = window.WebVideoCtrl
  const defaultOption = {
    iPTZSpeed: 4,
    success: function (xmlDoc) {
      callback(new Result(true, operationType + " 执行成功\n" + xmlDoc))
    },
    error: function (httpCode, xmlDoc) {
      callback(new Result(false, "🚀 ~ operationPTZ ~ defaultOption.httpCode, xmlDoc:" +  httpCode+"\n"+xmlDoc))
    }
  }

  const option = options || defaultOption
  webViewCtrl.I_PTZControl(operationType, isStop, option)
}

/**
 * 获取设备端口数据
 * @param {String} ip_port 设备唯一标识
 * @returns 端口对象,失败为空,端口对象格式:{iRtspPort: 554, HttpPort: 80, iDevicePort: 8000}
 */
export function getDevicePort(ip_port) {
  const webViewCtrl = window.WebVideoCtrl
  const res = webViewCtrl.I_GetDevicePort(ip_port)
  return res
}

问题:

能预览,但是不能PTZ,但是demo是可以PTZ操作的

这里是vue组件登录、播放后cookie里的数据,nginx会取该值

我感觉是nginx配置的问题,或者是vue项目配置的问题

我发现:demo发出的请求是/ISAPI/PTZCtrl/channels/1/continuous, 但是vue打包后的请求是 ISAPI/ContentMgmt/PTZCtrlProxy/channels/1/continuous

echo_lovely的主页 echo_lovely | 小虾三级 | 园豆:1584
提问于:2024-07-29 14:02
< >
分享
最佳答案
0

WebVideoCtrl.js 去这个文件的发请求的方法里打断点,看看是不是vue里面的function和源文件的function冲突了,被重写了

收获园豆:20
天气说变冷就变冷 | 小虾三级 |园豆:573 | 2024-07-29 15:05

WebVideoCtrl.js 被压缩过了,里面是一大坨

echo_lovely | 园豆:1584 (小虾三级) | 2024-07-29 15:06

@echo_lovely: 有可以解压的编辑器解压一下比如Hbuilder,你这不就是vue里用了这个js,好好的put请求被改成了get,估计fuction被重写了

天气说变冷就变冷 | 园豆:573 (小虾三级) | 2024-07-29 15:23

@大爷我啊有低保!: 我发现:demo发出的请求是/ISAPI/PTZCtrl/channels/1/continuous, 但是vue打包后的请求是 ISAPI/ContentMgmt/PTZCtrlProxy/channels/1/continuous
然后我
去项目里查找了 ContentMgmt 这个单词,然后发现只有 WebVideoCtrl.js 用了
我把 /ContentMgmt/PTZCtrlProxy 给替换成了 /PTZCtrl , 然后就成了!

echo_lovely | 园豆:1584 (小虾三级) | 2024-07-29 16:23

@echo_lovely: 。。。原来是地址不对,不知道怎么会put变get的,不会是nginx put404 然后转到404页面才变成get的吧。。

天气说变冷就变冷 | 园豆:573 (小虾三级) | 2024-07-29 16:49

@echo_lovely: 估计是option里有匹配是否使用代理的选项,demo里有其它js设置好了,封装的没设置,然后走了代理接口

天气说变冷就变冷 | 园豆:573 (小虾三级) | 2024-07-29 16:52

@大爷我啊有低保!: 应该是这个404

echo_lovely | 园豆:1584 (小虾三级) | 2024-07-30 08:11
其他回答(1)
0

我发现:demo发出的请求是/ISAPI/PTZCtrl/channels/1/continuous, 但是vue打包后的请求是 ISAPI/ContentMgmt/PTZCtrlProxy/channels/1/continuous
然后我
去项目里查找了 ContentMgmt 这个单词,然后发现只有 WebVideoCtrl.js 用了
我把 /ContentMgmt/PTZCtrlProxy 给替换成了 /PTZCtrl , 然后就成了!

echo_lovely | 园豆:1584 (小虾三级) | 2024-07-29 16:25
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册