diff --git a/src/components/BootstrapBlazor.HikVision/BootstrapBlazor.HikVision.csproj b/src/components/BootstrapBlazor.HikVision/BootstrapBlazor.HikVision.csproj index b71ac968..ade73aaa 100644 --- a/src/components/BootstrapBlazor.HikVision/BootstrapBlazor.HikVision.csproj +++ b/src/components/BootstrapBlazor.HikVision/BootstrapBlazor.HikVision.csproj @@ -1,7 +1,7 @@ - 10.0.0-beta02 + 10.0.0-beta03 diff --git a/src/components/BootstrapBlazor.HikVision/Components/HikVisionAnalogChannelInfo.cs b/src/components/BootstrapBlazor.HikVision/Components/HikVisionAnalogChannelInfo.cs new file mode 100644 index 00000000..33ebfed5 --- /dev/null +++ b/src/components/BootstrapBlazor.HikVision/Components/HikVisionAnalogChannelInfo.cs @@ -0,0 +1,31 @@ +// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +/// +/// 模拟通道信息 +/// +public class HikVisionAnalogChannelInfo() +{ + /// + /// 获得 通道 Id + /// + public int Id { get; set; } + + /// + /// 获得 通道号 + /// + public int InputPort { get; set; } + + /// + /// 获得 通道名称 + /// + public string? Name { get; set; } + + /// + /// 获得 通道制式 + /// + public string? VideoFormat { get; set; } +} diff --git a/src/components/BootstrapBlazor.HikVision/Components/HikVisionChannel.cs b/src/components/BootstrapBlazor.HikVision/Components/HikVisionChannel.cs new file mode 100644 index 00000000..efa4ae1f --- /dev/null +++ b/src/components/BootstrapBlazor.HikVision/Components/HikVisionChannel.cs @@ -0,0 +1,26 @@ +// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +/// +/// 海康威视网络摄像机通道信息 +/// +public class HikVisionChannel +{ + /// + /// 获得/设置 模拟通道信息集合 + /// + public List AnalogChannels { get; set; } = []; + + /// + /// 获得/设置 数字通道信息集合 + /// + public List DigitalChannels { get; set; } = []; + + /// + /// 获得/设置 数字通道信息集合 + /// + public List ZeroChannels { get; set; } = []; +} diff --git a/src/components/BootstrapBlazor.HikVision/Components/HikVisionDigitalChannelInfo.cs b/src/components/BootstrapBlazor.HikVision/Components/HikVisionDigitalChannelInfo.cs new file mode 100644 index 00000000..ffb54937 --- /dev/null +++ b/src/components/BootstrapBlazor.HikVision/Components/HikVisionDigitalChannelInfo.cs @@ -0,0 +1,31 @@ +// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +/// +/// 模拟通道信息 +/// +public class HikVisionDigitalChannelInfo() +{ + /// + /// 获得 通道 Id + /// + public int Id { get; set; } + + /// + /// 获得 通道号 + /// + public int InputPort { get; set; } + + /// + /// 获得 通道名称 + /// + public string? Name { get; set; } + + /// + /// 获得 通道制式 + /// + public string? VideoFormat { get; set; } +} diff --git a/src/components/BootstrapBlazor.HikVision/LoginType.cs b/src/components/BootstrapBlazor.HikVision/Components/HikVisionLoginType.cs similarity index 94% rename from src/components/BootstrapBlazor.HikVision/LoginType.cs rename to src/components/BootstrapBlazor.HikVision/Components/HikVisionLoginType.cs index eebf57ca..30e87b24 100644 --- a/src/components/BootstrapBlazor.HikVision/LoginType.cs +++ b/src/components/BootstrapBlazor.HikVision/Components/HikVisionLoginType.cs @@ -7,7 +7,7 @@ namespace BootstrapBlazor.Components; /// /// 登录方式 /// -public enum LoginType +public enum HikVisionLoginType { /// /// http 方式 diff --git a/src/components/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.cs b/src/components/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.cs index abe3dd9c..f7da81bc 100644 --- a/src/components/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.cs +++ b/src/components/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.cs @@ -7,7 +7,7 @@ namespace BootstrapBlazor.Components; /// -/// 海康威视网络摄像机组件 (Websdk Plugin 插件版本) +/// 海康威视网络摄像机组件 (WebSdk Plugin 插件版本) /// [JSModuleAutoLoader("./_content/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.js", JSObjectReference = true)] public partial class HikVisionWebPlugin @@ -37,10 +37,10 @@ public partial class HikVisionWebPlugin public string? Password { get; set; } /// - /// 获得/设置 网络摄像机 登录类型 默认值 + /// 获得/设置 网络摄像机 登录类型 默认值 /// [Parameter] - public LoginType LoginType { get; set; } + public HikVisionLoginType LoginType { get; set; } /// /// 获得/设置 视频图像窗口宽度 默认值 500px @@ -64,13 +64,19 @@ public partial class HikVisionWebPlugin /// 获得/设置 登录成功后回调方法 /// [Parameter] - public Func? OnLoginedAsync { get; set; } + public Func? OnLoginAsync { get; set; } + + /// + /// 获得/设置 停止预览后回调方法 + /// + [Parameter] + public Func? OnGetChannelsAsync { get; set; } /// /// 获得/设置 注销成功后回调方法 /// [Parameter] - public Func? OnLogoutedAsync { get; set; } + public Func? OnLogoutAsync { get; set; } /// /// 获得/设置 开始预览后回调方法 @@ -95,14 +101,14 @@ public partial class HikVisionWebPlugin .Build(); /// - /// 获得 Websdk 插件是否初始化成功 + /// 获得 Web sdk 插件是否初始化成功 /// public bool Inited { get; private set; } /// /// 获得 是否已登录 /// - public bool IsLogined { get; private set; } + public bool IsLogin { get; private set; } /// /// 获得 是否正在实时预览 @@ -129,22 +135,22 @@ protected override void OnParametersSet() /// /// /// - public async Task Login(string ip, int port, string userName, string password, LoginType loginType = LoginType.Http) + public async Task Login(string ip, int port, string userName, string password, HikVisionLoginType loginType = HikVisionLoginType.Http) { ThrowIfNotInited(); - IsLogined = await InvokeAsync("login", Id, ip, port, userName, password, (int)loginType) ?? false; - if (IsLogined) + IsLogin = await InvokeAsync("login", Id, ip, port, userName, password, (int)loginType) ?? false; + if (IsLogin) { - await TriggerLogined(); + await TriggerLogin(); } - return IsLogined; + return IsLogin; } - private async Task TriggerLogined() + private async Task TriggerLogin() { - if (OnLoginedAsync != null) + if (OnLoginAsync != null) { - await OnLoginedAsync(); + await OnLoginAsync(); } } @@ -154,30 +160,40 @@ private async Task TriggerLogined() /// public async Task Logout() { - if (IsLogined) + if (IsLogin) { await InvokeVoidAsync("logout", Id); } IsRealPlaying = false; - IsLogined = false; - await TriggerLogouted(); + IsLogin = false; + await TriggerLogout(); } - private async Task TriggerLogouted() + private async Task TriggerLogout() { - if (OnLogoutedAsync != null) + if (OnLogoutAsync != null) { - await OnLogoutedAsync(); + await OnLogoutAsync(); } } + /// + /// 获得通道列表方法 + /// + /// + public async Task GetChannelList() + { + ThrowIfNotInited(); + await InvokeVoidAsync("getChannelList", Id); + } + /// /// 开始实时预览方法 /// /// public async Task StartRealPlay(int streamType, int channelId) { - if (IsLogined && !IsRealPlaying) + if (IsLogin && !IsRealPlaying) { IsRealPlaying = await InvokeAsync("startRealPlay", Id, streamType, channelId) ?? false; if (IsRealPlaying) @@ -239,4 +255,18 @@ public async Task TriggerInited(bool inited) await OnInitedAsync(inited); } } + + /// + /// 触发 回调方法由 JavaScript 调用 + /// + /// + /// + [JSInvokable] + public async Task TriggerGetChannelList(HikVisionChannel channel) + { + if (OnGetChannelsAsync != null) + { + await OnGetChannelsAsync(channel); + } + } } diff --git a/src/components/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.js b/src/components/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.js index 88a03384..2f32f39a 100644 --- a/src/components/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.js +++ b/src/components/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.js @@ -1,4 +1,5 @@ -import { init as initVision, login, logout, startRealPlay, stopRealPlay, dispose as disposeVision } from '../hikvision.js'; +import { init as initVision, login as loginVision, logout, startRealPlay, stopRealPlay, dispose as disposeVision } from '../hikvision.js'; +import Data from '../../BootstrapBlazor/modules/data.js'; import EventHandler from '../../BootstrapBlazor/modules/event-handler.js'; export async function init(id, invoke) { @@ -7,11 +8,29 @@ export async function init(id, invoke) { return; } + Data.set(id, { + invoke + }); + const inited = await initVision(id); await invoke.invokeMethodAsync('TriggerInited', inited); } -export { login, logout, startRealPlay, stopRealPlay } +export async function login(id, ip, port, userName, password, loginType) { + const vision = Data.get(id); + await loginVision(id, ip, port, userName, password, loginType); + const { logined, invoke } = vision; + if (logined) { + await invoke.invokeMethodAsync('TriggerGetChannelList', { + analogChannels: vision.analogChannels, + digitalChannels: vision.digitalChannels, + zeroChannels: vision.zeroChannels + }); + } + return logined; +} + +export { logout, startRealPlay, stopRealPlay } export function dispose(id) { disposeVision(id); diff --git a/src/components/BootstrapBlazor.HikVision/Components/HikVisionZeroChannelInfo.cs b/src/components/BootstrapBlazor.HikVision/Components/HikVisionZeroChannelInfo.cs new file mode 100644 index 00000000..5ce9ab48 --- /dev/null +++ b/src/components/BootstrapBlazor.HikVision/Components/HikVisionZeroChannelInfo.cs @@ -0,0 +1,26 @@ +// Copyright (c) BootstrapBlazor & Argo Zhang (argo@live.ca). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +/// +/// 模拟通道信息 +/// +public class HikVisionZeroChannelInfo() +{ + /// + /// 获得 通道 Id + /// + public int Id { get; set; } + + /// + /// 获得 通道号 + /// + public int InputPort { get; set; } + + /// + /// 获得 是否使能 + /// + public bool Enabled { get; set; } +} diff --git a/src/components/BootstrapBlazor.HikVision/Services/DefaultHicVision.cs b/src/components/BootstrapBlazor.HikVision/Services/DefaultHicVision.cs index d5000272..88b52494 100644 --- a/src/components/BootstrapBlazor.HikVision/Services/DefaultHicVision.cs +++ b/src/components/BootstrapBlazor.HikVision/Services/DefaultHicVision.cs @@ -10,7 +10,7 @@ sealed class DefaultHicVision(IJSRuntime jsRuntime) : IHikVision private bool _initialized; private bool _logined; - public async Task Login(string ip, int port, string userName, string password, LoginType loginType = LoginType.Http) + public async Task Login(string ip, int port, string userName, string password, HikVisionLoginType loginType = HikVisionLoginType.Http) { await LoadAsync(); diff --git a/src/components/BootstrapBlazor.HikVision/Services/IHikVision.cs b/src/components/BootstrapBlazor.HikVision/Services/IHikVision.cs index a6e6d37e..10119036 100644 --- a/src/components/BootstrapBlazor.HikVision/Services/IHikVision.cs +++ b/src/components/BootstrapBlazor.HikVision/Services/IHikVision.cs @@ -12,13 +12,13 @@ public interface IHikVision : IAsyncDisposable /// /// 登录方法 /// - /// 登录方式 实例 + /// 登录方式 实例 /// 设备 Ip 地址 /// 设备端口 /// 用户名 /// 密码 /// - Task Login(string ip, int port, string userName, string password, LoginType loginType = LoginType.Http); + Task Login(string ip, int port, string userName, string password, HikVisionLoginType loginType = HikVisionLoginType.Http); /// /// 登出方法 diff --git a/src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js b/src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js index 14f4ede9..d942834c 100644 --- a/src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js +++ b/src/components/BootstrapBlazor.HikVision/wwwroot/hikvision.js @@ -19,10 +19,9 @@ export async function init(id) { return false; } - Data.set(id, { - iWndIndex: result.iWndIndex, - inited: true - }); + const vision = Data.get(id); + vision.iWndIndex = result.iWndIndex; + vision.inited = true; return true; } @@ -64,6 +63,7 @@ export async function login(id, ip, port, userName, password, loginType) { const vision = Data.get(id); const { inited, logined } = vision; if (inited !== true || ip.length === 0 || port <= 0 || userName.length === 0 || password.length === 0) { + vision.logined = false; return false; } if (logined === true) { @@ -78,13 +78,15 @@ export async function login(id, ip, port, userName, password, loginType) { WebVideoCtrl.I_Login(ip, loginType, port, userName, password, { timeout: 3000, success: function (xmlDoc) { - vision.logined = true; + getChannelList(vision).then(() => { + vision.logined = true; + }); }, error: function (oError) { const ERROR_CODE_LOGIN_REPEATLOGIN = 2001; if (oError.errorCode === ERROR_CODE_LOGIN_REPEATLOGIN) { vision.logined = true; - return; + return true; } vision.logined = false; @@ -103,16 +105,17 @@ export async function login(id, ip, port, userName, password, loginType) { }); } -const getChannelInfo = vision => { - const { szDeviceIdentify } = vision; +const getChannelList = vision => { + const { szDeviceIdentify, logined } = vision; + let analog_completed = false; WebVideoCtrl.I_GetAnalogChannelInfo(szDeviceIdentify, { success: function (xmlDoc) { const channels = [...getTagNameValues(xmlDoc, "VideoInputChannel")]; vision.analogChannels = channels.map(channel => { return { - id: getTagNameFirstValue(channel, "id"), - inputPort: getTagNameFirstValue(channel, "inputPort"), + id: parseInt(getTagNameFirstValue(channel, "id")), + inputPort: parseInt(getTagNameFirstValue(channel, "inputPort")), name: getTagNameFirstValue(channel, "name"), videoFormat: getTagNameFirstValue(channel, "videoFormat") }; @@ -130,8 +133,7 @@ const getChannelInfo = vision => { const channels = [...getTagNameValues(xmlDoc, "InputProxyChannelStatus")]; vision.digitalChannels = channels.map(channel => { return { - id: getTagNameFirstValue(channel, "id"), - name: getTagNameFirstValue(channel, "name"), + id: parseInt(getTagNameFirstValue(channel, "id")), online: getTagNameFirstValue(channel, "online") }; }); @@ -148,8 +150,9 @@ const getChannelInfo = vision => { const channels = [...getTagNameValues(xmlDoc, "ZeroVideoChannel")]; vision.zeroChannels = channels.map(channel => { return { - id: getTagNameFirstValue(channel, "id"), - name: getTagNameFirstValue(channel, "name") + id: parseInt(getTagNameFirstValue(channel, "id")), + inputPort: parseInt(getTagNameFirstValue(channel, "inputPort")), + enabled: getTagNameFirstValue(channel, "enabled") === 'true', }; }); zero_completed = true; @@ -187,11 +190,8 @@ export async function startRealPlay(id, iStreamType, iChannelID) { const vision = Data.get(id); const { iWndIndex, szDeviceIdentify } = vision; - vision.devicePort = await WebVideoCtrl.I_GetDevicePort(vision.szDeviceIdentify); - await getChannelInfo(vision); - - const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex); - const iRtspPort = vision.devicePort.iRtspPort; + vision.devicePort = await WebVideoCtrl.I_GetDevicePort(szDeviceIdentify); + const { iRtspPort } = vision.devicePort; const bZeroChannel = false; let completed = null; const startRealPlay = function () { @@ -212,6 +212,7 @@ export async function startRealPlay(id, iStreamType, iChannelID) { }); }; + const oWndInfo = WebVideoCtrl.I_GetWindowStatus(iWndIndex); if (oWndInfo !== null) { WebVideoCtrl.I_Stop({ success: function () {