mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-27 21:57:10 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
346c560f8b | ||
|
|
8e3bd89f61 | ||
|
|
6da142d080 | ||
|
|
ff7d029e6f | ||
|
|
21b4695683 | ||
|
|
02ad494a26 | ||
|
|
280366e1b2 | ||
|
|
6660ce3e34 | ||
|
|
7499162c1a | ||
|
|
40208a5cd6 | ||
|
|
fa347f4f68 | ||
|
|
d7df6fc605 | ||
|
|
eb4bb2fd48 | ||
|
|
faa9858974 | ||
|
|
1b3d2dda49 | ||
|
|
a8a9453611 | ||
|
|
e84f42ce14 | ||
|
|
6f814cf6b8 | ||
|
|
e36432e4e9 | ||
|
|
ebd71e807b | ||
|
|
34000d8d7d | ||
|
|
e785f6660c | ||
|
|
831c611797 | ||
|
|
453817ef86 | ||
|
|
8ce0b981c1 | ||
|
|
4e5c51b54c | ||
|
|
3cc9d31f28 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -364,6 +364,7 @@ FodyWeavers.xsd
|
|||||||
|
|
||||||
/src/*Pro*/
|
/src/*Pro*/
|
||||||
/src/*Pro*
|
/src/*Pro*
|
||||||
|
/src/**/*Pro*
|
||||||
/src/*pro*
|
/src/*pro*
|
||||||
/src/*pro*/
|
/src/*pro*/
|
||||||
/src/ThingsGateway.Server/Configuration/GiteeOAuthSettings.json
|
/src/ThingsGateway.Server/Configuration/GiteeOAuthSettings.json
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||||
<!-- 避免 DLL 被打包到 lib/ -->
|
<!-- 避免 DLL 被打包到 lib/ -->
|
||||||
<EnableSourceGenerator>true</EnableSourceGenerator>
|
<EnableSourceGenerator>true</EnableSourceGenerator>
|
||||||
|
|
||||||
<!-- 可选 -->
|
<!-- 可选 -->
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class FileController : ControllerBase
|
|||||||
var filePath = Path.Combine(wwwroot, fileName);
|
var filePath = Path.Combine(wwwroot, fileName);
|
||||||
// 防止路径穿越攻击
|
// 防止路径穿越攻击
|
||||||
#pragma warning disable CA3003
|
#pragma warning disable CA3003
|
||||||
if (!filePath.StartsWith(wwwroot, StringComparison.OrdinalIgnoreCase) || !System.IO.File.Exists(filePath))
|
if ((!fileName.StartsWith(@"..\Logs\") && filePath.Contains("..")) || !System.IO.File.Exists(filePath))
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
@@ -49,6 +49,6 @@ public class FileController : ControllerBase
|
|||||||
|
|
||||||
Response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");
|
Response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");
|
||||||
|
|
||||||
return File(fileStream, "application/octet-stream", (fileName.Replace('/', '_')));
|
return File(fileStream, "application/octet-stream", (Path.GetFileName(filePath).Replace('/', '_')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class VerificatInfo : PrimaryIdEntity
|
|||||||
[AutoGenerateColumn(Filterable = true, Sortable = true)]
|
[AutoGenerateColumn(Filterable = true, Sortable = true)]
|
||||||
[SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true)]
|
[SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true)]
|
||||||
[IgnoreExcel]
|
[IgnoreExcel]
|
||||||
|
[System.ComponentModel.DataAnnotations.Key]
|
||||||
public override long Id { get; set; }
|
public override long Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -21,16 +21,7 @@
|
|||||||
"UserNoModule": "This account has not been assigned a module. Please contact the administrator",
|
"UserNoModule": "This account has not been assigned a module. Please contact the administrator",
|
||||||
"UserNull": "User {0} does not exist"
|
"UserNull": "User {0} does not exist"
|
||||||
},
|
},
|
||||||
"ThingsGateway.Admin.Application.BaseDataEntity": {
|
|
||||||
"CreateOrgId": "CreateOrgId"
|
|
||||||
},
|
|
||||||
"ThingsGateway.Admin.Application.BaseEntity": {
|
|
||||||
"CreateTime": "CreateTime",
|
|
||||||
"CreateUser": "CreateUser",
|
|
||||||
"SortCode": "SortCode",
|
|
||||||
"UpdateTime": "UpdateTime",
|
|
||||||
"UpdateUser": "UpdateUser"
|
|
||||||
},
|
|
||||||
"ThingsGateway.Admin.Application.BlazorAuthenticationHandler": {
|
"ThingsGateway.Admin.Application.BlazorAuthenticationHandler": {
|
||||||
"UserExpire": "User expired, please login again"
|
"UserExpire": "User expired, please login again"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,16 +21,7 @@
|
|||||||
"UserNoModule": "该账号未分配模块,请联系管理员",
|
"UserNoModule": "该账号未分配模块,请联系管理员",
|
||||||
"UserNull": "用户 {0} 不存在"
|
"UserNull": "用户 {0} 不存在"
|
||||||
},
|
},
|
||||||
"ThingsGateway.Admin.Application.BaseDataEntity": {
|
|
||||||
"CreateOrgId": "创建机构Id"
|
|
||||||
},
|
|
||||||
"ThingsGateway.Admin.Application.BaseEntity": {
|
|
||||||
"CreateTime": "创建时间",
|
|
||||||
"CreateUser": "创建人",
|
|
||||||
"SortCode": "排序",
|
|
||||||
"UpdateTime": "更新时间",
|
|
||||||
"UpdateUser": "更新人"
|
|
||||||
},
|
|
||||||
"ThingsGateway.Admin.Application.BlazorAuthenticationHandler": {
|
"ThingsGateway.Admin.Application.BlazorAuthenticationHandler": {
|
||||||
"UserExpire": "用户登录已过期,请重新登录"
|
"UserExpire": "用户登录已过期,请重新登录"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// QQ群:605534569
|
// QQ群:605534569
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace ThingsGateway.Gateway.Application;
|
namespace ThingsGateway.Admin.Application;
|
||||||
|
|
||||||
public class USheetDatas
|
public class USheetDatas
|
||||||
{
|
{
|
||||||
@@ -18,6 +18,7 @@ public class SessionOutput : PrimaryIdEntity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主键Id
|
/// 主键Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[System.ComponentModel.DataAnnotations.Key]
|
||||||
public override long Id { get; set; }
|
public override long Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -377,9 +377,9 @@ internal sealed class SysUserService : BaseService<SysUser>, ISysUserService
|
|||||||
/// 获取用户拥有的资源
|
/// 获取用户拥有的资源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">用户id</param>
|
/// <param name="id">用户id</param>
|
||||||
public async Task<GrantResourceData> OwnResourceAsync(long id)
|
public Task<GrantResourceData> OwnResourceAsync(long id)
|
||||||
{
|
{
|
||||||
return await _roleService.OwnResourceAsync(id, RelationCategoryEnum.UserHasResource).ConfigureAwait(false);
|
return _roleService.OwnResourceAsync(id, RelationCategoryEnum.UserHasResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -505,10 +505,10 @@ internal sealed class SysUserService : BaseService<SysUser>, ISysUserService
|
|||||||
var password = await GetDefaultPassWord(true).ConfigureAwait(false);//获取默认密码,这里不走Aop所以需要加密一下
|
var password = await GetDefaultPassWord(true).ConfigureAwait(false);//获取默认密码,这里不走Aop所以需要加密一下
|
||||||
using var db = GetDB();
|
using var db = GetDB();
|
||||||
//重置密码
|
//重置密码
|
||||||
if (await db.UpdateSetColumnsTrueAsync<SysUser>(it => new SysUser
|
if ((await db.UpdateSetColumnsTrueAsync<SysUser>(it => new SysUser
|
||||||
{
|
{
|
||||||
Password = password
|
Password = password
|
||||||
}, it => it.Id == id).ConfigureAwait(false))
|
}, it => it.Id == id).ConfigureAwait(false)) > 0)
|
||||||
{
|
{
|
||||||
DeleteUserFromCache(id);//从cache删除用户信息
|
DeleteUserFromCache(id);//从cache删除用户信息
|
||||||
var verificatInfoIds = _verificatInfoService.GetListByUserId(id);
|
var verificatInfoIds = _verificatInfoService.GetListByUserId(id);
|
||||||
|
|||||||
@@ -185,12 +185,12 @@ internal sealed class UserCenterService : BaseService<SysUser>, IUserCenterServi
|
|||||||
using var db = GetDB();
|
using var db = GetDB();
|
||||||
|
|
||||||
//更新指定字段
|
//更新指定字段
|
||||||
var result = await db.UpdateSetColumnsTrueAsync<SysUser>(it => new SysUser
|
var result = (await db.UpdateSetColumnsTrueAsync<SysUser>(it => new SysUser
|
||||||
{
|
{
|
||||||
Email = input.Email,
|
Email = input.Email,
|
||||||
Phone = input.Phone,
|
Phone = input.Phone,
|
||||||
Avatar = input.Avatar,
|
Avatar = input.Avatar,
|
||||||
}, it => it.Id == UserManager.UserId).ConfigureAwait(false);
|
}, it => it.Id == UserManager.UserId).ConfigureAwait(false)) > 0;
|
||||||
if (result)
|
if (result)
|
||||||
_userService.DeleteUserFromCache(UserManager.UserId);//cache删除用户数据
|
_userService.DeleteUserFromCache(UserManager.UserId);//cache删除用户数据
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||||
|
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||||
|
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||||
|
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||||
|
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||||
|
// 使用文档:https://thingsgateway.cn/
|
||||||
|
// QQ群:605534569
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ThingsGateway.Admin.Application;
|
||||||
|
|
||||||
|
public static class USheetDataHelpers
|
||||||
|
{
|
||||||
|
public static USheetDatas GetUSheetDatas(Dictionary<string, object> data)
|
||||||
|
{
|
||||||
|
var uSheetDatas = new USheetDatas();
|
||||||
|
|
||||||
|
foreach (var a in data)
|
||||||
|
{
|
||||||
|
var value = (a.Value as IEnumerable<Dictionary<string, object>>).ToList();
|
||||||
|
|
||||||
|
var uSheetData = new USheetData();
|
||||||
|
uSheetData.id = a.Key;
|
||||||
|
uSheetData.name = a.Key;
|
||||||
|
|
||||||
|
for (int row1 = 0; row1 < value.Count; row1++)
|
||||||
|
{
|
||||||
|
if (row1 == 0)
|
||||||
|
{
|
||||||
|
Dictionary<int, USheetCelldata> usheetColldata = new();
|
||||||
|
int col = 0;
|
||||||
|
foreach (var colData in value[row1])
|
||||||
|
{
|
||||||
|
usheetColldata.Add(col, new USheetCelldata() { v = colData.Key });
|
||||||
|
col++;
|
||||||
|
}
|
||||||
|
uSheetData.cellData.Add(row1, usheetColldata);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Dictionary<int, USheetCelldata> usheetColldata = new();
|
||||||
|
int col = 0;
|
||||||
|
foreach (var colData in value[row1])
|
||||||
|
{
|
||||||
|
usheetColldata.Add(col, new USheetCelldata() { v = colData.Value });
|
||||||
|
col++;
|
||||||
|
}
|
||||||
|
uSheetData.cellData.Add(row1 + 1, usheetColldata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uSheetData.rowCount = uSheetData.cellData.Count + 100;
|
||||||
|
uSheetData.columnCount = uSheetData.cellData.FirstOrDefault().Value?.Count ?? 0;
|
||||||
|
uSheetDatas.sheets.Add(a.Key, uSheetData);
|
||||||
|
}
|
||||||
|
return uSheetDatas;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
@namespace ThingsGateway.Gateway.Razor
|
@namespace ThingsGateway.Admin.Razor
|
||||||
@using ThingsGateway.Admin.Application
|
@using ThingsGateway.Admin.Application
|
||||||
@using ThingsGateway.Admin.Razor
|
@using ThingsGateway.Admin.Razor
|
||||||
@using ThingsGateway.Gateway.Application
|
|
||||||
|
|
||||||
<div class="h-600px">
|
<div class="h-600px">
|
||||||
<UniverSheet @ref="_sheetExcel" OnReadyAsync="OnReadyAsync"></UniverSheet>
|
<UniverSheet @ref="_sheetExcel" OnReadyAsync="OnReadyAsync"></UniverSheet>
|
||||||
@@ -8,9 +8,10 @@
|
|||||||
// QQ群:605534569
|
// QQ群:605534569
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using ThingsGateway.Admin.Application;
|
||||||
using ThingsGateway.NewLife.Json.Extension;
|
using ThingsGateway.NewLife.Json.Extension;
|
||||||
|
|
||||||
namespace ThingsGateway.Gateway.Razor;
|
namespace ThingsGateway.Admin.Razor;
|
||||||
|
|
||||||
public partial class USheet
|
public partial class USheet
|
||||||
{
|
{
|
||||||
@@ -30,7 +30,7 @@ public class BlazorAppContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 全部菜单
|
/// 全部菜单
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<SysResource> AllMenus { get; private set; }
|
public List<SysResource> AllMenus { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前用户
|
/// 当前用户
|
||||||
@@ -42,22 +42,22 @@ public class BlazorAppContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户个人菜单
|
/// 用户个人菜单
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<MenuItem> OwnMenuItems { get; private set; }
|
public List<MenuItem> OwnMenuItems { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 不同模块的菜单
|
/// 不同模块的菜单
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<MenuItem> AllOwnMenuItems { get; private set; }
|
public List<MenuItem> AllOwnMenuItems { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户个人菜单,多个模块
|
/// 用户个人菜单,多个模块
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<SysResource> OwnMenus { get; private set; }
|
public List<SysResource> OwnMenus { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户个人菜单,非树形
|
/// 用户个人菜单,非树形
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<MenuItem> OwnSameLevelMenuItems { get; private set; }
|
public List<MenuItem> OwnSameLevelMenuItems { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 个人工作台
|
/// 个人工作台
|
||||||
@@ -67,9 +67,9 @@ public class BlazorAppContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户个人快捷方式菜单
|
/// 用户个人快捷方式菜单
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<SysResource> UserWorkbenchOutputs { get; private set; }
|
public List<SysResource> UserWorkbenchOutputs { get; private set; }
|
||||||
|
|
||||||
public IEnumerable<SysResource> AllResource { get; private set; }
|
public List<SysResource> AllResource { get; private set; }
|
||||||
|
|
||||||
private ISysResourceService ResourceService { get; }
|
private ISysResourceService ResourceService { get; }
|
||||||
private ISysUserService SysUserService { get; }
|
private ISysUserService SysUserService { get; }
|
||||||
@@ -93,7 +93,7 @@ public class BlazorAppContext
|
|||||||
AllResource = sysResources;
|
AllResource = sysResources;
|
||||||
var ids = CurrentUser.ModuleList.Select(a => a.Id).ToHashSet();
|
var ids = CurrentUser.ModuleList.Select(a => a.Id).ToHashSet();
|
||||||
CurrentUser.ModuleList = AllResource.Where(a => ids.Contains(a.Id)).OrderBy(a => a.SortCode).ToList();
|
CurrentUser.ModuleList = AllResource.Where(a => ids.Contains(a.Id)).OrderBy(a => a.SortCode).ToList();
|
||||||
AllMenus = AllResource.Where(a => a.Category == ResourceCategoryEnum.Menu);
|
AllMenus = AllResource.Where(a => a.Category == ResourceCategoryEnum.Menu).ToList();
|
||||||
|
|
||||||
if (moduleId == null)
|
if (moduleId == null)
|
||||||
{
|
{
|
||||||
@@ -123,8 +123,8 @@ public class BlazorAppContext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var ownMenus = OwnMenus.Where(a => a.Module == CurrentModuleId);
|
var ownMenus = OwnMenus.Where(a => a.Module == CurrentModuleId);
|
||||||
OwnMenuItems = ResourceUtil.BuildMenuTrees(ownMenus).ToList();
|
OwnMenuItems = AdminResourceUtil.BuildMenuTrees(ownMenus).ToList();
|
||||||
AllOwnMenuItems = ResourceUtil.BuildMenuTrees(OwnMenus).ToList();
|
AllOwnMenuItems = AdminResourceUtil.BuildMenuTrees(OwnMenus).ToList();
|
||||||
OwnSameLevelMenuItems = ownMenus.Where(a => !a.Href.IsNullOrWhiteSpace()).Select(item => new MenuItem()
|
OwnSameLevelMenuItems = ownMenus.Where(a => !a.Href.IsNullOrWhiteSpace()).Select(item => new MenuItem()
|
||||||
{
|
{
|
||||||
Match = item.NavLinkMatch ?? Microsoft.AspNetCore.Components.Routing.NavLinkMatch.All,
|
Match = item.NavLinkMatch ?? Microsoft.AspNetCore.Components.Routing.NavLinkMatch.All,
|
||||||
@@ -132,8 +132,8 @@ public class BlazorAppContext
|
|||||||
Icon = item.Icon,
|
Icon = item.Icon,
|
||||||
Url = item.Href,
|
Url = item.Href,
|
||||||
Target = item.Target.ToString(),
|
Target = item.Target.ToString(),
|
||||||
});
|
}).ToList();
|
||||||
UserWorkbenchOutputs = AllMenus.Where(it => UserWorkBench.Shortcuts.Contains(it.Id));
|
UserWorkbenchOutputs = AllMenus.Where(it => UserWorkBench.Shortcuts.Contains(it.Id)).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public partial class EditPagePolicy
|
|||||||
|
|
||||||
protected override Task OnParametersSetAsync()
|
protected override Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
ShortcutsTreeViewItems = ResourceUtil.BuildTreeItemList(AppContext.OwnMenus.WhereIf(!ShortcutsSearchText.IsNullOrEmpty(), a => a.Title.Contains(ShortcutsSearchText)), Model.Shortcuts, null);
|
ShortcutsTreeViewItems = AdminResourceUtil.BuildTreeItemList(AppContext.OwnMenus.WhereIf(!ShortcutsSearchText.IsNullOrEmpty(), a => a.Title.Contains(ShortcutsSearchText)), Model.Shortcuts, null);
|
||||||
return base.OnParametersSetAsync();
|
return base.OnParametersSetAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +48,6 @@ public partial class EditPagePolicy
|
|||||||
{
|
{
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
ShortcutsSearchText = searchText;
|
ShortcutsSearchText = searchText;
|
||||||
return ResourceUtil.BuildTreeItemList(AppContext.OwnMenus.WhereIf(!ShortcutsSearchText.IsNullOrEmpty(), a => a.Title.Contains(ShortcutsSearchText)), Model.Shortcuts, null);
|
return AdminResourceUtil.BuildTreeItemList(AppContext.OwnMenus.WhereIf(!ShortcutsSearchText.IsNullOrEmpty(), a => a.Title.Contains(ShortcutsSearchText)), Model.Shortcuts, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public partial class MenuChoiceDialog
|
|||||||
var all = (await SysResourceService.GetAllAsync());
|
var all = (await SysResourceService.GetAllAsync());
|
||||||
var items = all.Where(a => a.Category == ResourceCategoryEnum.Menu && a.Module == ModuleId);
|
var items = all.Where(a => a.Category == ResourceCategoryEnum.Menu && a.Module == ModuleId);
|
||||||
ModuleTitle = all.FirstOrDefault(a => a.Id == ModuleId)?.Title;
|
ModuleTitle = all.FirstOrDefault(a => a.Id == ModuleId)?.Title;
|
||||||
Items = ResourceUtil.BuildTreeItemList(items, new List<long> { Value }, RenderTreeItem);
|
Items = AdminResourceUtil.BuildTreeItemList(items, new List<long> { Value }, RenderTreeItem);
|
||||||
await base.OnParametersSetAsync();
|
await base.OnParametersSetAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,12 +26,12 @@
|
|||||||
OnQueryAsync="OnQueryAsync" CustomerSearchModel="@CustomerSearchModel"
|
OnQueryAsync="OnQueryAsync" CustomerSearchModel="@CustomerSearchModel"
|
||||||
OnSaveAsync="Save" OnDeleteAsync="Delete">
|
OnSaveAsync="Save" OnDeleteAsync="Delete">
|
||||||
<TableToolbarTemplate>
|
<TableToolbarTemplate>
|
||||||
<PopConfirmButton Color=Color.Warning IsDisabled="SelectedRows.Count<=0||!AuthorizeButton(AdminOperConst.Add)" Text=@OperDescLocalizer["CopyResource"] Icon="fa fa-copy" OnConfirm="OnCopy">
|
<PopConfirmButton Color=Color.Warning IsKeepDisabled="SelectedRows.Count <= 0 || !AuthorizeButton(AdminOperConst.Add)" Text=@OperDescLocalizer["CopyResource"] Icon="fa fa-copy" OnConfirm="OnCopy">
|
||||||
<BodyTemplate>
|
<BodyTemplate>
|
||||||
<Select Items="ModuleSelectedItems" @bind-Value=CopyModule ShowLabel="false" />
|
<Select Items="ModuleSelectedItems" @bind-Value=CopyModule ShowLabel="false" />
|
||||||
</BodyTemplate>
|
</BodyTemplate>
|
||||||
</PopConfirmButton>
|
</PopConfirmButton>
|
||||||
<PopConfirmButton Color=Color.Warning IsDisabled="SelectedRows.Count!=1||!AuthorizeButton(AdminOperConst.Edit)" Text=@OperDescLocalizer["ChangeParentResource"] Icon="fa fa-copy" OnConfirm="OnChangeParent">
|
<PopConfirmButton Color=Color.Warning IsKeepDisabled="SelectedRows.Count != 1 || !AuthorizeButton(AdminOperConst.Edit)" Text=@OperDescLocalizer["ChangeParentResource"] Icon="fa fa-copy" OnConfirm="OnChangeParent">
|
||||||
<BodyTemplate>
|
<BodyTemplate>
|
||||||
<div class="overflow-y-auto" style="height:500px">
|
<div class="overflow-y-auto" style="height:500px">
|
||||||
<TreeView Items="MenuTreeItems" IsVirtualize="true" OnTreeItemClick="a=>{ChangeParentId=a.Value.Id;return Task.CompletedTask;}" />
|
<TreeView Items="MenuTreeItems" IsVirtualize="true" OnTreeItemClick="a=>{ChangeParentId=a.Value.Id;return Task.CompletedTask;}" />
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ public partial class SysResourcePage
|
|||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
ModuleSelectedItems = ResourceUtil.BuildModuleSelectList((await SysResourceService.GetAllAsync())).ToList();
|
ModuleSelectedItems = AdminResourceUtil.BuildModuleSelectList((await SysResourceService.GetAllAsync())).ToList();
|
||||||
MenuItems = ResourceUtil.BuildMenuSelectList((await SysResourceService.GetAllAsync())).Concat(new List<SelectedItem>() { new("0", AdminLocalizer["Root"]) }).ToList();
|
MenuItems = AdminResourceUtil.BuildMenuSelectList((await SysResourceService.GetAllAsync())).Concat(new List<SelectedItem>() { new("0", AdminLocalizer["Root"]) }).ToList();
|
||||||
|
|
||||||
await base.OnParametersSetAsync();
|
await base.OnParametersSetAsync();
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ public partial class SysResourcePage
|
|||||||
|
|
||||||
private async Task<QueryData<SysResource>> OnQueryAsync(QueryPageOptions options)
|
private async Task<QueryData<SysResource>> OnQueryAsync(QueryPageOptions options)
|
||||||
{
|
{
|
||||||
MenuTreeItems = new List<TreeViewItem<SysResource>>() { new TreeViewItem<SysResource>(new SysResource()) { Text = AdminLocalizer["Root"] } }.Concat(ResourceUtil.BuildTreeItemList((await SysResourceService.GetAllAsync()).Where(a => a.Module == CustomerSearchModel.Module), new(), null)).ToList();
|
MenuTreeItems = new List<TreeViewItem<SysResource>>() { new TreeViewItem<SysResource>(new SysResource()) { Text = AdminLocalizer["Root"] } }.Concat(AdminResourceUtil.BuildTreeItemList((await SysResourceService.GetAllAsync()).Where(a => a.Module == CustomerSearchModel.Module), new(), null)).ToList();
|
||||||
|
|
||||||
var data = await SysResourceService.PageAsync(options, CustomerSearchModel);
|
var data = await SysResourceService.PageAsync(options, CustomerSearchModel);
|
||||||
return data;
|
return data;
|
||||||
@@ -136,14 +136,14 @@ public partial class SysResourcePage
|
|||||||
private async Task<IEnumerable<TableTreeNode<SysResource>>> OnTreeExpand(SysResource menu)
|
private async Task<IEnumerable<TableTreeNode<SysResource>>> OnTreeExpand(SysResource menu)
|
||||||
{
|
{
|
||||||
var sysResources = await SysResourceService.GetAllAsync();
|
var sysResources = await SysResourceService.GetAllAsync();
|
||||||
var result = ResourceUtil.BuildTableTrees(sysResources, menu.Id);
|
var result = AdminResourceUtil.BuildTableTrees(sysResources, menu.Id);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IEnumerable<TableTreeNode<SysResource>>> TreeNodeConverter(IEnumerable<SysResource> items)
|
private static async Task<IEnumerable<TableTreeNode<SysResource>>> TreeNodeConverter(IEnumerable<SysResource> items)
|
||||||
{
|
{
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
var result = ResourceUtil.BuildTableTrees(items, 0);
|
var result = AdminResourceUtil.BuildTableTrees(items, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public partial class GrantResourceDialog
|
|||||||
{
|
{
|
||||||
var items = (await SysResourceService.GetAllAsync()).Where(a => a.Category != ResourceCategoryEnum.Module).OrderBy(a => a.Module).ThenBy(a => a.Id).ToList();
|
var items = (await SysResourceService.GetAllAsync()).Where(a => a.Category != ResourceCategoryEnum.Module).OrderBy(a => a.Module).ThenBy(a => a.Id).ToList();
|
||||||
|
|
||||||
Items = ResourceUtil.BuildTreeItemList(items, Value, RenderTreeItem);
|
Items = AdminResourceUtil.BuildTreeItemList(items, Value, RenderTreeItem);
|
||||||
ModuleList = (await SysResourceService.GetAllAsync()).Where(a => a.Category == ResourceCategoryEnum.Module).ToList();
|
ModuleList = (await SysResourceService.GetAllAsync()).Where(a => a.Category == ResourceCategoryEnum.Module).ToList();
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public partial class SysUserEdit
|
|||||||
BoolItems = LocalizerUtil.GetBoolItems(Model.GetType(), nameof(Model.Status));
|
BoolItems = LocalizerUtil.GetBoolItems(Model.GetType(), nameof(Model.Status));
|
||||||
var items = await SysPositionService.SelectorAsync(new PositionSelectorInput());
|
var items = await SysPositionService.SelectorAsync(new PositionSelectorInput());
|
||||||
Items = PositionUtil.BuildCascaderItemList(items);
|
Items = PositionUtil.BuildCascaderItemList(items);
|
||||||
ModuleSelectedItems = ResourceUtil.BuildModuleSelectList((await SysResourceService.GetAllAsync())).ToList();
|
ModuleSelectedItems = AdminResourceUtil.BuildModuleSelectList((await SysResourceService.GetAllAsync())).ToList();
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj" />
|
<ProjectReference Include="..\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj" />
|
||||||
<PackageReference Include="BootstrapBlazor.Chart" Version="9.0.0" />
|
<PackageReference Include="BootstrapBlazor.Chart" Version="9.0.0" />
|
||||||
|
<PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)'=='net8.0'">
|
<ItemGroup Condition="'$(TargetFramework)'=='net8.0'">
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
||||||
|
|
||||||
<!--<UseRazorSourceGenerator>false</UseRazorSourceGenerator>-->
|
<!--<UseRazorSourceGenerator>false</UseRazorSourceGenerator>-->
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace ThingsGateway.Admin.Razor;
|
|||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[ThingsGateway.DependencyInjection.SuppressSniffer]
|
[ThingsGateway.DependencyInjection.SuppressSniffer]
|
||||||
public static class ResourceUtil
|
public static class AdminResourceUtil
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造选择项,ID/TITLE
|
/// 构造选择项,ID/TITLE
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<Target Name="AdminPostPublish" AfterTargets="Publish">
|
<Target Name="AdminPostPublish" AfterTargets="Publish">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- setting up the variable for convenience -->
|
<!-- setting up the variable for convenience -->
|
||||||
<AdminFiles Include="bin\$(Configuration)\$(TargetFramework)\SeedData\**" />
|
<AdminFiles Include="$(OutputPath)\$(TargetFramework)\SeedData\**" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
#推送:docker push registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway
|
#推送:docker push registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway
|
||||||
|
|
||||||
#aspnetcore9.0环境
|
#aspnetcore9.0环境
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
#FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0-noble AS base
|
||||||
COPY . /app
|
COPY . /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
#默认web
|
#默认web
|
||||||
@@ -13,6 +14,8 @@ EXPOSE 5000
|
|||||||
|
|
||||||
# 添加时区环境变量,亚洲,上海
|
# 添加时区环境变量,亚洲,上海
|
||||||
ENV TimeZone=Asia/Shanghai
|
ENV TimeZone=Asia/Shanghai
|
||||||
|
# 转发头
|
||||||
|
ENV ASPNETCORE_FORWARDEDHEADERS_ENABLED=true
|
||||||
# 使用软连接,并且将时区配置覆盖/etc/timezone
|
# 使用软连接,并且将时区配置覆盖/etc/timezone
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TimeZone /etc/localtime && echo $TimeZone > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TimeZone /etc/localtime && echo $TimeZone > /etc/timezone
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
#推送:docker push registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway_arm64
|
#推送:docker push registry.cn-shenzhen.aliyuncs.com/thingsgateway/thingsgateway_arm64
|
||||||
|
|
||||||
#aspnetcore9.0环境
|
#aspnetcore9.0环境
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine-arm64v8 AS base
|
#FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine-arm64v8 AS base
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0-noble-arm64v8 AS base
|
||||||
COPY . /app
|
COPY . /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
#默认web
|
#默认web
|
||||||
@@ -13,6 +14,8 @@ EXPOSE 5000
|
|||||||
|
|
||||||
# 添加时区环境变量,亚洲,上海
|
# 添加时区环境变量,亚洲,上海
|
||||||
ENV TimeZone=Asia/Shanghai
|
ENV TimeZone=Asia/Shanghai
|
||||||
|
# 转发头
|
||||||
|
ENV ASPNETCORE_FORWARDEDHEADERS_ENABLED=true
|
||||||
# 使用软连接,并且将时区配置覆盖/etc/timezone
|
# 使用软连接,并且将时区配置覆盖/etc/timezone
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TimeZone /etc/localtime && echo $TimeZone > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TimeZone /etc/localtime && echo $TimeZone > /etc/timezone
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
<BlazorReconnector @rendermode="new InteractiveServerRenderMode(false)" />
|
<BlazorReconnector @rendermode="new InteractiveServerRenderMode(false)" />
|
||||||
|
|
||||||
<script src=@($"_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js?v={this.GetType().Assembly.GetName().Version}")></script>
|
<script src=@($"_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js?v={this.GetType().Assembly.GetName().Version}")></script>
|
||||||
<script src=@($"{WebsiteConst.DefaultResourceUrl}js/culture.js?v={this.GetType().Assembly.GetName().Version}")></script>
|
<script src=@($"{WebsiteConst.DefaultResourceUrl}js/localStorageUtil.js?v={this.GetType().Assembly.GetName().Version}")></script>
|
||||||
<script src="_framework/blazor.web.js"></script>
|
<script src="_framework/blazor.web.js"></script>
|
||||||
<!-- PWA Service Worker -->
|
<!-- PWA Service Worker -->
|
||||||
<script type="text/javascript">'serviceWorker' in navigator && navigator.serviceWorker.register('./service-worker.js')</script>
|
<script type="text/javascript">'serviceWorker' in navigator && navigator.serviceWorker.register('./service-worker.js')</script>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</app>
|
</app>
|
||||||
|
|
||||||
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
|
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
|
||||||
<script src=@($"{WebsiteConst.DefaultResourceUrl}js/culture.js")></script>
|
<script src=@($"{WebsiteConst.DefaultResourceUrl}js/localStorageUtil.js")></script>
|
||||||
<script src="_framework/blazor.server.js"></script>
|
<script src="_framework/blazor.server.js"></script>
|
||||||
|
|
||||||
<!-- PWA Service Worker -->
|
<!-- PWA Service Worker -->
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ public class Startup : AppStartup
|
|||||||
options.ServicesStopConcurrently = true;
|
options.ServicesStopConcurrently = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
//// 事件总线
|
// 事件总线
|
||||||
//services.AddEventBus(options =>
|
services.AddEventBus(options =>
|
||||||
//{
|
{
|
||||||
|
|
||||||
//});
|
});
|
||||||
|
|
||||||
// 任务调度
|
// 任务调度
|
||||||
services.AddSchedule(options => options.AddPersistence<JobPersistence>());
|
services.AddSchedule(options => options.AddPersistence<JobPersistence>());
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!--<Import Project="Admin.targets" Condition=" '$(Configuration)' != 'Debug' " />-->
|
<!--<Import Project="Admin.targets" Condition=" '$(Configuration)' != 'Debug' " />-->
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// QQ群:605534569
|
// QQ群:605534569
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace ThingsGateway.Gateway.Application;
|
namespace ThingsGateway.Common;
|
||||||
|
|
||||||
public class SmartTriggerScheduler
|
public class SmartTriggerScheduler
|
||||||
{
|
{
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
// QQ群:605534569
|
// QQ群:605534569
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace ThingsGateway.Gateway.Application;
|
namespace ThingsGateway.Common;
|
||||||
|
|
||||||
public sealed class StringOrdinalIgnoreCaseEqualityComparer : EqualityComparer<string>
|
public sealed class StringOrdinalIgnoreCaseEqualityComparer : EqualityComparer<string>
|
||||||
{
|
{
|
||||||
@@ -27,11 +27,11 @@ public class WebsiteOptions : IConfigurableOptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Demo { get; set; }
|
public bool Demo { get; set; }
|
||||||
|
|
||||||
public bool WebPageEnable { get; set; } = true;
|
|
||||||
|
|
||||||
public int MaxBlazorConnections { get; set; } = 5;
|
public int MaxBlazorConnections { get; set; } = 5;
|
||||||
public bool BlazorConnectionLimitEnable { get; set; } = false;
|
public bool BlazorConnectionLimitEnable { get; set; } = false;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否显示关于页面
|
/// 是否显示关于页面
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||||
@@ -13,7 +14,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.6" />
|
<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.6" />
|
||||||
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
||||||
<PackageReference Include="BootstrapBlazor" Version="9.9.0" />
|
<PackageReference Include="BootstrapBlazor" Version="9.9.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public abstract class PrimaryIdEntity : IPrimaryIdEntity
|
|||||||
[SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true)]
|
[SugarColumn(ColumnDescription = "Id", IsPrimaryKey = true)]
|
||||||
[IgnoreExcel]
|
[IgnoreExcel]
|
||||||
[AutoGenerateColumn(Visible = false, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false, Sortable = true, DefaultSort = true, DefaultSortOrder = SortOrder.Asc)]
|
[AutoGenerateColumn(Visible = false, IsVisibleWhenEdit = false, IsVisibleWhenAdd = false, Sortable = true, DefaultSort = true, DefaultSortOrder = SortOrder.Asc)]
|
||||||
|
[System.ComponentModel.DataAnnotations.Key]
|
||||||
public virtual long Id { get; set; }
|
public virtual long Id { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ public static class QueryPageOptionsExtensions
|
|||||||
return datas;
|
return datas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static IEnumerable<T> GetQuery<T>(this IEnumerable<T> query, QueryPageOptions option, Func<IEnumerable<T>, IEnumerable<T>>? queryFunc = null, FilterKeyValueAction where = null)
|
public static IEnumerable<T> GetQuery<T>(this IEnumerable<T> query, QueryPageOptions option, Func<IEnumerable<T>, IEnumerable<T>>? queryFunc = null, FilterKeyValueAction where = null)
|
||||||
{
|
{
|
||||||
if (queryFunc != null)
|
if (queryFunc != null)
|
||||||
@@ -123,7 +125,36 @@ public static class QueryPageOptionsExtensions
|
|||||||
};
|
};
|
||||||
var items = datas.GetData(option, out var totalCount, where);
|
var items = datas.GetData(option, out var totalCount, where);
|
||||||
ret.TotalCount = totalCount;
|
ret.TotalCount = totalCount;
|
||||||
|
|
||||||
|
if (totalCount > 0)
|
||||||
|
{
|
||||||
|
if (!items.Any() && option.PageIndex != 1)
|
||||||
|
{
|
||||||
|
option.PageIndex = 1;
|
||||||
|
items = datas.GetData(option, out totalCount, where);
|
||||||
|
}
|
||||||
|
}
|
||||||
ret.Items = items.ToList();
|
ret.Items = items.ToList();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据查询条件返回QueryData
|
||||||
|
/// </summary>
|
||||||
|
public static QueryData<SelectedItem> GetQueryData<T>(this IEnumerable<T> datas, VirtualizeQueryOption option, Func<IEnumerable<T>, IEnumerable<SelectedItem>> func, FilterKeyValueAction where = null)
|
||||||
|
{
|
||||||
|
var ret = new QueryData<SelectedItem>()
|
||||||
|
{
|
||||||
|
IsSorted = false,
|
||||||
|
IsFiltered = false,
|
||||||
|
IsAdvanceSearch = false,
|
||||||
|
IsSearch = !option.SearchText.IsNullOrWhiteSpace()
|
||||||
|
};
|
||||||
|
|
||||||
|
var items = datas.Skip((option.StartIndex)).Take(option.Count);
|
||||||
|
ret.TotalCount = datas.Count();
|
||||||
|
|
||||||
|
ret.Items = func(items).ToList();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,16 +209,10 @@ public static class SqlSugarExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public static async Task<bool> UpdateRangeAsync<T>(this SqlSugarClient db, List<T> updateObjs) where T : class, new()
|
public static Task<int> UpdateSetColumnsTrueAsync<T>(this SqlSugarClient db, Expression<Func<T, T>> columns, Expression<Func<T, bool>> whereExpression) where T : class, new()
|
||||||
{
|
{
|
||||||
return await db.Updateable(updateObjs).ExecuteCommandAsync().ConfigureAwait(false) > 0;
|
return db.Updateable<T>().SetColumns(columns, appendColumnsByDataFilter: true).Where(whereExpression)
|
||||||
}
|
.ExecuteCommandAsync();
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public static async Task<bool> UpdateSetColumnsTrueAsync<T>(this SqlSugarClient db, Expression<Func<T, T>> columns, Expression<Func<T, bool>> whereExpression) where T : class, new()
|
|
||||||
{
|
|
||||||
return await db.Updateable<T>().SetColumns(columns, appendColumnsByDataFilter: true).Where(whereExpression)
|
|
||||||
.ExecuteCommandAsync().ConfigureAwait(false) > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<T> Sort<T>(this IEnumerable<T> list, BasePageInput basePageInput)
|
private static IEnumerable<T> Sort<T>(this IEnumerable<T> list, BasePageInput basePageInput)
|
||||||
|
|||||||
13
src/Admin/ThingsGateway.DB/Locales/en-US.json
Normal file
13
src/Admin/ThingsGateway.DB/Locales/en-US.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
"ThingsGateway.Admin.Application.BaseDataEntity": {
|
||||||
|
"CreateOrgId": "CreateOrgId"
|
||||||
|
},
|
||||||
|
"ThingsGateway.Admin.Application.BaseEntity": {
|
||||||
|
"CreateTime": "CreateTime",
|
||||||
|
"CreateUser": "CreateUser",
|
||||||
|
"SortCode": "SortCode",
|
||||||
|
"UpdateTime": "UpdateTime",
|
||||||
|
"UpdateUser": "UpdateUser"
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/Admin/ThingsGateway.DB/Locales/zh-CN.json
Normal file
13
src/Admin/ThingsGateway.DB/Locales/zh-CN.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
"ThingsGateway.DB.BaseDataEntity": {
|
||||||
|
"CreateOrgId": "创建机构Id"
|
||||||
|
},
|
||||||
|
"ThingsGateway.DB.BaseEntity": {
|
||||||
|
"CreateTime": "创建时间",
|
||||||
|
"CreateUser": "创建人",
|
||||||
|
"SortCode": "排序",
|
||||||
|
"UpdateTime": "更新时间",
|
||||||
|
"UpdateUser": "更新人"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ public class BaseService<T> : IDataService<T>, IDisposable where T : class, new(
|
|||||||
public async Task<bool> DeleteAsync(IEnumerable<T> models)
|
public async Task<bool> DeleteAsync(IEnumerable<T> models)
|
||||||
{
|
{
|
||||||
using var db = GetDB();
|
using var db = GetDB();
|
||||||
return await db.Deleteable<T>().In(models.ToList()).ExecuteCommandHasChangeAsync().ConfigureAwait(false);
|
return await db.Deleteable<T>(models.ToList()).ExecuteCommandHasChangeAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -140,18 +140,22 @@ public class BaseService<T> : IDataService<T>, IDisposable where T : class, new(
|
|||||||
return (await db.UpdateableT(model).ExecuteCommandAsync().ConfigureAwait(false)) > 0;
|
return (await db.UpdateableT(model).ExecuteCommandAsync().ConfigureAwait(false)) > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual async Task<bool> SaveAsync(List<T> model, ItemChangedType changedType)
|
public virtual async Task<bool> SaveAsync(List<T> model, ItemChangedType changedType)
|
||||||
|
{
|
||||||
|
return (await SaveReturnCountAsync(model, changedType).ConfigureAwait(false)) > 0;
|
||||||
|
}
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async Task<int> SaveReturnCountAsync(List<T> model, ItemChangedType changedType)
|
||||||
{
|
{
|
||||||
using var db = GetDB();
|
using var db = GetDB();
|
||||||
if (changedType == ItemChangedType.Add)
|
if (changedType == ItemChangedType.Add)
|
||||||
{
|
{
|
||||||
return (await db.Insertable(model).ExecuteCommandAsync().ConfigureAwait(false)) > 0;
|
return (await db.Insertable(model).ExecuteCommandAsync().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (await db.Updateable(model).ExecuteCommandAsync().ConfigureAwait(false)) > 0;
|
return (await db.Updateable(model).ExecuteCommandAsync().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||||
@@ -18,6 +19,12 @@
|
|||||||
<None Remove="..\..\..\README.zh-CN.md" Pack="false" PackagePath="\" />
|
<None Remove="..\..\..\README.zh-CN.md" Pack="false" PackagePath="\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Locales\en-US.json" />
|
||||||
|
<EmbeddedResource Include="Locales\zh-CN.json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!--<PackageReference Include="ThingsGateway.Razor" Version="$(SourceGeneratorVersion)" />-->
|
<!--<PackageReference Include="ThingsGateway.Razor" Version="$(SourceGeneratorVersion)" />-->
|
||||||
<!--<ProjectReference Include="..\ThingsGateway.Razor\ThingsGateway.Razor.csproj" />-->
|
<!--<ProjectReference Include="..\ThingsGateway.Razor\ThingsGateway.Razor.csproj" />-->
|
||||||
|
|||||||
@@ -27,18 +27,27 @@ using System.Security.Claims;
|
|||||||
using ThingsGateway.ConfigurableOptions;
|
using ThingsGateway.ConfigurableOptions;
|
||||||
using ThingsGateway.NewLife.Caching;
|
using ThingsGateway.NewLife.Caching;
|
||||||
using ThingsGateway.NewLife.Collections;
|
using ThingsGateway.NewLife.Collections;
|
||||||
|
using ThingsGateway.NewLife.Extension;
|
||||||
using ThingsGateway.NewLife.Log;
|
using ThingsGateway.NewLife.Log;
|
||||||
using ThingsGateway.Reflection;
|
using ThingsGateway.Reflection;
|
||||||
using ThingsGateway.Templates;
|
using ThingsGateway.Templates;
|
||||||
|
|
||||||
namespace ThingsGateway;
|
namespace ThingsGateway;
|
||||||
|
|
||||||
|
|
||||||
|
public static class WebEnableVariable
|
||||||
|
{
|
||||||
|
public static bool WebEnable => Environment.GetEnvironmentVariable(nameof(WebEnable)).ToBoolean(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 全局应用类
|
/// 全局应用类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SuppressSniffer]
|
[SuppressSniffer]
|
||||||
public static class App
|
public static class App
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 私有设置,避免重复解析
|
/// 私有设置,避免重复解析
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -157,7 +166,7 @@ public static class App
|
|||||||
var httpContextAccessor = RootServices?.GetService<IHttpContextAccessor>();
|
var httpContextAccessor = RootServices?.GetService<IHttpContextAccessor>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return httpContextAccessor.HttpContext;
|
return httpContextAccessor?.HttpContext;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -545,10 +554,9 @@ public static class App
|
|||||||
{
|
{
|
||||||
types = ass.GetTypes();
|
types = ass.GetTypes();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
XTrace.Log.Warn($"Error load `{ass.FullName}` assembly.");
|
XTrace.Log.Warn($"Error load `{ass.FullName}` assembly. : {ex.Message}");
|
||||||
Console.WriteLine($"Error load `{ass.FullName}` assembly.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.Where(u => u.IsPublic && !u.IsDefined(typeof(SuppressSnifferAttribute), false));
|
return types.Where(u => u.IsPublic && !u.IsDefined(typeof(SuppressSnifferAttribute), false));
|
||||||
|
|||||||
@@ -213,12 +213,18 @@ public static class AppServiceCollectionExtensions
|
|||||||
// 缓存
|
// 缓存
|
||||||
if (cacheOptions.CacheType == CacheType.Memory)
|
if (cacheOptions.CacheType == CacheType.Memory)
|
||||||
{
|
{
|
||||||
services.AddSingleton<ICache, MemoryCache>(a => new()
|
services.AddSingleton<ICache>(a =>
|
||||||
{
|
{
|
||||||
Capacity = cacheOptions.MemoryCacheOptions.Capacity,
|
Cache.Default = new MemoryCache()
|
||||||
Expire = cacheOptions.MemoryCacheOptions.Expire,
|
{
|
||||||
Period = cacheOptions.MemoryCacheOptions.Period
|
Capacity = cacheOptions.MemoryCacheOptions.Capacity,
|
||||||
});
|
Expire = cacheOptions.MemoryCacheOptions.Expire,
|
||||||
|
Period = cacheOptions.MemoryCacheOptions.Period
|
||||||
|
};
|
||||||
|
return Cache.Default;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (cacheOptions.CacheType == CacheType.Redis)
|
else if (cacheOptions.CacheType == CacheType.Redis)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -85,11 +85,14 @@ internal static class InternalApp
|
|||||||
// 存储根服务(解决 Web 主机还未启动时在 HostedService 中使用 App.GetService 问题
|
// 存储根服务(解决 Web 主机还未启动时在 HostedService 中使用 App.GetService 问题
|
||||||
services.AddHostedService<GenericHostLifetimeEventsHostedService>();
|
services.AddHostedService<GenericHostLifetimeEventsHostedService>();
|
||||||
|
|
||||||
// 注册 Startup 过滤器
|
if (WebEnableVariable.WebEnable == true)
|
||||||
services.AddTransient<IStartupFilter, StartupFilter>();
|
{
|
||||||
|
// 注册 Startup 过滤器
|
||||||
|
services.AddTransient<IStartupFilter, StartupFilter>();
|
||||||
|
|
||||||
// 注册 HttpContextAccessor 服务
|
// 注册 HttpContextAccessor 服务
|
||||||
services.AddHttpContextAccessor();
|
services.AddHttpContextAccessor();
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化应用服务
|
// 初始化应用服务
|
||||||
services.AddApp();
|
services.AddApp();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace ThingsGateway;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class AppSettingsOptions : IConfigurableOptions<AppSettingsOptions>
|
public sealed class AppSettingsOptions : IConfigurableOptions<AppSettingsOptions>
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否启用规范化文档
|
/// 是否启用规范化文档
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
341
src/Admin/ThingsGateway.Furion/App/Options/MiniRunOptions.cs
Normal file
341
src/Admin/ThingsGateway.Furion/App/Options/MiniRunOptions.cs
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// 版权信息
|
||||||
|
// 版权归百小僧及百签科技(广东)有限公司所有。
|
||||||
|
// 所有权利保留。
|
||||||
|
// 官方网站:https://baiqian.com
|
||||||
|
//
|
||||||
|
// 许可证信息
|
||||||
|
// 项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。
|
||||||
|
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
using ThingsGateway;
|
||||||
|
|
||||||
|
namespace System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="WebApplication"/> 方式配置选项
|
||||||
|
/// </summary>
|
||||||
|
[SuppressSniffer]
|
||||||
|
public sealed class MiniRunOptions : IRunOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内部构造函数
|
||||||
|
/// </summary>
|
||||||
|
internal MiniRunOptions()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认配置
|
||||||
|
/// </summary>
|
||||||
|
public static MiniRunOptions Default { get; } = new MiniRunOptions();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认配置(带启动参数)
|
||||||
|
/// </summary>
|
||||||
|
public static MiniRunOptions Main(string[] args)
|
||||||
|
{
|
||||||
|
return Default.WithArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认配置(静默启动)
|
||||||
|
/// </summary>
|
||||||
|
public static MiniRunOptions DefaultSilence { get; } = new MiniRunOptions().Silence();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认配置(静默启动 + 启动参数)
|
||||||
|
/// </summary>
|
||||||
|
public static MiniRunOptions MainSilence(string[] args)
|
||||||
|
{
|
||||||
|
return DefaultSilence.WithArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置 <see cref="WebApplicationOptions"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <returns><see cref="MiniRunOptions"/></returns>
|
||||||
|
public MiniRunOptions ConfigureOptions(WebApplicationOptions options)
|
||||||
|
{
|
||||||
|
Options = options;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置 <see cref="IWebHostBuilder"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configureAction"></param>
|
||||||
|
/// <returns><see cref="MiniRunOptions"/></returns>
|
||||||
|
public MiniRunOptions ConfigureBuilder(Action<IWebHostBuilder> configureAction)
|
||||||
|
{
|
||||||
|
ActionBuilder = configureAction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 配置 <see cref="IHostBuilder"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configureAction"></param>
|
||||||
|
/// <returns><see cref="MiniRunOptions"/></returns>
|
||||||
|
public MiniRunOptions ConfigureFirstActionBuilder(Action<IHostBuilder> configureAction)
|
||||||
|
{
|
||||||
|
FirstActionBuilder = configureAction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置 <see cref="IServiceCollection"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configureAction"></param>
|
||||||
|
/// <returns><see cref="MiniRunOptions"/></returns>
|
||||||
|
public MiniRunOptions ConfigureServices(Action<IServiceCollection> configureAction)
|
||||||
|
{
|
||||||
|
ActionServices = configureAction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置 <see cref="InjectOptions"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configureAction"></param>
|
||||||
|
/// <returns><see cref="MiniRunOptions"/></returns>
|
||||||
|
public MiniRunOptions ConfigureInject(Action<IWebHostBuilder, InjectOptions> configureAction)
|
||||||
|
{
|
||||||
|
ActionInject = configureAction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置 <see cref="WebApplication"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configureAction">配置委托</param>
|
||||||
|
/// <returns><see cref="MiniRunOptions"/></returns>
|
||||||
|
public MiniRunOptions Configure(Action<IHost> configureAction)
|
||||||
|
{
|
||||||
|
ActionConfigure = configureAction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置 <see cref="ConfigurationManager"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configureAction">配置委托</param>
|
||||||
|
/// <returns><see cref="MiniRunOptions"/></returns>
|
||||||
|
public MiniRunOptions ConfigureConfiguration(Action<IHostEnvironment, IConfiguration> configureAction)
|
||||||
|
{
|
||||||
|
ActionConfigurationManager = configureAction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加应用服务组件
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TComponent">组件类型</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions AddComponent<TComponent>()
|
||||||
|
where TComponent : class, IServiceComponent, new()
|
||||||
|
{
|
||||||
|
ServiceComponents.Add(typeof(TComponent), null);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加应用服务组件
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TComponent">组件类型</typeparam>
|
||||||
|
/// <typeparam name="TComponentOptions"></typeparam>
|
||||||
|
/// <param name="options">组件参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions AddComponent<TComponent, TComponentOptions>(TComponentOptions options)
|
||||||
|
where TComponent : class, IServiceComponent, new()
|
||||||
|
{
|
||||||
|
ServiceComponents.Add(typeof(TComponent), options);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加应用服务组件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="componentType">组件类型</param>
|
||||||
|
/// <param name="options">组件参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions AddComponent(Type componentType, object options)
|
||||||
|
{
|
||||||
|
ServiceComponents.Add(componentType, options);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加应用中间件组件
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TComponent">组件类型</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions UseComponent<TComponent>()
|
||||||
|
where TComponent : class, IApplicationComponent, new()
|
||||||
|
{
|
||||||
|
ApplicationComponents.Add(typeof(TComponent), null);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加应用中间件组件
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TComponent">组件类型</typeparam>
|
||||||
|
/// <typeparam name="TComponentOptions"></typeparam>
|
||||||
|
/// <param name="options">组件参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions UseComponent<TComponent, TComponentOptions>(TComponentOptions options)
|
||||||
|
where TComponent : class, IApplicationComponent, new()
|
||||||
|
{
|
||||||
|
ApplicationComponents.Add(typeof(TComponent), options);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加应用中间件组件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="componentType">组件类型</param>
|
||||||
|
/// <param name="options">组件参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions UseComponent(Type componentType, object options)
|
||||||
|
{
|
||||||
|
ApplicationComponents.Add(componentType, options);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加 IWebHostBuilder 组件
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TComponent">组件类型</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions AddWebComponent<TComponent>()
|
||||||
|
where TComponent : class, IWebComponent, new()
|
||||||
|
{
|
||||||
|
WebComponents.Add(typeof(TComponent), null);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加 IWebHostBuilder 组件
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TComponent">组件类型</typeparam>
|
||||||
|
/// <typeparam name="TComponentOptions"></typeparam>
|
||||||
|
/// <param name="options">组件参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions AddWebComponent<TComponent, TComponentOptions>(TComponentOptions options)
|
||||||
|
where TComponent : class, IWebComponent, new()
|
||||||
|
{
|
||||||
|
WebComponents.Add(typeof(TComponent), options);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加 IWebHostBuilder 组件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="componentType">组件类型</param>
|
||||||
|
/// <param name="options">组件参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions AddWebComponent(Type componentType, object options)
|
||||||
|
{
|
||||||
|
WebComponents.Add(componentType, options);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标识主机静默启动
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>不阻塞程序运行</remarks>
|
||||||
|
/// <param name="silence">静默启动</param>
|
||||||
|
/// <param name="logging">静默启动日志状态,默认 false</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions Silence(bool silence = true, bool logging = false)
|
||||||
|
{
|
||||||
|
IsSilence = silence;
|
||||||
|
SilenceLogging = logging;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置进程启动参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">启动参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public MiniRunOptions WithArgs(string[] args)
|
||||||
|
{
|
||||||
|
Args = args;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="WebApplicationOptions"/>
|
||||||
|
/// </summary>
|
||||||
|
internal WebApplicationOptions Options { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义 <see cref="IServiceCollection"/> 委托
|
||||||
|
/// </summary>
|
||||||
|
internal Action<IServiceCollection> ActionServices { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义 <see cref="IWebHostBuilder"/> 委托
|
||||||
|
/// </summary>
|
||||||
|
internal Action<IHostBuilder> FirstActionBuilder { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义 <see cref="IWebHostBuilder"/> 委托
|
||||||
|
/// </summary>
|
||||||
|
internal Action<IWebHostBuilder> ActionBuilder { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义 <see cref="InjectOptions"/> 委托
|
||||||
|
/// </summary>
|
||||||
|
internal Action<IWebHostBuilder, InjectOptions> ActionInject { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义 <see cref="IHost"/> 委托
|
||||||
|
/// </summary>
|
||||||
|
internal Action<IHost> ActionConfigure { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自定义 <see cref="IConfiguration"/> 委托
|
||||||
|
/// </summary>
|
||||||
|
internal Action<IHostEnvironment, IConfiguration> ActionConfigurationManager { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用服务组件
|
||||||
|
/// </summary>
|
||||||
|
internal Dictionary<Type, object> ServiceComponents { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IWebHostBuilder 组件
|
||||||
|
/// </summary>
|
||||||
|
internal Dictionary<Type, object> WebComponents { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用中间件组件
|
||||||
|
/// </summary>
|
||||||
|
internal Dictionary<Type, object> ApplicationComponents { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 静默启动
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>不阻塞程序运行</remarks>
|
||||||
|
internal bool IsSilence { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 静默启动日志状态
|
||||||
|
/// </summary>
|
||||||
|
internal bool SilenceLogging { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 命令行参数
|
||||||
|
/// </summary>
|
||||||
|
internal string[] Args { get; set; }
|
||||||
|
}
|
||||||
@@ -602,6 +602,33 @@ public static class Serve
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动 WebApplication 主机
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>未包含 Web 基础功能,需手动注册服务/中间件</remarks>
|
||||||
|
/// <param name="options">配置选项</param>
|
||||||
|
/// <param name="urls">默认 5000/5001 端口</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns><see cref="IHost"/></returns>
|
||||||
|
public static async Task<IHost> RunAsync(MiniRunOptions options, string urls = default, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
// 构建 WebApplication 对象
|
||||||
|
BuildMiniApplication(options, urls, out var app);
|
||||||
|
|
||||||
|
// 是否静默启动
|
||||||
|
if (!options.IsSilence)
|
||||||
|
{
|
||||||
|
// 配置启动地址和端口
|
||||||
|
await app.RunAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await app.StartAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建 WebApplication 对象
|
/// 构建 WebApplication 对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -616,8 +643,8 @@ public static class Serve
|
|||||||
|
|
||||||
// 初始化 WebApplicationBuilder
|
// 初始化 WebApplicationBuilder
|
||||||
var builder = (options.Options == null
|
var builder = (options.Options == null
|
||||||
? WebApplication.CreateBuilder(args)
|
? WebApplication.CreateBuilder(args)
|
||||||
: WebApplication.CreateBuilder(options.Options));
|
: WebApplication.CreateBuilder(options.Options));
|
||||||
|
|
||||||
// 调用自定义配置服务
|
// 调用自定义配置服务
|
||||||
options?.FirstActionBuilder?.Invoke(builder);
|
options?.FirstActionBuilder?.Invoke(builder);
|
||||||
@@ -799,6 +826,132 @@ public static class Serve
|
|||||||
App.AppStartups.Clear();
|
App.AppStartups.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建 IHost 对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">配置选项</param>
|
||||||
|
/// <param name="urls">默认 5000/5001 端口</param>
|
||||||
|
/// <param name="app"><see cref="IHost"/></param>
|
||||||
|
public static void BuildMiniApplication(MiniRunOptions options, string urls, out IHost app)
|
||||||
|
{
|
||||||
|
// 获取命令行参数
|
||||||
|
var args = options.Args ?? Environment.GetCommandLineArgs().Skip(1).ToArray();
|
||||||
|
|
||||||
|
|
||||||
|
var builder = Host.CreateDefaultBuilder(args);
|
||||||
|
|
||||||
|
// 静默启动排除指定日志类名
|
||||||
|
if (options.IsSilence && !options.SilenceLogging)
|
||||||
|
{
|
||||||
|
builder = builder.ConfigureLogging(logging =>
|
||||||
|
{
|
||||||
|
logging.AddFilter((provider, category, logLevel) => !SilenceExcludesOfLogCategoryName.Any(u => category.StartsWith(u)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 配置 Web 主机
|
||||||
|
builder = builder.ConfigureWebHost(webHostBuilder =>
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// 调用自定义配置服务
|
||||||
|
options?.FirstActionBuilder?.Invoke(builder);
|
||||||
|
|
||||||
|
// 注册 WebApplicationBuilder 组件
|
||||||
|
if (options.WebComponents.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var (componentType, opt) in options.WebComponents)
|
||||||
|
{
|
||||||
|
webHostBuilder.AddWebComponent(componentType, opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
webHostBuilder.Configure((WebHostBuilderContext app, IApplicationBuilder applicationBuilder) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
// 添加自定义配置
|
||||||
|
options.ActionConfigurationManager?.Invoke(app.HostingEnvironment, app.Configuration);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化框架
|
||||||
|
webHostBuilder.Inject(options.ActionInject);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 配置服务
|
||||||
|
if (options.ServiceComponents.Count > 0)
|
||||||
|
{
|
||||||
|
webHostBuilder = webHostBuilder.ConfigureServices(services =>
|
||||||
|
{
|
||||||
|
// 注册应用服务组件
|
||||||
|
foreach (var (componentType, opt) in options.ServiceComponents)
|
||||||
|
{
|
||||||
|
services.AddComponent(componentType, opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置启动地址和端口
|
||||||
|
var startUrls = !string.IsNullOrWhiteSpace(urls) ? urls : webHostBuilder.GetSetting(nameof(urls));
|
||||||
|
|
||||||
|
// 自定义启动端口
|
||||||
|
if (!string.IsNullOrWhiteSpace(startUrls))
|
||||||
|
{
|
||||||
|
webHostBuilder = webHostBuilder.UseUrls(startUrls);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 调用自定义配置
|
||||||
|
options?.ActionBuilder?.Invoke(webHostBuilder);
|
||||||
|
|
||||||
|
// 配置中间件
|
||||||
|
if (options.ApplicationComponents.Count > 0)
|
||||||
|
{
|
||||||
|
webHostBuilder = webHostBuilder.Configure((context, app) =>
|
||||||
|
{
|
||||||
|
// 注册应用中间件组件
|
||||||
|
foreach (var (componentType, opt) in options.ApplicationComponents)
|
||||||
|
{
|
||||||
|
app.UseComponent(context.HostingEnvironment, componentType, opt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
builder = builder.ConfigureServices(services =>
|
||||||
|
{
|
||||||
|
// 调用自定义配置服务
|
||||||
|
options?.ActionServices?.Invoke(services);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 构建主机
|
||||||
|
app = builder.Build();
|
||||||
|
|
||||||
|
InternalApp.RootServices ??= app.Services;
|
||||||
|
|
||||||
|
var applicationPartManager = app.Services.GetService<ApplicationPartManager>();
|
||||||
|
|
||||||
|
applicationPartManager?.ApplicationParts?.RemoveWhere(p => App.BakImageNames.Any(b => b == p.Name));
|
||||||
|
// 配置所有 Starup Configure
|
||||||
|
UseStartups(app.Services);
|
||||||
|
// 释放内存
|
||||||
|
App.AppStartups.Clear();
|
||||||
|
// 调用自定义配置
|
||||||
|
options?.ActionConfigure?.Invoke(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建 IHost 对象
|
/// 构建 IHost 对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -127,7 +127,8 @@ public sealed class DatabaseLogger : ILogger, IDisposable
|
|||||||
// 设置日志消息模板
|
// 设置日志消息模板
|
||||||
logMsg.Message = _options.MessageFormat != null
|
logMsg.Message = _options.MessageFormat != null
|
||||||
? _options.MessageFormat(logMsg)
|
? _options.MessageFormat(logMsg)
|
||||||
: Penetrates.OutputStandardMessage(logMsg, _options.DateFormat, withTraceId: _options.WithTraceId, withStackFrame: _options.WithStackFrame, provider: _options.FormatProvider);
|
: string.Empty;
|
||||||
|
//: Penetrates.OutputStandardMessage(logMsg, _options.DateFormat, withTraceId: _options.WithTraceId, withStackFrame: _options.WithStackFrame, provider: _options.FormatProvider);
|
||||||
|
|
||||||
// 空检查
|
// 空检查
|
||||||
if (logMsg.Message is null)
|
if (logMsg.Message is null)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -683,13 +683,20 @@ public class MachineInfo : IExtend
|
|||||||
if (dic.TryGetValue("MemTotal", out var str) && !str.IsNullOrEmpty())
|
if (dic.TryGetValue("MemTotal", out var str) && !str.IsNullOrEmpty())
|
||||||
Memory = (UInt64)str.TrimEnd(" kB").ToLong();
|
Memory = (UInt64)str.TrimEnd(" kB").ToLong();
|
||||||
|
|
||||||
|
ulong ma = 0;
|
||||||
if (dic.TryGetValue("MemAvailable", out str) && !str.IsNullOrEmpty())
|
if (dic.TryGetValue("MemAvailable", out str) && !str.IsNullOrEmpty())
|
||||||
AvailableMemory = (UInt64)str.TrimEnd(" kB").ToLong();
|
{
|
||||||
else if (dic.TryGetValue("MemFree", out str) && !str.IsNullOrEmpty())
|
ma = (UInt64)(str.TrimEnd(" kB").ToLong());
|
||||||
AvailableMemory =
|
}
|
||||||
(UInt64)(str.TrimEnd(" kB").ToLong() +
|
|
||||||
dic["Buffers"]?.TrimEnd(" kB").ToLong() ?? 0 +
|
//低于3.14内核的版本用 free+cache
|
||||||
dic["Cached"]?.TrimEnd(" kB").ToLong() ?? 0);
|
var mf = (UInt64)(dic["MemFree"]?.TrimEnd(" kB").ToLong() ?? 0);
|
||||||
|
var mc = (UInt64)(dic["Cached"]?.TrimEnd(" kB").ToLong() ?? 0);
|
||||||
|
var bf = (UInt64)(dic["Buffers"]?.TrimEnd(" kB").ToLong() ?? 0);
|
||||||
|
|
||||||
|
var free = mf + mc + bf;
|
||||||
|
|
||||||
|
AvailableMemory = ma > free ? ma : free;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A2/A4温度获取,Buildroot,CPU温度和主板温度
|
// A2/A4温度获取,Buildroot,CPU温度和主板温度
|
||||||
|
|||||||
@@ -190,7 +190,31 @@ public sealed class Crc32 //: HashAlgorithm
|
|||||||
crc.Update(stream, count);
|
crc.Update(stream, count);
|
||||||
return crc.Value;
|
return crc.Value;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 添加Sequence进行校验
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sequence"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Crc32 Update(ReadOnlySequence<byte> sequence)
|
||||||
|
{
|
||||||
|
foreach (var segment in sequence)
|
||||||
|
{
|
||||||
|
Update(segment.Span);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算校验码 (Sequence)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sequence"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static UInt32 Compute(ReadOnlySequence<byte> sequence)
|
||||||
|
{
|
||||||
|
var crc = new Crc32();
|
||||||
|
crc.Update(sequence);
|
||||||
|
return crc.Value;
|
||||||
|
}
|
||||||
//#region 抽象实现
|
//#region 抽象实现
|
||||||
///// <summary>哈希核心</summary>
|
///// <summary>哈希核心</summary>
|
||||||
///// <param name="array"></param>
|
///// <param name="array"></param>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<SignAssembly>True</SignAssembly>
|
<SignAssembly>True</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>newlife.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>newlife.snk</AssemblyOriginatorKeyFile>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -306,8 +306,19 @@ public class TimerScheduler : ILogFeature
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var func = timer.Method.As<Func<Object?, Task>>(target);
|
#if NET6_0_OR_GREATER
|
||||||
await func!(timer.State).ConfigureAwait(false);
|
if (timer.IsValueTask)
|
||||||
|
{
|
||||||
|
var func = timer.Method.As<Func<Object?, ValueTask>>(target);
|
||||||
|
await func!(timer.State).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
var func = timer.Method.As<Func<Object?, Task>>(target);
|
||||||
|
await func!(timer.State).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (ThreadAbortException) { throw; }
|
catch (ThreadAbortException) { throw; }
|
||||||
catch (ThreadInterruptedException) { throw; }
|
catch (ThreadInterruptedException) { throw; }
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ public class TimerX : ITimer, ITimerx, IDisposable
|
|||||||
|
|
||||||
private DateTime _AbsolutelyNext;
|
private DateTime _AbsolutelyNext;
|
||||||
private readonly Cron[]? _crons;
|
private readonly Cron[]? _crons;
|
||||||
|
|
||||||
|
internal bool IsValueTask { get; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// #region 静态
|
// #region 静态
|
||||||
@@ -158,6 +160,29 @@ public class TimerX : ITimer, ITimerx, IDisposable
|
|||||||
Init(dueTime);
|
Init(dueTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
|
||||||
|
/// <summary>实例化一个不可重入的定时器</summary>
|
||||||
|
/// <param name="callback">委托</param>
|
||||||
|
/// <param name="state">用户数据</param>
|
||||||
|
/// <param name="dueTime">多久之后开始。毫秒</param>
|
||||||
|
/// <param name="period">间隔周期。毫秒</param>
|
||||||
|
/// <param name="scheduler">调度器</param>
|
||||||
|
public TimerX(Func<Object, ValueTask> callback, Object? state, Int32 dueTime, Int32 period, String? scheduler = null) : this(callback.Target, callback.Method, state, scheduler)
|
||||||
|
{
|
||||||
|
IsValueTask = true;
|
||||||
|
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
||||||
|
if (dueTime < 0) throw new ArgumentOutOfRangeException(nameof(dueTime));
|
||||||
|
|
||||||
|
IsAsyncTask = true;
|
||||||
|
Async = true;
|
||||||
|
Period = period;
|
||||||
|
|
||||||
|
Init(dueTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>实例化一个绝对定时器,指定时刻执行,跟当前时间和SetNext无关</summary>
|
/// <summary>实例化一个绝对定时器,指定时刻执行,跟当前时间和SetNext无关</summary>
|
||||||
/// <param name="callback">委托</param>
|
/// <param name="callback">委托</param>
|
||||||
/// <param name="state">用户数据</param>
|
/// <param name="state">用户数据</param>
|
||||||
@@ -210,6 +235,37 @@ public class TimerX : ITimer, ITimerx, IDisposable
|
|||||||
Init(ms);
|
Init(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
|
||||||
|
/// <summary>实例化一个绝对定时器,指定时刻执行,跟当前时间和SetNext无关</summary>
|
||||||
|
/// <param name="callback">委托</param>
|
||||||
|
/// <param name="state">用户数据</param>
|
||||||
|
/// <param name="startTime">绝对开始时间</param>
|
||||||
|
/// <param name="period">间隔周期。毫秒</param>
|
||||||
|
/// <param name="scheduler">调度器</param>
|
||||||
|
public TimerX(Func<Object, ValueTask> callback, Object? state, DateTime startTime, Int32 period, String? scheduler = null) : this(callback.Target, callback.Method, state, scheduler)
|
||||||
|
{
|
||||||
|
IsValueTask = true;
|
||||||
|
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
||||||
|
if (startTime <= DateTime.MinValue) throw new ArgumentOutOfRangeException(nameof(startTime));
|
||||||
|
if (period <= 0) throw new ArgumentOutOfRangeException(nameof(period));
|
||||||
|
|
||||||
|
IsAsyncTask = true;
|
||||||
|
Async = true;
|
||||||
|
Period = period;
|
||||||
|
Absolutely = true;
|
||||||
|
|
||||||
|
//var now = DateTime.Now;
|
||||||
|
var now = Scheduler.GetNow();
|
||||||
|
var next = startTime;
|
||||||
|
while (next < now) next = next.AddMilliseconds(period);
|
||||||
|
|
||||||
|
var ms = (Int64)(next - now).TotalMilliseconds;
|
||||||
|
_AbsolutelyNext = next;
|
||||||
|
Init(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
/// <summary>实例化一个Cron定时器</summary>
|
/// <summary>实例化一个Cron定时器</summary>
|
||||||
/// <param name="callback">委托</param>
|
/// <param name="callback">委托</param>
|
||||||
/// <param name="state">用户数据</param>
|
/// <param name="state">用户数据</param>
|
||||||
@@ -274,6 +330,42 @@ public class TimerX : ITimer, ITimerx, IDisposable
|
|||||||
//Init(_AbsolutelyNext = _cron.GetNext(DateTime.Now));
|
//Init(_AbsolutelyNext = _cron.GetNext(DateTime.Now));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NET6_0_OR_GREATER
|
||||||
|
/// <summary>实例化一个Cron定时器</summary>
|
||||||
|
/// <param name="callback">委托</param>
|
||||||
|
/// <param name="state">用户数据</param>
|
||||||
|
/// <param name="cronExpression">Cron表达式。支持多个表达式,分号分隔</param>
|
||||||
|
/// <param name="scheduler">调度器</param>
|
||||||
|
public TimerX(Func<Object, ValueTask> callback, Object? state, String cronExpression, String? scheduler = null) : this(callback.Target, callback.Method, state, scheduler)
|
||||||
|
{
|
||||||
|
IsValueTask = true;
|
||||||
|
if (callback == null) throw new ArgumentNullException(nameof(callback));
|
||||||
|
if (cronExpression.IsNullOrEmpty()) throw new ArgumentNullException(nameof(cronExpression));
|
||||||
|
|
||||||
|
var list = new List<Cron>();
|
||||||
|
foreach (var item in cronExpression.Split(";"))
|
||||||
|
{
|
||||||
|
var cron = new Cron();
|
||||||
|
if (!cron.Parse(item)) throw new ArgumentException($"Invalid Cron expression[{item}]", nameof(cronExpression));
|
||||||
|
|
||||||
|
list.Add(cron);
|
||||||
|
}
|
||||||
|
_crons = list.ToArray();
|
||||||
|
|
||||||
|
IsAsyncTask = true;
|
||||||
|
Async = true;
|
||||||
|
Absolutely = true;
|
||||||
|
|
||||||
|
//var now = DateTime.Now;
|
||||||
|
var now = Scheduler.GetNow();
|
||||||
|
var next = _crons.Min(e => e.GetNext(now));
|
||||||
|
var ms = (Int64)(next - now).TotalMilliseconds;
|
||||||
|
_AbsolutelyNext = next;
|
||||||
|
Init(ms);
|
||||||
|
//Init(_AbsolutelyNext = _cron.GetNext(DateTime.Now));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public bool Disposed { get; private set; }
|
public bool Disposed { get; private set; }
|
||||||
/// <summary>销毁定时器</summary>
|
/// <summary>销毁定时器</summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
// QQ群:605534569
|
// QQ群:605534569
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
using ThingsGateway.Common.Extension;
|
|
||||||
using ThingsGateway.NewLife;
|
using ThingsGateway.NewLife;
|
||||||
|
using ThingsGateway.Razor.Extension;
|
||||||
|
|
||||||
namespace ThingsGateway.Razor;
|
namespace ThingsGateway.Razor;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<Step @ref="@step" IsVertical="true">
|
<Step @ref="@step" IsVertical="true">
|
||||||
<StepItem Text=@Localizer["First"] Title=@Localizer["Upload"]>
|
<StepItem Text=@Localizer["First"] Title=@Localizer["Upload"]>
|
||||||
<InputUpload ShowDeleteButton="true" @bind-Value=_importFile Accept=".xlsx"></InputUpload>
|
<InputUpload ShowDeleteButton="true" @bind-Value=_importFile Accept=".xlsx"></InputUpload>
|
||||||
<Button class="mt-2" IsAsync OnClick="() => DeviceImport(_importFile)">@Localizer["Validate"]</Button>
|
<PopConfirmButton IsAsync Color=Color.Warning class="mt-2" OnConfirm=@(SaveDeviceImport)>@Localizer["Import"]</PopConfirmButton>
|
||||||
</StepItem>
|
</StepItem>
|
||||||
<StepItem Text=@Localizer["Second"] Title=@Localizer["ValidateText"]>
|
<StepItem Text=@Localizer["Second"] Title=@Localizer["ValidateText"]>
|
||||||
|
|
||||||
@@ -41,16 +41,12 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<PopConfirmButton IsAsync IsDisabled=@_importPreviews.Any(it => it.Value.HasError) Color=Color.Warning class="mt-2" OnConfirm=@(SaveDeviceImport)>@Localizer["Import"]</PopConfirmButton>
|
<Button class="mt-2" IsAsync OnClick="() => DeviceImport()">@RazorLocalizer["Close"]</Button>
|
||||||
|
|
||||||
@*
|
|
||||||
<Button IsAsync class="mt-2" IsDisabled=@_importPreviews.Any(it => it.Value.HasError) OnClick="() => step.Next()">@Localizer["Next"]</Button> *@
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</StepItem>
|
</StepItem>
|
||||||
@* <StepItem Text=@Localizer["Third"] Title=@Localizer["Import"]>
|
|
||||||
<PopConfirmButton IsAsync Color=Color.Warning class="mt-2" OnConfirm=@(SaveDeviceImport)>@Localizer["Import"]</PopConfirmButton>
|
|
||||||
</StepItem> *@
|
|
||||||
</Step>
|
</Step>
|
||||||
@code {
|
@code {
|
||||||
[NotNull]
|
[NotNull]
|
||||||
|
|||||||
@@ -24,18 +24,17 @@ public partial class ImportExcel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[EditorRequired]
|
[EditorRequired]
|
||||||
public Func<Dictionary<string, ImportPreviewOutputBase>, Task> Import { get; set; }
|
public Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> Import { get; set; }
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
[NotNull]
|
[NotNull]
|
||||||
private IStringLocalizer<ImportExcel>? Localizer { get; set; }
|
private IStringLocalizer<ImportExcel>? Localizer { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
[Inject]
|
||||||
/// 预览
|
[NotNull]
|
||||||
/// </summary>
|
private IStringLocalizer<ThingsGateway.Razor._Imports>? RazorLocalizer { get; set; }
|
||||||
[Parameter]
|
|
||||||
[EditorRequired]
|
|
||||||
public Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> Preview { get; set; }
|
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
[NotNull]
|
[NotNull]
|
||||||
@@ -47,13 +46,17 @@ public partial class ImportExcel
|
|||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
private Func<Task>? OnCloseAsync { get; set; }
|
private Func<Task>? OnCloseAsync { get; set; }
|
||||||
|
|
||||||
private async Task DeviceImport(IBrowserFile file)
|
private async Task DeviceImport()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_importPreviews.Clear();
|
_importPreviews.Clear();
|
||||||
_importPreviews = await Preview.Invoke(file);
|
await InvokeAsync(async () =>
|
||||||
await step.Next();
|
{
|
||||||
|
if (OnCloseAsync != null)
|
||||||
|
await OnCloseAsync();
|
||||||
|
await ToastService.Default();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -67,16 +70,12 @@ public partial class ImportExcel
|
|||||||
{
|
{
|
||||||
await Task.Run(async () =>
|
await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Import.Invoke(_importPreviews);
|
_importPreviews = await Import.Invoke(_importFile);
|
||||||
_importFile = null;
|
_importFile = null;
|
||||||
|
|
||||||
await InvokeAsync(async () =>
|
|
||||||
{
|
|
||||||
if (OnCloseAsync != null)
|
|
||||||
await OnCloseAsync();
|
|
||||||
await ToastService.Default();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
await step.Next();
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
@using ThingsGateway.Extension
|
||||||
|
@namespace ThingsGateway.Razor
|
||||||
|
<Button OnClick="() => step.Reset()">@Localizer["Reset"]</Button>
|
||||||
|
<h6 class="my-3 green--text">@Localizer["Tip"] </h6>
|
||||||
|
<Step @ref="@step" IsVertical="true">
|
||||||
|
<StepItem Text=@Localizer["First"] Title=@Localizer["Upload"]>
|
||||||
|
<InputUpload ShowDeleteButton="true" @bind-Value=_importFile Accept=".xlsx"></InputUpload>
|
||||||
|
<Button class="mt-2" IsAsync OnClick="() => DeviceImport(_importFile)">@Localizer["Validate"]</Button>
|
||||||
|
</StepItem>
|
||||||
|
<StepItem Text=@Localizer["Second"] Title=@Localizer["ValidateText"]>
|
||||||
|
|
||||||
|
<div class="overflow-y-auto">
|
||||||
|
|
||||||
|
@foreach (var item in _importPreviews)
|
||||||
|
{
|
||||||
|
<div class="mt-2">
|
||||||
|
@(
|
||||||
|
Localizer["UploadCount", item.Key, item.Value.DataCount]
|
||||||
|
)
|
||||||
|
</div>
|
||||||
|
<div class=@((item.Value.HasError ? "my-2 red--text" : "my-2 green--text"))>
|
||||||
|
@(
|
||||||
|
(item.Value.HasError ? "Error" : "Success")
|
||||||
|
)
|
||||||
|
</div>
|
||||||
|
if (item.Value.HasError)
|
||||||
|
{
|
||||||
|
<div style="height:300px;" class="overflow-y-scroll">
|
||||||
|
<Virtualize Items="item.Value.Results.Where(a => !a.Success).OrderBy(a => a.Row).ToList()" Context="item1" ItemSize="60" OverscanCount=2>
|
||||||
|
<ItemContent>
|
||||||
|
<div class="row g-0">
|
||||||
|
<span class="col mx-2">@item1.Row</span>
|
||||||
|
<span class=@((item1.Success ? "green--text col-auto" : "red--text col-auto"))>
|
||||||
|
<strong>@item1.ErrorMessage</strong>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</ItemContent>
|
||||||
|
</Virtualize>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
<PopConfirmButton IsAsync IsKeepDisabled=@_importPreviews.Any(it => it.Value.HasError) Color=Color.Warning class="mt-2" OnConfirm=@(SaveDeviceImport)>@Localizer["Import"]</PopConfirmButton>
|
||||||
|
|
||||||
|
@*
|
||||||
|
<Button IsAsync class="mt-2" IsDisabled=@_importPreviews.Any(it => it.Value.HasError) OnClick="() => step.Next()">@Localizer["Next"]</Button> *@
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</StepItem>
|
||||||
|
@* <StepItem Text=@Localizer["Third"] Title=@Localizer["Import"]>
|
||||||
|
<PopConfirmButton IsAsync Color=Color.Warning class="mt-2" OnConfirm=@(SaveDeviceImport)>@Localizer["Import"]</PopConfirmButton>
|
||||||
|
</StepItem> *@
|
||||||
|
</Step>
|
||||||
|
@code {
|
||||||
|
[NotNull]
|
||||||
|
Step? step { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||||
|
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||||
|
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||||
|
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||||
|
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||||
|
// 使用文档:https://thingsgateway.cn/
|
||||||
|
// QQ群:605534569
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace ThingsGateway.Razor;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class ImportExcelConfirm
|
||||||
|
{
|
||||||
|
private Dictionary<string, ImportPreviewOutputBase> _importPreviews = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导入
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
[EditorRequired]
|
||||||
|
public Func<Dictionary<string, ImportPreviewOutputBase>, Task> Import { get; set; }
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
[NotNull]
|
||||||
|
private IStringLocalizer<ImportExcelConfirm>? Localizer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 预览
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
[EditorRequired]
|
||||||
|
public Func<IBrowserFile, Task<Dictionary<string, ImportPreviewOutputBase>>> Preview { get; set; }
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
[NotNull]
|
||||||
|
private ToastService? ToastService { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
private IBrowserFile _importFile { get; set; }
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
private Func<Task>? OnCloseAsync { get; set; }
|
||||||
|
|
||||||
|
private async Task DeviceImport(IBrowserFile file)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importPreviews.Clear();
|
||||||
|
_importPreviews = await Preview.Invoke(file);
|
||||||
|
await step.Next();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await ToastService.Warn(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveDeviceImport()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Import.Invoke(_importPreviews);
|
||||||
|
_importFile = null;
|
||||||
|
|
||||||
|
await InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
if (OnCloseAsync != null)
|
||||||
|
await OnCloseAsync();
|
||||||
|
await ToastService.Default();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await InvokeAsync(async () => await ToastService.Warn(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
::deep .avatar {
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
background-color: var(--bs-red);
|
||||||
|
color: #fff;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
@namespace ThingsGateway.Razor
|
||||||
|
|
||||||
|
@if (show)
|
||||||
|
{
|
||||||
|
<Spinner class="ms-auto"></Spinner>
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
// QQ群:605534569
|
// QQ群:605534569
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace ThingsGateway.Gateway.Razor;
|
namespace ThingsGateway.Razor;
|
||||||
|
|
||||||
public partial class SpinnerComponent
|
public partial class SpinnerComponent
|
||||||
{
|
{
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
|
|
||||||
namespace ThingsGateway.Common.Extension;
|
namespace ThingsGateway.Razor.Extension;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// JSRuntime扩展方法
|
/// JSRuntime扩展方法
|
||||||
@@ -49,4 +49,28 @@ public static class JSRuntimeExtensions
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async ValueTask<T> GetLocalStorage<T>(this IJSRuntime jsRuntime, string name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await jsRuntime.InvokeAsync<T>("getLocalStorage", name).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async ValueTask SetLocalStorage<T>(this IJSRuntime jsRuntime, string name, T data)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await jsRuntime.InvokeVoidAsync("setLocalStorage", name, data).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,8 @@
|
|||||||
"Success": "Success",
|
"Success": "Success",
|
||||||
"TablesExportButtonExcelText": "Export Excel",
|
"TablesExportButtonExcelText": "Export Excel",
|
||||||
"TablesImportButtonExcelText": "Import Excel",
|
"TablesImportButtonExcelText": "Import Excel",
|
||||||
"True": "Yes"
|
"True": "Yes",
|
||||||
|
"Info": "Info"
|
||||||
},
|
},
|
||||||
"ThingsGateway.Razor.About": {
|
"ThingsGateway.Razor.About": {
|
||||||
"Community": "Community",
|
"Community": "Community",
|
||||||
@@ -59,6 +60,19 @@
|
|||||||
"SearchText": "Search Page"
|
"SearchText": "Search Page"
|
||||||
},
|
},
|
||||||
"ThingsGateway.Razor.ImportExcel": {
|
"ThingsGateway.Razor.ImportExcel": {
|
||||||
|
"First": "Step 1",
|
||||||
|
"Import": "If there are no errors during verification, it will be directly imported into the database",
|
||||||
|
"Next": "Next",
|
||||||
|
"Reset": "Reset",
|
||||||
|
"Second": "Step 2",
|
||||||
|
"Third": "Step 3",
|
||||||
|
"Tip": "When the data volume is large (more than 200,000), the import may take more than 1 minute, please be patient",
|
||||||
|
"Upload": "Upload File",
|
||||||
|
"UploadCount": " Table {0}, import {1} records",
|
||||||
|
"Validate": "Validate",
|
||||||
|
"ValidateText": "Validation Content"
|
||||||
|
},
|
||||||
|
"ThingsGateway.Razor.ImportExcelConfirm": {
|
||||||
"First": "Step 1",
|
"First": "Step 1",
|
||||||
"Import": "Import",
|
"Import": "Import",
|
||||||
"Next": "Next",
|
"Next": "Next",
|
||||||
@@ -67,7 +81,7 @@
|
|||||||
"Third": "Step 3",
|
"Third": "Step 3",
|
||||||
"Tip": "When the data volume is large (more than 200,000), the import may take more than 1 minute, please be patient",
|
"Tip": "When the data volume is large (more than 200,000), the import may take more than 1 minute, please be patient",
|
||||||
"Upload": "Upload File",
|
"Upload": "Upload File",
|
||||||
"UploadCount": " Table {0}, expecting to import {1} records",
|
"UploadCount": " Table {0}, import {1} records",
|
||||||
"Validate": "Validate",
|
"Validate": "Validate",
|
||||||
"ValidateText": "Validation Content"
|
"ValidateText": "Validation Content"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,7 +25,8 @@
|
|||||||
"Success": "成功",
|
"Success": "成功",
|
||||||
"TablesExportButtonExcelText": "导出Excel",
|
"TablesExportButtonExcelText": "导出Excel",
|
||||||
"TablesImportButtonExcelText": "导入Excel",
|
"TablesImportButtonExcelText": "导入Excel",
|
||||||
"True": "是"
|
"True": "是",
|
||||||
|
"Info": "详情"
|
||||||
},
|
},
|
||||||
"ThingsGateway.Razor.About": {
|
"ThingsGateway.Razor.About": {
|
||||||
"Community": "社区",
|
"Community": "社区",
|
||||||
@@ -59,6 +60,19 @@
|
|||||||
"SearchText": "搜索页面"
|
"SearchText": "搜索页面"
|
||||||
},
|
},
|
||||||
"ThingsGateway.Razor.ImportExcel": {
|
"ThingsGateway.Razor.ImportExcel": {
|
||||||
|
"First": "第一步",
|
||||||
|
"Import": "若验证无错误,将直接导入数据库",
|
||||||
|
"Next": "下一步",
|
||||||
|
"Reset": "重置",
|
||||||
|
"Second": "第二步",
|
||||||
|
"Third": "第三",
|
||||||
|
"Tip": "数据量较大时(大于20万),所需导入时间可能超过1分钟,请耐心等待",
|
||||||
|
"Upload": "上传文件",
|
||||||
|
"UploadCount": " 表 {0},导入 {1} 条数据",
|
||||||
|
"Validate": "验证",
|
||||||
|
"ValidateText": "验证内容"
|
||||||
|
},
|
||||||
|
"ThingsGateway.Razor.ImportExcelConfirm": {
|
||||||
"First": "第一步",
|
"First": "第一步",
|
||||||
"Import": "导入",
|
"Import": "导入",
|
||||||
"Next": "下一步",
|
"Next": "下一步",
|
||||||
@@ -67,7 +81,7 @@
|
|||||||
"Third": "第三",
|
"Third": "第三",
|
||||||
"Tip": "数据量较大时(大于20万),所需导入时间可能超过1分钟,请耐心等待",
|
"Tip": "数据量较大时(大于20万),所需导入时间可能超过1分钟,请耐心等待",
|
||||||
"Upload": "上传文件",
|
"Upload": "上传文件",
|
||||||
"UploadCount": " 表 {0},预计导入 {1} 条数据",
|
"UploadCount": " 表 {0},导入 {1} 条数据",
|
||||||
"Validate": "验证",
|
"Validate": "验证",
|
||||||
"ValidateText": "验证内容"
|
"ValidateText": "验证内容"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<Import Project="..\..\PackNuget.props" />
|
<Import Project="..\..\PackNuget.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0</TargetFrameworks>
|
<TargetFrameworks>net8.0</TargetFrameworks>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.1.0" />
|
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.1.0" />
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
// 设置 culture
|
|
||||||
function setCultureLocalStorage(culture) {
|
|
||||||
localStorage.setItem("culture", culture);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取 culture
|
|
||||||
function getCultureLocalStorage() {
|
|
||||||
return localStorage.getItem("culture");
|
|
||||||
}
|
|
||||||
18
src/Admin/ThingsGateway.Razor/wwwroot/js/localStorageUtil.js
Normal file
18
src/Admin/ThingsGateway.Razor/wwwroot/js/localStorageUtil.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// 设置 culture
|
||||||
|
function setCultureLocalStorage(culture) {
|
||||||
|
localStorage.setItem("culture", culture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 culture
|
||||||
|
function getCultureLocalStorage() {
|
||||||
|
return localStorage.getItem("culture");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLocalStorage(name) {
|
||||||
|
return JSON.parse(localStorage.getItem(name)) ?? 0;
|
||||||
|
}
|
||||||
|
function setLocalStorage(name, data) {
|
||||||
|
if (localStorage) {
|
||||||
|
localStorage.setItem(name, JSON.stringify(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,16 +27,17 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
/// <typeparam name="T">数据类型</typeparam>
|
||||||
/// <param name="insertDatas">要插入的数据列表</param>
|
/// <param name="insertDatas">要插入的数据列表</param>
|
||||||
|
/// <param name="tableName">表名称</param>
|
||||||
/// <param name="dateFormat">日期格式字符串</param>
|
/// <param name="dateFormat">日期格式字符串</param>
|
||||||
/// <returns>插入的记录数</returns>
|
/// <returns>插入的记录数</returns>
|
||||||
public int BulkCopy<T>(IEnumerable<T> insertDatas, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
public int BulkCopy<T>(IEnumerable<T> insertDatas, string tableName = null, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
// 使用分页方式处理大数据量插入
|
// 使用分页方式处理大数据量插入
|
||||||
db.Utilities.PageEach(insertDatas, pageSize, pageItems =>
|
db.Utilities.PageEach(insertDatas, pageSize, pageItems =>
|
||||||
{
|
{
|
||||||
// 同步调用批量插入API并累加结果
|
// 同步调用批量插入API并累加结果
|
||||||
result += questDbRestAPI.BulkCopyAsync(pageItems, dateFormat).GetAwaiter().GetResult();
|
result += questDbRestAPI.BulkCopyAsync(pageItems, tableName, dateFormat).GetAwaiter().GetResult();
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -46,16 +47,17 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
/// <typeparam name="T">数据类型</typeparam>
|
||||||
/// <param name="insertDatas">要插入的数据列表</param>
|
/// <param name="insertDatas">要插入的数据列表</param>
|
||||||
|
/// <param name="tableName">表名称</param>
|
||||||
/// <param name="dateFormat">日期格式字符串</param>
|
/// <param name="dateFormat">日期格式字符串</param>
|
||||||
/// <returns>插入的记录数</returns>
|
/// <returns>插入的记录数</returns>
|
||||||
public async Task<int> BulkCopyAsync<T>(IEnumerable<T> insertDatas, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
public async Task<int> BulkCopyAsync<T>(IEnumerable<T> insertDatas, string tableName = null, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
// 异步分页处理大数据量插入
|
// 异步分页处理大数据量插入
|
||||||
await db.Utilities.PageEachAsync(insertDatas, pageSize, async pageItems =>
|
await db.Utilities.PageEachAsync(insertDatas, pageSize, async pageItems =>
|
||||||
{
|
{
|
||||||
// 异步调用批量插入API并累加结果
|
// 异步调用批量插入API并累加结果
|
||||||
result += await questDbRestAPI.BulkCopyAsync(pageItems, dateFormat).ConfigureAwait(false);
|
result += await questDbRestAPI.BulkCopyAsync(pageItems, tableName, dateFormat).ConfigureAwait(false);
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,16 +7,12 @@ namespace ThingsGateway.SqlSugar
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 绑定RestAPI需要的信息
|
/// 绑定RestAPI需要的信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void SetRestApiInfo(DbConnectionStringBuilder builder, ref string host, ref string httpPort, ref string username, ref string password)
|
public static void SetRestApiInfo(DbConnectionStringBuilder builder, ref string host, ref string username, ref string password)
|
||||||
{
|
{
|
||||||
if (builder.TryGetValue("Host", out object hostValue))
|
if (builder.TryGetValue("Host", out object hostValue))
|
||||||
{
|
{
|
||||||
host = Convert.ToString(hostValue);
|
host = Convert.ToString(hostValue);
|
||||||
}
|
}
|
||||||
if (builder.TryGetValue("HttpPort", out object httpPortValue))
|
|
||||||
{
|
|
||||||
httpPort = Convert.ToString(httpPortValue);
|
|
||||||
}
|
|
||||||
if (builder.TryGetValue("Username", out object usernameValue))
|
if (builder.TryGetValue("Username", out object usernameValue))
|
||||||
{
|
{
|
||||||
username = Convert.ToString(usernameValue);
|
username = Convert.ToString(usernameValue);
|
||||||
|
|||||||
@@ -28,16 +28,16 @@ namespace ThingsGateway.SqlSugar
|
|||||||
/// 初始化 QuestDbRestAPI 实例
|
/// 初始化 QuestDbRestAPI 实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="db">SqlSugar 数据库客户端</param>
|
/// <param name="db">SqlSugar 数据库客户端</param>
|
||||||
public QuestDbRestAPI(ISqlSugarClient db)
|
/// <param name="httpPort">restApi端口</param>
|
||||||
|
public QuestDbRestAPI(ISqlSugarClient db, int httpPort = 9000)
|
||||||
{
|
{
|
||||||
var builder = new DbConnectionStringBuilder();
|
var builder = new DbConnectionStringBuilder();
|
||||||
builder.ConnectionString = db.CurrentConnectionConfig.ConnectionString;
|
builder.ConnectionString = db.CurrentConnectionConfig.ConnectionString;
|
||||||
this.db = db;
|
this.db = db;
|
||||||
string httpPort = String.Empty;
|
|
||||||
string host = String.Empty;
|
string host = String.Empty;
|
||||||
string username = String.Empty;
|
string username = String.Empty;
|
||||||
string password = String.Empty;
|
string password = String.Empty;
|
||||||
QuestDbRestAPHelper.SetRestApiInfo(builder, ref host, ref httpPort, ref username, ref password);
|
QuestDbRestAPHelper.SetRestApiInfo(builder, ref host, ref username, ref password);
|
||||||
BindHost(host, httpPort, username, password);
|
BindHost(host, httpPort, username, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,9 +51,14 @@ namespace ThingsGateway.SqlSugar
|
|||||||
// HTTP GET 请求执行SQL
|
// HTTP GET 请求执行SQL
|
||||||
var result = string.Empty;
|
var result = string.Empty;
|
||||||
var url = $"{this.url}/exec?query={HttpUtility.UrlEncode(sql)}";
|
var url = $"{this.url}/exec?query={HttpUtility.UrlEncode(sql)}";
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
if (!string.IsNullOrWhiteSpace(authorization))
|
if (!string.IsNullOrWhiteSpace(authorization))
|
||||||
client.DefaultRequestHeaders.Add("Authorization", authorization);
|
{
|
||||||
var httpResponseMessage = await client.GetAsync(url).ConfigureAwait(false);
|
request.Headers.Authorization = AuthenticationHeaderValue.Parse(authorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var httpResponseMessage = await client.SendAsync(request).ConfigureAwait(false);
|
||||||
result = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
|
result = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -68,34 +73,34 @@ namespace ThingsGateway.SqlSugar
|
|||||||
return ExecuteCommandAsync(sql).GetAwaiter().GetResult();
|
return ExecuteCommandAsync(sql).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 异步批量插入单条数据
|
///// 异步批量插入单条数据
|
||||||
/// </summary>
|
///// </summary>
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
///// <typeparam name="T">数据类型</typeparam>
|
||||||
/// <param name="insertData">要插入的数据</param>
|
///// <param name="insertData">要插入的数据</param>
|
||||||
/// <param name="dateFormat">日期格式字符串</param>
|
///// <param name="dateFormat">日期格式字符串</param>
|
||||||
/// <returns>影响的行数</returns>
|
///// <returns>影响的行数</returns>
|
||||||
public async Task<int> BulkCopyAsync<T>(T insertData, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
//public async Task<int> BulkCopyAsync<T>(T insertData, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
||||||
{
|
//{
|
||||||
if (db.CurrentConnectionConfig.MoreSettings == null)
|
// if (db.CurrentConnectionConfig.MoreSettings == null)
|
||||||
db.CurrentConnectionConfig.MoreSettings = new ConnMoreSettings();
|
// db.CurrentConnectionConfig.MoreSettings = new ConnMoreSettings();
|
||||||
db.CurrentConnectionConfig.MoreSettings.DisableNvarchar = true;
|
// db.CurrentConnectionConfig.MoreSettings.DisableNvarchar = true;
|
||||||
var sql = db.InsertableT(insertData).ToSqlString();
|
// var sql = db.InsertableT(insertData).ToSqlString();
|
||||||
var result = await ExecuteCommandAsync(sql).ConfigureAwait(false);
|
// var result = await ExecuteCommandAsync(sql).ConfigureAwait(false);
|
||||||
return result.Contains("OK", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
|
// return result.Contains("OK", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
|
||||||
}
|
//}
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 同步批量插入单条数据
|
///// 同步批量插入单条数据
|
||||||
/// </summary>
|
///// </summary>
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
///// <typeparam name="T">数据类型</typeparam>
|
||||||
/// <param name="insertData">要插入的数据</param>
|
///// <param name="insertData">要插入的数据</param>
|
||||||
/// <param name="dateFormat">日期格式字符串</param>
|
///// <param name="dateFormat">日期格式字符串</param>
|
||||||
/// <returns>影响的行数</returns>
|
///// <returns>影响的行数</returns>
|
||||||
public int BulkCopy<T>(T insertData, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
//public int BulkCopy<T>(T insertData, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
||||||
{
|
//{
|
||||||
return BulkCopyAsync(insertData, dateFormat).GetAwaiter().GetResult();
|
// return BulkCopyAsync(insertData, dateFormat).GetAwaiter().GetResult();
|
||||||
}
|
//}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建分页批量插入器
|
/// 创建分页批量插入器
|
||||||
@@ -115,9 +120,10 @@ namespace ThingsGateway.SqlSugar
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
/// <typeparam name="T">数据类型</typeparam>
|
||||||
/// <param name="insertList">要插入的数据列表</param>
|
/// <param name="insertList">要插入的数据列表</param>
|
||||||
|
/// <param name="tableName">表名称</param>
|
||||||
/// <param name="dateFormat">日期格式字符串</param>
|
/// <param name="dateFormat">日期格式字符串</param>
|
||||||
/// <returns>插入的记录数</returns>
|
/// <returns>插入的记录数</returns>
|
||||||
public async Task<int> BulkCopyAsync<T>(List<T> insertList, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
public async Task<int> BulkCopyAsync<T>(List<T> insertList, string tableName = null, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
||||||
{
|
{
|
||||||
var result = 0;
|
var result = 0;
|
||||||
var fileName = $"{Guid.NewGuid()}.csv";
|
var fileName = $"{Guid.NewGuid()}.csv";
|
||||||
@@ -126,35 +132,43 @@ namespace ThingsGateway.SqlSugar
|
|||||||
{
|
{
|
||||||
// 准备多部分表单数据
|
// 准备多部分表单数据
|
||||||
var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
|
var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
|
||||||
var list = new List<Hashtable>();
|
|
||||||
var name = db.EntityMaintenance.GetEntityInfo<T>().DbTableName;
|
tableName ??= db.EntityMaintenance.GetEntityInfo<T>().DbTableName;
|
||||||
|
|
||||||
// 获取或创建列信息缓存
|
// 获取或创建列信息缓存
|
||||||
var key = "QuestDbBulkCopy" + typeof(T).FullName + typeof(T).GetHashCode();
|
var key = "QuestDbBulkCopy" + typeof(T).FullName + typeof(T).GetHashCode();
|
||||||
var columns = ReflectionInoCacheService.Instance.GetOrCreate(key, () =>
|
var columns = ReflectionInoCacheService.Instance.GetOrCreate(key, () =>
|
||||||
db.CopyNew().DbMaintenance.GetColumnInfosByTableName(name));
|
db.CopyNew().DbMaintenance.GetColumnInfosByTableName(tableName));
|
||||||
|
var list = ReflectionInoCacheService.Instance.GetOrCreate($"{key}{dateFormat}List<Hashtable>", () =>
|
||||||
// 构建schema信息
|
|
||||||
columns.ForEach(d =>
|
|
||||||
{
|
{
|
||||||
if (d.DataType == "TIMESTAMP")
|
var list = new List<Hashtable>();
|
||||||
|
|
||||||
|
// 构建schema信息
|
||||||
|
columns.ForEach(d =>
|
||||||
{
|
{
|
||||||
list.Add(new Hashtable()
|
if (d.DataType == "TIMESTAMP")
|
||||||
|
{
|
||||||
|
list.Add(new Hashtable()
|
||||||
{
|
{
|
||||||
{ "name", d.DbColumnName },
|
{ "name", d.DbColumnName },
|
||||||
{ "type", d.DataType },
|
{ "type", d.DataType },
|
||||||
{ "pattern", dateFormat}
|
{ "pattern", dateFormat}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
list.Add(new Hashtable()
|
list.Add(new Hashtable()
|
||||||
{
|
{
|
||||||
{ "name", d.DbColumnName },
|
{ "name", d.DbColumnName },
|
||||||
{ "type", d.DataType }
|
{ "type", d.DataType }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
var schema = JsonConvert.SerializeObject(list);
|
var schema = JsonConvert.SerializeObject(list);
|
||||||
|
|
||||||
// 写入CSV文件
|
// 写入CSV文件
|
||||||
@@ -170,8 +184,8 @@ namespace ThingsGateway.SqlSugar
|
|||||||
// 准备HTTP请求内容
|
// 准备HTTP请求内容
|
||||||
using var httpContent = new MultipartFormDataContent(boundary);
|
using var httpContent = new MultipartFormDataContent(boundary);
|
||||||
using var fileStream = File.OpenRead(filePath);
|
using var fileStream = File.OpenRead(filePath);
|
||||||
if (!string.IsNullOrWhiteSpace(this.authorization))
|
//if (!string.IsNullOrWhiteSpace(this.authorization))
|
||||||
client.DefaultRequestHeaders.Add("Authorization", this.authorization);
|
// client.DefaultRequestHeaders.Add("Authorization", this.authorization);
|
||||||
httpContent.Add(new StringContent(schema), "schema");
|
httpContent.Add(new StringContent(schema), "schema");
|
||||||
var streamContent = new StreamContent(fileStream);
|
var streamContent = new StreamContent(fileStream);
|
||||||
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
|
||||||
@@ -183,8 +197,8 @@ namespace ThingsGateway.SqlSugar
|
|||||||
"multipart/form-data; boundary=" + boundary);
|
"multipart/form-data; boundary=" + boundary);
|
||||||
|
|
||||||
// 发送请求并处理响应
|
// 发送请求并处理响应
|
||||||
var httpResponseMessage =
|
using var httpResponseMessage =
|
||||||
await Post(client, name, httpContent).ConfigureAwait(false);
|
await Post(client, tableName, httpContent).ConfigureAwait(false);
|
||||||
var readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
|
var readAsStringAsync = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||||
var splitByLine = QuestDbRestAPHelper.SplitByLine(readAsStringAsync);
|
var splitByLine = QuestDbRestAPHelper.SplitByLine(readAsStringAsync);
|
||||||
|
|
||||||
@@ -266,11 +280,12 @@ namespace ThingsGateway.SqlSugar
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">数据类型</typeparam>
|
/// <typeparam name="T">数据类型</typeparam>
|
||||||
/// <param name="insertList">要插入的数据列表</param>
|
/// <param name="insertList">要插入的数据列表</param>
|
||||||
|
/// <param name="tableName">表名称</param>
|
||||||
/// <param name="dateFormat">日期格式字符串</param>
|
/// <param name="dateFormat">日期格式字符串</param>
|
||||||
/// <returns>插入的记录数</returns>
|
/// <returns>插入的记录数</returns>
|
||||||
public int BulkCopy<T>(List<T> insertList, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
public int BulkCopy<T>(List<T> insertList, string tableName = null, string dateFormat = "yyyy/M/d H:mm:ss") where T : class, new()
|
||||||
{
|
{
|
||||||
return BulkCopyAsync(insertList, dateFormat).GetAwaiter().GetResult();
|
return BulkCopyAsync(insertList, tableName, dateFormat).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -280,7 +295,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
/// <param name="httpPort">HTTP端口</param>
|
/// <param name="httpPort">HTTP端口</param>
|
||||||
/// <param name="username">用户名</param>
|
/// <param name="username">用户名</param>
|
||||||
/// <param name="password">密码</param>
|
/// <param name="password">密码</param>
|
||||||
private void BindHost(string host, string httpPort, string username, string password)
|
private void BindHost(string host, int httpPort, string username, string password)
|
||||||
{
|
{
|
||||||
url = host;
|
url = host;
|
||||||
if (url.EndsWith('/'))
|
if (url.EndsWith('/'))
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
{
|
{
|
||||||
public static class QuestDbSqlSugarClientExtensions
|
public static class QuestDbSqlSugarClientExtensions
|
||||||
{
|
{
|
||||||
public static QuestDbRestAPI RestApi(this ISqlSugarClient db)
|
public static QuestDbRestAPI RestApi(this ISqlSugarClient db, int httpPort = 9000)
|
||||||
{
|
{
|
||||||
return new QuestDbRestAPI(db);
|
return new QuestDbRestAPI(db, httpPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
/// <param name="context">SqlSugar提供者</param>
|
/// <param name="context">SqlSugar提供者</param>
|
||||||
/// <param name="dataRecord">数据记录器</param>
|
/// <param name="dataRecord">数据记录器</param>
|
||||||
/// <param name="fieldNames">字段名列表</param>
|
/// <param name="fieldNames">字段名列表</param>
|
||||||
public IDataReaderEntityBuilder(SqlSugarProvider context, IDataRecord dataRecord, List<string> fieldNames)
|
public IDataReaderEntityBuilder(SqlSugarProvider context, IDataRecord dataRecord, IEnumerable<string> fieldNames)
|
||||||
{
|
{
|
||||||
this.Context = context;
|
this.Context = context;
|
||||||
this.DataRecord = dataRecord;
|
this.DataRecord = dataRecord;
|
||||||
|
|||||||
@@ -679,7 +679,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
IDataReaderEntityBuilder<T> entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
IDataReaderEntityBuilder<T> entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
||||||
{
|
{
|
||||||
var cacheResult = new IDataReaderEntityBuilder<T>(this.Context, dr,
|
var cacheResult = new IDataReaderEntityBuilder<T>(this.Context, dr,
|
||||||
columns.Select(it => it.Item1).ToList()).CreateBuilder(typeof(T));
|
columns.Select(it => it.Item1)).CreateBuilder(typeof(T));
|
||||||
return cacheResult;
|
return cacheResult;
|
||||||
});
|
});
|
||||||
using (dr)
|
using (dr)
|
||||||
@@ -706,7 +706,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
IDataReaderEntityBuilder<T> entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
IDataReaderEntityBuilder<T> entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
||||||
{
|
{
|
||||||
var cacheResult = new IDataReaderEntityBuilder<T>(this.Context, dr,
|
var cacheResult = new IDataReaderEntityBuilder<T>(this.Context, dr,
|
||||||
columns.Select(it => it.Item1).ToList()).CreateBuilder(typeof(T));
|
columns.Select(it => it.Item1)).CreateBuilder(typeof(T));
|
||||||
return cacheResult;
|
return cacheResult;
|
||||||
});
|
});
|
||||||
if (cancellationToken.IsCancellationRequested) yield break;
|
if (cancellationToken.IsCancellationRequested) yield break;
|
||||||
@@ -743,7 +743,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
IDataReaderEntityBuilder<T> entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
IDataReaderEntityBuilder<T> entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
||||||
{
|
{
|
||||||
var cacheResult = new IDataReaderEntityBuilder<T>(this.Context, dr,
|
var cacheResult = new IDataReaderEntityBuilder<T>(this.Context, dr,
|
||||||
columns.Select(it => it.Item1).ToList()).CreateBuilder(typeof(T));
|
columns.Select(it => it.Item1)).CreateBuilder(typeof(T));
|
||||||
return cacheResult;
|
return cacheResult;
|
||||||
});
|
});
|
||||||
using (dr)
|
using (dr)
|
||||||
@@ -775,7 +775,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
IDataReaderEntityBuilder<T> entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
IDataReaderEntityBuilder<T> entytyList = this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
||||||
{
|
{
|
||||||
var cacheResult = new IDataReaderEntityBuilder<T>(this.Context, dr,
|
var cacheResult = new IDataReaderEntityBuilder<T>(this.Context, dr,
|
||||||
columns.Select(it => it.Item1).ToList()).CreateBuilder(typeof(T));
|
columns.Select(it => it.Item1)).CreateBuilder(typeof(T));
|
||||||
return cacheResult;
|
return cacheResult;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,6 @@
|
|||||||
V Get<V>(string key);
|
V Get<V>(string key);
|
||||||
IEnumerable<string> GetAllKey<V>();
|
IEnumerable<string> GetAllKey<V>();
|
||||||
void Remove<V>(string key);
|
void Remove<V>(string key);
|
||||||
V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = int.MaxValue);
|
V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = 3600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
return ReflectionInoCore<V>.GetInstance().GetAllKey();
|
return ReflectionInoCore<V>.GetInstance().GetAllKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
public V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = int.MaxValue)
|
public V GetOrCreate<V>(string cacheKey, Func<V> create, int cacheDurationInSeconds = 3600)
|
||||||
{
|
{
|
||||||
return ReflectionInoCore<V>.GetInstance().GetOrCreate(cacheKey, create);
|
return ReflectionInoCore<V>.GetInstance().GetOrCreate(cacheKey, create);
|
||||||
}
|
}
|
||||||
@@ -43,10 +43,13 @@ namespace ThingsGateway.SqlSugar
|
|||||||
}
|
}
|
||||||
public class ReflectionInoCore<V>
|
public class ReflectionInoCore<V>
|
||||||
{
|
{
|
||||||
private MemoryCache InstanceCache => MemoryCache.Instance;
|
private MemoryCache InstanceCache = new MemoryCache() { Expire = 180 };
|
||||||
private static ReflectionInoCore<V> _instance = null;
|
private static ReflectionInoCore<V> _instance = null;
|
||||||
private static readonly object _instanceLock = new object();
|
private static readonly object _instanceLock = new object();
|
||||||
private ReflectionInoCore() { }
|
private ReflectionInoCore()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public V this[string key]
|
public V this[string key]
|
||||||
{
|
{
|
||||||
@@ -86,7 +89,7 @@ namespace ThingsGateway.SqlSugar
|
|||||||
|
|
||||||
public void Add(string key, V value, int cacheDurationInSeconds)
|
public void Add(string key, V value, int cacheDurationInSeconds)
|
||||||
{
|
{
|
||||||
Check.ThrowNotSupportedException("ReflectionInoCache.Add(string key, V value, int cacheDurationInSeconds)");
|
this.InstanceCache.Add<V>(key, value, cacheDurationInSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(string key)
|
public void Remove(string key)
|
||||||
@@ -107,9 +110,10 @@ namespace ThingsGateway.SqlSugar
|
|||||||
return this.InstanceCache.Keys;
|
return this.InstanceCache.Keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public V GetOrCreate(string cacheKey, Func<V> create)
|
public V GetOrCreate(string cacheKey, Func<V> create, int expire = 3600)
|
||||||
{
|
{
|
||||||
return InstanceCache.GetOrAdd<V>(cacheKey, (a) => create());
|
return InstanceCache.GetOrAdd<V>(cacheKey, (a) =>
|
||||||
|
create(), expire);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static class ReflectionInoHelper
|
public static class ReflectionInoHelper
|
||||||
|
|||||||
@@ -447,6 +447,28 @@ namespace ThingsGateway.SqlSugar
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override List<DbColumnInfo> GetColumnInfosByTableName(string tableName, bool isCache = true)
|
public override List<DbColumnInfo> GetColumnInfosByTableName(string tableName, bool isCache = true)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(tableName)) return new List<DbColumnInfo>();
|
||||||
|
string cacheKey = "QuestDB.GetColumnInfosByTableName." + this.SqlBuilder.GetNoTranslationColumnName(tableName).ToLower() + this.Context.CurrentConnectionConfig.ConfigId;
|
||||||
|
cacheKey = GetCacheKey(cacheKey);
|
||||||
|
|
||||||
|
if (isCache)
|
||||||
|
{
|
||||||
|
|
||||||
|
return this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
||||||
|
{
|
||||||
|
return GetColInfo(tableName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetColInfo(tableName);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DbColumnInfo> GetColInfo(string tableName)
|
||||||
{
|
{
|
||||||
var sql = String.Format(GetColumnInfosByTableNameSql, tableName);
|
var sql = String.Format(GetColumnInfosByTableNameSql, tableName);
|
||||||
List<DbColumnInfo> result = new List<DbColumnInfo>();
|
List<DbColumnInfo> result = new List<DbColumnInfo>();
|
||||||
|
|||||||
@@ -717,8 +717,32 @@ namespace ThingsGateway.SqlSugar
|
|||||||
/// <returns>列信息列表</returns>
|
/// <returns>列信息列表</returns>
|
||||||
public override List<DbColumnInfo> GetColumnInfosByTableName(string tableName, bool isCache = true)
|
public override List<DbColumnInfo> GetColumnInfosByTableName(string tableName, bool isCache = true)
|
||||||
{
|
{
|
||||||
var sql = $"select * from {this.SqlBuilder.GetTranslationColumnName(tableName)} where 1=2 ";
|
|
||||||
|
if (string.IsNullOrEmpty(tableName)) return new List<DbColumnInfo>();
|
||||||
|
string cacheKey = "TDengine.GetColumnInfosByTableName." + this.SqlBuilder.GetNoTranslationColumnName(tableName).ToLower() + this.Context.CurrentConnectionConfig.ConfigId;
|
||||||
|
cacheKey = GetCacheKey(cacheKey);
|
||||||
|
|
||||||
|
if (isCache)
|
||||||
|
{
|
||||||
|
|
||||||
|
return this.Context.Utilities.GetReflectionInoCacheInstance().GetOrCreate(cacheKey, () =>
|
||||||
|
{
|
||||||
|
return GetColInfo(tableName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return GetColInfo(tableName);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DbColumnInfo> GetColInfo(string tableName)
|
||||||
|
{
|
||||||
List<DbColumnInfo> result = new List<DbColumnInfo>();
|
List<DbColumnInfo> result = new List<DbColumnInfo>();
|
||||||
|
|
||||||
|
var sql = $"select * from {this.SqlBuilder.GetTranslationColumnName(tableName)} where 1=2 ";
|
||||||
DataTable dt = null;
|
DataTable dt = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
<TargetFrameworks>net8.0;net9.0;</TargetFrameworks>
|
||||||
@@ -29,11 +30,11 @@
|
|||||||
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||||
<PackageReference Include="CsvHelper" Version="33.1.0" />
|
<PackageReference Include="CsvHelper" Version="33.1.0" />
|
||||||
<PackageReference Include="TDengine.Connector" Version="3.1.7" />
|
<PackageReference Include="TDengine.Connector" Version="3.1.8" />
|
||||||
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.9.1" />
|
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.9.1" />
|
||||||
<PackageReference Include="Oscar.Data.SqlClient" Version="4.2.21" />
|
<PackageReference Include="Oscar.Data.SqlClient" Version="4.2.23" />
|
||||||
<PackageReference Include="System.Data.Common" Version="4.3.0" />
|
<PackageReference Include="System.Data.Common" Version="4.3.0" />
|
||||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.0" />
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.1" />
|
||||||
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
|
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
|
||||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||||
<PackageReference Include="System.Formats.Asn1" Version="8.0.2" />
|
<PackageReference Include="System.Formats.Asn1" Version="8.0.2" />
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PluginVersion>10.10.1</PluginVersion>
|
<PluginVersion>10.11.2</PluginVersion>
|
||||||
<ProPluginVersion>10.10.1</ProPluginVersion>
|
<ProPluginVersion>10.11.2</ProPluginVersion>
|
||||||
<DefaultVersion>10.10.2</DefaultVersion>
|
<DefaultVersion>10.11.2</DefaultVersion>
|
||||||
<AuthenticationVersion>2.9.29</AuthenticationVersion>
|
<AuthenticationVersion>10.11.2</AuthenticationVersion>
|
||||||
<SourceGeneratorVersion>10.9.29</SourceGeneratorVersion>
|
<SourceGeneratorVersion>10.11.2</SourceGeneratorVersion>
|
||||||
<NET8Version>8.0.18</NET8Version>
|
<NET8Version>8.0.19</NET8Version>
|
||||||
<NET9Version>9.0.7</NET9Version>
|
<NET9Version>9.0.8</NET9Version>
|
||||||
<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
|
||||||
|
<IsTrimmable>false</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
3088
src/Drivers/ThingsGateway.AllenBradley.deps.json
Normal file
3088
src/Drivers/ThingsGateway.AllenBradley.deps.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/Drivers/ThingsGateway.AllenBradley.dll
Normal file
BIN
src/Drivers/ThingsGateway.AllenBradley.dll
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net462;netstandard2.0;net6.0;</TargetFrameworks>
|
<TargetFrameworks>net462;netstandard2.0;net6.0;net8.0</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;</TargetFrameworks>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CS-Script" Version="4.10.1" />
|
<PackageReference Include="CS-Script" Version="4.11.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public partial class ChannelComponent : ComponentBase
|
|||||||
await Channel.SetupAsync(config);
|
await Channel.SetupAsync(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Channel.ConnectAsync(Channel.ChannelOptions.ConnectTimeout, default);
|
await Channel.ConnectAsync(default);
|
||||||
|
|
||||||
if (OnConnectClick.HasDelegate)
|
if (OnConnectClick.HasDelegate)
|
||||||
await OnConnectClick.InvokeAsync(Channel);
|
await OnConnectClick.InvokeAsync(Channel);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<EditorItem @bind-Field=Model.EncodingName>
|
<EditorItem @bind-Field=Model.EncodingName>
|
||||||
<EditTemplate Context="value">
|
<EditTemplate Context="value">
|
||||||
<div class="col-12 col-sm-4">
|
<div class="col-12 col-sm-4">
|
||||||
<Select @bind-Value=value.EncodingName Items="EncodingItems" />
|
<Select @bind-Value=value.EncodingName Items="EncodingItems" IsClearable/>
|
||||||
</div>
|
</div>
|
||||||
</EditTemplate>
|
</EditTemplate>
|
||||||
</EditorItem>
|
</EditorItem>
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ public partial class ConverterConfigComponent : ComponentBase
|
|||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
BoolItems = LocalizerUtil.GetBoolItems(Model.GetType(), nameof(Model.VariableStringLength), true);
|
BoolItems = LocalizerUtil.GetBoolItems(Model.GetType(), nameof(Model.VariableStringLength), true);
|
||||||
EncodingItems = new List<SelectedItem>() { new SelectedItem("", "none") }.Concat(Encoding.GetEncodings().Select(a => new SelectedItem(a.CodePage.ToString(), a.DisplayName))).ToList();
|
EncodingItems = Encoding.GetEncodings().Select(a => new SelectedItem(a.CodePage.ToString(), a.DisplayName)).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,8 @@ public partial class LogConsole : IDisposable
|
|||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private ToastService ToastService { get; set; }
|
private ToastService ToastService { get; set; }
|
||||||
|
[Inject]
|
||||||
|
ITextFileReadService TextFileReadService { get; set; }
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Disposed = true;
|
Disposed = true;
|
||||||
@@ -94,7 +95,7 @@ public partial class LogConsole : IDisposable
|
|||||||
|
|
||||||
if (LogPath != null)
|
if (LogPath != null)
|
||||||
{
|
{
|
||||||
var files = TextFileReader.GetFiles(LogPath);
|
var files = await TextFileReadService.GetLogFilesAsync(LogPath);
|
||||||
if (!files.IsSuccess)
|
if (!files.IsSuccess)
|
||||||
{
|
{
|
||||||
Messages = new List<LogMessage>();
|
Messages = new List<LogMessage>();
|
||||||
@@ -105,7 +106,7 @@ public partial class LogConsole : IDisposable
|
|||||||
await Task.Run(async () =>
|
await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
var result = TextFileReader.LastLog(files.Content.FirstOrDefault());
|
var result = await TextFileReadService.LastLogDataAsync(files.Content.FirstOrDefault());
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
{
|
{
|
||||||
Messages = result.Content.Where(a => a.LogLevel >= LogLevel).Select(a => new LogMessage((int)a.LogLevel, $"{a.LogTime} - {a.Message}{(a.ExceptionString.IsNullOrWhiteSpace() ? null : $"{Environment.NewLine}{a.ExceptionString}")}")).ToList();
|
Messages = result.Content.Where(a => a.LogLevel >= LogLevel).Select(a => new LogMessage((int)a.LogLevel, $"{a.LogTime} - {a.Message}{(a.ExceptionString.IsNullOrWhiteSpace() ? null : $"{Environment.NewLine}{a.ExceptionString}")}")).ToList();
|
||||||
@@ -143,7 +144,7 @@ public partial class LogConsole : IDisposable
|
|||||||
{
|
{
|
||||||
if (LogPath != null)
|
if (LogPath != null)
|
||||||
{
|
{
|
||||||
var files = TextFileReader.GetFiles(LogPath);
|
var files = await TextFileReadService.GetLogFilesAsync(LogPath);
|
||||||
if (files.IsSuccess)
|
if (files.IsSuccess)
|
||||||
{
|
{
|
||||||
foreach (var item in files.Content)
|
foreach (var item in files.Content)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// QQ群:605534569
|
// QQ群:605534569
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace ThingsGateway.Gateway.Razor;
|
namespace ThingsGateway.Debug;
|
||||||
|
|
||||||
public class ValueTransformConfig
|
public class ValueTransformConfig
|
||||||
{
|
{
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
@namespace ThingsGateway.Gateway.Razor
|
@namespace ThingsGateway.Debug
|
||||||
@using ThingsGateway.Admin.Application
|
|
||||||
@using ThingsGateway.Admin.Razor
|
|
||||||
@using ThingsGateway.Foundation
|
@using ThingsGateway.Foundation
|
||||||
@using ThingsGateway.Gateway.Application
|
|
||||||
@inherits ComponentDefault
|
|
||||||
|
|
||||||
<ValidateForm class="p-4 h-100" Model="@ValueTransformConfig" OnValidSubmit="OnSave">
|
<ValidateForm class="p-4 h-100" Model="@ValueTransformConfig" OnValidSubmit="OnSave">
|
||||||
<EditorForm AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=1 LabelWidth=150 Model="ValueTransformConfig">
|
<EditorForm AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=1 LabelWidth=150 Model="ValueTransformConfig">
|
||||||
@@ -14,7 +14,7 @@ using System.Text.RegularExpressions;
|
|||||||
|
|
||||||
using ThingsGateway.NewLife.Extension;
|
using ThingsGateway.NewLife.Extension;
|
||||||
|
|
||||||
namespace ThingsGateway.Gateway.Razor;
|
namespace ThingsGateway.Debug;
|
||||||
|
|
||||||
public partial class ValueTransformConfigPage
|
public partial class ValueTransformConfigPage
|
||||||
{
|
{
|
||||||
@@ -205,5 +205,10 @@ public partial class ValueTransformConfigPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
ToastService ToastService { get; set; }
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
IStringLocalizer<ThingsGateway.Razor._Imports> RazorLocalizer { get; set; }
|
||||||
#endregion 修改
|
#endregion 修改
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,23 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
"ThingsGateway.Debug.ValueTransformType": {
|
||||||
|
"None": "None",
|
||||||
|
"Linear": "Linear",
|
||||||
|
"Sqrt": "Sqrt"
|
||||||
|
},
|
||||||
|
|
||||||
|
"ThingsGateway.Debug.ValueTransformConfig": {
|
||||||
|
"TransformType": "TransformType",
|
||||||
|
"MinMax": "MinMax",
|
||||||
|
"ClampToRawRange": "ClampToRawRange",
|
||||||
|
"DecimalPlaces": "DecimalPlaces",
|
||||||
|
"RawMin": "RawMin",
|
||||||
|
"RawMax": "RawMax",
|
||||||
|
"ActualMin": "ActualMin",
|
||||||
|
"ActualMax": "ActualMax"
|
||||||
|
},
|
||||||
|
|
||||||
"ThingsGateway.Debug.ChannelComponent": {
|
"ThingsGateway.Debug.ChannelComponent": {
|
||||||
"BaudRate": "Baud Rate",
|
"BaudRate": "Baud Rate",
|
||||||
"BindUrl": "Local Bind IP Address",
|
"BindUrl": "Local Bind IP Address",
|
||||||
|
|||||||
@@ -1,4 +1,21 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
"ThingsGateway.Debug.ValueTransformType": {
|
||||||
|
"None": "无",
|
||||||
|
"Linear": "线性",
|
||||||
|
"Sqrt": "开方"
|
||||||
|
},
|
||||||
|
"ThingsGateway.Debug.ValueTransformConfig": {
|
||||||
|
"TransformType": "转换方式",
|
||||||
|
"MinMax": "最小最大值",
|
||||||
|
"ClampToRawRange": "限制范围",
|
||||||
|
"DecimalPlaces": "保留小数位",
|
||||||
|
"RawMin": "原始最小值",
|
||||||
|
"RawMax": "原始最大值",
|
||||||
|
"ActualMin": "实际最小值",
|
||||||
|
"ActualMax": "实际最大值"
|
||||||
|
},
|
||||||
|
|
||||||
"ThingsGateway.Debug.ChannelComponent": {
|
"ThingsGateway.Debug.ChannelComponent": {
|
||||||
"BaudRate": "波特率",
|
"BaudRate": "波特率",
|
||||||
"BindUrl": "本地url",
|
"BindUrl": "本地url",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class PlatformService : IPlatformService
|
|||||||
|
|
||||||
public async Task OnLogExport(string logPath)
|
public async Task OnLogExport(string logPath)
|
||||||
{
|
{
|
||||||
var files = TextFileReader.GetFiles(logPath);
|
var files = TextFileReader.GetLogFilesAsync(logPath);
|
||||||
if (!files.IsSuccess)
|
if (!files.IsSuccess)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -40,7 +40,7 @@ public class PlatformService : IPlatformService
|
|||||||
await using var jSObject = await JSRuntime.InvokeAsync<IJSObjectReference>("import", $"{WebsiteConst.DefaultResourceUrl}js/downloadFile.js");
|
await using var jSObject = await JSRuntime.InvokeAsync<IJSObjectReference>("import", $"{WebsiteConst.DefaultResourceUrl}js/downloadFile.js");
|
||||||
var path = Path.GetRelativePath("wwwroot", item);
|
var path = Path.GetRelativePath("wwwroot", item);
|
||||||
string fileName = DateTime.Now.ToFileDateTimeFormat();
|
string fileName = DateTime.Now.ToFileDateTimeFormat();
|
||||||
await jSObject.InvokeVoidAsync("blazor_downloadFile", url, fileName, new { FileName = path });
|
await jSObject.InvokeAsync<bool>("blazor_downloadFile", url, fileName, new { FileName = path });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,5 +33,6 @@ public class Startup : AppStartup
|
|||||||
}
|
}
|
||||||
|
|
||||||
services.AddScoped<IPlatformService, PlatformService>();
|
services.AddScoped<IPlatformService, PlatformService>();
|
||||||
|
services.AddSingleton<ITextFileReadService, TextFileReadService>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<Import Project="..\..\PackNuget.props" />
|
<Import Project="..\..\PackNuget.props" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net8.0;</TargetFrameworks>
|
<TargetFrameworks>net8.0;</TargetFrameworks>
|
||||||
|
|
||||||
<!--<UseRazorSourceGenerator>false</UseRazorSourceGenerator>-->
|
<!--<UseRazorSourceGenerator>false</UseRazorSourceGenerator>-->
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||||
<SignAssembly>false</SignAssembly>
|
<SignAssembly>false</SignAssembly>
|
||||||
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user