update v0.0.2 twa sys

This commit is contained in:
2025-11-18 11:48:01 +07:00
parent b4b191f829
commit a586da6edc
40 changed files with 1347 additions and 937 deletions

View File

@ -1,6 +1,7 @@
using AppLibs.Libs;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TWASys_App.Models;
namespace TWASys_App.Controllers
{
@ -13,5 +14,37 @@ namespace TWASys_App.Controllers
{
return await this.ViewAsync();
}
[HttpPost]
public async Task<IActionResult> SignIn([FromForm] UserModel user)
{
if (user.Username is not null && user.Password is not null && user.Username.Length > 0 && user.Password.Length > 0)
{
await Task.Delay(100);
if (user.Username.ToLower().Equals("admin") && user.Password.Equals("TWA@2025"))
{
HttpContext.Session.SetString("userID", "admin");
return Json(new MessageHeader
{
ID = 10003,
Message = "Login Success",
Status = 1
});
}
return Json(new MessageHeader
{
ID = 10002,
Message = "The username or password you entered is incorrect",
Status = 0
});
}
return Json(new MessageHeader
{
ID = 10001,
Message = "The username and password are required",
Status = 0
});
}
}
}

View File

@ -67,6 +67,12 @@ namespace TWASys_App.Controllers
return await TypeStorageServerModel.GetAllTypeStorage();
}
[HttpPost]
public async Task<IActionResult> GetStorage([FromForm] StorageModel model)
{
return await model.GetStorages();
}
[HttpGet]
public async Task<IActionResult> GetValidationDomain()
{
@ -85,6 +91,13 @@ namespace TWASys_App.Controllers
return Json(await model.AddAsync());
}
[HttpPost]
public async Task<IActionResult> UpdateStorageSize([FromForm] StorageModel model)
{
return Json(await model.UpdateStorageSize());
}
[HttpGet]
public async Task<IActionResult> GenerationAccessToken()
{
@ -116,6 +129,19 @@ namespace TWASys_App.Controllers
});
}
[HttpGet]
public async Task<IActionResult> CheckStorageInit()
{
await Task.Delay(1);
var f = System.IO.File.Exists(System.IO.Path.GetFullPath("Json/dataServer.json"));
return Json(new MessageHeader
{
ID= 61011,
Message=f?"has":"no",
Status=1
});
}
[HttpGet]
public async Task<IActionResult> GetSysInfo()
{

View File

@ -17,5 +17,8 @@ namespace TWASys_App.DBModels
[NotMapped()]
public ICollection<ServerAuthorization_has_Token> Tokens { get; set; } = new List<ServerAuthorization_has_Token>();
[NotMapped()]
public ICollection<RefreshToken> RefreshTokens { get; set; } = new List<RefreshToken>();
}
}

View File

@ -17,9 +17,12 @@ namespace TWASys_App.DBModels
public DateTime? CreateDate { get; set; }
public int? Size { get; set; } = null;
public string ControllerID { get; set; } = "";
public int Status { get; set; } = 0;
[NotMapped]
public TypeStorageServer TypeStorageServer { set; get; } = null!;
}
}

View File

@ -0,0 +1,3 @@
{
}

View File

