update TWA Management v0.0.1
This commit is contained in:
17
TWASys-App/Controllers/LoginController.cs
Normal file
17
TWASys-App/Controllers/LoginController.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using AppLibs.Libs;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace TWASys_App.Controllers
|
||||
{
|
||||
[AllowAnonymous]
|
||||
public class LoginController : Controller
|
||||
{
|
||||
[Layout(LayoutOptions.Custom, "Login")]
|
||||
[PageInfor("10001", "Login")]
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
return await this.ViewAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,9 @@
|
||||
using AppLibs.Libs;
|
||||
using TWASys_App.Models;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Encodings;
|
||||
using System.Text;
|
||||
using AppLibs.Libs.Crypt;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using System.Security.Cryptography;
|
||||
using TWASys_App.Models;
|
||||
using TWASys_App.Models.ServerInfo;
|
||||
|
||||
namespace TWASys_App.Controllers
|
||||
@ -83,36 +79,40 @@ namespace TWASys_App.Controllers
|
||||
return Json(await model.UpdateAsync());
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> SetStorageData([FromForm] StorageModel model)
|
||||
{
|
||||
return Json(await model.AddAsync());
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GenerationAccessToken()
|
||||
{
|
||||
var t1 = Task<string>.Run(() =>
|
||||
var t1 = Task<Guid>.Run(() =>
|
||||
{
|
||||
var g = Guid.NewGuid();
|
||||
return Base64UrlTextEncoder.Encode(g.ToByteArray().Concat(BitConverter.GetBytes(DateTime.UtcNow.ToFileTime())).ToArray());
|
||||
return UUID7.NewUuid7();
|
||||
});
|
||||
|
||||
var t2 = Task<string>.Run(() => {
|
||||
var g = Guid.NewGuid();
|
||||
var bytes = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
|
||||
var tokenValue = Base64UrlTextEncoder.Encode(
|
||||
Guid.NewGuid().ToByteArray()
|
||||
.Concat(BitConverter.GetBytes(DateTime.UtcNow.ToFileTimeUtc()))
|
||||
.ToArray()
|
||||
);
|
||||
using var sha = SHA256.Create();
|
||||
var idToken = WebEncoders.Base64UrlEncode(sha.ComputeHash(
|
||||
System.Text.Encoding.UTF8.GetBytes(tokenValue)
|
||||
));
|
||||
|
||||
Array.Resize(ref bytes, 16);
|
||||
|
||||
|
||||
byte[] data = new byte[32];
|
||||
bytes.CopyTo(data, 0);
|
||||
g.ToByteArray().CopyTo(data, 16);
|
||||
var hash = new CRC64();
|
||||
|
||||
return hash.HashToString(data);
|
||||
return idToken;
|
||||
|
||||
});
|
||||
await Task.WhenAll(t1, t2);
|
||||
|
||||
return Json(new
|
||||
{
|
||||
idToken = t2.Result.ToLower(),
|
||||
tokenValue = t1.Result
|
||||
idToken = t1.Result.ToString(),
|
||||
tokenValue = t2.Result.ToLower()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ namespace TWASys_App.DBModels
|
||||
{
|
||||
public class DBManagement
|
||||
{
|
||||
public static string GetConnectionString()
|
||||
public static string GetConnectionString(bool allowVar = false)
|
||||
{
|
||||
string fp = Path.GetFullPath("Keys/db/");
|
||||
|
||||
@ -28,6 +28,7 @@ namespace TWASys_App.DBModels
|
||||
SslCa = Path.Combine(fp, "ca-cert.pem"),
|
||||
SslCert = Path.Combine(fp, "client-cert.pem"),
|
||||
SslKey = Path.Combine(fp, "client-key.pem"),
|
||||
AllowUserVariables = allowVar
|
||||
};
|
||||
//172.168.192.204
|
||||
return builder.ConnectionString;
|
||||
|
||||
26
TWASys-App/DBModels/Files.cs
Normal file
26
TWASys-App/DBModels/Files.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class Files
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public ulong IdFiles { get; set; }
|
||||
|
||||
[ForeignKey("IdFolders")]
|
||||
public ulong IdFolders { get; set; } // BIGINT FK → Folders.idFolders
|
||||
|
||||
public string Code { get; set; } = ""; // VARCHAR(100)
|
||||
public string Name { get; set; } = ""; // VARCHAR(100)
|
||||
public string Path { get; set; } = ""; // TEXT
|
||||
public string Options { get; set; } = ""; // LONGTEXT (JSON, metadata)
|
||||
|
||||
public DateTime CreateDate { get; set; } = DateTime.UtcNow; // DATETIME (UTC khuyên dùng)
|
||||
public DateTime? LastModified { get; set; } = null; // DATETIME NULL
|
||||
public int Status { get; set; } // INT(11)
|
||||
|
||||
public Folder? Folder { get; set; } = null!; // nav
|
||||
}
|
||||
}
|
||||
27
TWASys-App/DBModels/Folder.cs
Normal file
27
TWASys-App/DBModels/Folder.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class Folder
|
||||
{
|
||||
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
|
||||
public ulong IdFolders { get; set; } // BIGINT PK
|
||||
public ulong? IdParent { get; set; } // BIGINT FK, null = root
|
||||
|
||||
public string Name { get; set; } = ""; // VARCHAR(45)
|
||||
public string Code { get; set; } = ""; // VARCHAR(100)
|
||||
public string Path { get; set; } = ""; // TEXT
|
||||
public string Options { get; set; } = ""; // LONGTEXT
|
||||
|
||||
public DateTime CreateDate { get; set; } = DateTime.UtcNow; // DATETIME
|
||||
public DateTime? LastModified { get; set; } = null; // DATETIME NULL
|
||||
public int Status { get; set; } // INT(11)
|
||||
|
||||
public Folder? Parent { get; set; } = null;
|
||||
public ICollection<Folder> Children { get; set; } = new List<Folder>();
|
||||
}
|
||||
}
|
||||
16
TWASys-App/DBModels/Folders_has_StorageArea.cs
Normal file
16
TWASys-App/DBModels/Folders_has_StorageArea.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class Folders_has_StorageArea
|
||||
{
|
||||
[ForeignKey("")]
|
||||
public ulong IdFolders { get; set; }
|
||||
|
||||
[ForeignKey("")]
|
||||
public long IdStorage { get; set; }
|
||||
|
||||
public Folder Folder { get; set; } = null!;
|
||||
public StorageArea Storage { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
@ -7,66 +7,30 @@ namespace TWASys_App.DBModels
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("idLocalServer")]
|
||||
public int IdLocalServer { get; set; } = 0;
|
||||
public long IdLocalServer { get; set; } = 0;
|
||||
|
||||
[StringLength(20)]
|
||||
[Column("ipPrivateServer")]
|
||||
public string IpPrivateServer { get; set; } = "";
|
||||
|
||||
[StringLength(100)]
|
||||
[Column("ipPrivateServer6")]
|
||||
public string IpPrivateServer6 { get; set; } = "";
|
||||
|
||||
[StringLength(100)]
|
||||
[Column("ipPublicServer")]
|
||||
public string IpPrivateServerv6 { get; set; } = "";
|
||||
public string IpPublicServer { get; set; } = "";
|
||||
|
||||
[StringLength(45)]
|
||||
[Column("pathServer")]
|
||||
public string PathServer { get; set; } = "";
|
||||
|
||||
[StringLength(100)]
|
||||
[Column("serialNumber")]
|
||||
public string SerialNumber { get; set; } = "";
|
||||
|
||||
// Ảnh gốc ghi "osVesion" (sai chính tả). Giữ nguyên để khớp DB.
|
||||
[StringLength(100)]
|
||||
[Column("osVesion")]
|
||||
|
||||
public string OsVersion { get; set; } = "";
|
||||
|
||||
[StringLength(100)]
|
||||
[Column("osName")]
|
||||
public string OsName { get; set; } = "";
|
||||
|
||||
[StringLength(45)]
|
||||
[Column("osArch")]
|
||||
public string OsArch { get; set; } = "";
|
||||
|
||||
// Ảnh gốc ghi "osKernal". Giữ nguyên để khớp DB.
|
||||
[StringLength(100)]
|
||||
[Column("osKernal")]
|
||||
public string OsKernel { get; set; } = "";
|
||||
|
||||
[Column("socketNum")]
|
||||
public string OsKernal { get; set; } = "";
|
||||
public int SocketNum { get; set; } = 0;
|
||||
|
||||
[StringLength(150)]
|
||||
[Column("cpuName")]
|
||||
public string CpuName { get; set; } = "";
|
||||
public float TotalRam { get; set; } = 0;
|
||||
|
||||
[Column("totalRam")]
|
||||
public int TotalRam { get; set; } = 0;
|
||||
|
||||
[StringLength(100)]
|
||||
[Column("biosVendor")]
|
||||
public string BiosVendor { get; set; } = "";
|
||||
|
||||
[StringLength(100)]
|
||||
[Column("productUUID")]
|
||||
public string BiosVender { get; set; } = "";
|
||||
public string ProductUuid { get; set; } = "";
|
||||
|
||||
[Column("status")]
|
||||
public int Status { get; set; } = 0;
|
||||
|
||||
}
|
||||
|
||||
26
TWASys-App/DBModels/MicrosoftAccount.cs
Normal file
26
TWASys-App/DBModels/MicrosoftAccount.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class MicrosoftAccount
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public long IdCloudAccount { get; set; }
|
||||
public string AccName { get; set; } = null!;
|
||||
public string ClientID { get; set; } = null!; // GUID string
|
||||
public string TenantID { get; set; } = null!;
|
||||
public string? ClientSecret { get; set; } // encrypted at rest
|
||||
public string? SiteID { get; set; }
|
||||
public string? DriveID { get; set; }
|
||||
public string? PathSharePoint { get; set; }
|
||||
public string? RefreshToken { get; set; } // encrypted
|
||||
public string? AccessToken { get; set; } // optional cache
|
||||
public DateTime? ExpiresAt { get; set; }
|
||||
public string? Scopes { get; set; }
|
||||
public DateTime CreateDate { get; set; }
|
||||
public DateTime? LastModified { get; set; }
|
||||
public int Status { get; set; }
|
||||
}
|
||||
}
|
||||
18
TWASys-App/DBModels/RefreshToken.cs
Normal file
18
TWASys-App/DBModels/RefreshToken.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class RefreshToken
|
||||
{
|
||||
[Key]
|
||||
public string IdRefreshToken { get; set; } = "";
|
||||
|
||||
[ForeignKey("IdServerAuthorization")]
|
||||
public ulong IdServerAuthorization { get; set; }
|
||||
public string __RefreshToken { get; set; } = ""; // refreshToken
|
||||
public DateTime CreateDate { get; set; }
|
||||
public DateTime ExpireDate { get; set; }
|
||||
public int Status { get; set; }
|
||||
}
|
||||
}
|
||||
19
TWASys-App/DBModels/RefreshToken_Log.cs
Normal file
19
TWASys-App/DBModels/RefreshToken_Log.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class RefreshToken_Log
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public ulong IdRefreshTokenLog { get; set; }
|
||||
public string IdRefreshToken { get; set; } = null!;
|
||||
public DateTime DateRenew { get; set; } // UTC
|
||||
public int Count { get; set; } = 1;
|
||||
public int LifeTime { get; set; }
|
||||
public int Status { get; set; } = 1;
|
||||
|
||||
public RefreshToken RefreshToken { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
21
TWASys-App/DBModels/ServerAuthorization.cs
Normal file
21
TWASys-App/DBModels/ServerAuthorization.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class ServerAuthorization
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public ulong IdServerAuthorization { get; set; }
|
||||
|
||||
[ForeignKey("IdStorageServer")]
|
||||
public long IdStorageServer { get; set; }
|
||||
public DateTime CreateDate { get; set; }
|
||||
public int Count { get; set; }
|
||||
public int Status { get; set; }
|
||||
|
||||
[NotMapped()]
|
||||
public ICollection<ServerAuthorization_has_Token> Tokens { get; set; } = new List<ServerAuthorization_has_Token>();
|
||||
}
|
||||
}
|
||||
19
TWASys-App/DBModels/ServerAuthorization_has_Token.cs
Normal file
19
TWASys-App/DBModels/ServerAuthorization_has_Token.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class ServerAuthorization_has_Token
|
||||
{
|
||||
[ForeignKey("")]
|
||||
public ulong IdServerAuthorization { get; set; }
|
||||
|
||||
[ForeignKey("")]
|
||||
public string IdToken { get; set; } = "";
|
||||
|
||||
public int Count { get; set; }
|
||||
public int Status { get; set; }
|
||||
|
||||
public ServerAuthorization ServerAuthorization { get; set; } = null!;
|
||||
public Token Token { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
21
TWASys-App/DBModels/StorageArea.cs
Normal file
21
TWASys-App/DBModels/StorageArea.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class StorageArea
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public long IdStorage { get; set; } // PK (AUTO_INCREMENT nếu DB đang để vậy)
|
||||
|
||||
public ulong? IdEmp { get; set; } = null; // FK -> Emp (nếu có)
|
||||
|
||||
|
||||
public DateTime CreateDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public double TotalSize { get; set; } = 0; // map FLOAT MySQL -> double
|
||||
|
||||
public int Status { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
24
TWASys-App/DBModels/StorageArea_has_StorageServer.cs
Normal file
24
TWASys-App/DBModels/StorageArea_has_StorageServer.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class StorageArea_has_StorageServer
|
||||
{
|
||||
|
||||
[ForeignKey("IdStorage")]
|
||||
public long IdStorage { get; set; }
|
||||
|
||||
[ForeignKey("IdStorageServer")]
|
||||
public long IdStorageServer { get; set; }
|
||||
|
||||
[Column("priority", TypeName = "int")]
|
||||
public int Priority { get; set; } = 0;
|
||||
|
||||
[Column("createDate", TypeName = "datetime")]
|
||||
public DateTime CreateDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[Column("status", TypeName = "int")]
|
||||
public int Status { get; set; } = 0;
|
||||
|
||||
}
|
||||
}
|
||||
25
TWASys-App/DBModels/StorageServer.cs
Normal file
25
TWASys-App/DBModels/StorageServer.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class StorageServer
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public long IdStorageServer { get; set; }
|
||||
public long? IdEmp { get; set; }
|
||||
|
||||
[ForeignKey("IdTypeStorageServer")]
|
||||
public long IdTypeStorageServer { get; set; }
|
||||
|
||||
public string StorageName { get; set; } = "";
|
||||
|
||||
public DateTime? CreateDate { get; set; }
|
||||
|
||||
|
||||
public string ControllerID { get; set; } = "";
|
||||
|
||||
public int Status { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
@ -2,22 +2,22 @@
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class StorageServerHasLocalServer
|
||||
public class StorageServer_has_LocalServer
|
||||
{
|
||||
|
||||
[Column("idStorageServer")]
|
||||
public int IdStorageServer { get; set; } = 0;
|
||||
|
||||
[Column("idLocalServer")]
|
||||
public int IdLocalServer { get; set; } = 0;
|
||||
[ForeignKey("IdStorageServer")]
|
||||
public long IdStorageServer { get; set; } = 0;
|
||||
|
||||
[Column("createDate")]
|
||||
[ForeignKey("IdLocalServer")]
|
||||
public long IdLocalServer { get; set; } = 0;
|
||||
|
||||
|
||||
public DateTime CreateDate { get; set; } = DateTime.UtcNow; // nên lưu UTC
|
||||
|
||||
[Column("modifyDate")]
|
||||
|
||||
public DateTime? ModifyDate { get; set; } = null; // nên lưu UTC
|
||||
|
||||
[Column("status")]
|
||||
|
||||
public int Status { get; set; } = 0;
|
||||
}
|
||||
}
|
||||
|
||||
17
TWASys-App/DBModels/StorageServer_has_MicrosoftAccount.cs
Normal file
17
TWASys-App/DBModels/StorageServer_has_MicrosoftAccount.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class StorageServer_has_MicrosoftAccount
|
||||
{
|
||||
[ForeignKey("")]
|
||||
public long IdStorageServer { get; set; }
|
||||
[ForeignKey("")]
|
||||
public long IdCloudAccount { get; set; }
|
||||
public DateTime CreateDate { get; set; } = DateTime.UtcNow;
|
||||
public int Status { get; set; } = 1;
|
||||
|
||||
public StorageServer StorageServer { get; set; } = null!;
|
||||
public MicrosoftAccount CloudAccount { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
24
TWASys-App/DBModels/StorageServers_ValidationDomain.cs
Normal file
24
TWASys-App/DBModels/StorageServers_ValidationDomain.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class StorageServers_ValidationDomain
|
||||
{
|
||||
[ForeignKey("")]
|
||||
public long IdStorageServer { get; set; }
|
||||
|
||||
[ForeignKey("")]
|
||||
public long IdValidationDomain { get; set; }
|
||||
|
||||
[Column("modifyDate", TypeName = "datetime")]
|
||||
public DateTime? ModifyDate { get; set; } = null;
|
||||
|
||||
[Column("createDate", TypeName = "datetime")]
|
||||
public DateTime CreateDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[Column("status", TypeName = "int")]
|
||||
public int Status { get; set; } = 0;
|
||||
|
||||
}
|
||||
}
|
||||
27
TWASys-App/DBModels/SyncFile_Log.cs
Normal file
27
TWASys-App/DBModels/SyncFile_Log.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class SyncFile_Log
|
||||
{
|
||||
public ulong Id { get; set; }
|
||||
|
||||
[ForeignKey("")]
|
||||
public long IdFiles { get; set; }
|
||||
|
||||
[ForeignKey("")]
|
||||
public long IdStorageServer { get; set; }
|
||||
[ForeignKey("")]
|
||||
public long IdLocalServer { get; set; }
|
||||
|
||||
[ForeignKey("")]
|
||||
public long IdCloudAccount { get; set; } // FK -> CloudAccounts.id
|
||||
public DateTime SyncDate { get; set; } = DateTime.UtcNow; // UTC
|
||||
public string? PathOnServer { get; set; } // đường dẫn lưu trên đích
|
||||
public int Status { get; set; } // 0=pending,1=ok,2=retry,3=failed,...
|
||||
|
||||
// nav
|
||||
public Files File { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
15
TWASys-App/DBModels/Token.cs
Normal file
15
TWASys-App/DBModels/Token.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class Token
|
||||
{
|
||||
[Key]
|
||||
public string IdToken { get; set; } = "";
|
||||
public string AccessToken { get; set; } = "";
|
||||
public DateTime CreateDate { get; set; }
|
||||
public DateTime ExpireDate { get; set; }
|
||||
public int Status { get; set; }
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class TypeStorageServer
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int IdTypeStorageServer { get; set; }
|
||||
public string TypeName { get; set; }
|
||||
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace TWASys_App.DBModels
|
||||
{
|
||||
public class ValidationDomain
|
||||
{
|
||||
[Key]
|
||||
public int IdValidationDomain { set; get; }
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public long IdValidationDomain { set; get; }
|
||||
|
||||
public string Protocol { set; get; }
|
||||
public int PortNumber { set; get; }
|
||||
|
||||
329
TWASys-App/Dapper.AExtentions/BatchInsert.cs
Normal file
329
TWASys-App/Dapper.AExtentions/BatchInsert.cs
Normal file
@ -0,0 +1,329 @@
|
||||
using Dapper;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using MySqlConnector;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using System.Text;
|
||||
|
||||
namespace TWASys_App.Dapper.AExtentions
|
||||
{
|
||||
public class DataValue
|
||||
{
|
||||
public object? Data { set; get; }
|
||||
|
||||
public string Name { set; get; } = "";
|
||||
|
||||
public string PKName { set; get; } = "";
|
||||
}
|
||||
|
||||
public class BatchInsert
|
||||
{
|
||||
private IDbConnection _connect;
|
||||
private IDbTransaction _transaction;
|
||||
private Dictionary<string, DataValue> _dataKey;
|
||||
private List<DataValue> _list;
|
||||
private StringBuilder queryBatch = new();
|
||||
public int IdTable = 100;
|
||||
public BatchInsert(IDbConnection connect, IDbTransaction transaction)
|
||||
{
|
||||
_connect = connect;
|
||||
_transaction = transaction;
|
||||
_dataKey = new Dictionary<string, DataValue>();
|
||||
_list = new List<DataValue>();
|
||||
}
|
||||
|
||||
public void AddRow<T>(T obj)
|
||||
{
|
||||
var dt = new DataValue
|
||||
{
|
||||
Name = "",
|
||||
PKName = "",
|
||||
Data = obj
|
||||
};
|
||||
_list.Add(dt);
|
||||
|
||||
var p = DapperCommand.QueryInsert(obj, _dataKey, IdTable);
|
||||
IdTable++;
|
||||
dt.Name = p.Name;
|
||||
dt.PKName = p.KeyVar;
|
||||
if (p.IsKeyAI)
|
||||
{
|
||||
_dataKey.TryAdd(p.KeyVar, dt);
|
||||
}
|
||||
queryBatch.AppendLine(p.Query);
|
||||
}
|
||||
|
||||
public string GetQuery()
|
||||
{
|
||||
string query = string.Empty;
|
||||
foreach (var (key, value) in _dataKey)
|
||||
{
|
||||
query += $"Select @tb{value.Name}_{key} As {key}; \n";
|
||||
}
|
||||
queryBatch.AppendLine(query);
|
||||
return queryBatch.ToString();
|
||||
}
|
||||
|
||||
public async Task ExcuteQuery()
|
||||
{
|
||||
|
||||
var dynamic = ToDynamicParametersSeqPrefix(_list);
|
||||
var str = GetQuery();
|
||||
Console.WriteLine(str);
|
||||
using var grid = await _connect.QueryMultipleAsync(str, dynamic, _transaction);
|
||||
await MapAutoIncrementIdsAsync(grid, _dataKey.Values);
|
||||
|
||||
}
|
||||
|
||||
public static async Task MapAutoIncrementIdsAsync(SqlMapper.GridReader grid,IEnumerable<DataValue> items)
|
||||
{
|
||||
foreach (var dv in items)
|
||||
{
|
||||
var obj = dv?.Data;
|
||||
if (obj is null) continue;
|
||||
|
||||
var (pk, isAuto) = FindPrimaryKey(obj.GetType());
|
||||
if (pk is null || !isAuto) continue; // không phải auto-inc → không đọc scalar
|
||||
|
||||
// nếu object đã có ID (không rỗng) thì bỏ qua để không lệch thứ tự result set
|
||||
var cur = pk.GetValue(obj);
|
||||
if (!IsEmptyId(cur)) continue;
|
||||
|
||||
// đọc scalar từ SELECT kế tiếp và gán lại cho property khóa
|
||||
var raw = await grid.ReadSingleAsync<object>();
|
||||
var targetType = Nullable.GetUnderlyingType(pk.PropertyType) ?? pk.PropertyType;
|
||||
|
||||
if (raw is IDictionary<string, object> row)
|
||||
{
|
||||
if (!row.TryGetValue(dv?.PKName, out raw))
|
||||
throw new InvalidOperationException($"Missing column {dv?.PKName}");
|
||||
}
|
||||
|
||||
// MySqlDecimal → decimal
|
||||
if (raw?.GetType().FullName == "MySql.Data.Types.MySqlDecimal")
|
||||
{
|
||||
var t = raw.GetType();
|
||||
raw = (decimal)t.GetProperty("Value")!.GetValue(raw)!;
|
||||
}
|
||||
|
||||
// Giờ o phải là số: long/ulong/int/decimal/…
|
||||
var target = Nullable.GetUnderlyingType(pk.PropertyType) ?? pk.PropertyType;
|
||||
pk.SetValue(obj, ConvertNumericTo(target, raw));
|
||||
|
||||
}
|
||||
}
|
||||
static object ConvertNumericTo(Type target, object? x)
|
||||
{
|
||||
// ưu tiên xử lý 2 nhánh chính
|
||||
if (target == typeof(ulong) || target == typeof(uint) || target == typeof(ushort) || target == typeof(byte))
|
||||
{
|
||||
ulong u = x switch
|
||||
{
|
||||
ulong v => v,
|
||||
long v => v < 0 ? throw new OverflowException() : (ulong)v,
|
||||
int v => v < 0 ? throw new OverflowException() : (ulong)v,
|
||||
decimal v => v < 0 ? throw new OverflowException() : checked((ulong)v),
|
||||
_ => Convert.ToUInt64(x, System.Globalization.CultureInfo.InvariantCulture)
|
||||
};
|
||||
return target == typeof(ulong) ? u :
|
||||
target == typeof(uint) ? checked((uint)u) :
|
||||
target == typeof(ushort) ? checked((ushort)u) :
|
||||
checked((byte)u);
|
||||
}
|
||||
else
|
||||
{
|
||||
long s = x switch
|
||||
{
|
||||
long v => v,
|
||||
ulong v => v > (ulong)long.MaxValue ? throw new OverflowException() : (long)v,
|
||||
int v => v,
|
||||
decimal v => checked((long)v),
|
||||
_ => Convert.ToInt64(x, System.Globalization.CultureInfo.InvariantCulture)
|
||||
};
|
||||
return target == typeof(long) ? s :
|
||||
target == typeof(int) ? checked((int)s) :
|
||||
target == typeof(short) ? checked((short)s) :
|
||||
checked((sbyte)s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static DynamicParameters ToDynamicParametersSeqPrefix(
|
||||
IEnumerable<DataValue> inputs // 0 coi là "trống" (trừ property tên Status)
|
||||
)
|
||||
{
|
||||
var dp = new DynamicParameters();
|
||||
var seen = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
foreach (var src in inputs)
|
||||
{
|
||||
var t = src.Data?.GetType();
|
||||
|
||||
var props = t?.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
foreach (var p in props)
|
||||
{
|
||||
if (!p.CanRead) continue;
|
||||
if (IsNotMapped(p)) continue;
|
||||
if (IsKeyOrForeignKey(p, src.Data))
|
||||
continue;
|
||||
|
||||
|
||||
var paramName = "tb" + src.Name + "_" + p.Name;
|
||||
var val = p.GetValue(src.Data);
|
||||
dp.Add("@" + paramName, val);
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
private static (PropertyInfo? Key, bool IsAutoInc) FindPrimaryKey(Type t)
|
||||
{
|
||||
PropertyInfo? key = null; bool auto = false;
|
||||
|
||||
foreach (var p in t.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
if (HasAttr(p, "System.ComponentModel.DataAnnotations.KeyAttribute", "KeyAttribute",
|
||||
"Dapper.Contrib.Extensions.KeyAttribute"))
|
||||
{ key = p; auto = IsDatabaseGeneratedIdentity(p); break; }
|
||||
|
||||
if (HasAttr(p, "Dapper.Contrib.Extensions.ExplicitKeyAttribute", "ExplicitKeyAttribute"))
|
||||
{ key = p; auto = false; break; }
|
||||
}
|
||||
|
||||
// fallback theo tên "Id" nếu không có attribute
|
||||
key ??= t.GetProperty("Id", BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
// nếu không tìm được attribute, đoán auto-inc cho kiểu số
|
||||
if (key != null && !auto)
|
||||
{
|
||||
var k = Nullable.GetUnderlyingType(key.PropertyType) ?? key.PropertyType;
|
||||
auto = k == typeof(int) || k == typeof(long) || k == typeof(uint) || k == typeof(ulong);
|
||||
}
|
||||
return (key, auto);
|
||||
}
|
||||
|
||||
private static bool IsDatabaseGeneratedIdentity(PropertyInfo p)
|
||||
{
|
||||
// [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
foreach (var ca in p.CustomAttributes)
|
||||
{
|
||||
var full = ca.AttributeType.FullName ?? ca.AttributeType.Name;
|
||||
if (full is "System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute"
|
||||
or "DatabaseGeneratedAttribute")
|
||||
{
|
||||
if (ca.ConstructorArguments.Count == 1 && ca.ConstructorArguments[0].ArgumentType.IsEnum)
|
||||
return Convert.ToInt32(ca.ConstructorArguments[0].Value) == 1; // Identity = 1
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsNotMapped(PropertyInfo p)
|
||||
{
|
||||
return HasAttr(p, "System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute", "NotMappedAttribute");
|
||||
}
|
||||
private static bool IsKey(PropertyInfo p, object? obj)
|
||||
{
|
||||
if( HasAttr(p,
|
||||
"System.ComponentModel.DataAnnotations.KeyAttribute", "KeyAttribute",
|
||||
"Dapper.Contrib.Extensions.KeyAttribute"))
|
||||
{
|
||||
var val = p.GetValue(obj);
|
||||
ulong t = 0;
|
||||
if (val == null && string.IsNullOrWhiteSpace(val?.ToString()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ulong.TryParse(val?.ToString(), out t) && t == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static bool IsKeyOrForeignKey(PropertyInfo p, object? obj)
|
||||
{
|
||||
return IsKey(p, obj) || IsForeignKeyProperty(p, obj);
|
||||
}
|
||||
|
||||
private static bool HasAttr(MemberInfo m, params string[] names)
|
||||
{
|
||||
return m.CustomAttributes.Any(ca =>
|
||||
{
|
||||
var full = ca.AttributeType.FullName ?? ca.AttributeType.Name;
|
||||
var shortName = ca.AttributeType.Name;
|
||||
return names.Contains(full) || names.Contains(shortName);
|
||||
});
|
||||
}
|
||||
|
||||
private static bool IsForeignKeyProperty(PropertyInfo p, object? obj)
|
||||
{
|
||||
// [ForeignKey] ngay trên property
|
||||
if (HasAttr(p, "System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute", "ForeignKeyAttribute"))
|
||||
{
|
||||
var val = p.GetValue(obj);
|
||||
ulong t = 0;
|
||||
if (val == null && string.IsNullOrWhiteSpace(val?.ToString()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ulong.TryParse(val?.ToString(), out t) && t == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//// [ForeignKey("PropName")] đặt trên navigation khác, trỏ tới property này
|
||||
//var my = p.Name;
|
||||
//foreach (var nav in allProps)
|
||||
//{
|
||||
// if (ReferenceEquals(nav, p)) continue;
|
||||
// var fkAttr = nav.CustomAttributes.FirstOrDefault(ca =>
|
||||
// (ca.AttributeType.FullName ?? ca.AttributeType.Name) is
|
||||
// "System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute" or "ForeignKeyAttribute");
|
||||
// if (fkAttr == default) continue;
|
||||
|
||||
// var nameArg = fkAttr.ConstructorArguments.FirstOrDefault().Value?.ToString();
|
||||
// if (string.IsNullOrWhiteSpace(nameArg))
|
||||
// nameArg = fkAttr.NamedArguments.FirstOrDefault(a => a.MemberName == "Name").TypedValue.Value?.ToString();
|
||||
|
||||
// if (string.IsNullOrWhiteSpace(nameArg)) continue;
|
||||
|
||||
// var names = nameArg.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
// .Select(s => s.Trim());
|
||||
// if (names.Any(n => string.Equals(n, my, StringComparison.OrdinalIgnoreCase)))
|
||||
// return true;
|
||||
//}
|
||||
return false;
|
||||
}
|
||||
private static bool IsEmptyId(object? v)
|
||||
{
|
||||
if (v is null) return true;
|
||||
var t = Nullable.GetUnderlyingType(v.GetType()) ?? v.GetType();
|
||||
if (!t.IsValueType) return false;
|
||||
try { return v.Equals(Activator.CreateInstance(t)); } catch { return false; }
|
||||
}
|
||||
}
|
||||
public sealed class PropMeta
|
||||
{
|
||||
public required PropertyInfo Prop { get; init; }
|
||||
public required Func<object, object?> Getter { get; init; }
|
||||
public required Type UnderlyingType { get; init; }
|
||||
public required bool IsNotMapped { get; init; }
|
||||
public required bool IsKeyOrForeignKey { get; init; }
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,80 @@
|
||||
using Dapper;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Net.WebSockets;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace TWASys_App.Dapper.AExtentions
|
||||
{
|
||||
public static class DapperCommand
|
||||
{
|
||||
public static async Task Insert<T>(this DbConnection connection, T obj, bool identityInsert = true)
|
||||
|
||||
public static dynamic QueryInsert<T>(T obj)
|
||||
{
|
||||
return QueryInsert(obj, new Dictionary<string, DataValue>());
|
||||
}
|
||||
|
||||
public static dynamic QueryInsert<T>(T obj, Dictionary<string, DataValue> data, int IdTable = 100)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var tableName = TableMapper.GetTableName(type);
|
||||
var allProperties = PropertiesCache.TypePropertiesCache(type);
|
||||
var keyProperties = PropertiesCache.KeyPropertiesCache(type);
|
||||
var fkProperties = PropertiesCache.FKPropertiesCache(type);
|
||||
var computedProperties = PropertiesCache.ComputedPropertiesCache(type);
|
||||
var columns = PropertiesCache.GetColumnNamesCache(type);
|
||||
|
||||
var insertProperties = allProperties.Except(computedProperties).Except(fkProperties).ToList();
|
||||
var insertPropertiesString = string.Empty;
|
||||
var stringKeyProperty = string.Empty;
|
||||
var keyAI = string.Empty;
|
||||
var flag = false;
|
||||
var q = string.Empty;
|
||||
if (keyProperties.Count > 0)
|
||||
{
|
||||
flag = true;
|
||||
insertProperties = insertProperties.Except(keyProperties).ToList();
|
||||
stringKeyProperty = GetColumnsString(keyProperties.ToList(), columns);
|
||||
keyAI = $@"SET @{GetColumnsString(keyProperties.ToList(), columns, IdTable.ToString(), "")} := LAST_INSERT_ID();";
|
||||
}
|
||||
insertPropertiesString = GetColumnsString(insertProperties, columns);
|
||||
var fkPropertiesString = string.Empty;
|
||||
var fkValuesString = string.Empty;
|
||||
if (data.Count > 0)
|
||||
{
|
||||
fkPropertiesString = GetColumnsString(fkProperties, columns);
|
||||
|
||||
|
||||
fkValuesString = string.Join(", ", fkProperties.Select(u => {
|
||||
var ok = data.TryGetValue(u.Name, out var v);
|
||||
if (ok)
|
||||
{
|
||||
return $"@tb{v?.Name}_{u.Name}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"@tb{IdTable}_{u.Name}";
|
||||
}
|
||||
}));
|
||||
fkPropertiesString += (string.IsNullOrEmpty(fkPropertiesString))?"": ", ";
|
||||
fkValuesString += (string.IsNullOrEmpty(fkValuesString)) ? "" : ", ";
|
||||
}
|
||||
q = $@"INSERT INTO {FormatTableName(tableName)} ({fkPropertiesString + insertPropertiesString}) VALUES ({fkValuesString + GetColumnsString(insertProperties, columns, IdTable.ToString(), "@")});
|
||||
{keyAI}";
|
||||
|
||||
return new
|
||||
{
|
||||
IsKeyAI = flag,
|
||||
Query = q,
|
||||
Name = IdTable.ToString(),
|
||||
KeyVar = stringKeyProperty
|
||||
};
|
||||
}
|
||||
public static async Task Insert<T>(this DbConnection connection, T obj, IDbTransaction? tx = null)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var tableName = TableMapper.GetTableName(type);
|
||||
@ -17,13 +85,14 @@ namespace TWASys_App.Dapper.AExtentions
|
||||
|
||||
var insertProperties = allProperties.Except(computedProperties).ToList();
|
||||
var insertPropertiesString = string.Empty;
|
||||
if (identityInsert)
|
||||
|
||||
if (keyProperties.Count > 0)
|
||||
{
|
||||
insertProperties = insertProperties.Except(keyProperties).ToList();
|
||||
insertPropertiesString = GetColumnsString(insertProperties, columns);
|
||||
var insertedId = await connection.QueryFirstAsync<int>($@"
|
||||
INSERT INTO {FormatTableName(tableName)} ({insertPropertiesString}) VALUES ({GetColumnsString(insertProperties, columns, "@")});
|
||||
SELECT LAST_INSERT_ID()", obj);
|
||||
SELECT LAST_INSERT_ID()", obj, tx);
|
||||
keyProperties[0].SetValue(obj, insertedId);
|
||||
|
||||
}
|
||||
@ -32,7 +101,7 @@ namespace TWASys_App.Dapper.AExtentions
|
||||
insertPropertiesString = GetColumnsString(insertProperties, columns);
|
||||
await connection.QueryFirstAsync($@"
|
||||
INSERT INTO {FormatTableName(tableName)}({insertPropertiesString})
|
||||
VALUES ({GetColumnsString(insertProperties, columns, "@")})", obj);
|
||||
VALUES ({GetColumnsString(insertProperties, columns, "@")})", obj, tx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,17 +140,24 @@ namespace TWASys_App.Dapper.AExtentions
|
||||
{
|
||||
return string.Join(prefix, properties.Select(p => $"{columnNames[p.Name]} = @{p.Name}"));
|
||||
}
|
||||
private static string GetColumnsString(IEnumerable<PropertyInfo> properties, IReadOnlyDictionary<string, string> columnNames, string tablePrefix = null)
|
||||
|
||||
|
||||
private static string GetColumnsString(IEnumerable<PropertyInfo> properties, IReadOnlyDictionary<string, string> columnNames, string tbName, string tablePrefix = "")
|
||||
{
|
||||
if (tbName != string.Empty) tbName = "tb" + tbName + "_";
|
||||
if (tablePrefix == "target.")
|
||||
{
|
||||
return string.Join(", ", properties.Select(property => $"{tablePrefix}{columnNames[property.Name]} as {property.Name}"));
|
||||
}
|
||||
else if(tablePrefix == "@")
|
||||
{
|
||||
return string.Join(", ", properties.Select(property => $"{tablePrefix}{property.Name}"));
|
||||
return string.Join(", ", properties.Select(property => $"{tablePrefix}{tbName + property.Name}"));
|
||||
}
|
||||
return string.Join(", ", properties.Select(property => $"{tablePrefix}{columnNames[property.Name]}"));
|
||||
return string.Join(", ", properties.Select(property => $"{tablePrefix}{tbName + columnNames[property.Name].Replace("__", "")}"));
|
||||
}
|
||||
private static string GetColumnsString(IEnumerable<PropertyInfo> properties, IReadOnlyDictionary<string, string> columnNames, string tablePrefix = null)
|
||||
{
|
||||
return GetColumnsString(properties, columnNames, "", tablePrefix);
|
||||
}
|
||||
private static string FormatTableName(string table)
|
||||
{
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
@ -7,10 +9,12 @@ namespace TWASys_App.Dapper.AExtentions
|
||||
public class PropertiesCache
|
||||
{
|
||||
private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> KeyProperties = new();
|
||||
private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> FKProperties = new();
|
||||
private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> TypeProperties = new();
|
||||
private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> ComputedProperties = new();
|
||||
private static readonly ConcurrentDictionary<RuntimeTypeHandle, IReadOnlyDictionary<string, string>> ColumnNames = new();
|
||||
|
||||
|
||||
public static List<PropertyInfo> TypePropertiesCache(Type type)
|
||||
{
|
||||
if (TypeProperties.TryGetValue(type.TypeHandle, out var cachedProps))
|
||||
@ -60,6 +64,28 @@ namespace TWASys_App.Dapper.AExtentions
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool IsPkAutoIncrement(PropertyInfo p)
|
||||
{
|
||||
|
||||
// ===== Fallback by-name (nếu không thể tham chiếu typed)
|
||||
var attrs = p.GetCustomAttributes(true);
|
||||
bool hasKeyByName = attrs.Any(a => a.GetType().Name is "KeyAttribute");
|
||||
|
||||
var dbgenByName = attrs.FirstOrDefault(a => a.GetType().Name is "DatabaseGeneratedAttribute");
|
||||
bool isIdentityByName = false;
|
||||
if (dbgenByName != null)
|
||||
{
|
||||
// Tìm property "DatabaseGeneratedOption" (enum) và đọc giá trị "Identity"
|
||||
var prop = dbgenByName.GetType().GetProperty("DatabaseGeneratedOption");
|
||||
var val = prop?.GetValue(dbgenByName)?.ToString(); // ví dụ "Identity"
|
||||
isIdentityByName = string.Equals(val, "Identity", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (hasKeyByName && isIdentityByName) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<PropertyInfo> KeyPropertiesCache(Type type)
|
||||
{
|
||||
if (KeyProperties.TryGetValue(type.TypeHandle, out var cachedProps))
|
||||
@ -68,19 +94,42 @@ namespace TWASys_App.Dapper.AExtentions
|
||||
}
|
||||
|
||||
var allProperties = TypePropertiesCache(type);
|
||||
var keyProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a.GetType().Name == "KeyAttribute")).ToList();
|
||||
var keyProperties = allProperties.Where(IsPkAutoIncrement).ToList();
|
||||
KeyProperties[type.TypeHandle] = keyProperties; // ghi cache khi miss
|
||||
return keyProperties;
|
||||
}
|
||||
|
||||
if (keyProperties.Count == 0)
|
||||
|
||||
public static List<PropertyInfo> FKPropertiesCache(Type type)
|
||||
{
|
||||
if (FKProperties.TryGetValue(type.TypeHandle, out var cachedProps))
|
||||
{
|
||||
var idProp = allProperties.Find(p => string.Equals(p.Name, "id", StringComparison.CurrentCultureIgnoreCase));
|
||||
if (idProp != null)
|
||||
return cachedProps.ToList();
|
||||
}
|
||||
var allProperties = TypePropertiesCache(type);
|
||||
var keyProperties = allProperties.Where(HasForeignKeyAttribute).ToList();
|
||||
FKProperties[type.TypeHandle] = keyProperties;
|
||||
return keyProperties;
|
||||
}
|
||||
static bool HasForeignKeyAttribute(PropertyInfo p)
|
||||
{
|
||||
if (p.GetCustomAttribute<ForeignKeyAttribute>() != null) return true;
|
||||
|
||||
// FK đặt trên navigation và chỉ ra tên prop FK
|
||||
var t = p.DeclaringType!;
|
||||
foreach (var nav in t.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
|
||||
// Fallback by-name nếu không tham chiếu DataAnnotations (tùy dự án)
|
||||
var attr = nav.GetCustomAttributes(true).FirstOrDefault(a => a.GetType().Name == "ForeignKeyAttribute");
|
||||
if (attr != null)
|
||||
{
|
||||
keyProperties.Add(idProp);
|
||||
var val = attr.GetType().GetProperty("Name")?.GetValue(attr);
|
||||
if (val == null && string.IsNullOrWhiteSpace(val?.ToString()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
KeyProperties[type.TypeHandle] = keyProperties;
|
||||
return keyProperties;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<PropertyInfo> ComputedPropertiesCache(Type type)
|
||||
@ -95,7 +144,7 @@ namespace TWASys_App.Dapper.AExtentions
|
||||
return computedProperties;
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<string, string> GetColumnNames(IEnumerable<PropertyInfo> props)
|
||||
public static IReadOnlyDictionary<string, string> GetColumnNames(IEnumerable<PropertyInfo> props)
|
||||
{
|
||||
var ret = new Dictionary<string, string>();
|
||||
foreach (var prop in props)
|
||||
|
||||
55
TWASys-App/Models/Login/LoginCheckFilter.cs
Normal file
55
TWASys-App/Models/Login/LoginCheckFilter.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace TWASys_App.Models.Login
|
||||
{
|
||||
public sealed class LoginCheckFilter : IAsyncActionFilter, IOrderedFilter
|
||||
{
|
||||
public int Order => int.MinValue;
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
|
||||
var http = context.HttpContext;
|
||||
|
||||
// 1) Bỏ qua nếu endpoint cho phép anonymous
|
||||
var endpoint = http.GetEndpoint();
|
||||
if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null ||
|
||||
context.Filters.OfType<IAllowAnonymousFilter>().Any())
|
||||
{
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) Nếu chưa đăng nhập → redirect (web) hoặc 401 (API/Ajax)
|
||||
var uid = http.Session.GetString("userID");
|
||||
if (string.IsNullOrEmpty(uid))
|
||||
{
|
||||
// API/Ajax → trả 401 JSON; Web → redirect login
|
||||
var accepts = http.Request.Headers.Accept.ToString();
|
||||
var isApi = accepts.Contains("application/json", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (isApi)
|
||||
{
|
||||
context.Result = new JsonResult(new MessageHeader
|
||||
{
|
||||
ID = 1000,
|
||||
Message = "Required Login",
|
||||
Status = 0
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var returnUrl = UrlEncoder.Default.Encode(http.Request.Path + http.Request.QueryString);
|
||||
context.Result = new RedirectResult($"/login?returnUrl={returnUrl}");
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
await next();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,6 @@
|
||||
namespace TWASys_App.Models
|
||||
using MySqlConnector;
|
||||
|
||||
namespace TWASys_App.Models
|
||||
{
|
||||
public abstract class ModelBase: IPaging
|
||||
{
|
||||
@ -12,6 +14,6 @@
|
||||
public int PageNumber { get; set; }
|
||||
public int MaxRow { get; set; }
|
||||
|
||||
|
||||
protected MySqlConnection _connection = null!;
|
||||
}
|
||||
}
|
||||
|
||||
12
TWASys-App/Models/Shared.cs
Normal file
12
TWASys-App/Models/Shared.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace TWASys_App.Models
|
||||
{
|
||||
public class Shared
|
||||
{
|
||||
private static List<string> _list = new List<string> { "80633.jpg", "806372.jpg", "806459.jpg" };
|
||||
public static string RandomImages()
|
||||
{
|
||||
var r = new Random();
|
||||
return _list[r.Next(0, _list.Count - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
159
TWASys-App/Models/StorageModel.cs
Normal file
159
TWASys-App/Models/StorageModel.cs
Normal file
@ -0,0 +1,159 @@
|
||||
|
||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||
using Microsoft.VisualBasic;
|
||||
using MySqlConnector;
|
||||
using System.Data.Common;
|
||||
using System.Xml.Linq;
|
||||
using TWASys_App.Dapper.AExtentions;
|
||||
using TWASys_App.DBModels;
|
||||
|
||||
namespace TWASys_App.Models
|
||||
{
|
||||
public class StorageModel : ModelBase
|
||||
{
|
||||
public long StorageTypeID { set; get; }
|
||||
|
||||
public string ControllerName { set; get; } = "";
|
||||
|
||||
public string StorageName { set; get; } = "";
|
||||
|
||||
public ICollection<ValidationDomain> ValidationDomains { set; get; } = new List<ValidationDomain>();
|
||||
|
||||
public string IpPublic { set; get; } = "";
|
||||
|
||||
public string IpPrivatev4 { set; get; } = "";
|
||||
|
||||
public string IpPrivatev6 { set; get; } = "";
|
||||
|
||||
public string OsName { set; get; } = "";
|
||||
|
||||
public string OsPlatform { set; get; } = "";
|
||||
|
||||
public string OsVersion { set; get; } = "";
|
||||
|
||||
public string OsKernel { set; get; } = "";
|
||||
|
||||
public string OsArch { set; get; } = "";
|
||||
|
||||
public string BiosSN { set; get; } = "";
|
||||
public string BiosVendor { set; get; } = "";
|
||||
|
||||
public string BiosUUID { set; get; } = "";
|
||||
|
||||
public int SocketN { set; get; }
|
||||
|
||||
public string CpuName { set; get; } = "";
|
||||
|
||||
public float TotalRam { set; get; }
|
||||
|
||||
public string TokenID { set; get; } = "";
|
||||
|
||||
public string TokenValue { set; get; } = "";
|
||||
|
||||
public string RTokenID { set; get; } = "";
|
||||
|
||||
public string RTokenValue { set; get; } = "";
|
||||
|
||||
public override async Task<MessageHeader> AddAsync()
|
||||
{
|
||||
await using var con = new MySqlConnector.MySqlConnection(DBManagement.GetConnectionString(true));
|
||||
|
||||
await con.OpenAsync();
|
||||
var trans = await con.BeginTransactionAsync();
|
||||
var f = new MessageHeader();
|
||||
try
|
||||
{
|
||||
var localServer = new LocalServer
|
||||
{
|
||||
IpPrivateServer = IpPrivatev4,
|
||||
IpPrivateServerv6 = IpPrivatev6,
|
||||
IpPublicServer = IpPublic,
|
||||
PathServer = "",
|
||||
SerialNumber = BiosSN,
|
||||
OsVersion = OsVersion,
|
||||
OsName = OsName,
|
||||
OsArch = OsArch,
|
||||
OsKernal = OsKernel,
|
||||
SocketNum = SocketN,
|
||||
CpuName = CpuName,
|
||||
TotalRam = TotalRam,
|
||||
BiosVender = BiosVendor,
|
||||
ProductUuid = BiosUUID,
|
||||
Status = 0
|
||||
};//idTypeStorageServer
|
||||
var storageServer = new StorageServer
|
||||
{
|
||||
IdEmp = null,
|
||||
IdTypeStorageServer = StorageTypeID,
|
||||
StorageName = StorageName,
|
||||
CreateDate = DateTime.UtcNow,
|
||||
ControllerID = ControllerName,
|
||||
Status = 0
|
||||
};
|
||||
var ss_lc = new StorageServer_has_LocalServer
|
||||
{
|
||||
IdStorageServer = storageServer.IdStorageServer,
|
||||
IdLocalServer = localServer.IdLocalServer,
|
||||
CreateDate = DateTime.UtcNow,
|
||||
ModifyDate = null,
|
||||
Status = 0
|
||||
};
|
||||
|
||||
var serverAuthorization = new ServerAuthorization
|
||||
{
|
||||
IdStorageServer = storageServer.IdStorageServer,
|
||||
CreateDate = DateTime.UtcNow,
|
||||
Count = 1,
|
||||
Status = 0
|
||||
};
|
||||
var token = new Token
|
||||
{
|
||||
IdToken = TokenID,
|
||||
AccessToken = TokenValue,
|
||||
CreateDate = DateTime.UtcNow,
|
||||
ExpireDate = DateTime.UtcNow.AddMonths(3),
|
||||
Status = 0
|
||||
};
|
||||
var rT = new RefreshToken
|
||||
{
|
||||
IdRefreshToken = RTokenID,
|
||||
IdServerAuthorization = serverAuthorization.IdServerAuthorization,
|
||||
__RefreshToken = RTokenValue,
|
||||
CreateDate = DateTime.UtcNow,
|
||||
ExpireDate = DateTime.UtcNow.AddMonths(9),
|
||||
Status = 0
|
||||
};
|
||||
BatchInsert bi = new BatchInsert(con, trans);
|
||||
bi.AddRow(localServer);
|
||||
bi.AddRow(storageServer);
|
||||
bi.AddRow(ss_lc);
|
||||
bi.AddRow(serverAuthorization);
|
||||
bi.AddRow(token);
|
||||
bi.AddRow(rT);
|
||||
await bi.ExcuteQuery();
|
||||
await trans.CommitAsync();
|
||||
f.Status = 1;
|
||||
f.Message = "OK";
|
||||
}
|
||||
catch (DbException ex)
|
||||
{
|
||||
await trans.RollbackAsync();
|
||||
await trans.DisposeAsync();
|
||||
f.Status = 0;
|
||||
f.Message = ex.Message;
|
||||
f.ID = 61031;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
public override Task<MessageHeader> DeleteAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Task<MessageHeader> UpdateAsync()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,29 @@
|
||||
|
||||
using AppLibs.Libs;
|
||||
using AppLibs.Libs;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
await WSNavigation.LoadJson();
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.Configure<FormOptions>(o => {
|
||||
o.MultipartBodyLengthLimit = 200_000_000; // 200 MB
|
||||
});
|
||||
builder.Services.AddControllers(options =>
|
||||
{
|
||||
options.Filters.Add<AsyncGateAttribute>();
|
||||
}).AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.PropertyNamingPolicy = null;
|
||||
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
|
||||
});
|
||||
builder.Services.AddDistributedMemoryCache(); // IDistributedCache in-memory
|
||||
builder.Services.AddSession(o =>
|
||||
{
|
||||
o.IdleTimeout = TimeSpan.FromHours(8);
|
||||
o.Cookie.HttpOnly = true;
|
||||
o.Cookie.IsEssential = true;
|
||||
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
||||
});
|
||||
builder.Services.AddControllersWithViews().AddRazorRuntimeCompilation();
|
||||
|
||||
// Add services to the container.
|
||||
@ -23,11 +44,10 @@ app.UseRouting();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapStaticAssets();
|
||||
|
||||
app.UseSession();
|
||||
app.MapControllerRoute(
|
||||
name: "default",
|
||||
pattern: "{controller=Home}/{action=Index}/{id?}")
|
||||
.WithStaticAssets();
|
||||
|
||||
|
||||
app.Run();
|
||||
|
||||
@ -1,50 +1,56 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net9.0-windows10.0.19041.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>TWASys_App</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition="$([System.String]::Copy('$(TargetFramework)').Contains('-windows'))">
|
||||
<PackageReference Include="System.Management" Version="9.0.0" />
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net9.0-windows;net9.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>TWASys_App</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net9.0-windows'">
|
||||
<PackageReference Include="System.Management" Version="9.0.10" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="wwwroot\css\atg-font\atg-admin-font.css" />
|
||||
<None Include="wwwroot\css\atg-font\atg-font.css" />
|
||||
<None Include="wwwroot\css\atg-lib\atg-core-min.css" />
|
||||
<None Include="wwwroot\css\atg-lib\atg-core.css" />
|
||||
<None Include="wwwroot\css\atg-lib\atg-upload.css" />
|
||||
<None Include="wwwroot\css\atg-lib\datepicker.css" />
|
||||
<None Include="wwwroot\css\atg-lib\swiper-bundle.min.css" />
|
||||
<None Include="wwwroot\css\atg-lib\waves.min.css" />
|
||||
<None Include="wwwroot\css\atg-ui\atg-gui.css" />
|
||||
<None Include="wwwroot\css\atg-ui\table.css" />
|
||||
<None Include="wwwroot\css\site.css" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AppLibs\AppLibs\AppLibs.csproj" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net9.0-windows'">
|
||||
<DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="wwwroot\css\atg-font\atg-admin-font.css" />
|
||||
<None Include="wwwroot\css\atg-font\atg-font.css" />
|
||||
<None Include="wwwroot\css\atg-lib\atg-core-min.css" />
|
||||
<None Include="wwwroot\css\atg-lib\atg-core.css" />
|
||||
<None Include="wwwroot\css\atg-lib\atg-upload.css" />
|
||||
<None Include="wwwroot\css\atg-lib\datepicker.css" />
|
||||
<None Include="wwwroot\css\atg-lib\swiper-bundle.min.css" />
|
||||
<None Include="wwwroot\css\atg-lib\waves.min.css" />
|
||||
<None Include="wwwroot\css\atg-ui\atg-gui.css" />
|
||||
<None Include="wwwroot\css\atg-ui\table.css" />
|
||||
<None Include="wwwroot\css\site.css" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="9.0.10" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="9.0.10" />
|
||||
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Keys\db\ca-cert.pem">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Keys\db\client-cert.pem">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Keys\db\client-key.pem">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AppLibs\AppLibs\AppLibs.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Keys\db\ca-cert.pem">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Keys\db\client-cert.pem">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Keys\db\client-key.pem">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -6,3 +6,7 @@
|
||||
<h1 class="display-4">Welcome</h1>
|
||||
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
|
||||
</div>
|
||||
|
||||
@section jsLib {
|
||||
<script type="module" src="@Url.AbsoluteContent("~/js/js-page/1000.js")" js-lib></script>
|
||||
}
|
||||
@ -1,43 +1,122 @@
|
||||
<div class="c">
|
||||
<div class="r j-c-center h-100vh pt-5 pb-5">
|
||||
<div class="c-s-12 c-m-10 c-l-8 c-x-10 c-sx-8 w-login mt-auto mb-auto">
|
||||
<div class="r-n-g j-c-center a-i-center">
|
||||
<div class="d-n c-x-6 d-x-b">
|
||||
<img src="~/images/img1.jpg" class="w-100" />
|
||||
</div>
|
||||
<div class="c-12 c-x-6">
|
||||
<div class="h-100 d-f a-i-center">
|
||||
<div class="ws-login d-f f-c a-i-center">
|
||||
<span class="ws-title">Đăng Nhập</span>
|
||||
<div class="ws-input mb-4">
|
||||
<span class="label-input">Tài khoản</span>
|
||||
<div class="c-input d-f a-i-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M313.6 304c-28.7 0-42.5 16-89.6 16-47.1 0-60.8-16-89.6-16C60.2 304 0 364.2 0 438.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-25.6c0-74.2-60.2-134.4-134.4-134.4zM400 464H48v-25.6c0-47.6 38.8-86.4 86.4-86.4 14.6 0 38.3 16 89.6 16 51.7 0 74.9-16 89.6-16 47.6 0 86.4 38.8 86.4 86.4V464zM224 288c79.5 0 144-64.5 144-144S303.5 0 224 0 80 64.5 80 144s64.5 144 144 144zm0-240c52.9 0 96 43.1 96 96s-43.1 96-96 96-96-43.1-96-96 43.1-96 96-96z" /></svg>
|
||||
<input type="text" class="input" placeholder="Nhập tài khoản" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-input">
|
||||
<span class="label-input">Mật khẩu</span>
|
||||
<div class="c-input d-f a-i-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zM264 392c0 22.1-17.9 40-40 40s-40-17.9-40-40v-48c0-22.1 17.9-40 40-40s40 17.9 40 40v48zm32-168H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z" /></svg>
|
||||
<input type="password" class="input" placeholder="Nhập mật khẩu" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-forgot ml-auto">
|
||||
<a href="#">Quên mật khẩu?</a>
|
||||
</div>
|
||||
<div class="ws-btn d-f j-c-center">
|
||||
<div class="btn-mask"></div>
|
||||
<button class="btn btn-effect">Đăng nhập</button>
|
||||
</div>
|
||||
<div class="ws-signup d-f f-c a-i-center">
|
||||
<span>Đăng ký tài khoản bằng ID</span>
|
||||
<a href="#">Đăng Ký</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-login">
|
||||
<div class="con-img">
|
||||
<img src="~/images/login/@Shared.RandomImages()" />
|
||||
</div>
|
||||
<div class="c-login">
|
||||
<div class="frm-login">
|
||||
<div class="ws-login">
|
||||
<div class="frm-header d-f f-c a-i-center">
|
||||
<a app-nav href="@Url.AbsoluteContent("~/")" class="c_logo d-f j-c-center">
|
||||
<img src="@Url.AbsoluteContent("~/images/logo/slogo.png")">
|
||||
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<div class="AWizard tabcontents">
|
||||
<div class="tabcontent">
|
||||
|
||||
<div class="frm-header">
|
||||
<h2 class="title">Sign In</h2>
|
||||
<span class="d-f f-wrap desc">Bạn chưa có tài khoản? <a href="javascript:void(0)" class="ml-2" id="navSignUp">Đăng ký ngay</a></span>
|
||||
</div>
|
||||
<div class="frm-input mt-4">
|
||||
<label>Username</label>
|
||||
<div class="c-input">
|
||||
<span class="ico atg a-1x atg-user"></span>
|
||||
<input type="text" class="input" placeholder="Your username" />
|
||||
<span class="line"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frm-input">
|
||||
<label>Password</label>
|
||||
<div class="c-input">
|
||||
<span class="ico atg a-1x atg-user"></span>
|
||||
<input type="password" class="input" placeholder="Your password" />
|
||||
<span class="line"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frm-header d-f f-wrap j-c-between a-i-center">
|
||||
<a href="javascript:void(0)" id="forgetPass">Forget the password?</a>
|
||||
<button class="btn btn-primary btn-effect">Sign In</button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="tabcontent">
|
||||
<div class="frm-header">
|
||||
<h2 class="title">Don't You Remember Password?</h2>
|
||||
|
||||
</div>
|
||||
<div class="frm-input mt-4">
|
||||
<label>Địa chỉ email</label>
|
||||
<div class="c-input">
|
||||
<span class="ico atg a-1x atg-user"></span>
|
||||
<input type="text" class="input" placeholder="Nhập email" />
|
||||
<span class="line"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frm-header d-f j-c-end">
|
||||
<button class="btn btn-secondary btnCB btn-effect mr-2">Quay lại</button>
|
||||
<button class="btn btn-primary btn-effect">Lấy lại mật khẩu</button>
|
||||
</div>
|
||||
<div class="frm-header d-f f-c">
|
||||
<span class="hint">
|
||||
Mật khẩu mới sẽ được gửi về hộp thư trong email của bạn.
|
||||
</span>
|
||||
<span class="hint mt-2">
|
||||
Sau khi được cấp mật khẩu mới vui lòng đổi lại mật khẩu trong trang thông tin tài khoản.
|
||||
</span>
|
||||
<span class="mt-2 hint">Trường hợp không nhận được email? <a href="javascript:void(0)" class="">Hãy nhắn tin cho chúng tôi!</a></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabcontent">
|
||||
<div class="frm-header">
|
||||
<h2 class="title">Sign Up</h2>
|
||||
|
||||
</div>
|
||||
<div class="frm-input mt-4">
|
||||
<label>Địa chỉ email</label>
|
||||
<div class="c-input">
|
||||
<span class="ico atg a-1x atg-user"></span>
|
||||
<input type="text" class="input" placeholder="Nhập email" />
|
||||
<span class="line"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frm-input">
|
||||
<label>Mật khẩu</label>
|
||||
<div class="c-input">
|
||||
<span class="ico atg a-1x atg-user"></span>
|
||||
<input type="password" class="input" placeholder="Nhập mật khẩu" />
|
||||
<span class="line"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frm-input">
|
||||
<label>Nhập lại mật khẩu</label>
|
||||
<div class="c-input">
|
||||
<span class="ico atg a-1x atg-user"></span>
|
||||
<input type="password" class="input" placeholder="Nhập lại mật khẩu" />
|
||||
<span class="line"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frm-input">
|
||||
<label>Họ & tên</label>
|
||||
<div class="c-input">
|
||||
<span class="ico atg a-1x atg-user"></span>
|
||||
<input type="text" class="input" placeholder="Nhập họ tên" />
|
||||
<span class="line"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="frm-header d-f j-c-end">
|
||||
<button class="btn btn-secondary btnCB btn-effect mr-2">Quay lại</button>
|
||||
<button class="btn btn-primary btn-effect">Đăng ký</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@section jsLib {
|
||||
<script type="module" src="@Url.AbsoluteContent("~/js/js-page/10001.js")" js-lib></script>
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<div class="c-logo">
|
||||
<div class="logo d-f f-c a-i-center">
|
||||
<img src="~/images/logo3.svg" />
|
||||
<span class="mt-1 logo-name">Resort Management</span>
|
||||
<img src="~/images/logo/slogo.png" />
|
||||
<span class="pt-3 pb-2 logo-name">Management System</span>
|
||||
</div>
|
||||
<div class="d-b d-x-n hd-close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" stroke="#7367f0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="d-block d-xl-none feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
||||
@ -18,7 +18,7 @@
|
||||
</div>
|
||||
<div class="m-footer d-f f-c">
|
||||
<span>
|
||||
<b>Copyright<sup>©</sup></b> 2024 ATG Technology
|
||||
<b>Copyright<sup>©</sup></b> 2025 TWA
|
||||
</span>
|
||||
<span class="mt-1"><b>Version: </b> 0.0.1a</span>
|
||||
</div>
|
||||
@ -62,6 +62,7 @@
|
||||
<div id="footer">
|
||||
@await Html.PartialAsync("~/Views/Partial/Footer.cshtml")
|
||||
</div>
|
||||
|
||||
@section jsLib {
|
||||
<script type="module" src="@Url.AbsoluteContent("~/js/js-page/asyncLayout.js")" js-lib></script>
|
||||
}
|
||||
|
||||
9
TWASys-App/Views/Shared/_LayoutLogin.cshtml
Normal file
9
TWASys-App/Views/Shared/_LayoutLogin.cshtml
Normal file
@ -0,0 +1,9 @@
|
||||
<section id="header">
|
||||
|
||||
</section>
|
||||
<section id="footer">
|
||||
|
||||
</section>
|
||||
@section jsLib {
|
||||
<script type="module" src="@Url.AbsoluteContent("~/js/js-page/asyncLoginLayout.js")" js-lib></script>
|
||||
}
|
||||
@ -23,7 +23,7 @@
|
||||
user-select: none
|
||||
}
|
||||
|
||||
a {
|
||||
a {,
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
@ -197,6 +197,11 @@ h1, h2, h3, h4, h5, h6, p {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.r-n-g.n{
|
||||
margin-left:-20px;
|
||||
margin-right:-20px
|
||||
}
|
||||
|
||||
.r > .c, .r > [class^=c-] {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
|
||||
165
TWASys-App/wwwroot/css/pages/login.css
Normal file
165
TWASys-App/wwwroot/css/pages/login.css
Normal file
@ -0,0 +1,165 @@
|
||||
.con-img {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.con-img > img {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
min-height: 100vw;
|
||||
}
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
.con-img > img {
|
||||
width: 100% !important;
|
||||
max-width: 100vw;
|
||||
height: auto;
|
||||
min-height: auto;
|
||||
max-height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
.c-login {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
transform: translateY(-50%);
|
||||
top: 50%;
|
||||
right: 0;
|
||||
margin: 0 auto
|
||||
}
|
||||
|
||||
.frm-login {
|
||||
max-width: 100%;
|
||||
margin: 0 25px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media (min-width: 568px) {
|
||||
.frm-login {
|
||||
max-width: 380px !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.c-login {
|
||||
right: 100px;
|
||||
width: 420px;
|
||||
}
|
||||
|
||||
.frm-login {
|
||||
max-width: 100% !important
|
||||
}
|
||||
}
|
||||
|
||||
.ws-login {
|
||||
box-shadow: 0 2px 3px rgba(96, 96, 96, 0.1);
|
||||
background-color: #fff;
|
||||
border-radius: var(--radius);
|
||||
padding: 55px 35px;
|
||||
}
|
||||
|
||||
.ws-login .c_logo {
|
||||
height: 60px
|
||||
}
|
||||
|
||||
.ws-login .title {
|
||||
color: var(--color-primary)
|
||||
}
|
||||
|
||||
.ws-login .ico {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
transform: translateY(-50%)
|
||||
}
|
||||
|
||||
.ws-login input {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.ws-login .title, .ws-login .desc {
|
||||
}
|
||||
|
||||
.ws-login .hint {
|
||||
font-size: .82rem;
|
||||
}
|
||||
|
||||
|
||||
.frm-inline.search button {
|
||||
padding: 4px 15px;
|
||||
}
|
||||
|
||||
.frm-inline button {
|
||||
margin-left: calc(var(--radius) * -1);
|
||||
}
|
||||
|
||||
.frm-inline input {
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 10px 12px;
|
||||
width: 100%;
|
||||
font-weight: 500;
|
||||
color: var(--text-color-primary)
|
||||
}
|
||||
|
||||
.frm-group {
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
.frm-input, .frm-header {
|
||||
padding: 0 15px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.frm-input {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.frm-input label {
|
||||
color: var(--text-color-primary);
|
||||
font-size: .92rem;
|
||||
margin-bottom: 2px;
|
||||
font-weight: 500
|
||||
}
|
||||
|
||||
.frm-input input, .frm-input .aselect {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #444C6185;
|
||||
background-color: #fff;
|
||||
transition: .3s all ease-in-out;
|
||||
font-size: .9rem;
|
||||
font-weight: 400
|
||||
}
|
||||
|
||||
.frm-input .con-aselect input {
|
||||
border-radius: var(--radius);
|
||||
padding: 0 15px;
|
||||
border: 1px solid #444C6185
|
||||
}
|
||||
|
||||
.frm-input input {
|
||||
min-height: 35px;
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
.frm-input .line {
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
width: 0;
|
||||
background-color: var(--color-primary);
|
||||
transition: width .4s cubic-bezier( 0.19, 0.6, 0.86, 0.01 )
|
||||
}
|
||||
|
||||
.frm-input input:focus + .line, .frm-input input:hover + .line {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.frm-input .c-input:not(.line) input:hover, .frm-input .c-input:not(.line) input:focus, .frm-input .con-aselect.active .aselect {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
@ -8,13 +8,14 @@
|
||||
--text-color-primary: #09205c;
|
||||
--text-color-1: #5e5873;
|
||||
--text-color-heading-1: #5d596c;
|
||||
--text-disable: #a5a3ae
|
||||
--text-disable: #a5a3ae;
|
||||
--radius:10px
|
||||
}
|
||||
.pointer:hover{
|
||||
cursor: pointer
|
||||
}
|
||||
.mini-scrollbar{
|
||||
height: calc(100vh - 176px)
|
||||
height: calc(100vh - 196px)
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
@ -26,6 +27,17 @@ html {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
}
|
||||
a{
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
body[page="10001"] .main-wrapper{
|
||||
padding: 0 !important;
|
||||
margin: 0
|
||||
}
|
||||
body[page="10001"] #header {
|
||||
left:-500px
|
||||
}
|
||||
/*Control*/
|
||||
[data-dropdown]:not(.nav-i) .sub-item {
|
||||
border-radius: var(--border-radius);
|
||||
@ -208,7 +220,8 @@ nav {
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
height: calc(100% - 172px)
|
||||
padding-top:20px;
|
||||
height: calc(100% - 176px)
|
||||
}
|
||||
|
||||
.m-footer {
|
||||
@ -219,12 +232,12 @@ nav {
|
||||
}
|
||||
|
||||
.nav-overlay {
|
||||
margin-top: -.7rem;
|
||||
margin-top: -10px;
|
||||
background: -webkit-gradient(linear,left top,left bottom,color-stop(41%,#fff),color-stop(95%,hsla(0,0%,100%,.11)),to(hsla(0,0%,100%,0)));
|
||||
background: linear-gradient(#fff 41%,hsla(0,0%,100%,.11) 95%,hsla(0,0%,100%,0));
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
height: 50px;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
pointer-events: none;
|
||||
-webkit-filter: blur(5px);
|
||||
@ -574,7 +587,7 @@ nav {
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
color: #a8aaae;
|
||||
color: #5e5873;
|
||||
border-color: rgba(0, 0, 0, 0);
|
||||
background: #f1f1f2;
|
||||
}
|
||||
|
||||
BIN
TWASys-App/wwwroot/images/login/80633.jpg
Normal file
BIN
TWASys-App/wwwroot/images/login/80633.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 634 KiB |
BIN
TWASys-App/wwwroot/images/login/806372.jpg
Normal file
BIN
TWASys-App/wwwroot/images/login/806372.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 852 KiB |
BIN
TWASys-App/wwwroot/images/login/806459.jpg
Normal file
BIN
TWASys-App/wwwroot/images/login/806459.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 497 KiB |
BIN
TWASys-App/wwwroot/images/logo/icon.png
Normal file
BIN
TWASys-App/wwwroot/images/logo/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
BIN
TWASys-App/wwwroot/images/logo/slogo.png
Normal file
BIN
TWASys-App/wwwroot/images/logo/slogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
4
TWASys-App/wwwroot/js/js-page/1000.js
Normal file
4
TWASys-App/wwwroot/js/js-page/1000.js
Normal file
@ -0,0 +1,4 @@
|
||||
window.L1000 = function () {
|
||||
|
||||
}
|
||||
window.AScript.set("1000", true);
|
||||
26
TWASys-App/wwwroot/js/js-page/10001.js
Normal file
26
TWASys-App/wwwroot/js/js-page/10001.js
Normal file
@ -0,0 +1,26 @@
|
||||
import AWizard from "/js/libs/js-AWizard.js";
|
||||
|
||||
window.L10001 = function () {
|
||||
Waves.attach('.btn-effect', ['waves-float']);
|
||||
Waves.init({ duration: 1000, delay: 200 });
|
||||
var wrd1 = new AWizard(document.querySelector(".AWizard"));
|
||||
const forget = document.getElementById("forgetPass");
|
||||
const btnCB = document.querySelectorAll(".btnCB");
|
||||
const navSignUp = document.getElementById("navSignUp")
|
||||
forget.addEventListener("click", (e) => {
|
||||
wrd1.nextPage(1);
|
||||
});
|
||||
btnCB.forEach((el) => {
|
||||
el.addEventListener("click", (e) => {
|
||||
ComeBack(e, wrd1);
|
||||
});
|
||||
});
|
||||
navSignUp.addEventListener("click", (e) => {
|
||||
wrd1.nextPage(2);
|
||||
});
|
||||
}
|
||||
|
||||
function ComeBack(e, wrd) {
|
||||
wrd.nextPage(0);
|
||||
}
|
||||
window.AScript.set("10001", true);
|
||||
@ -38,9 +38,15 @@ const tmp = `<div class="slider-scrollbar" data-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="pathServer">Controller Name</label>
|
||||
<label for="controllerName">Controller Name</label>
|
||||
<div class="input-group">
|
||||
<input id="pathServer" type="text" placeholder="Controller Name" validation-isEmpty />
|
||||
<input id="controllerName" type="text" placeholder="Controller Name" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="storageName">Storage Name</label>
|
||||
<div class="input-group">
|
||||
<input id="storageName" type="text" placeholder="Storage Name" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
@ -103,9 +109,9 @@ const tmp = `<div class="slider-scrollbar" data-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="expiredDate">SharePoint Path</label>
|
||||
<label for="sharepointPath">SharePoint Path</label>
|
||||
<div class="input-group">
|
||||
<input id="expiredDate" type="password" placeholder="Client ID" validation-isEmpty />
|
||||
<input id="sharepointPath" type="text" placeholder="Client ID" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -140,7 +146,7 @@ const tmp = `<div class="slider-scrollbar" data-scrollbar>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="clientID">OS Platform</label>
|
||||
<div class="input-group">
|
||||
<input id="osName" data-id="osPlatform" type="text" placeholder="OS Platform" validation-isEmpty />
|
||||
<input id="osPlatform" data-id="osPlatform" type="text" placeholder="OS Platform" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
@ -158,7 +164,7 @@ const tmp = `<div class="slider-scrollbar" data-scrollbar>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="clientID">OS Architecture</label>
|
||||
<div class="input-group">
|
||||
<input id="osKernel" data-id="osArch" type="text" placeholder="OS Architecture" validation-isEmpty />
|
||||
<input id="osArch" data-id="osArch" type="text" placeholder="OS Architecture" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
@ -203,30 +209,51 @@ const tmp = `<div class="slider-scrollbar" data-scrollbar>
|
||||
<h5 class="mb-2">Server Authenicator</h4>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="clientID">IP Server</label>
|
||||
<label for="idToken">Token ID</label>
|
||||
<div class="input-group">
|
||||
<input id="clientID" type="text" placeholder="Client ID" validation-isEmpty />
|
||||
<input id="idToken" type="text" placeholder="Token ID" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="clientID">Machine ID</label>
|
||||
<label for="vToken">Token Value</label>
|
||||
<div class="input-group">
|
||||
<input id="clientID" type="text" placeholder="Client ID" validation-isEmpty />
|
||||
<input id="vToken" type="password" placeholder="Token Value" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="clientID">OS Version</label>
|
||||
<label for="idRefreshToken">Refresh Token ID</label>
|
||||
<div class="input-group">
|
||||
<input id="clientID" type="text" placeholder="Client ID" validation-isEmpty />
|
||||
<input id="idRefreshToken" type="text" placeholder="Refresh Token ID" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group d-f f-c">
|
||||
<label for="clientID">Proccessor ID</label>
|
||||
<label for="refreshTokenValue">Refresh Token Value</label>
|
||||
<div class="input-group">
|
||||
<input id="clientID" type="text" placeholder="Client ID" validation-isEmpty />
|
||||
<input id="refreshTokenValue" type="password" placeholder="Refresh Token Value" validation-isEmpty />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabcontent">
|
||||
<div class="form-group">
|
||||
<h5 class="mb-2">Storage Data Summary</h4>
|
||||
</div>
|
||||
<div class="form-group mb-0 d-f">
|
||||
<label>Storage Server Type</label>
|
||||
<span class="ml-2"></span>
|
||||
</div>
|
||||
<div class="form-group mb-0 d-f">
|
||||
<label>Controller Name</label>
|
||||
<span class="ml-2"></span>
|
||||
</div>
|
||||
<div class="form-group mb-0 d-f">
|
||||
<label>Storage Name</label>
|
||||
<span class="ml-2"></span>
|
||||
</div>
|
||||
<div class="form-group mb-0 d-f">
|
||||
<label>Validation Domains</label>
|
||||
<span class="ml-2"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabcontent">
|
||||
@ -262,24 +289,99 @@ window.L6101 = function () {
|
||||
var ov = new AOverlay(document.body);
|
||||
ov.createOverlay();
|
||||
|
||||
|
||||
const $v = id => (document.getElementById(id)?.value ?? '').trim();
|
||||
var ele1 = new ASpinButton(document.getElementById("totalSize"));
|
||||
var ele2 = new AMultiTag(document.getElementById("listStorage"));
|
||||
|
||||
var slider = new AModal(tmp);
|
||||
slider.createModal("CustomForm", "slider-right");
|
||||
var Scrollbar = window.Scrollbar;
|
||||
Scrollbar.init(slider.CustomContainer.querySelector(".slider-scrollbar"), window.scroll_options);
|
||||
|
||||
const mScroll = Scrollbar.init(slider.CustomContainer.querySelector(".slider-scrollbar"), window.scroll_options);
|
||||
slider.overlay.isCloseOverlay(true);
|
||||
|
||||
var tabs = new ATab(slider.CustomContainer.querySelector(".atabs"), slider.CustomContainer.querySelector(".StorageTabs"));
|
||||
var wrd1 = new AWizard(slider.CustomContainer.querySelector(".AWizard"));
|
||||
var as = new ASelect(slider.CustomContainer.querySelectorAll(".aselect"));
|
||||
window.testV = as;
|
||||
var asIdType = as.get(0);
|
||||
wrd1.on("onBeforeBack", (evt) => {
|
||||
mScroll.scrollTo(0, 0);
|
||||
});
|
||||
wrd1.on("onAfterNext", (evt) => {
|
||||
if (evt.indexPage > 0) {
|
||||
if (as.get(0).isLockElement() || as.get(1).isLockElement()) {
|
||||
return;
|
||||
}
|
||||
switch (asIdType.getSelectedItem().vSearch) {
|
||||
case "Microsoft Cloud":
|
||||
break;
|
||||
case "Physical Server":
|
||||
if (evt.indexPage > 3) {
|
||||
(async () => {
|
||||
|
||||
const fd = new FormData();
|
||||
fd.append('StorageTypeID', asIdType.getSelectedItem()?.id ?? '');
|
||||
fd.append('ControllerName', $v('controllerName'));
|
||||
fd.append('StorageName', $v('storageName'));
|
||||
|
||||
fd.append('IpPublic', $v('ipPublic'));
|
||||
fd.append('IpPrivatev4', $v('ipPrivatev4'));
|
||||
fd.append('IpPrivatev6', $v('ipPrivatev6'));
|
||||
|
||||
fd.append('OsName', $v('osName'));
|
||||
fd.append('OsPlatform', $v('osPlatform'));
|
||||
fd.append('OsVersion', $v('osVersion'));
|
||||
fd.append('OsKernel', $v('osKernel'));
|
||||
fd.append('OsArch', $v('osArch'));
|
||||
|
||||
fd.append('BiosSN', $v('biosSerial'));
|
||||
fd.append('BiosVendor', $v('biosVender'));
|
||||
fd.append('BiosUUID', $v('biosUUID'));
|
||||
|
||||
const i = 0;
|
||||
as.get(1).multiSelectedItem.forEach((item) => {
|
||||
fd.append(`ValidationDomains[${i}].IdValidationDomain`, item.getAttribute("data-value"));
|
||||
});
|
||||
|
||||
fd.append('SocketN', $v('socketN'));
|
||||
fd.append('CpuName', $v('cpuName'));
|
||||
fd.append('TotalRam', $v('totalRam'));
|
||||
|
||||
fd.append('TokenID', $v('idToken'));
|
||||
fd.append('TokenValue', $v('vToken'));
|
||||
fd.append('RTokenID', $v('idRefreshToken'));
|
||||
fd.append('RTokenValue', $v('refreshTokenValue'))
|
||||
const response = await fetch("/Storage/SetStorageData", {
|
||||
method: 'POST',
|
||||
body: fd
|
||||
});
|
||||
})();
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
wrd1.on("onBeforeNext", (evt) => {
|
||||
mScroll.scrollTo(0, 0);
|
||||
if (evt.indexPage == 0) {
|
||||
if (asIdType.isLockElement() && asVD.isLockElement()) {
|
||||
if (as.get(0).isLockElement() || as.get(1).isLockElement()) {
|
||||
wrd1.isStopNextPage = true;
|
||||
return;
|
||||
} else {
|
||||
wrd1.isStopNextPage = false;
|
||||
}
|
||||
let flag = false;
|
||||
if ($v('controllerName').length == 0) {
|
||||
flag = true;
|
||||
}
|
||||
if ($v('storageName').length == 0) {
|
||||
flag = true;
|
||||
}
|
||||
if (as.get(1).multiSelectedItem.length == 0) {
|
||||
flag = true;
|
||||
}
|
||||
if (flag) {
|
||||
wrd1.isStopNextPage = true;
|
||||
return;
|
||||
} else {
|
||||
@ -289,9 +391,11 @@ window.L6101 = function () {
|
||||
case "Microsoft Cloud":
|
||||
wrd1.showPage(1);
|
||||
wrd1.hidePage(2);
|
||||
wrd1.hidePage(3);
|
||||
break;
|
||||
case "Physical Server":
|
||||
wrd1.showPage(2);
|
||||
wrd1.showPage(3);
|
||||
wrd1.hidePage(1);
|
||||
let promise = new Promise(async function (resolve, reject) {
|
||||
const response = await fetch(`/Storage/GetSysInfo`, {
|
||||
@ -305,10 +409,43 @@ window.L6101 = function () {
|
||||
const autoF = new AAutoFill(document.querySelector(".awStorageConnector"));
|
||||
autoF.fill(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
}e
|
||||
} else if (evt.indexPage == 1)
|
||||
{
|
||||
|
||||
}
|
||||
else if (evt.indexPage == 2) {
|
||||
|
||||
(async () => {
|
||||
const response = await fetch(`/Storage/GenerationAccessToken`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data) {
|
||||
document.getElementById("idToken").value = data.idToken;
|
||||
document.getElementById("vToken").value = data.tokenValue;
|
||||
}
|
||||
})();
|
||||
(async () => {
|
||||
const response = await fetch(`/Storage/GenerationAccessToken`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data) {
|
||||
document.getElementById("idRefreshToken").value = data.idToken;
|
||||
document.getElementById("refreshTokenValue").value = data.tokenValue;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
}, true);
|
||||
|
||||
var asVD = as.get(1);
|
||||
@ -321,6 +458,7 @@ window.L6101 = function () {
|
||||
let promise = new Promise(function (resolve, reject) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", window.GetAbsoluteURL("/Storage/GetTypeStorage"));
|
||||
xhr.setRequestHeader('Accept', 'application/json; charset=UTF-8');
|
||||
var f = function (ev) {
|
||||
if (ev.currentTarget.readyState == 4) {
|
||||
if (ev.currentTarget.status == 200) {
|
||||
@ -344,6 +482,7 @@ window.L6101 = function () {
|
||||
let promise1 = new Promise(function (resolve, reject) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", window.GetAbsoluteURL("/Storage/GetValidationDomain"));
|
||||
xhr.setRequestHeader('Accept', 'application/json; charset=UTF-8');
|
||||
var f = function (ev) {
|
||||
if (ev.currentTarget.readyState == 4) {
|
||||
if (ev.currentTarget.status == 200) {
|
||||
@ -374,7 +513,7 @@ window.L6101 = function () {
|
||||
asAddStorage.on("click_btAddStorage", (e) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/Storage/AddStorageServer");
|
||||
xhr.setRequestHeader('Content-type', 'application/json; charset=UTF-8');
|
||||
xhr.setRequestHeader('Accept', 'application/json; charset=UTF-8');
|
||||
var data = {
|
||||
"Name": document.getElementById("inpType").value
|
||||
};
|
||||
|
||||
@ -14,6 +14,7 @@ class AsyncLayout extends ALayout {
|
||||
super.dispose();
|
||||
}
|
||||
renderMenu() {
|
||||
console.log("ÁDASD");
|
||||
this.isLoaded = true;
|
||||
var asyncStyleSheets = [
|
||||
'https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap',
|
||||
|
||||
39
TWASys-App/wwwroot/js/js-page/asyncLoginLayout.js
Normal file
39
TWASys-App/wwwroot/js/js-page/asyncLoginLayout.js
Normal file
@ -0,0 +1,39 @@
|
||||
import ALayout from '/js/libs/js-ALayout.js'
|
||||
|
||||
class LoginLayout extends ALayout {
|
||||
constructor() {
|
||||
super();
|
||||
this.isLoaded = false;
|
||||
}
|
||||
dispose() {
|
||||
this.isLoaded = false;
|
||||
window.app.removeSytemEventParent(window.app.lName);
|
||||
window.app.removeCustomEventParent(window.app.lName);
|
||||
super.dispose();
|
||||
}
|
||||
renderMenu() {
|
||||
this.isLoaded = true;
|
||||
var asyncStyleSheets = [
|
||||
'https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap',
|
||||
'/css/atg-font/atg-admin-font.css',
|
||||
'/css/atg-lib/waves.min.css',
|
||||
'/css/pages/login.css'
|
||||
];
|
||||
window.app.loadCSS(asyncStyleSheets);
|
||||
window.app.initNavs("Login");
|
||||
|
||||
var sOption = {
|
||||
damping: (window.getOS() == "Android") ? .06 : .04,
|
||||
thumbMinSize: 25,
|
||||
renderByPixel: true,
|
||||
alwaysShowTracks: true,
|
||||
continuousScrolling: true
|
||||
};
|
||||
|
||||
window.Scrollbar.use(window.OverscrollPlugin);
|
||||
window.app.initScrollBar();
|
||||
}
|
||||
}
|
||||
|
||||
window.ALayout.set("Login", new LoginLayout());
|
||||
window.AScript.set("asyncLoginLayout", true);
|
||||
@ -106,12 +106,12 @@ export default class AWizard extends ATab {
|
||||
btnNext_Click(e, idx) {
|
||||
this.trigger("onBeforeNext", { "currentPage": this.ctabs[idx], "indexPage": idx, "currentButton": e.currentTarget });
|
||||
if (this.isStopNextPage) return;
|
||||
console.log(idx);
|
||||
this.selectedTab(this.checkSelectedNext(idx));
|
||||
|
||||
this.trigger("onAfterNext");
|
||||
this.trigger("onAfterNext", { "currentPage": this.ctabs[idx], "indexPage": idx + 1, "currentButton": e.currentTarget });
|
||||
}
|
||||
btnBack_Click(e, idx) {
|
||||
this.trigger("onBeforeBack", { "currentPage": this.ctabs[idx], "indexPage": idx, "currentButton": e.currentTarget });
|
||||
this.selectedTab(this.checkSelectedBack(idx));
|
||||
}
|
||||
btnFinish_Click(e) {
|
||||
|
||||
@ -541,6 +541,7 @@ class AApp extends window.AObject {
|
||||
this.metaPage = document.head.querySelector("meta[name=idPage]");
|
||||
this.pageName = this.metaPage.getAttribute("pageName");
|
||||
this.lName = this.metaPage.getAttribute("layName");
|
||||
console.log(this.lName);
|
||||
var tmp = document.querySelector(container);
|
||||
this.mainApp = tmp.querySelector("[main-content]") ? tmp.querySelector("[main-content]") : tmp;
|
||||
var f = function (ev) {
|
||||
@ -688,6 +689,7 @@ class AApp extends window.AObject {
|
||||
doc: doc,
|
||||
dynamicF: a.dynamicF
|
||||
};
|
||||
|
||||
this.setContentPage(obj, url);
|
||||
} else {
|
||||
this.getPage(url, result)
|
||||
@ -721,7 +723,9 @@ class AApp extends window.AObject {
|
||||
document.title = page.title + " - " + this.pageName;
|
||||
var meta = document.head.querySelector("meta[name=idPage]");
|
||||
document.body.setAttribute("page", page.idPage);
|
||||
|
||||
meta.content = page.idPage;
|
||||
this.lName = page.lName;
|
||||
meta.setAttribute("layName", page.lName);
|
||||
this.loadContentPage(page.html);
|
||||
window.history.pushState({"url":url}, page.title, url);
|
||||
@ -821,6 +825,7 @@ class AApp extends window.AObject {
|
||||
}).bind(this)();
|
||||
}
|
||||
loadedLayout() {
|
||||
console.log(this.lName);
|
||||
if (this.lName !== "None") {
|
||||
const l = window.ALayout.get(this.lName);
|
||||
if (!l.isLoaded) {
|
||||
@ -831,7 +836,6 @@ class AApp extends window.AObject {
|
||||
}
|
||||
}
|
||||
setLayout(o) {
|
||||
|
||||
var oP = new DOMParser();
|
||||
var pHtml = oP.parseFromString(o.Content, 'text/html');
|
||||
(function () {
|
||||
|
||||
Reference in New Issue
Block a user