WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>10.0.0-beta02</Version>
<Version>10.0.0-beta03</Version>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) BootstrapBlazor & Argo Zhang ([email protected]). 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;

/// <summary>
/// 模拟通道信息
/// </summary>
public class HikVisionAnalogChannelInfo()
{
/// <summary>
/// 获得 通道 Id
/// </summary>
public int Id { get; set; }

/// <summary>
/// 获得 通道号
/// </summary>
public int InputPort { get; set; }

/// <summary>
/// 获得 通道名称
/// </summary>
public string? Name { get; set; }

/// <summary>
/// 获得 通道制式
/// </summary>
public string? VideoFormat { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) BootstrapBlazor & Argo Zhang ([email protected]). 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;

/// <summary>
/// 海康威视网络摄像机通道信息
/// </summary>
public class HikVisionChannel
{
/// <summary>
/// 获得/设置 模拟通道信息集合
/// </summary>
public List<HikVisionAnalogChannelInfo> AnalogChannels { get; set; } = [];

/// <summary>
/// 获得/设置 数字通道信息集合
/// </summary>
public List<HikVisionDigitalChannelInfo> DigitalChannels { get; set; } = [];

/// <summary>
/// 获得/设置 数字通道信息集合
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on line 23 says "数字通道信息集合" (digital channel info collection) which is identical to the comment on line 18 for DigitalChannels. The comment for ZeroChannels should be "零通道信息集合" (zero channel info collection) instead.

Suggested change
/// 获得/设置 数字通道信息集合
/// 获得/设置 零通道信息集合

Copilot uses AI. Check for mistakes.
/// </summary>
public List<HikVisionZeroChannelInfo> ZeroChannels { get; set; } = [];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) BootstrapBlazor & Argo Zhang ([email protected]). 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;

/// <summary>
/// 模拟通道信息
Comment on lines +7 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (typo): The XML summary for HikVisionDigitalChannelInfo refers to it as an analog channel.

The summary text currently says 模拟通道信息 (analog channel info), which conflicts with this type representing digital channel information and with HikVisionAnalogChannelInfo. Please update the summary to describe it as a digital channel type to avoid confusion in the API docs.

Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation comment incorrectly states "模拟通道信息" (analog channel info), but this class represents digital channel information. It should be "数字通道信息" (digital channel info) instead.

Suggested change
/// 模拟通道信息
/// 数字通道信息

Copilot uses AI. Check for mistakes.
/// </summary>
public class HikVisionDigitalChannelInfo()
{
/// <summary>
/// 获得 通道 Id
/// </summary>
public int Id { get; set; }

/// <summary>
/// 获得 通道号
/// </summary>
Comment on lines +10 to +19
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): The HikVisionDigitalChannelInfo model doesn’t align with the JS channel data shape.

On the JS side digitalChannels are shaped as { id, online }, but this class exposes Id, InputPort, Name, and VideoFormat. When JS data is marshalled, only Id will bind and online will be dropped. Please either add an Online property (and remove any unused ones) or update the JS mapping to populate the properties defined here so the interop model matches the actual payload.

public int InputPort { get; set; }

/// <summary>
/// 获得 通道名称
/// </summary>
public string? Name { get; set; }

/// <summary>
/// 获得 通道制式
/// </summary>
public string? VideoFormat { get; set; }
Comment on lines +18 to +30
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JavaScript code in hikvision.js (lines 134-138) sets an online property for digital channels, not InputPort, Name, or VideoFormat. This mismatch will cause deserialization issues when JavaScript passes data to C#. The HikVisionDigitalChannelInfo class should have an Online property (string or bool) instead of InputPort, Name, and VideoFormat, or the JavaScript code needs to be updated to extract these fields from the XML.

Suggested change
/// 获得 通道号
/// </summary>
public int InputPort { get; set; }
/// <summary>
/// 获得 通道名称
/// </summary>
public string? Name { get; set; }
/// <summary>
/// 获得 通道制式
/// </summary>
public string? VideoFormat { get; set; }
/// 获得 通道在线状态
/// </summary>
public string? Online { get; set; }

Copilot uses AI. Check for mistakes.
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace BootstrapBlazor.Components;
/// <summary>
/// 登录方式
/// </summary>
public enum LoginType
public enum HikVisionLoginType
{
/// <summary>
/// http 方式
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace BootstrapBlazor.Components;

/// <summary>
/// 海康威视网络摄像机组件 (Websdk Plugin 插件版本)
/// 海康威视网络摄像机组件 (WebSdk Plugin 插件版本)
/// </summary>
[JSModuleAutoLoader("./_content/BootstrapBlazor.HikVision/Components/HikVisionWebPlugin.razor.js", JSObjectReference = true)]
public partial class HikVisionWebPlugin
Expand Down Expand Up @@ -37,10 +37,10 @@ public partial class HikVisionWebPlugin
public string? Password { get; set; }

/// <summary>
/// 获得/设置 网络摄像机 登录类型 默认值 <see cref="LoginType.Http"/>
/// 获得/设置 网络摄像机 登录类型 默认值 <see cref="HikVisionLoginType.Http"/>
/// </summary>
[Parameter]
public LoginType LoginType { get; set; }
public HikVisionLoginType LoginType { get; set; }

/// <summary>
/// 获得/设置 视频图像窗口宽度 默认值 500px
Expand All @@ -64,13 +64,19 @@ public partial class HikVisionWebPlugin
/// 获得/设置 登录成功后回调方法
/// </summary>
[Parameter]
public Func<Task>? OnLoginedAsync { get; set; }
public Func<Task>? OnLoginAsync { get; set; }

/// <summary>
/// 获得/设置 停止预览后回调方法
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation comment incorrectly states "停止预览后回调方法" (callback method after stopping preview), but this parameter is OnGetChannelsAsync which is called after getting the channel list. The comment should be something like "获取通道列表后回调方法" (callback method after getting channel list) instead.

Suggested change
/// 获得/设置 停止预览后回调方法
/// 获得/设置 获取通道列表后回调方法

Copilot uses AI. Check for mistakes.
/// </summary>
[Parameter]
public Func<HikVisionChannel, Task>? OnGetChannelsAsync { get; set; }

/// <summary>
/// 获得/设置 注销成功后回调方法
/// </summary>
[Parameter]
public Func<Task>? OnLogoutedAsync { get; set; }
public Func<Task>? OnLogoutAsync { get; set; }

/// <summary>
/// 获得/设置 开始预览后回调方法
Expand All @@ -95,14 +101,14 @@ public partial class HikVisionWebPlugin
.Build();

/// <summary>
/// 获得 Websdk 插件是否初始化成功
/// 获得 Web sdk 插件是否初始化成功
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment uses "Web sdk" (with a space and lowercase "sdk") while line 10 uses "WebSdk" (no space, camelCase). For consistency, this should also be "WebSdk" to match the naming convention used elsewhere in the file.

Suggested change
/// 获得 Web sdk 插件是否初始化成功
/// 获得 WebSdk 插件是否初始化成功

Copilot uses AI. Check for mistakes.
/// </summary>
public bool Inited { get; private set; }

/// <summary>
/// 获得 是否已登录
/// </summary>
public bool IsLogined { get; private set; }
public bool IsLogin { get; private set; }
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The property name IsLogin is grammatically awkward. Consider using IsLoggedIn instead, which is the standard past participle form used in similar contexts (e.g., User.IsLoggedIn() is a common pattern). Alternatively, IsAuthenticated would also be appropriate.

Suggested change
public bool IsLogin { get; private set; }
public bool IsLoggedIn { get; private set; }

Copilot uses AI. Check for mistakes.

/// <summary>
/// 获得 是否正在实时预览
Expand All @@ -129,22 +135,22 @@ protected override void OnParametersSet()
/// <param name="password"></param>
/// <param name="loginType"></param>
/// <returns></returns>
public async Task<bool> Login(string ip, int port, string userName, string password, LoginType loginType = LoginType.Http)
public async Task<bool> Login(string ip, int port, string userName, string password, HikVisionLoginType loginType = HikVisionLoginType.Http)
{
ThrowIfNotInited();
IsLogined = await InvokeAsync<bool?>("login", Id, ip, port, userName, password, (int)loginType) ?? false;
if (IsLogined)
IsLogin = await InvokeAsync<bool?>("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();
}
}

Expand All @@ -154,30 +160,40 @@ private async Task TriggerLogined()
/// <returns></returns>
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();
}
}