@ -46,7 +46,7 @@
},
{
"id": "8000",
"name": "Rooms Management",
"name": "Website Management",
"icon": "",
"group": 1,
"url": "",

View File

@ -1,7 +1,11 @@

using AppLibs.Libs;
using Dapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Microsoft.VisualBasic;
using MySqlConnector;
using Newtonsoft.Json;
using System.Data.Common;
using System.Xml.Linq;
using TWASys_App.Dapper.AExtentions;
@ -11,6 +15,7 @@ namespace TWASys_App.Models
{
public class StorageModel : ModelBase
{
public long IdStorageServer { set; get; }
public long StorageTypeID { set; get; }
public string ControllerName { set; get; } = "";
@ -19,6 +24,7 @@ namespace TWASys_App.Models
public ICollection<ValidationDomain> ValidationDomains { set; get; } = new List<ValidationDomain>();
public int Size { set; get; };
public string IpPublic { set; get; } = "";
public string IpPrivatev4 { set; get; } = "";
@ -54,6 +60,45 @@ namespace TWASys_App.Models
public string RTokenValue { set; get; } = "";
public async Task<IActionResult> GetStorages(int status = 0)
{
await using (var con = new MySqlConnection(DBManagement.GetConnectionString()))
{
string sql = @"
WITH d AS (
SELECT *
FROM StorageServer
WHERE status = @status
ORDER BY idStorageServer
LIMIT @PageSize OFFSET @Offset)
SELECT d.*,t.typeName FROM d
JOIN TypeStorageServer t ON t.idTypeStorageServer = d.idTypeStorageServer;
";
await con.OpenAsync();
if (IsFirstQuery)
{
await using (var multi = await con
.QueryMultipleAsync("SELECT COUNT(*) FROM StorageServer;" + sql, new { Offset = (PageNumber - 1) * PageSize, PageSize = this.PageSize, status = status }))
{
int maxRow = await multi.ReadSingleAsync<int>();
var types = await multi.ReadAsync();
return new JsonResult(new
{
mrows = maxRow,
data = JsonConvert.SerializeObject(types)
});
}
}
else
{
var t = (await con.QueryAsync(sql, new { Offset = (PageNumber - 1) * PageSize, PageSize = this.PageSize, status = status }));
return new JsonResult(new
{
data = JsonConvert.SerializeObject(t)
});
}
}
}
public override async Task<MessageHeader> AddAsync()
{
await using var con = new MySqlConnector.MySqlConnection(DBManagement.GetConnectionString(true));
@ -114,6 +159,12 @@ namespace TWASys_App.Models
ExpireDate = DateTime.UtcNow.AddMonths(3),
Status = 0
};
var ssAT = new ServerAuthorization_has_Token
{
IdToken = TokenID,
Count = 1,
Status = 0
};
var rT = new RefreshToken
{
IdRefreshToken = RTokenID,
@ -129,6 +180,7 @@ namespace TWASys_App.Models
bi.AddRow(ss_lc);
bi.AddRow(serverAuthorization);
bi.AddRow(token);
bi.AddRow(ssAT);
bi.AddRow(rT);
await bi.ExcuteQuery();
await trans.CommitAsync();
@ -155,5 +207,73 @@ namespace TWASys_App.Models
{
throw new NotImplementedException();
}
public async Task<MessageHeader> UpdateStorageSize()
{
var fMess = new MessageHeader();
string sql = @"UPDATE StorageServer
SET Size = @size
Where idStorageServer = @idStorage;
WITH sa_need AS (
SELECT idServerAuthorization
FROM ServerAuthorization
WHERE idStorageServer = @idStorage
),
maxc AS (
SELECT idServerAuthorization, MAX(`count`) AS max_count
FROM ServerAuthorization_has_Token
WHERE idServerAuthorization IN (SELECT idServerAuthorization FROM sa_need)
GROUP BY idServerAuthorization
)
SELECT
sa.idServerAuthorization,
st.idToken,
t.accessToken
FROM sa_need sa
JOIN maxc m ON m.idServerAuthorization = sa.idServerAuthorization
JOIN ServerAuthorization_has_Token st
ON st.idServerAuthorization = sa.idServerAuthorization AND st.`count` = m.max_count
LEFT JOIN Token t ON t.idToken = st.idToken;
WITH sa_need AS (
SELECT idServerAuthorization
FROM ServerAuthorization
WHERE idStorageServer = @idStorage)
SELECT r.*
FROM sa_need s
JOIN RefreshToken r
ON r.idServerAuthorization = s.idServerAuthorization
WHERE r.idRefreshToken = (
SELECT r2.idRefreshToken
FROM RefreshToken r2
WHERE r2.idServerAuthorization = s.idServerAuthorization and r2.status = 0
ORDER BY r2.expireDate DESC
LIMIT 1);";
try
{
await using var con = new MySqlConnection(DBManagement.GetConnectionString(true));
await con.OpenAsync();
using var trans = await con.BeginTransactionAsync();
using var multi = await con.QueryMultipleAsync(sql, new { size = Size, id = IdStorageServer }, trans);
IList<dynamic> tokens = (await multi.ReadAsync()).AsList();
IList<dynamic> rTokens = (await multi.ReadAsync()).AsList();
using (var writer = new StreamWriter(Path.GetFullPath("Json/dataServer.json"), false))
{
await writer.WriteAsync(JsonConvert.SerializeObject(new
{
idRToken = "",
rToken = "",
cDate = "",
eDate = "",
token = "",
idToken = ""
}));
}
}
catch (DbException ex)
{
}
return fMess;
}
}
}

View File

@ -0,0 +1,8 @@
namespace TWASys_App.Models
{
public class UserModel
{
public string Username { set; get; } = "";
public string Password { set; get; } = "";
}
}

View File

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Http.Features;
using System.Net;
using System.Text;
using TWASys_App.Models.Login;
await WSNavigation.LoadJson();
var builder = WebApplication.CreateBuilder(args);
@ -10,6 +11,7 @@ builder.Services.Configure<FormOptions>(o => {
});
builder.Services.AddControllers(options =>
{
options.Filters.Add(new LoginCheckFilter());
options.Filters.Add<AsyncGateAttribute>();
}).AddJsonOptions(options =>
{

View File

@ -38,7 +38,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AppLibs\AppLibs\AppLibs.csproj" />
<ProjectReference Include="..\AppLibs\AppLibs\AppLibs.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -6,113 +6,116 @@
<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">
<a app-nav href="@Url.AbsoluteContent("~/")" class="c_logo d-f j-c-center mb-4">
<img src="@Url.AbsoluteContent("~/images/logo/slogo.png")">
</a>
<div class="AWizard tabcontents">
<div class="tabcontent">
<div class="frm-header">
<h2 class="title">Sign In</h2>
<span class="d-f f-wrap desc a-i-center">Dont have an account? <a href="javascript:void(0)" class="ml-2" id="navSignUp">Sign up</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 id="txtUser" type="text" class="input" placeholder="Your username" />
<span class="line"></span>
</div>
</div>
<div class="frm-input mb-2">
<label>Password</label>
<div class="c-input">
<span class="ico atg a-1x atg-user"></span>
<input id="txtPass" type="password" class="input" placeholder="Your password" />
<span class="line"></span>
</div>
</div>
<div class="c_validation" id="frm_login_summary">
<p class="mess_error"></p>
</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" id="SignIn">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 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>

View File

@ -19,120 +19,122 @@
<div class="cfull">
<div class="r-n-g">
<div class="c-12">
<div class="card-body">
<div class="d-f">
<div class="card-body" data-dropdown>
<div class="d-f dropdown aslidedown">
<h4>Storage Initialization</h4>
<div class="more"><span class="atg atg-more"></span></div>
</div>
<div class="d-f f-c form-group-con mb-2 ">
<div class="form-group d-f f-c">
<label>Total Size</label>
<div class="input-custom d-f c-12 c-s-6">
<button class="input-append left d-f a-i-center minus btn-effect waves-float">
<span class="atg atg-minus"></span>
</button>
<div class="d-f w-100">
<input id="totalSize" type="text" default-value="1" max-value="10000" min-value="1" step-value="1" placeholder="Dung Lượng Storage" validation-isEmpty />
<span class="input-append right">Gb</span>
<div class="sub-item">
<div class="d-f f-c form-group-con mb-2 ">
<div class="form-group d-f f-c">
<label>Total Size</label>
<div class="input-custom d-f c-12 c-s-6">
<button class="input-append left d-f a-i-center minus btn-effect waves-float">
<span class="atg atg-minus"></span>
</button>
<div class="d-f w-100">
<input id="totalSize" type="text" default-value="1" max-value="10000" min-value="1" step-value="1" placeholder="Dung Lượng Storage" validation-isEmpty />
<span class="input-append right">Gb</span>
</div>
<button class="input-append right d-f a-i-center plus btn-effect waves-float">
<span class="atg atg-1x atg-plus"></span>
</button>
</div>
<button class="input-append right d-f a-i-center plus btn-effect waves-float">
<span class="atg atg-1x atg-plus"></span>
</button>
</div>
<label>List Storage Server</label>
<div class="input-custom amultitag d-f c-12 c-s-6" id="listStorage">
<div class="d-f w-100 input-content"></div>
<div class="input-append right d-f a-i-center plus btn-effect waves-float btn-Add">
<span class="atg atg-plus"></span>
<label>List Storage Server</label>
<div class="input-custom amultitag d-f c-12 c-s-6" id="listStorage">
<div class="d-f w-100 input-content"></div>
<div class="input-append right d-f a-i-center plus btn-effect waves-float btn-Add">
<span class="atg atg-plus"></span>
</div>
</div>
<div class="d-f f-c mt-1">
<div class="invalid-feedback mess-empty"></div>
</div>
<div class="brn-group">
<button id="btAdd" type="button" class="btn btn-effect btn-primary mt-2 waves-effect waves-float d-f a-i-center">
Save
</button>
</div>
</div>
<div class="d-f f-c mt-1">
<div class="invalid-feedback mess-empty"></div>
</div>
<div class="brn-group">
<button id="btAdd" type="button" class="btn btn-effect btn-primary mt-2 waves-effect waves-float d-f a-i-center">
Add
</button>
<button id="btLogin" type="button" class="btn btn-effect btn-primary mt-2 waves-effect waves-float d-f a-i-center">
Login Microsoft 365
</button>
</div>
</div>
</div>
</div>
</div>
<div class="c-12">
<div class="card-body">
<div class="d-f">
<div class="card-body" data-dropdown>
<a class="d-f dropdown aslidedown">
<h4>Storage Setting</h4>
<div class="more"><span class="atg atg-more"></span></div>
</div>
<h5 class="mt-2 mb-2">Search Fillter</h5>
<div class="d-f f-c form-group-con mb-2 ">
<div class="form-group d-f f-c">
<div class="input-group">
<input id="inpKey" type="text" placeholder="Keyword" validation-isEmpty />
</div>
<div class="d-f f-c mt-1">
<div class="invalid-feedback mess-empty"></div>
</a>
<div class="sub-item">
<h5 class="mt-2 mb-2">Search Fillter</h5>
<div class="d-f f-c form-group-con mb-2 ">
<div class="form-group d-f f-c">
<div class="input-group">
<input id="inpKey" type="text" placeholder="Keyword" validation-isEmpty />
</div>
<div class="d-f f-c mt-1">
<div class="invalid-feedback mess-empty"></div>
</div>
<div class="brn-group">
<button id="btSearch" type="button" class="btn btn-effect btn-primary mt-2 waves-effect waves-float d-f a-i-center">
Search
</button>
</div>
</div>
</div>
<div class="atabs">
<div class="tab-item">
<a href="javascript:void(0)" class="item active">Searched Result</a>
</div>
<div class="tab-item">
<a href="javascript:void(0)" class="item" disabled>Update Item</a>
</div>
</div>
<div class="d-f f-c form-group-con">
<div class="form-group tabcontents">
<div class="tabcontent">
<div class="c-table">
</div>
<div class="brn-group">
<button id="btSearch" type="button" class="btn btn-effect btn-primary mt-2 waves-effect waves-float d-f a-i-center">
Search
</button>
</div>
</div>
<div class="tabcontent">
<div class="d-f f-c form-group-con mb-2 ">
<div class="form-group d-f f-c">
<h5 class="mt-2 mb-2">Edit Storage Type</h5>
<label for="inpType">Storage Type Name</label>
<div class="input-group">
<input id="inpEID" type="hidden" />
<input id="inpEType" type="text" placeholder="Type Name" validation-isEmpty />
</div>
<div class="d-f f-c mt-1">
<div class="invalid-feedback mess-empty"></div>
</div>
<div class="brn-group d-f mt-2">
<button id="btUpdate" type="button" class="btn btn-effect btn-primary waves-effect waves-float d-f a-i-center">
Update
</button>
<button id="btBack" type="button" class="btn btn-effect btn-primary ml-2 waves-effect waves-float d-f a-i-center">
Cancel
</button>
</div>
<div class="atabs">
<div class="tab-item">
<a href="javascript:void(0)" class="item active">Searched Result</a>
</div>
<div class="tab-item">
<a href="javascript:void(0)" class="item" disabled>Update Item</a>
</div>
</div>
<div class="d-f f-c form-group-con">
<div class="form-group tabcontents">
<div class="tabcontent">
<div class="c-table">
</div>
</div>
<div class="tabcontent">
<div class="d-f f-c form-group-con mb-2 ">
<div class="form-group d-f f-c">
<h5 class="mt-2 mb-2">Edit Storage Type</h5>
<label for="inpType">Storage Type Name</label>
<div class="input-group">
<input id="inpEID" type="hidden" />
<input id="inpEType" type="text" placeholder="Type Name" validation-isEmpty />
</div>
<div class="d-f f-c mt-1">
<div class="invalid-feedback mess-empty"></div>
</div>
<div class="brn-group d-f mt-2">
<button id="btUpdate" type="button" class="btn btn-effect btn-primary waves-effect waves-float d-f a-i-center">
Update
</button>
<button id="btBack" type="button" class="btn btn-effect btn-primary ml-2 waves-effect waves-float d-f a-i-center">
Cancel
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="c-12">
<div class="card-body">
<div class="d-f">
<div class="card-body" data-dropdown>
<div class="d-f dropdown aslidedown">
<h4>Your Storage</h4>
<div class="more"><span class="atg atg-more"></span></div>
</div>
<div class="sub-item">
</div>
</div>
</div>
</div>

View File

@ -23,7 +23,7 @@
user-select: none
}
a {,
a {
text-decoration: none
}

View File

@ -43,9 +43,9 @@
.abs-table th {
color: #fff;
background-color: #36304a;
padding: 20px 10px 20px;
font-size: .9rem;
font-weight: 500;
padding: 18px 10px 18px;
font-size: .82rem;
font-weight: 600;
text-transform: capitalize;
letter-spacing: .5px
}
@ -64,7 +64,7 @@
text-align: center;
font-weight: 400;
color: #808080;
padding: 8px 15px
padding: 15px
}
.abs-container {

View File

@ -53,7 +53,6 @@
max-width: 100% !important
}
}
.ws-login {
box-shadow: 0 2px 3px rgba(96, 96, 96, 0.1);
background-color: #fff;
@ -79,11 +78,12 @@
padding-left: 25px;
}
.ws-login .title, .ws-login .desc {
.ws-login .desc{
font-size: .92rem;
}
.ws-login .hint {
font-size: .82rem;
font-size: .8rem;
}
@ -109,8 +109,8 @@
margin-right: -15px;
}
.frm-input, .frm-header {
padding: 0 15px;
.frm-input, .frm-header, .c_validation {
padding: 0 5px;
margin-bottom: 25px;
}
@ -162,4 +162,10 @@
.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);
}
}
.main-login a {
color: #454545;
font-size: .85rem;
font-weight: 600
}

