refactor: ♻️ 框架代码同步 (#181)

Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
nsnail 2024-10-30 14:40:52 +08:00 committed by GitHub
parent f0c3ec109f
commit bac4a39544
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 256 additions and 111 deletions

View File

@ -19,7 +19,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Roslynator.Analyzers" Version="4.12.8"> <PackageReference Include="Roslynator.Analyzers" Version="4.12.9">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -3,7 +3,7 @@
"isRoot": true, "isRoot": true,
"tools": { "tools": {
"dotnet-t4": { "dotnet-t4": {
"version": "2.3.1", "version": "3.0.0",
"commands": [ "commands": [
"t4" "t4"
] ]

View File

@ -9,8 +9,10 @@ fi
# 获取外部传入的 URL 参数 # 获取外部传入的 URL 参数
URL="$1" URL="$1"
# 初始化返回值 # 初始化返回值和时间限制
response="" response=""
start_time=$(date +%s)
time_limit=600 # 10分钟的秒数
# 循环检查 API 返回值 # 循环检查 API 返回值
while [ "$response" != "1" ]; do while [ "$response" != "1" ]; do
@ -22,7 +24,16 @@ while [ "$response" != "1" ]; do
# 打印返回值 (可选) # 打印返回值 (可选)
echo "$1: $response" echo "$1: $response"
# 检查时间是否超过限制
current_time=$(date +%s)
elapsed_time=$((current_time - start_time))
if [ "$elapsed_time" -ge "$time_limit" ]; then
echo "Time limit exceeded. Continuing with the script..."
break
fi
done done
# 当返回值为 "1" 时,继续执行后续脚本 # 无论是因为返回值为 "1" 还是超时,继续执行后续脚本
echo "API returned 1. Continuing with the script..." echo "Continuing with the script..."

View File

@ -74,7 +74,7 @@ global using NetAdmin.Domain.DbMaps.Sys;
global using CsvIgnore = CsvHelper.Configuration.Attributes.IgnoreAttribute; global using CsvIgnore = CsvHelper.Configuration.Attributes.IgnoreAttribute;
global using CsvIndex = CsvHelper.Configuration.Attributes.IndexAttribute; global using CsvIndex = CsvHelper.Configuration.Attributes.IndexAttribute;
global using CsvName = CsvHelper.Configuration.Attributes.NameAttribute; global using CsvName = CsvHelper.Configuration.Attributes.NameAttribute;
global using DynamicFilterInfo = NetAdmin.Domain.Dto.Dependency.DynamicFilterInfo; global using DynamicFilterInfo = NetAdmin.Domain.Dto.DynamicFilterInfo;
global using DynamicFilterOperators = NetAdmin.Domain.Enums.DynamicFilterOperators; global using DynamicFilterOperators = NetAdmin.Domain.Enums.DynamicFilterOperators;
global using SqlIndex = FreeSql.DataAnnotations.IndexAttribute; global using SqlIndex = FreeSql.DataAnnotations.IndexAttribute;
#endif #endif

View File

@ -22,12 +22,7 @@
*/ */
using NetAdmin.AdmServer.Host; using NetAdmin.AdmServer.Host;
using NetAdmin.AdmServer.Host.Extensions;
using NetAdmin.Host.Extensions;
using NetAdmin.Host.Middlewares;
using NetAdmin.SysComponent.Host.Extensions;
using NetAdmin.SysComponent.Host.Middlewares; using NetAdmin.SysComponent.Host.Middlewares;
using Spectre.Console.Cli;
using ValidationResult = Spectre.Console.ValidationResult; using ValidationResult = Spectre.Console.ValidationResult;
NetAdmin.Host.Startup.Entry<Startup>(args); NetAdmin.Host.Startup.Entry<Startup>(args);
@ -51,6 +46,8 @@ namespace NetAdmin.AdmServer.Host
public void Configure(IApplicationBuilder app, IHostApplicationLifetime lifeTime) public void Configure(IApplicationBuilder app, IHostApplicationLifetime lifeTime)
#pragma warning restore S2325 #pragma warning restore S2325
{ {
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
_ = app // _ = app //
.UseMiddleware<SafetyShopHostMiddleware>() // 安全停机中间件 .UseMiddleware<SafetyShopHostMiddleware>() // 安全停机中间件
.EnableBuffering() // 启用请求体缓冲,允许多次读取请求体 .EnableBuffering() // 启用请求体缓冲,允许多次读取请求体

View File

@ -1,4 +1,4 @@
namespace NetAdmin.Host.Extensions; namespace NetAdmin.Application.Extensions;
/// <summary> /// <summary>
/// 工作单元管理器扩展方法 /// 工作单元管理器扩展方法

View File

@ -32,7 +32,7 @@ public record Sys_DicContent : VersionEntity, IFieldEnabled, IFieldSummary
/// <summary> /// <summary>
/// 键名称 /// 键名称
/// </summary> /// </summary>
[Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_63)] [Column(DbType = Chars.FLG_DB_FIELD_TYPE_VARCHAR_255)]
[CsvIgnore] [CsvIgnore]
[JsonIgnore] [JsonIgnore]
public virtual string Key { get; init; } public virtual string Key { get; init; }

View File

@ -0,0 +1,17 @@
using NetAdmin.Domain.Enums;
namespace NetAdmin.Domain.Dto;
/// <summary>
/// 动态过滤条件生成器
/// </summary>
public sealed record DfBuilder
{
/// <summary>
/// 构建生成器
/// </summary>
public static DynamicFilterInfo New(DynamicFilterLogics logic)
{
return new DynamicFilterInfo { Logic = logic, Filters = [] };
}
}

View File

@ -1,6 +1,6 @@
using NetAdmin.Domain.Enums; using NetAdmin.Domain.Enums;
namespace NetAdmin.Domain.Dto.Dependency; namespace NetAdmin.Domain.Dto;
/// <summary> /// <summary>
/// 动态过滤条件 /// 动态过滤条件
@ -42,6 +42,43 @@ public sealed record DynamicFilterInfo : DataAbstraction
return ret; return ret;
} }
/// <summary>
/// 添加子过滤条件
/// </summary>
public DynamicFilterInfo Add(DynamicFilterInfo df)
{
if (Filters == null) {
return this with { Filters = [df] };
}
Filters.Add(df);
return this;
}
/// <summary>
/// 添加过滤条件
/// </summary>
public DynamicFilterInfo Add(string field, DynamicFilterOperators opt, object val)
{
return Add(new DynamicFilterInfo { Field = field, Operator = opt, Value = val });
}
/// <summary>
/// 添加过滤条件
/// </summary>
public DynamicFilterInfo AddIf(bool condition, string field, DynamicFilterOperators opt, object val)
{
return !condition ? this : Add(field, opt, val);
}
/// <summary>
/// 添加过滤条件
/// </summary>
public DynamicFilterInfo AddIf(bool condition, DynamicFilterInfo df)
{
return !condition ? this : Add(df);
}
private static void ParseDateExp(FreeSql.Internal.Model.DynamicFilterInfo d) private static void ParseDateExp(FreeSql.Internal.Model.DynamicFilterInfo d)
{ {
var values = ((JsonElement)d.Value).Deserialize<string[]>(); var values = ((JsonElement)d.Value).Deserialize<string[]>();

View File

@ -0,0 +1,40 @@
using NetAdmin.Domain.Dto.Sys.User;
namespace NetAdmin.Domain.Events.Sys;
/// <summary>
/// 用户被创建事件
/// </summary>
public sealed record UserCreatedEvent : DataAbstraction, IEventSourceGeneric<UserInfoRsp>
{
/// <summary>
/// Initializes a new instance of the <see cref="UserCreatedEvent" /> class.
/// </summary>
public UserCreatedEvent(UserInfoRsp data, DateTime createdTime = default, bool isConsumOnce = false, object payload = default
, CancellationToken cancellationToken = default)
{
Data = data;
CancellationToken = cancellationToken;
CreatedTime = createdTime;
IsConsumOnce = isConsumOnce;
Payload = payload;
}
/// <inheritdoc />
public CancellationToken CancellationToken { get; }
/// <inheritdoc />
public DateTime CreatedTime { get; }
/// <inheritdoc />
public UserInfoRsp Data { get; }
/// <inheritdoc />
public string EventId => nameof(UserCreatedEvent);
/// <inheritdoc />
public bool IsConsumOnce { get; }
/// <inheritdoc />
public object Payload { get; }
}

View File

@ -1,5 +1,4 @@
using NetAdmin.Host.Attributes; using NetAdmin.Host.Attributes;
using NetAdmin.Host.Extensions;
namespace NetAdmin.Host.Filters; namespace NetAdmin.Host.Filters;

View File

@ -1,8 +1,3 @@
using NetAdmin.Domain.Contexts;
using NetAdmin.Domain.Dto.Sys.RequestLog;
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
using NetAdmin.Domain.Events.Sys;
using Yitter.IdGenerator;
using HttpMethods = NetAdmin.Domain.Enums.HttpMethods; using HttpMethods = NetAdmin.Domain.Enums.HttpMethods;
namespace NetAdmin.Host.Utils; namespace NetAdmin.Host.Utils;
@ -44,6 +39,7 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
, ResponseContentType = context.Response.ContentType , ResponseContentType = context.Response.ContentType
, ResponseHeaders = context.Response.Headers.Json() , ResponseHeaders = context.Response.Headers.Json()
, ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32() , ServerIp = context.GetLocalIpAddressToIPv4()?.IpV4ToInt32()
, CreatedTime = DateTime.Now
} }
, Duration = (int)duration , Duration = (int)duration
, HttpMethod = Enum.Parse<HttpMethods>(context.Request.Method, true) , HttpMethod = Enum.Parse<HttpMethods>(context.Request.Method, true)
@ -54,6 +50,7 @@ public sealed class RequestLogger(ILogger<RequestLogger> logger, IEventPublisher
, OwnerDeptId = associatedUser?.DeptId , OwnerDeptId = associatedUser?.DeptId
, Id = id , Id = id
, TraceId = context.GetTraceId() , TraceId = context.GetTraceId()
, CreatedTime = DateTime.Now
}; };
// ReSharper disable once InvertIf // ReSharper disable once InvertIf

View File

@ -77,7 +77,6 @@ public static class Chars
public const string FLG_PATH_API_RPOBE = "api/probe"; public const string FLG_PATH_API_RPOBE = "api/probe";
public const string FLG_PATH_API_SYS_USER_LOGIN_BY_PWD = "api/sys/user/login.by.pwd"; public const string FLG_PATH_API_SYS_USER_LOGIN_BY_PWD = "api/sys/user/login.by.pwd";
public const string FLG_PATH_PREFIX_HEALTH_CHECK = "probe/health.check";
public const string FLG_PATH_WEBSOCKET_PREFIX = "ws"; public const string FLG_PATH_WEBSOCKET_PREFIX = "ws";
public const string FLG_RANDOM_UNAME_PWD = "VcXlp7WY"; public const string FLG_RANDOM_UNAME_PWD = "VcXlp7WY";
public const string FLG_REDIS_INSTANCE_DATA_CACHE = "DataCache"; public const string FLG_REDIS_INSTANCE_DATA_CACHE = "DataCache";

View File

@ -28,7 +28,22 @@ public static class HttpResponseMessageExtensions
private static async Task<string> BuildJsonAsync( // private static async Task<string> BuildJsonAsync( //
this HttpResponseMessage me, Func<string, string> bodyHandle = null) this HttpResponseMessage me, Func<string, string> bodyHandle = null)
{ {
var body = me?.Content is null ? null : await me.Content!.ReadAsStringAsync().ConfigureAwait(false); var body = string.Empty;
try {
body = me?.Content is null ? null : await me.Content!.ReadAsStringAsync().ConfigureAwait(false);
}
catch (Exception ex) when (ex.Message.Contains("The character set provided in ContentType is invalid") &&
ex.InnerException?.Message.Contains("is not a supported encoding name") == true) {
#pragma warning disable S2589
var sr = me?.Content is null ? null : await me.Content!.ReadAsStreamAsync().ConfigureAwait(false);
if (sr != null) {
#pragma warning restore S2589
await using var ms = new MemoryStream();
await sr.CopyToAsync(ms).ConfigureAwait(false);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
return new { Header = me?.ToString(), RequestHeader = me?.RequestMessage?.Headers, Body = bodyHandle is null ? body : bodyHandle(body) } return new { Header = me?.ToString(), RequestHeader = me?.RequestMessage?.Headers, Body = bodyHandle is null ? body : bodyHandle(body) }
.Json(); .Json();
} }

View File

@ -16,6 +16,7 @@
<PackageReference Include="Minio" Version="6.0.3"/> <PackageReference Include="Minio" Version="6.0.3"/>
<PackageReference Include="NSExt" Version="2.2.0"/> <PackageReference Include="NSExt" Version="2.2.0"/>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4"/> <PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.4"/>
<PackageReference Include="System.Drawing.Common" Version="9.0.0-rc.2.24474.1"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="*.json"> <None Update="*.json">

View File

@ -1,9 +1,6 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Cache;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
using StackExchange.Redis;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -82,6 +79,7 @@ public sealed class CacheService(IConnectionMultiplexer connectionMultiplexer) /
/// <inheritdoc /> /// <inheritdoc />
public async Task<GetEntryRsp> GetEntryAsync(GetEntriesReq req) public async Task<GetEntryRsp> GetEntryAsync(GetEntriesReq req)
{ {
req.ThrowIfInvalid();
var database = connectionMultiplexer.GetDatabase(_redisInstance.Database); var database = connectionMultiplexer.GetDatabase(_redisInstance.Database);
var ret = new GetEntryRsp { var ret = new GetEntryRsp {

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Config;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -53,6 +51,7 @@ public sealed class ConfigService(BasicRepository<Sys_Config, long> rpo) //
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryConfigRsp> EditAsync(EditConfigReq req) public async Task<QueryConfigRsp> EditAsync(EditConfigReq req)
{ {
req.ThrowIfInvalid();
#if DBTYPE_SQLSERVER #if DBTYPE_SQLSERVER
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryConfigRsp>(); return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryConfigRsp>();
#else #else

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Dept;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -71,6 +69,7 @@ public sealed class DeptService(BasicRepository<Sys_Dept, long> rpo) //
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryDeptRsp> EditAsync(EditDeptReq req) public async Task<QueryDeptRsp> EditAsync(EditDeptReq req)
{ {
req.ThrowIfInvalid();
#if DBTYPE_SQLSERVER #if DBTYPE_SQLSERVER
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryDeptRsp>(); return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryDeptRsp>();
#else #else

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Dic.Catalog;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -90,6 +88,7 @@ public sealed class DicCatalogService(BasicRepository<Sys_DicCatalog, long> rpo)
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QueryDicCatalogReq> req) public Task<IActionResult> ExportAsync(QueryReq<QueryDicCatalogReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Menu;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -55,6 +53,7 @@ public sealed class MenuService(BasicRepository<Sys_Menu, long> rpo, IUserServic
/// <inheritdoc /> /// <inheritdoc />
public async Task<QueryMenuRsp> EditAsync(EditMenuReq req) public async Task<QueryMenuRsp> EditAsync(EditMenuReq req)
{ {
req.ThrowIfInvalid();
#if DBTYPE_SQLSERVER #if DBTYPE_SQLSERVER
return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryMenuRsp>(); return (await UpdateReturnListAsync(req, null).ConfigureAwait(false)).FirstOrDefault()?.Adapt<QueryMenuRsp>();
#else #else
@ -76,6 +75,7 @@ public sealed class MenuService(BasicRepository<Sys_Menu, long> rpo, IUserServic
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QueryMenuReq> req) public Task<IActionResult> ExportAsync(QueryReq<QueryMenuReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.RequestLogDetail;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -64,6 +62,7 @@ public sealed class RequestLogDetailService(BasicRepository<Sys_RequestLogDetail
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QueryRequestLogDetailReq> req) public Task<IActionResult> ExportAsync(QueryReq<QueryRequestLogDetailReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.SiteMsgDept;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -64,6 +62,7 @@ public sealed class SiteMsgDeptService(BasicRepository<Sys_SiteMsgDept, long> rp
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QuerySiteMsgDeptReq> req) public Task<IActionResult> ExportAsync(QueryReq<QuerySiteMsgDeptReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.SiteMsgFlag;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -64,6 +62,7 @@ public sealed class SiteMsgFlagService(BasicRepository<Sys_SiteMsgFlag, long> rp
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QuerySiteMsgFlagReq> req) public Task<IActionResult> ExportAsync(QueryReq<QuerySiteMsgFlagReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.SiteMsgRole;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -64,6 +62,7 @@ public sealed class SiteMsgRoleService(BasicRepository<Sys_SiteMsgRole, long> rp
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QuerySiteMsgRoleReq> req) public Task<IActionResult> ExportAsync(QueryReq<QuerySiteMsgRoleReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -1,7 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.SiteMsgUser;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -64,6 +62,7 @@ public sealed class SiteMsgUserService(BasicRepository<Sys_SiteMsgUser, long> rp
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QuerySiteMsgUserReq> req) public Task<IActionResult> ExportAsync(QueryReq<QuerySiteMsgUserReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -1,5 +1,4 @@
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Sys.Tool;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -17,6 +16,7 @@ public sealed class ToolsService : ServiceBase<IToolsService>, IToolsService
/// <inheritdoc /> /// <inheritdoc />
public Task<object[][]> ExecuteSqlAsync(ExecuteSqlReq req) public Task<object[][]> ExecuteSqlAsync(ExecuteSqlReq req)
{ {
req.ThrowIfInvalid();
return App.GetService<IFreeSql>().Ado.CommandFluent(req.Sql).CommandTimeout(req.TimeoutSecs).ExecuteArrayAsync(); return App.GetService<IFreeSql>().Ado.CommandFluent(req.Sql).CommandTimeout(req.TimeoutSecs).ExecuteArrayAsync();
} }

View File

@ -1,9 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Contexts;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Dic.Content;
using NetAdmin.Domain.Dto.Sys.UserProfile;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -73,6 +69,7 @@ public sealed class UserProfileService(BasicRepository<Sys_UserProfile, long> rp
/// <inheritdoc /> /// <inheritdoc />
public Task<int> EditAsync(EditUserProfileReq req) public Task<int> EditAsync(EditUserProfileReq req)
{ {
req.ThrowIfInvalid();
return UpdateAsync(req.Adapt<Sys_UserProfile>(), null); return UpdateAsync(req.Adapt<Sys_UserProfile>(), null);
} }
@ -90,6 +87,7 @@ public sealed class UserProfileService(BasicRepository<Sys_UserProfile, long> rp
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QueryUserProfileReq> req) public Task<IActionResult> ExportAsync(QueryReq<QueryUserProfileReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -1,11 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Contexts;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.User;
using NetAdmin.Domain.Dto.Sys.UserProfile;
using NetAdmin.Domain.Dto.Sys.VerifyCode;
using NetAdmin.Domain.Events.Sys;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -100,8 +94,12 @@ public sealed class UserService(
, AppConfig = appConfig , AppConfig = appConfig
}) })
.ConfigureAwait(false); .ConfigureAwait(false);
var ret = await QueryAsync(new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = dbUser.Id } }).ConfigureAwait(false); var userList = await QueryAsync(new QueryReq<QueryUserReq> { Filter = new QueryUserReq { Id = dbUser.Id } }).ConfigureAwait(false);
return ret.First();
// 发布用户创建事件
var ret = userList.First();
await eventPublisher.PublishAsync(new UserCreatedEvent(ret.Adapt<UserInfoRsp>())).ConfigureAwait(false);
return ret;
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -1,9 +1,5 @@
using NetAdmin.Application.Repositories; using NetAdmin.Application.Repositories;
using NetAdmin.Application.Services; using NetAdmin.Application.Services;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.VerifyCode;
using NetAdmin.Domain.Enums.Sys;
using NetAdmin.Domain.Events.Sys;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Application.Services.Sys; namespace NetAdmin.SysComponent.Application.Services.Sys;
@ -74,6 +70,7 @@ public sealed class VerifyCodeService(BasicRepository<Sys_VerifyCode, long> rpo,
/// <inheritdoc /> /// <inheritdoc />
public Task<IActionResult> ExportAsync(QueryReq<QueryVerifyCodeReq> req) public Task<IActionResult> ExportAsync(QueryReq<QueryVerifyCodeReq> req)
{ {
req.ThrowIfInvalid();
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -144,6 +141,7 @@ public sealed class VerifyCodeService(BasicRepository<Sys_VerifyCode, long> rpo,
/// <inheritdoc /> /// <inheritdoc />
public Task<int> SetVerifyCodeStatusAsync(SetVerifyCodeStatusReq req) public Task<int> SetVerifyCodeStatusAsync(SetVerifyCodeStatusReq req)
{ {
req.ThrowIfInvalid();
return UpdateAsync(req, [nameof(req.Status)]); return UpdateAsync(req, [nameof(req.Status)]);
} }

View File

@ -1,6 +1,4 @@
using NetAdmin.Cache; using NetAdmin.Cache;
using NetAdmin.Domain.Dto.Dependency;
using NetAdmin.Domain.Dto.Sys.Dic.Content;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency; using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
using NetAdmin.SysComponent.Cache.Sys.Dependency; using NetAdmin.SysComponent.Cache.Sys.Dependency;
@ -69,8 +67,7 @@ public sealed class DicContentCache(IDistributedCache cache, IDicContentService
{ {
#if !DEBUG #if !DEBUG
return GetOrCreateAsync( // return GetOrCreateAsync( //
GetCacheKey(catalogCode), () => Service.QueryByCatalogCodeAsync(catalogCode) GetCacheKey(catalogCode), () => Service.QueryByCatalogCodeAsync(catalogCode), TimeSpan.FromSeconds(Numbers.SECS_CACHE_DIC_CATALOG_CODE));
, TimeSpan.FromSeconds(Numbers.SECS_CACHE_DIC_CATALOG_CODE));
#else #else
return Service.QueryByCatalogCodeAsync(catalogCode); return Service.QueryByCatalogCodeAsync(catalogCode);
#endif #endif

View File

@ -1,13 +1,5 @@
using FreeSql.Internal;
using Furion.RemoteRequest;
using Furion.RemoteRequest.Extensions;
using Furion.Schedule;
using NetAdmin.Domain.Dto.Sys.Job;
using NetAdmin.Domain.Dto.Sys.JobRecord;
using NetAdmin.Host.BackgroundRunning; using NetAdmin.Host.BackgroundRunning;
using NetAdmin.Host.Extensions;
using NetAdmin.Host.Middlewares; using NetAdmin.Host.Middlewares;
using NetAdmin.SysComponent.Application.Services.Sys.Dependency;
namespace NetAdmin.SysComponent.Host.Jobs; namespace NetAdmin.SysComponent.Host.Jobs;

View File

@ -10,15 +10,15 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "2.3.1", "@element-plus/icons-vue": "2.3.1",
"ace-builds": "1.36.2", "ace-builds": "1.36.3",
"aieditor": "1.1.7", "aieditor": "1.2.3",
"axios": "1.7.7", "axios": "1.7.7",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"core-js": "3.38.1", "core-js": "3.38.1",
"cropperjs": "1.6.2", "cropperjs": "1.6.2",
"crypto-js": "4.2.0", "crypto-js": "4.2.0",
"echarts": "5.5.1", "echarts": "5.5.1",
"element-plus": "2.8.5", "element-plus": "2.8.6",
"json-bigint": "1.0.0", "json-bigint": "1.0.0",
"json5-to-table": "0.1.8", "json5-to-table": "0.1.8",
"markdown-it": "14.1.0", "markdown-it": "14.1.0",
@ -40,9 +40,9 @@
"@vitejs/plugin-vue": "5.1.4", "@vitejs/plugin-vue": "5.1.4",
"prettier": "3.3.3", "prettier": "3.3.3",
"prettier-plugin-organize-attributes": "1.0.0", "prettier-plugin-organize-attributes": "1.0.0",
"sass": "1.79.5", "sass": "1.80.5",
"terser": "5.34.1", "terser": "5.36.0",
"vite": "5.4.8" "vite": "5.4.10"
}, },
"browserslist": [ "browserslist": [
"> 1%", "> 1%",

View File

@ -95,5 +95,5 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
@import '@/style/style.scss'; @use '@/style/style.scss' as *;
</style> </style>

View File

@ -0,0 +1,33 @@
<template>
<el-table-column v-bind="$attrs" :prop="prop">
<template #default="{ row }">
<el-tag
v-if="row[prop]"
:type="['success', 'danger', 'info', 'primary', 'warning'][$TOOL.crypto.hashCode(row[prop]) % 5]"
@click="$emit('click', row)">
{{ row[prop] }}
</el-tag>
</template>
</el-table-column>
</template>
<script>
export default {
emits: ['click'],
props: {
prop: { type: String },
},
data() {
return {}
},
mounted() {},
created() {},
components: {},
computed: {},
methods: {},
}
</script>
<style scoped>
.el-tag {
cursor: pointer;
}
</style>

View File

@ -30,7 +30,7 @@
</template> </template>
</el-input> </el-input>
<el-dialog v-model="dialogVisible" :title="$t('Cron 规则生成器')" :width="800" append-to-body destroy-on-close> <el-dialog v-model="dialogVisible" :title="$t('Cron 规则生成器')" append-to-body destroy-on-close>
<div class="sc-cron"> <div class="sc-cron">
<el-tabs> <el-tabs>
<el-tab-pane> <el-tab-pane>

View File

@ -10,7 +10,7 @@
<template> <template>
<div class="sc-select-filter"> <div class="sc-select-filter">
<div v-if="data.length <= 0" class="sc-select-filter__no-data">{{ $t('暂无数据') }}</div> <div v-if="data.length <= 0" class="sc-select-filter__no-data">{{ $t('暂无数据') }}</div>
<div v-for="item in data" :key="item.key" class="sc-select-filter__item"> <div v-for="item in data" :class="`sc-select-filter__item${item.w100p ? ' sc-select-filter__item-w100p' : ''}`" :key="item.key">
<div :style="{ width: labelWidth + 'rem' }" class="sc-select-filter__item-title"> <div :style="{ width: labelWidth + 'rem' }" class="sc-select-filter__item-title">
<label>{{ item.title }}</label> <label>{{ item.title }}</label>
</div> </div>
@ -196,4 +196,7 @@ export default {
.sc-select-filter__no-data { .sc-select-filter__no-data {
color: #999; color: #999;
} }
.sc-select-filter__item-w100p {
width: 100%;
}
</style> </style>

View File

@ -31,6 +31,9 @@
</template> </template>
</span> </span>
<span v-if="suffix" class="sc-statistic-content-suffix">{{ suffix }}</span> <span v-if="suffix" class="sc-statistic-content-suffix">{{ suffix }}</span>
<span class="sc-statistic-icon">
<slot v-if="$slots.icon" name="icon"></slot>
</span>
</div> </div>
<div v-if="description || $slots.default" class="sc-statistic-description"> <div v-if="description || $slots.default" class="sc-statistic-description">
<slot> <slot>
@ -102,4 +105,8 @@ export default {
.dark .sc-statistic-content { .dark .sc-statistic-content {
color: #c0c0c0; color: #c0c0c0;
} }
.sc-statistic-icon {
float: right;
}
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<sc-dialog v-model="visible" :title="$t('高级筛选')" :width="800" destroy-on-close> <sc-dialog v-model="visible" :title="$t('高级筛选')" destroy-on-close>
<el-form :model="form" :rules="rules" label-width="10rem" ref="form"> <el-form :model="form" :rules="rules" label-width="10rem" ref="form">
<el-form-item :label="$t('字段名')" prop="field"> <el-form-item :label="$t('字段名')" prop="field">
<el-input v-model="form.field" :placeholder="$t('字段名')" clearable /> <el-input v-model="form.field" :placeholder="$t('字段名')" clearable />

View File

@ -51,6 +51,7 @@ import naColAvatar from '@/components/naColAvatar'
import naColId from '@/components/naColId/index.vue' import naColId from '@/components/naColId/index.vue'
import naColIndicator from '@/components/naColIndicator/index.vue' import naColIndicator from '@/components/naColIndicator/index.vue'
import naColOperation from '@/components/naColOperation' import naColOperation from '@/components/naColOperation'
import naColTag from '@/components/naColTag/index.vue'
import naColTags from '@/components/naColTags/index.vue' import naColTags from '@/components/naColTags/index.vue'
import naColTime from '@/components/naColTime/index.vue' import naColTime from '@/components/naColTime/index.vue'
import naColUser from '@/components/naColUser/index.vue' import naColUser from '@/components/naColUser/index.vue'
@ -93,6 +94,7 @@ export default {
app.component('naColId', naColId) app.component('naColId', naColId)
app.component('naColIndicator', naColIndicator) app.component('naColIndicator', naColIndicator)
app.component('naColOperation', naColOperation) app.component('naColOperation', naColOperation)
app.component('naColTag', naColTag)
app.component('naColTags', naColTags) app.component('naColTags', naColTags)
app.component('naColTime', naColTime) app.component('naColTime', naColTime)
app.component('naColUser', naColUser) app.component('naColUser', naColUser)

View File

@ -466,7 +466,6 @@ export default {
用户列表: 'User list', 用户列表: 'User list',
: 'Yes', : 'Yes',
: 'No', : 'No',
资源复用: 'Resource reuse',
手机: 'Mobile', 手机: 'Mobile',
'您已退出登录或无权限访问当前资源,请重新登录后再操作': '您已退出登录或无权限访问当前资源,请重新登录后再操作':
'You have logged out or do not have permission to access the current resource, please log in again before operating', 'You have logged out or do not have permission to access the current resource, please log in again before operating',

View File

@ -464,7 +464,6 @@ export default {
用户列表: '用户列表', 用户列表: '用户列表',
: '是', : '是',
: '否', : '否',
资源复用: '资源复用',
手机: '手机', 手机: '手机',
'您已退出登录或无权限访问当前资源,请重新登录后再操作': '您已退出登录或无权限访问当前资源,请重新登录后再操作', '您已退出登录或无权限访问当前资源,请重新登录后再操作': '您已退出登录或无权限访问当前资源,请重新登录后再操作',
访问受限: '访问受限', 访问受限: '访问受限',

View File

@ -1,4 +1,4 @@
@import 'element-plus/theme-chalk/src/dark/css-vars.scss'; @use 'element-plus/theme-chalk/src/dark/css-vars.scss' as *;
html.dark { html.dark {
//变量 //变量

View File

@ -293,6 +293,32 @@
.el-dialog__body { .el-dialog__body {
flex: 1; flex: 1;
> * {
height: 100%;
}
.el-tabs,
.el-tab-pane,
.el-form {
height: 100%;
}
.el-tabs__content,
.el-tabs__content > * {
height: 100%;
}
.el-tab-pane {
overflow-y: scroll;
overflow-x: hidden;
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0; /* 隐藏纵向滚动条 */
background: transparent; /* 隐藏背景 */
}
}
} }
} }

View File

@ -1,5 +1,5 @@
@import 'app.scss'; @use 'app.scss' as *;
@import 'fix.scss'; @use 'fix.scss' as *;
@import 'pages.scss'; @use 'pages.scss' as *;
@import 'media.scss'; @use 'media.scss' as *;
@import 'dark.scss'; @use 'dark.scss' as *;

View File

@ -43,7 +43,7 @@ export default {
}), }),
) )
this.loading = false this.loading = false
this.option.xAxis.data = res[0].data.map((x) => { this.option.xAxis.data = res[res.length - 1].data.map((x) => {
return x.timestamp return x.timestamp
}) })
let i = 0 let i = 0

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" :title="$t('设置邮箱')" :width="800" @closed="$emit('closed')" destroy-on-close> <el-dialog v-model="visible" :title="$t('设置邮箱')" @closed="$emit('closed')" destroy-on-close>
<el-form :model="form" :rules="rules" label-position="top" ref="form"> <el-form :model="form" :rules="rules" label-position="top" ref="form">
<el-row class="is-justify-space-evenly"> <el-row class="is-justify-space-evenly">
<el-col v-if="$GLOBAL.user.mobile" :lg="10"> <el-col v-if="$GLOBAL.user.mobile" :lg="10">

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" :title="`${titleMap[mode]}`" :width="800" @closed="$emit('closed')" destroy-on-close> <el-dialog v-model="visible" :title="`${titleMap[mode]}`" @closed="$emit('closed')" destroy-on-close>
<el-form :model="form" :rules="rules" label-position="top" ref="form"> <el-form :model="form" :rules="rules" label-position="top" ref="form">
<el-row class="items-center justify-content-center"> <el-row class="items-center justify-content-center">
<el-col v-if="mode === 'edit'" :lg="10"> <el-col v-if="mode === 'edit'" :lg="10">

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" :title="$t('修改密码')" :width="800" @closed="$emit('closed')" destroy-on-close> <el-dialog v-model="visible" :title="$t('修改密码')" @closed="$emit('closed')" destroy-on-close>
<el-form :model="form" :rules="rules" label-width="15rem" ref="form"> <el-form :model="form" :rules="rules" label-width="15rem" ref="form">
<el-form-item :label="$t('旧密码')" prop="oldPassword"> <el-form-item :label="$t('旧密码')" prop="oldPassword">
<el-input <el-input

View File

@ -59,16 +59,7 @@
</el-header> </el-header>
<el-main class="nopadding"> <el-main class="nopadding">
<sc-table <sc-table
:context-menus="[ :context-menus="['id', 'userRegisterConfirm', 'userRegisterDept.name', 'userRegisterRole.name', 'enabled', 'createdTime']"
'id',
'userRegisterConfirm',
'userRegisterDept.name',
'userRegisterRole.name',
'enabled',
'createdTime',
'phoneReuseTimes',
'emailReuseTimes',
]"
:export-api="$API.sys_config.export" :export-api="$API.sys_config.export"
:on-command="this.getStatistics" :on-command="this.getStatistics"
:params="query" :params="query"
@ -93,7 +84,7 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table-column> </el-table-column>
<el-table-column :label="$t('启用')" align="center" prop="enabled" width="100"> <el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-switch v-model="row.enabled" @change="changeSwitch($event, row)"></el-switch> <el-switch v-model="row.enabled" @change="changeSwitch($event, row)"></el-switch>
</template> </template>

View File

@ -25,7 +25,6 @@
</el-form-item> </el-form-item>
</div> </div>
</el-collapse-item> </el-collapse-item>
<el-collapse-item :title="$t('其他设置')" name="2"></el-collapse-item>
</el-collapse> </el-collapse>
<el-form-item :label="$t('启用')" prop="enabled"> <el-form-item :label="$t('启用')" prop="enabled">

View File

@ -1,5 +1,5 @@
<template> <template>
<sc-dialog v-model="visible" :title="`${titleMap[mode]}${form?.id ?? '...'}`" :width="800" @closed="$emit('closed')" destroy-on-close> <sc-dialog v-model="visible" :title="`${titleMap[mode]}${form?.id ?? '...'}`" @closed="$emit('closed')" destroy-on-close>
<div v-loading="loading"> <div v-loading="loading">
<el-tabs tab-position="top"> <el-tabs tab-position="top">
<el-tab-pane :label="$t('基本信息')"> <el-tab-pane :label="$t('基本信息')">

View File

@ -1,5 +1,5 @@
<template> <template>
<sc-dialog v-model="visible" :title="$t('批量修改')" :width="800" @closed="$emit('closed')" destroy-on-close> <sc-dialog v-model="visible" :title="$t('批量修改')" @closed="$emit('closed')" destroy-on-close>
<div v-loading="loading"> <div v-loading="loading">
<el-tabs tab-position="top"> <el-tabs tab-position="top">
<el-tab-pane :label="$t('基本信息')"> <el-tab-pane :label="$t('基本信息')">

View File

@ -1,5 +1,5 @@
<template> <template>
<sc-dialog v-model="visible" :title="`${titleMap[mode]}${form?.id ?? '...'}`" :width="800" @closed="$emit('closed')" destroy-on-close> <sc-dialog v-model="visible" :title="`${titleMap[mode]}${form?.id ?? '...'}`" @closed="$emit('closed')" destroy-on-close>
<el-form v-loading="loading" :model="form" :rules="rules" label-width="10rem" ref="dialogForm"> <el-form v-loading="loading" :model="form" :rules="rules" label-width="10rem" ref="dialogForm">
<el-form-item :label="$t('字典名称')" prop="name"> <el-form-item :label="$t('字典名称')" prop="name">
<el-input v-model="form.name" :placeholder="$t('字典名称')" clearable></el-input> <el-input v-model="form.name" :placeholder="$t('字典名称')" clearable></el-input>

View File

@ -7,13 +7,13 @@
destroy-on-close destroy-on-close
full-screen> full-screen>
<el-form <el-form
v-loading="loading"
:disabled="mode === 'view' && tabId !== 'log'" :disabled="mode === 'view' && tabId !== 'log'"
:model="form" :model="form"
:rules="rules" :rules="rules"
label-position="right" label-position="right"
label-width="12rem" label-width="12rem"
ref="dialogForm"> ref="dialogForm"
style="height: 100%">
<el-tabs v-model="tabId" tab-position="top"> <el-tabs v-model="tabId" tab-position="top">
<el-tab-pane :label="$t('基本信息')"> <el-tab-pane :label="$t('基本信息')">
<el-form-item prop="avatar"> <el-form-item prop="avatar">