/// <summary>
/// 获得通道列表方法
/// </summary>
/// <returns></returns>
public async Task GetChannelList()
{
ThrowIfNotInited();
await InvokeVoidAsync("getChannelList", Id);
Comment on lines +184 to +187
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The C# GetChannelList method invokes a JS function that is not exported, which will cause a JS interop error at runtime.

This calls InvokeVoidAsync("getChannelList", Id), but HikVisionWebPlugin.razor.js doesn’t export getChannelList, and in hikvision.js it is only defined as an internal const (not exported). This will cause the interop call to fail at runtime. Please either export getChannelList on the JS side and re-export it via the .razor.js module, or remove/repurpose this C# method and rely on the existing login callback that fetches channel information.

}

/// <summary>
/// 开始实时预览方法
/// </summary>
/// <returns></returns>
public async Task StartRealPlay(int streamType, int channelId)
{
if (IsLogined && !IsRealPlaying)
if (IsLogin && !IsRealPlaying)
{
IsRealPlaying = await InvokeAsync<bool?>("startRealPlay", Id, streamType, channelId) ?? false;
if (IsRealPlaying)
Expand Down Expand Up @@ -239,4 +255,18 @@ public async Task TriggerInited(bool inited)
await OnInitedAsync(inited);
}
}

/// <summary>
/// 触发 <see cref="OnGetChannelsAsync"/> 回调方法由 JavaScript 调用
/// </summary>
/// <param name="channel"></param>
/// <returns></returns>
[JSInvokable]
public async Task TriggerGetChannelList(HikVisionChannel channel)
{
if (OnGetChannelsAsync != null)
{
await OnGetChannelsAsync(channel);
}
}
}
Original file line number Diff line number Diff line change
@@ -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';