View File

@ -28,6 +28,7 @@ html {
font-weight: 500;
}
a{
position: relative;
text-decoration: none
}
@ -73,8 +74,10 @@ body[page="10001"] #header {
h1, h2, h3, h4, h5, h6 {
font-weight: 600;
color: #5e5873;
margin-bottom: 5px
color: #5e5873
}
h2{
font-size: 2rem;
}
h5 {
@ -332,7 +335,7 @@ nav {
cursor:pointer
}
.active .more span{
.active .more span {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
@ -340,7 +343,8 @@ nav {
transform: rotate(90deg);
}
.more span {
transition: all .3s ease-in;
display: inline-block;
transition: all .3s ease-in-out;
transform: rotate(0)
}
.more {
@ -464,6 +468,16 @@ nav {
right: 0
}
.card-body .dropdown{
cursor: pointer
}
.card-body .sub-item{
box-shadow: none !important;
position: relative !important
}
.card-body {
border-radius: var(--border-radius);
padding: 20px 20px;
@ -793,6 +807,40 @@ nav {
box-shadow: 0 3px 10px 0 rgb(34 41 47 / 10%);
}
.amultitag .item{
transition: all .3s ease-in-out;
cursor: pointer;
border-radius: var(--radius);
margin: 5px;
background: var(--color-primary);
padding: 5px 10px;
font-size: .8rem;
color: #fff
}
.amultitag .item .con-ico {
margin-left: 0;
height: 20px;
border-radius: 50%;
color: #5e5873;
visibility: hidden;
width: 0;
transition-delay: 0;
transition: width .3s ease-in-out, visibility .3s ease-in-out;
transition-delay: .3s;
transition: background .3s ease-in-out, margin-left .3s ease-in-out
}
.amultitag .item:hover .con-ico {
margin-left: 10px;
background: #fff;
visibility: visible;
width: 20px
}
.amultitag .item:hover .con-ico:hover{
color:#fff;
background: var(--secondary);
}
.form-group input, .form-group .aselect, .form-group textarea {
font-size: .85rem;
width: 100%;
@ -1210,17 +1258,17 @@ input[type=checkbox] {
top: 50%;
transform: translateY(-50%)
}
.mess-info{
[class^=mess_] {
font-size: .82rem;
font-weight: 400;
margin: 5px 0;
}
.mess-success {
.mess_success {
color: #28c76f;
}
.mess-error {
.mess_error {
color: #ea5455;
}
@ -1261,10 +1309,10 @@ input[type=checkbox] {
background-color: #7367f0;
box-shadow: 0 .125rem .25rem rgba(165, 163, 174, .3);
}
.animationSlide {
width: 100%;
overflow-x: hidden;
overflow: hidden;
}
.animationSlide .slideContent {
@ -1273,11 +1321,16 @@ input[type=checkbox] {
}
.animationSlide .tabcontent.show {
visibility: visible;
height: auto;
opacity: 1;
}
.animationSlide .tabcontent {
opacity: 0;
transition: .3s all ease-in-out
visibility:hidden;
height: 0;
opacity: 0
}
.animationFade .tabcontent {
@ -1302,4 +1355,10 @@ input[type=checkbox] {
.awStorageConnector .tabcontent .form-group{
padding: 0;
}
/*******************End Page**********************/
/*******************End Page**********************/
/*********Login Form**********/
.c_validation{
margin-bottom: 15px !important
}

View File

@ -1,4 +1,5 @@
import AWizard from "/js/libs/js-AWizard.js";
import AButton from "/js/libs/js-AButton.js";
window.L10001 = function () {
Waves.attach('.btn-effect', ['waves-float']);
@ -18,6 +19,49 @@ window.L10001 = function () {
navSignUp.addEventListener("click", (e) => {
wrd1.nextPage(2);
});
window.requestTimeout(() => {
const v = document.querySelector(".c-login");
let top = (v.parentElement.clientHeight / 2) - (v.clientHeight / 2);
if (v.clientHeight <= window.innerHeight) {
top = top - (window.innerHeight - v.clientHeight) / 2
} else {
top = top - 40;
}
if (window.getOS() == "iOS") {
} else {
window.smScroll.scrollTop = top;
}
}, 500);
let btn = new AButton(document.getElementById("SignIn"));
btn.on("click_SignIn", (el) => {
btn.AddLoading(el);
document.querySelector("#frm_login_summary .mess_error").innerHTML = "";
let promise = new Promise(async function (resolve, reject) {
const fd = new FormData();
fd.append("username", document.getElementById("txtUser").value);
fd.append("password", document.getElementById("txtPass").value)
const response = await fetch(`/Login/SignIn`, {
method: 'POST',
body: fd
});
const data = await response.json();
if (data) {
switch (data.Status) {
case 0:
document.querySelector("#frm_login_summary .mess_error").innerHTML = data.Message;
break;
case 1:
window.app.initNavApp("/");
break;
}
btn.RemoveLoading(el);
}
});
});
}
function ComeBack(e, wrd) {

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,6 @@ 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',
@ -46,9 +45,6 @@ class AsyncLayout extends ALayout {
window.app.initScrollBar();
window.Scrollbar.init(document.querySelector('.mini-scrollbar'), sOption);
}
}

View File

@ -22,16 +22,9 @@ class LoginLayout extends ALayout {
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();
}
}

View File

@ -44,12 +44,16 @@
}).bind(this);
break;
case "Slide":
var slideC = document.createElement("div");
slideC.classList.add("slideContent");
while (this.params.parent.childNodes.length > 0) {
slideC.appendChild(this.params.parent.childNodes[0]);
var slideC = this.params.parent.querySelector(".slideContent");
if (slideC == null) {
slideC = document.createElement("div");
slideC.classList.add("slideContent");
while (this.params.parent.childNodes.length > 0) {
slideC.appendChild(this.params.parent.childNodes[0]);
}
this.params.parent.appendChild(slideC);
}
this.params.parent.appendChild(slideC);
slideC.querySelectorAll(".tabcontent").forEach((el) => {
let style = this.params.parent.currentStyle || window.getComputedStyle(this.params.parent);

View File

@ -51,7 +51,6 @@ export default class Dropdown extends window.AObject {
if (this.isLock) {
return;
}
console.log("Asdasd");
var t1 = e.currentTarget;
var p = t1.closest('[data-dropdown]');
var p1 = e.target.closest(".noopen");

View File

@ -10,10 +10,10 @@ export default class AMenu extends window.AObject {
this.navD = document.querySelector(nav);
this.transition = new ATransitionEffect();
this.overlay = new AOverlay(document.body);
this.isMDiffD = isMDiffD;
this.changeActive();
if (btnMs != null) {
if (!(Array.isArray(btnMs) || btnMs instanceof NodeList || btnMs instanceof HTMLCollection)) {
const tmp = [];
@ -21,14 +21,14 @@ export default class AMenu extends window.AObject {
btnMs = tmp;
}
btnMs.forEach((el => {
var f = function (e) {
this.mobileMenu.call(this, e, el);
}.bind(this);
el.addEventListener(this.eventName, f, false);
this.addSystemEvent(this.eventName, el, f, "icomenu");
this.listIco.push(el);
}).bind(this));
this.overlay.createOverlay();
this.overlay.setIndex(2000);
@ -54,7 +54,7 @@ export default class AMenu extends window.AObject {
this.initNav(this.navM, "M");
}
}
initNav(ele, type = "D") {
let arr = ele.querySelectorAll(".nav-i.has-sub .nav-link, .navmain > .nav-i:not(.has-sub) a");
Array.from(arr).forEach(el => {
@ -81,10 +81,10 @@ export default class AMenu extends window.AObject {
}
updateIdPage() {
this.idPage = document.head.querySelector("meta[name=idPage]").content;
this.navActiveD = this.navD.querySelector("a[nav-id='" + this.idPage + "']");
if (this.isMDiffD) {
this.navActiveM = this.navM.querySelector("a[nav-id='" + this.idPage + "']");
this.navActiveM = this.navM.querySelector("a[nav-id='" + this.idPage + "']");
}
window.removeStopCollapsed();
}
@ -140,7 +140,7 @@ export default class AMenu extends window.AObject {
}
}).bind(this));
}).bind(this), 100);
}
closeExpandMenu() {
Array.from(this.navM.querySelectorAll(".nav-i.has-sub")).forEach(el => {

View File

@ -52,7 +52,9 @@ export default class AModal extends window.AObject {
showModal() {
this.overlay.showOverlay();
}
removeModal() {
this.overlay.removeOverlay();
}
}
class AModalOK {

View File

@ -3,8 +3,8 @@ export default class AMultiTag extends window.AObject {
super();
this.parent = ele;
this.cItems = ele.querySelector(".input-content");
this.itemEles = [];
this.itemDatas = [];
this.itemEles = new Map();
this.itemDatas = new Map();
this.btnAdd = ele.querySelector(".btn-Add");
this.btnAdd.addEventListener("click", ((e) => {
this.parent.classList.add("active");
@ -16,6 +16,11 @@ export default class AMultiTag extends window.AObject {
}
initGlobalVar() {
var f = function (ev) {
const close = ev.target.closest(".con-ico");
if (close) {
const t = close.closest(".item[data-id]");
if (t) this.removeItem(1 * t.getAttribute("data-id"));
}
if (ev.target.closest(".amultitag") || ev.target.closest(".c-aoverlay")) {
return;
} else {
@ -26,22 +31,32 @@ export default class AMultiTag extends window.AObject {
window.AMultiTag = true;
}
addItem(id, name, obj, action = null) {
var ele = this.addItem(id, name, action);
this.itemEles.push(ele);
this.itemDatas.push(obj);
var ele = this.createItem(id, name, action);
this.itemEles.set(id, ele);
this.itemDatas.set(id, obj);
this.cItems.appendChild(ele);
}
removeItem(id) {
const t = this.itemEles.get(id);
this.itemDatas.delete(id);
this.itemEles.delete(id);
t.remove();
}
createItem(id, name, action) {
var p = document.createElement("div");
p.setAttribute("data-id", id);
p.classList.add("item");
p.classList.add("item", "d-f", "a-i-center");
var label = document.createElement("span");
label.innerHTML = name;
label.classList.add("name");
if (action != null) {
p.appendChild(action);
}
let close = document.createElement("div");
close.classList.add("con-ico", "d-f", "a-i-center", "j-c-center");
p.appendChild(label);
close.innerHTML = `<span class="atg a-1x atg-x"></span>`;
p.appendChild(close);
return p;
}
}

View File

@ -182,6 +182,7 @@ class ASelectEle extends window.AObject {
if (this.selectedEleItem != null) this.selectedEleItem.classList.remove("active");
this.selectedEleItem = this.listItems[idx].element;
this.selectedItem = this.listItems[idx];
this.removeAllChildNodes(this.cSelectedItem);
this.cloneNodes(this.selectedEleItem, this.cSelectedItem);
this.setElement(this.selectedEleItem);
@ -398,7 +399,6 @@ class ASelectEle extends window.AObject {
}
if (tmp != null && tmp.classList.contains("a-option")) {
this.updateIndex(tmp.getAttribute("index"));
console.log(tmp.offsetTop);
this.scroll.scrollIntoView(tmp, {
alignToTop: false,
offsetBottom: 0,

View File

@ -0,0 +1,69 @@
import ATransitionEffect from '/js/libs/js-ATransitionEffect.js'
export default class ASlideDown extends window.AObject {
constructor(el) {
super();
this._eleM = [];
if (el instanceof NodeList) {
Array.from(el).forEach((e) => {
this._eleM.push(new ASlideDownEle(e))
});
} else {
this._eleM.push(new ASlideDownEle(el));
}
}
get(i) {
return this._eleM[i];
}
}
class ASlideDownEle extends window.AObject {
constructor(ele) {
super();
this.transition = new ATransitionEffect();
this._ele = ele;
this._pCon = ele.closest('[data-dropdown]');
this._subI = this._pCon.querySelector(".sub-item");
var f = function (ev) {
if (window.isValidPointerClick(ev)) return;
this.onClick.call(this, ev);
}.bind(this);
this.addSystemEvent(this.eventName, this._ele, f);
}
enable() {
this._ele.classList.remove("disabled");
}
disable() {
this._ele.classList.add("disabled");
}
enable_Open() {
this.enable();
this.open();
}
disable_Close() {
this.disable();
this.close();
}
open() {
if (this._ele.classList.contains("disabled")) {
return;
}
this._pCon.classList.add("active");
this.transition.expandEffect(this._subI, function () {
this.trigger("opened");
}.bind(this));
}
close() {
this._pCon.classList.remove("active");
this.transition.collapsedEffect(this._subI, function () {
this.trigger("closed");
}.bind(this));
}
onClick(e) {
if (this._pCon.classList.contains("active")) {
this.close();
} else {
this.open();
}
}
}

View File

@ -33,7 +33,14 @@ export default class AWizard extends ATab {
Cancel
</button>
</div>`;
const ro = new ResizeObserver((entries => {
for (const e of entries) {
const { width, height } = e.contentRect;
this.aAnimation.setType(this.typeAnimation, { "parent": this.tabContents });
}
}).bind(this));
ro.observe(this.tabContents);
}
showPage(i) {
this.cPage = i;

View File

@ -6,6 +6,7 @@
this.pElement = e;
this.Headers = [];
this.lSysRows = [];
this.labelID = "";
this.InitStructure();
this.InitCss();
this.SetIdCheckBox();
@ -18,7 +19,8 @@
}
}
SetScrollBarY(height) {
this.absContainerRows.style.height = height + "px";
this.absContainerRows.style.height = "auto";
this.absContainerRows.style.maxHeight = height + "px";
}
AddHeader(name, width, minWidth, id = "", rowTemp = null) {
var d = document.createElement("th");
@ -184,10 +186,15 @@
this.data.forEach((e, i) => {
var r = document.createElement("tr");
r.setAttribute("data-id", i);
this.Headers.forEach((o) => {
this.Headers.forEach((o, j) => {
var td = document.createElement("td");
if (o.rowTemp != null) {
td.appendChild(o.rowTemp(i, e));
const rT = o.rowTemp(i, e);
if (this.isCheckBox && j < 1) {
rT.setAttribute("id", (this.labelID.length >0)?e[this.labelID]:"");
}
td.appendChild(rT);
} else {
td.innerHTML = e[o.id];
}

View File

@ -104,14 +104,14 @@ window.getOS = function () {
return os;
}
window.GetAbsoluteURL = function(relativeURL) {
window.GetAbsoluteURL = function (relativeURL) {
if (relativeURL.startsWith(window.location.origin)) {
return relativeURL;
}
return window.location.origin + relativeURL;
}
window.getPathFromUrl = function(url) {
window.getPathFromUrl = function (url) {
const parsed = new URL(url);
return parsed.pathname + parsed.search + parsed.hash;
}
@ -377,9 +377,9 @@ window.AObject = class {
const eventMap = this.systemEvents.get(element);
if (eventMap) {
const data = eventMap.get(eventName);
if (data && typeof data.callback === 'function') {
element.removeEventListener(eventName , data.callback, false);
element.removeEventListener(eventName, data.callback, false);
eventMap.delete(eventName);
// Nếu element không còn event nào, xóa khỏi systemEvents
if (eventMap.size === 0) {
@ -387,7 +387,7 @@ window.AObject = class {
}
}
}
}
this.parentEventMap.delete(parent);
}
@ -406,7 +406,7 @@ window.AObject = class {
}
addCustomEvent(id, element, groups = null) {
if (!this.customEvents.has(id)) {
this.customEvents.set(id, { "ele":element, "groups":groups });
this.customEvents.set(id, { "ele": element, "groups": groups });
}
if (groups) {
if (!this.parentEventMap.has("Custom" + parent)) {
@ -429,6 +429,7 @@ window.AObject = class {
}
this.parentEventMap.get(parent).add({ element, eventName });
}
}
removeAllChildNodes(parent) {
while (parent.firstChild) {
@ -541,12 +542,11 @@ 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) {
if (ev.state) {
this.cachePage.get(ev.state.url, ((result) => {
this.cachePage.get(ev.state.url, ((result) => {
if (result == null) {
} else {
@ -655,7 +655,7 @@ class AApp extends window.AObject {
this.addSystemEvent("click", el, f1, groups)
const f2 = (function (ev) {
if (window.isValidPointerClick(ev)) return;
this.initNavApp(ev.currentTarget.getAttribute("href"), ev.currentTarget.hasAttribute("isflexpage"));
}).bind(this);
this.addSystemEvent(this.eventName, el, f2, groups);
@ -689,8 +689,7 @@ class AApp extends window.AObject {
doc: doc,
dynamicF: a.dynamicF
};
this.setContentPage(obj, url);
this.setContentPage(obj, url);
} else {
this.getPage(url, result)
}
@ -699,17 +698,6 @@ class AApp extends window.AObject {
this.getPage(url);
}
}).bind(this));
//if (flex) {
//} else {
// this.cachePage.get(url, ((result) => {
// if (result) {
// // Set content page từ cache
// } else {
// this.getPage(url); // Load mới nếu chưa có trong cache
// }
// }).bind(this));
//}
}
loadContentPage(content) {
const tpl = document.createElement('template');
@ -723,12 +711,10 @@ 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);
meta.setAttribute("layName", page.lName);
this.loadContentPage(page.html);
window.history.pushState({"url":url}, page.title, url);
window.history.pushState({ "url": url }, page.title, url);
}
setContentPage(page, url) {
this.contentPage(page, url);
@ -778,7 +764,6 @@ class AApp extends window.AObject {
loadedPage() {
this.metaPage = document.head.querySelector("meta[name=idPage]");
if (this.metaPage != null && this.isLoadedLayout) {
console.log(window.location.href);
this.cachePage.searchFlexPage(window.getPathFromUrl(window.location.href), ((tmp) => {
tmp = tmp.layout.info;
if (tmp != null && tmp.dynamicF != null) {
@ -790,7 +775,7 @@ class AApp extends window.AObject {
this.initNavs(this.metaPage.content);
this.trigger("pageLoaded", null);
}).bind(this));
} else {
window.requestTimeout(this.loadedPage.bind(this), 10, window.registerCancel);
}
@ -803,9 +788,9 @@ class AApp extends window.AObject {
console.log("connect new Layout");
this.loadLayout(); // Load mới nếu chưa có trong cache
}
}).bind(this), "layout");
}
loadLayout() {
(function () {
@ -825,10 +810,9 @@ 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) {
if (!l.isLoaded) {
l.renderMenu();
this.isLoadedLayout = true;
this.trigger("layoutLoaded", null);
@ -928,7 +912,7 @@ class CacheManager {
// Lấy thông tin trang hoặc layout
// Lấy dữ liệu từ cache (localStorage hoặc IndexedDB nếu cần)
get(id, callback, type = "cahce") {
this._onReady(() => {
@ -986,7 +970,7 @@ class CacheManager {
this.countFP++;
}
this.storage.set("treePage", this.flexPages.toJSON(), function () { });
} else {
} else {
const layout = {
Content: obj.Content,
Scripts: obj.Scripts
@ -1054,7 +1038,7 @@ class CacheStorage {
del.onblocked = () => {
console.warn("deleteDatabase blocked (tab khác đang giữ kết nối)");
};
}
_flushQueue() {
while (this.queue.length) {
@ -1104,7 +1088,7 @@ class CacheStorage {
}
});
}
set(key, data, callback = () => { }, type="cache") {
set(key, data, callback = () => { }, type = "cache") {
this._onReady(() => {
if (this.db) {
let tx, store, req;
@ -1117,7 +1101,7 @@ class CacheStorage {
store = tx.objectStore("cache");
store.put({ key: this._key(key), value: data, ts: Date.now() });
}
tx.oncomplete = () => callback(null);
tx.onerror = (e) => callback(e);
} else {
@ -1126,7 +1110,7 @@ class CacheStorage {
localStorage.setItem(this._key(key), JSON.stringify({ data, ts: Date.now() }));
callback(null);
} catch (e) {
callback(e);
}
}