Comment on lines 3 to 4
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import EventHandler.

Suggested change
import EventHandler from '../../BootstrapBlazor/modules/event-handler.js';

Copilot uses AI. Check for mistakes.
export async function init(id, invoke) {
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) BootstrapBlazor & Argo Zhang ([email protected]). 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;

/// <summary>
/// 模拟通道信息
Comment on lines +7 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (typo): The XML summary for HikVisionZeroChannelInfo is misleading.

Please update the summary text to explicitly describe this as zero-channel information so it’s clearly distinguished from the analog and digital channel types.

Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation comment incorrectly states "模拟通道信息" (analog channel info), but this class represents zero channel information. It should be "零通道信息" (zero channel info) instead.

Suggested change
/// 模拟通道信息
/// 零通道信息

Copilot uses AI. Check for mistakes.
/// </summary>
public class HikVisionZeroChannelInfo()
{
/// <summary>
/// 获得 通道 Id
/// </summary>
public int Id { get; set; }

/// <summary>
/// 获得 通道号
/// </summary>
public int InputPort { get; set; }

/// <summary>
/// 获得 是否使能
/// </summary>
public bool Enabled { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ sealed class DefaultHicVision(IJSRuntime jsRuntime) : IHikVision
private bool _initialized;
private bool _logined;

public async Task<bool> Login(string ip, int port, string userName, string password, LoginType loginType = LoginType.Http)
public async Task<bool> Login(string ip, int port, string userName, string password, HikVisionLoginType loginType = HikVisionLoginType.Http)
{
await LoadAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ public interface IHikVision : IAsyncDisposable
/// <summary>
/// 登录方法
/// </summary>
/// <param name="loginType">登录方式 <see cref="LoginType"/> 实例</param>
/// <param name="loginType">登录方式 <see cref="HikVisionLoginType"/> 实例</param>
/// <param name="ip">设备 Ip 地址</param>
/// <param name="port">设备端口</param>
/// <param name="userName">用户名</param>
/// <param name="password">密码</param>
/// <returns></returns>
Task<bool> Login(string ip, int port, string userName, string password, LoginType loginType = LoginType.Http);
Task<bool> Login(string ip, int port, string userName, string password, HikVisionLoginType loginType = HikVisionLoginType.Http);

/// <summary>
/// 登出方法
Expand Down
Loading
Loading