diff --git a/AppLibs/AppLibs/Libs/AsyncGateAttribute.cs b/AppLibs/AppLibs/Libs/AsyncGateAttribute.cs index f58bbe4..1b9a90f 100644 --- a/AppLibs/AppLibs/Libs/AsyncGateAttribute.cs +++ b/AppLibs/AppLibs/Libs/AsyncGateAttribute.cs @@ -1,9 +1,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -35,6 +38,7 @@ namespace AppLibs.Libs // Không có vr => return ViewAsync ngay, bỏ qua action if (context.Controller is Controller c) { + ApplyActionAttributesToController(c, context.ActionDescriptor); var result = await ControllerExtensions.ViewAsync(c); context.Result = result; // short-circuit return; @@ -42,5 +46,31 @@ namespace AppLibs.Libs context.Result = new NotFoundResult(); } + private static void ApplyActionAttributesToController(Controller controller, ActionDescriptor ad) + { + if (ad is not ControllerActionDescriptor cad) return; + + // Lấy attribute từ method, fallback về controller (nếu bạn có gắn ở class) + var layoutAttr = cad.MethodInfo.GetCustomAttribute(inherit: true) + ?? cad.ControllerTypeInfo.GetCustomAttribute(inherit: true); + + var pageAttr = cad.MethodInfo.GetCustomAttribute(inherit: true) + ?? cad.ControllerTypeInfo.GetCustomAttribute(inherit: true); + + // Truyền qua ViewData (View đọc trực tiếp được), + // đồng thời bỏ bản gốc vào HttpContext.Items nếu View/Helper cần cả object. + if (layoutAttr != null) + { + controller.ViewData["LayoutName"] = layoutAttr.LayoutName; + } + + if (pageAttr != null) + { + controller.ViewData["PageID"] =pageAttr.PageID; + controller.ViewData["Title"] = pageAttr.PageName; + controller.ViewData["FlexPage"] = pageAttr.FlexPage; + } + } + } } diff --git a/AppLibs/AppLibs/Libs/LayoutAttribute.cs b/AppLibs/AppLibs/Libs/LayoutAttribute.cs index e27d5ee..2d69279 100644 --- a/AppLibs/AppLibs/Libs/LayoutAttribute.cs +++ b/AppLibs/AppLibs/Libs/LayoutAttribute.cs @@ -19,6 +19,7 @@ namespace AppLibs.Libs private string _layoutName; + public string LayoutName { set { _layoutName = value; } get { return _layoutName; } } public LayoutAttribute():this(LayoutOptions.Default) { } diff --git a/AppLibs/AppLibs/Libs/PageInforAttribute.cs b/AppLibs/AppLibs/Libs/PageInforAttribute.cs index ce2c4aa..b117422 100644 --- a/AppLibs/AppLibs/Libs/PageInforAttribute.cs +++ b/AppLibs/AppLibs/Libs/PageInforAttribute.cs @@ -11,15 +11,20 @@ namespace AppLibs.Libs public PageInforAttribute(string pageID, string pageName) { - this._pageID = pageID; - this._pageName = pageName; + this.PageID = pageID; + this.PageName = pageName; } public PageInforAttribute(string pageID, string pageName, string flexPage) : this(pageID, pageName) { - this._flexPage = flexPage; + this.FlexPage = flexPage; } + + public string PageID { get => _pageID; set => _pageID = value; } + public string PageName { get => _pageName; set => _pageName = value; } + public string FlexPage { get => _flexPage; set => _flexPage = value; } + public void OnActionExecuted(ActionExecutedContext context) { } @@ -29,9 +34,9 @@ namespace AppLibs.Libs Controller? controller = context.Controller as Controller; if (controller != null) { - controller.ViewData["PageID"] = this._pageID; - controller.ViewData["Title"] = this._pageName; - controller.ViewData["FlexPage"] = this._flexPage; + controller.ViewData["PageID"] = this.PageID; + controller.ViewData["Title"] = this.PageName; + controller.ViewData["FlexPage"] = this.FlexPage; } } } diff --git a/TWA-App/Json/news.json b/TWA-App/Json/news.json index 7dbeb18..336f740 100644 --- a/TWA-App/Json/news.json +++ b/TWA-App/Json/news.json @@ -1,4 +1,20 @@ [ + { + "id": 48151624, + "title": "Trans World Aviation announces expanded Cargo GSSA partnership with Philippine Airlines at DAD", + "contentDesc": "Trans World Aviation expands partnership with Philippine Airlines, appointed Cargo GSSA for Da Nang alongside Hanoi. TWA delivers proven sales, compliant operations, DGR/cold-chain handling, and real-time support as PR’s single cargo contact at both stations.", + "pathImage": "48151624.png", + "pathPdf": "VINCI wins rights to manage Phnom Penh\u2019s new airport as French-Cambodian entente cordiale takes off.pdf", + "catName": "Events" + }, + { + "id": 48151654, + "title": "Trans World Aviation appointed Passenger GSSA for SriLankan Airlines across Vietnam", + "contentDesc": "Trans World Aviation is appointed SriLankan Airlines’ Passenger GSSA for Vietnam, expanding on its Cargo GSSA since 2016. TWA now handles sales, ticketing, airport coordination, charters, compliance, and real-time customer support nationwide.", + "pathImage": "48151654.png", + "pathPdf": "VINCI wins rights to manage Phnom Penh\u2019s new airport as French-Cambodian entente cordiale takes off.pdf", + "catName": "Events" + }, { "id": 48151623, "title": "VINCI secures management rights for Cambodia\u0027s new Phnom Penh airport.", diff --git a/TWA-App/Json/servicesData.json b/TWA-App/Json/servicesData.json index 537251c..433b82f 100644 --- a/TWA-App/Json/servicesData.json +++ b/TWA-App/Json/servicesData.json @@ -16,21 +16,21 @@ { "id": "3012", "lang": "en", - "content-page": "

PAX

Our PAX GSSA Services

\"Air
  • Call Centre services, including handling of all airline reservations
  • FIT and group booking enquiries
  • Tour operator series and allotment handling and controlling
  • Handling enquiries of final consumers
  • Creation of monthly sales statistics; including revenue control & reporting
  • Dispatch of price sheets and product information
  • Telephone sales activities, product & destination advice
", + "content-page": "

Aviation Support

Our Operating Services

We currently provide Airport Handling Supervision service at 3 airports, namely Ho Chi Minh City (SGN), Hanoi (HAN) and Da Nang (DAD) airports included: RAMP Service; Station Management Services; Passenger and Baggage Handling Services; Load Control and Flight Operations Services; Cargo and Mail Warehouse Services; Executive Aviation Services; Training Services; Repair and Maintenance Services; Telephone Check-in Services; Lotus Lounge Services; Airport Ticket Office.

\"Overview

Cargo Handling Supervision

Our certified cargo handling team, accredited by IATA as well as the National Aviation Authority, is fully equipped to supervise the safe and compliant processing of all cargo types with strict adherence to international standards. We manage temperature control, segregation, labeling and documentation that ensure that each item is handled with precision, adhering to international standards to preserve cargo integrity and regulatory compliance from acceptance to delivery.

Cargo Type

  • General Cargo (GEN)
  • Dangerous Goods (DGR)
  • Live Animals (AVI)
  • Valuable Cargo (VAL)
  • Perishable Cargo (PER)
  • Wet Cargo (WET)
  • Human Remains (HUM)
  • Personal Effects (Unaccompanied Baggage)
  • Strongly Smelling Goods (SMELL)
  • Outsized and Heavy Cargo (HEA)
  • Arms, Ammunition, War Material
  • Cargos Needing Special Handling (Air Mail, Newspapers, Vulnerable Cargo-VUL)
\"Map

Ramp Supervision

With proven skills, our Ramp Officer supervises every piece of freight through its pallet building/ULD loading, coordinate sequencing and weight distribution and loaded or unloaded to ensure each flight achieves maximum capacity & profitability. Moreover, we establish a good working relationship with ground handling company and ensure smooth operation to maintain safety, efficiency, and smooth turnarounds.

\"Vital

Import/Export Supervision

Our import/export supervision service coordinates end‑to‑end clearance and movement for inbound and outbound shipments. We manage all paperwork, interact with freight forwarders, customs brokers and authorities, verifying to ensure its complies with local customs and international regulations. Besides, we are also able to streamline clearance procedures, minimize delays while maintaining full traceability throughout the logistics chain

\"Permit

Security-Screening protocol

We implement rigorous security-screening protocols in accordance with aviation safety regulations and national security requirements. Our trained personnel oversee screening procedures for cargo and mail, ensuring compliance with IATA and National Aviation Authorities standards. This includes X‑ray, physical inspections, and tamper‑evident procedures; verify-secure documentation and chain‑of‑custody; and apply risk‑based screening to protect the supply chain while minimizing operational disruption to safeguard the integrity of each shipment

\"Permit
", "styles": [], "scripts": [] }, { "id": "3013", "lang": "en", - "content-page": "

PAX

Our PAX GSSA Services

\"Air
  • Call Centre services, including handling of all airline reservations
  • FIT and group booking enquiries
  • Tour operator series and allotment handling and controlling
  • Handling enquiries of final consumers
  • Creation of monthly sales statistics; including revenue control & reporting
  • Dispatch of price sheets and product information
  • Telephone sales activities, product & destination advice
", + "content-page": "

Aviation Support

Our Warehousing Services

Trans World Aviation delivers integrated warehousing for air cargo, uniting end-to-end inventory control with disciplined SOPs to accelerate receipts, picking, consolidation, and dispatch. We safeguard airline assets via proactive ULD control—inventory oversight, inspection coordination, repair/reposition planning, and flight-by-flight forecasting to match cargo profiles and prevent shortages. For perishables and pharmaceuticals, validated cold-chain facilities provide multi-zone temperature control, continuous monitoring, and compliant handling, preserving product integrity from warehouse intake to airside handover.

\"Overview

Warehouse management

Our warehouse management delivers end-to-end inventory control and logistics tailored for air cargo. We handle receipts, storage, order picking, consolidation, and dispatch with real-time inventory visibility and strict SOPs. Processes are optimized for fast transit times, accurate documentation, and reduction of dwell time to improve airline and forwarder throughput

ULD Control

We represent airlines and coordinate with handling partners to ensure effective ULD management across each flight. We support handling companies with inventory oversight, inspections coordination, tagging and repair requests, and repositioning plans, while maintaining robust records and proactive turnaround planning to reduce loss and downtime. In addition, we estimate flight‑by‑flight ULD volume and pre‑plan required quantities and ULD types to match cargo profiles, and—when plans are disrupted—leverage our industry relationships to source or rent ULDs from other carriers for urgent shortfalls

Cold/Perishable storage facilities

Our cold and perishable storage provides temperature-controlled handling and specialized care for perishables, pharmaceuticals, and other temperature-sensitive cargo. Facilities support multiple temperature zones, continuous monitoring, validated cold chains, and dedicated handling protocols to preserve product integrity and ensure regulatory compliance from receipt to airside delivery

", "styles": [], "scripts": [] }, { "id": "3014", "lang": "en", - "content-page": "

PAX

Our PAX GSSA Services

\"Air
  • Call Centre services, including handling of all airline reservations
  • FIT and group booking enquiries
  • Tour operator series and allotment handling and controlling
  • Handling enquiries of final consumers
  • Creation of monthly sales statistics; including revenue control & reporting
  • Dispatch of price sheets and product information
  • Telephone sales activities, product & destination advice
", + "content-page": "

Aviation Support

Our Flight Support Services

Our Flight Support suite delivers regulatory, operational and safety services that keep aircraft on schedule and crews informed. We combine regulatory expertise, real‑time monitoring and technical analysis to secure permits, coordinate slots, manage clearances, and provide actionable flight planning and weather intelligence for safe, efficient operations

\"Overview

Overflight & Landing/Take-off Permit

Our team leverages long-standing relationships with civil aviation authorities and diplomatic channels to accelerate permit processing and reduce administrative steps for partners. We provide targeted guidance on documentation, fee handling, and route packaging to fast-track approvals and resolve bottlenecks before they impact operations

Slot & PPR

Through established contacts with airport operator & slot requests, Prior Permission Required (PPR), we could streamline request preferred slots, managing contingencies, and maintaining direct lines, that are able to minimize ground delays with optimal touchdown/takeoff windows and align schedules with network requirements

Air Traffic Clearances

Our operational liaisons and experienced dispatchers coordinate with ATC units to simplify clearance workflows and shorten lead times. By preparing robust, pre-vetted flight plans and ATC clearances as well as managing tactical negotiations on routing or altitude constraints, we help reduce delays and limit re-clearance cycles in congested airspace

Real-Time Flight Tracking

We provide continuous real‑time flight monitoring and situational awareness through integrated monitoring tools and automated alerts watch‑desk along with staffed operations desk to detect deviations, airspace constraints, and ground disruptions immediately. This enables proactive interventions, timely stakeholder notifications, and rapid contingency execution to protect schedules and cargo integrity

Inhouse Flight Planning

Our in-house flight planning team develops optimized routings, precise fuel calculations, weight and balance plans, and alternates tailored to aircraft performance and operational rules along with compliant alternate strategies. We incorporate NOTAMs, airspace constraints and cost‑effective routings to produce robust flight plans that minimize operational risk and support efficient dispatch decisions

Weather Briefing

We deliver concise, operational weather briefings covering enroute conditions, departure/arrival aerodrome forecasts, turbulence, icing, and volcanic ash or other hazards. Briefings include impact analysis, recommended mitigations measures and alternate planning considerations so crews and dispatchers can make informed, safety‑driven choices

Runway Analysis

Our runway analysis combines aerodrome data, aircraft performance modeling, and real-time conditions to produce accurate takeoff and landing performance parameters for each aerodrome and aircraft type. Analyses factors in temperature, pressure altitude, load and runway contamination to ensure regulatory compliance and operational safety across varying scenarios

", "styles": [], "scripts": [] }, diff --git a/TWA-App/Views/Home/TestPage.cshtml b/TWA-App/Views/Home/TestPage.cshtml new file mode 100644 index 0000000..ba31a87 --- /dev/null +++ b/TWA-App/Views/Home/TestPage.cshtml @@ -0,0 +1,66 @@ +
+

+ Aviation Support +

+

Our Flight Support Services

+ +

+ Our Flight Support suite delivers regulatory, operational and safety services that keep aircraft on schedule and crews informed. We combine regulatory expertise, real‑time monitoring and technical analysis to secure permits, coordinate slots, manage clearances, and provide actionable flight planning and weather intelligence for safe, efficient operations +

+
+ Overview of TWA cargo charter operations +
+ +
+ + + +
+

Overflight & Landing/Take-off Permit

+
+

+ Our team leverages long-standing relationships with civil aviation authorities and diplomatic channels to accelerate permit processing and reduce administrative steps for partners. We provide targeted guidance on documentation, fee handling, and route packaging to fast-track approvals and resolve bottlenecks before they impact operations +

+ +
+

Slot & PPR

+
+

+ Through established contacts with airport operator & slot requests, Prior Permission Required (PPR), we could streamline request preferred slots, managing contingencies, and maintaining direct lines, that are able to minimize ground delays with optimal touchdown/takeoff windows and align schedules with network requirements +

+ +
+

Air Traffic Clearances

+
+

+ Our operational liaisons and experienced dispatchers coordinate with ATC units to simplify clearance workflows and shorten lead times. By preparing robust, pre-vetted flight plans and ATC clearances as well as managing tactical negotiations on routing or altitude constraints, we help reduce delays and limit re-clearance cycles in congested airspace +

+ +
+

Real-Time Flight Tracking

+
+

+ We provide continuous real‑time flight monitoring and situational awareness through integrated monitoring tools and automated alerts watch‑desk along with staffed operations desk to detect deviations, airspace constraints, and ground disruptions immediately. This enables proactive interventions, timely stakeholder notifications, and rapid contingency execution to protect schedules and cargo integrity +

+ +
+

Inhouse Flight Planning

+
+

+ Our in-house flight planning team develops optimized routings, precise fuel calculations, weight and balance plans, and alternates tailored to aircraft performance and operational rules along with compliant alternate strategies. We incorporate NOTAMs, airspace constraints and cost‑effective routings to produce robust flight plans that minimize operational risk and support efficient dispatch decisions +

+ +
+

Weather Briefing

+
+

+ We deliver concise, operational weather briefings covering enroute conditions, departure/arrival aerodrome forecasts, turbulence, icing, and volcanic ash or other hazards. Briefings include impact analysis, recommended mitigations measures and alternate planning considerations so crews and dispatchers can make informed, safety‑driven choices +

+ +
+

Weather Briefing

+
+

+ Runway Analysis: Our runway analysis combines aerodrome data, aircraft performance modeling, and real-time conditions to produce accurate takeoff and landing performance parameters for each aerodrome and aircraft type. Analyses factors in temperature, pressure altitude, load and runway contamination to ensure regulatory compliance and operational safety across varying scenarios + +

\ No newline at end of file diff --git a/TWA-App/wwwroot/images/news/48151624.png b/TWA-App/wwwroot/images/news/48151624.png new file mode 100644 index 0000000..32f6165 Binary files /dev/null and b/TWA-App/wwwroot/images/news/48151624.png differ diff --git a/TWA-App/wwwroot/images/news/48151654.png b/TWA-App/wwwroot/images/news/48151654.png new file mode 100644 index 0000000..6e8bcc4 Binary files /dev/null and b/TWA-App/wwwroot/images/news/48151654.png differ diff --git a/TWA-App/wwwroot/js/js-page/4000.js b/TWA-App/wwwroot/js/js-page/4000.js index 3da4dca..d151d98 100644 --- a/TWA-App/wwwroot/js/js-page/4000.js +++ b/TWA-App/wwwroot/js/js-page/4000.js @@ -64,7 +64,7 @@ window.LoadingNews = function () { }); const data = await response.json(); totalPages = data.totalP; - + htm = ""; const initialSlides = data.data.forEach(d => { htm += `
diff --git a/TWA-App/wwwroot/js/libs/js-core.js b/TWA-App/wwwroot/js/libs/js-core.js index 96390f2..92606c9 100644 --- a/TWA-App/wwwroot/js/libs/js-core.js +++ b/TWA-App/wwwroot/js/libs/js-core.js @@ -771,7 +771,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) { diff --git a/TWASys-App/Controllers/LoginController.cs b/TWASys-App/Controllers/LoginController.cs index 65fe103..c35012e 100644 --- a/TWASys-App/Controllers/LoginController.cs +++ b/TWASys-App/Controllers/LoginController.cs @@ -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 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 + }); + } + } } diff --git a/TWASys-App/Controllers/StorageController.cs b/TWASys-App/Controllers/StorageController.cs index cdd74f2..85cd553 100644 --- a/TWASys-App/Controllers/StorageController.cs +++ b/TWASys-App/Controllers/StorageController.cs @@ -67,6 +67,12 @@ namespace TWASys_App.Controllers return await TypeStorageServerModel.GetAllTypeStorage(); } + [HttpPost] + public async Task GetStorage([FromForm] StorageModel model) + { + return await model.GetStorages(); + } + [HttpGet] public async Task GetValidationDomain() { @@ -85,6 +91,13 @@ namespace TWASys_App.Controllers return Json(await model.AddAsync()); } + [HttpPost] + public async Task UpdateStorageSize([FromForm] StorageModel model) + { + + return Json(await model.UpdateStorageSize()); + } + [HttpGet] public async Task GenerationAccessToken() { @@ -116,6 +129,19 @@ namespace TWASys_App.Controllers }); } + [HttpGet] + public async Task 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 GetSysInfo() { diff --git a/TWASys-App/DBModels/ServerAuthorization.cs b/TWASys-App/DBModels/ServerAuthorization.cs index 215af62..c4ca129 100644 --- a/TWASys-App/DBModels/ServerAuthorization.cs +++ b/TWASys-App/DBModels/ServerAuthorization.cs @@ -17,5 +17,8 @@ namespace TWASys_App.DBModels [NotMapped()] public ICollection Tokens { get; set; } = new List(); + + [NotMapped()] + public ICollection RefreshTokens { get; set; } = new List(); } } diff --git a/TWASys-App/DBModels/StorageServer.cs b/TWASys-App/DBModels/StorageServer.cs index b7a7adc..30a47da 100644 --- a/TWASys-App/DBModels/StorageServer.cs +++ b/TWASys-App/DBModels/StorageServer.cs @@ -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!; } } diff --git a/TWASys-App/Json/dataServer1.json b/TWASys-App/Json/dataServer1.json new file mode 100644 index 0000000..29091fa --- /dev/null +++ b/TWASys-App/Json/dataServer1.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/TWASys-App/Json/navlist.json b/TWASys-App/Json/navlist.json index 72666cf..0d73b7f 100644 --- a/TWASys-App/Json/navlist.json +++ b/TWASys-App/Json/navlist.json @@ -46,7 +46,7 @@ }, { "id": "8000", - "name": "Rooms Management", + "name": "Website Management", "icon": "", "group": 1, "url": "", diff --git a/TWASys-App/Models/StorageModel.cs b/TWASys-App/Models/StorageModel.cs index c240216..11a8af5 100644 --- a/TWASys-App/Models/StorageModel.cs +++ b/TWASys-App/Models/StorageModel.cs @@ -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 ValidationDomains { set; get; } = new List(); + 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 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(); + 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 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 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 tokens = (await multi.ReadAsync()).AsList(); + IList 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; + } } } diff --git a/TWASys-App/Models/UserModel.cs b/TWASys-App/Models/UserModel.cs new file mode 100644 index 0000000..531c0f3 --- /dev/null +++ b/TWASys-App/Models/UserModel.cs @@ -0,0 +1,8 @@ +namespace TWASys_App.Models +{ + public class UserModel + { + public string Username { set; get; } = ""; + public string Password { set; get; } = ""; + } +} diff --git a/TWASys-App/Program.cs b/TWASys-App/Program.cs index b6cb972..388cd65 100644 --- a/TWASys-App/Program.cs +++ b/TWASys-App/Program.cs @@ -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(o => { }); builder.Services.AddControllers(options => { + options.Filters.Add(new LoginCheckFilter()); options.Filters.Add(); }).AddJsonOptions(options => { diff --git a/TWASys-App/TWASys-App.csproj b/TWASys-App/TWASys-App.csproj index 2365058..a32a68d 100644 --- a/TWASys-App/TWASys-App.csproj +++ b/TWASys-App/TWASys-App.csproj @@ -38,7 +38,7 @@ - + diff --git a/TWASys-App/Views/Login/Index.cshtml b/TWASys-App/Views/Login/Index.cshtml index 7f9a50e..3dc545e 100644 --- a/TWASys-App/Views/Login/Index.cshtml +++ b/TWASys-App/Views/Login/Index.cshtml @@ -6,113 +6,116 @@
diff --git a/TWASys-App/Views/Storage/Index.cshtml b/TWASys-App/Views/Storage/Index.cshtml index 005a2eb..c0e1309 100644 --- a/TWASys-App/Views/Storage/Index.cshtml +++ b/TWASys-App/Views/Storage/Index.cshtml @@ -19,120 +19,122 @@
-
-
+
+ -
-
- -
- -
- - Gb +
+
+
+ +
+ +
+ + Gb +
+
- -
- -
-
-
- + +
+
+
+ +
+
+
+
+
+
+
-
-
-
-
-
- -
-
-
+ -
Search Fillter
-
-
-
- -
-
-
+
+
+
Search Fillter
+
+
+
+ +
+
+
-
-
- -
-
-
- -
-
-
-
+
+
+
-
-
-
-
Edit Storage Type
- -
- - -
-
-
-
-
- - +
+ +
+
+
+
+
+
+
+
+
+
Edit Storage Type
+ +
+ + +
+
+
+
+
+ + +
-
+
-
-
+
+ +
- +
diff --git a/TWASys-App/wwwroot/css/atg-lib/atg-core.css b/TWASys-App/wwwroot/css/atg-lib/atg-core.css index 3bfe423..feb7fba 100644 --- a/TWASys-App/wwwroot/css/atg-lib/atg-core.css +++ b/TWASys-App/wwwroot/css/atg-lib/atg-core.css @@ -23,7 +23,7 @@ user-select: none } -a {, +a { text-decoration: none } diff --git a/TWASys-App/wwwroot/css/atg-ui/table.css b/TWASys-App/wwwroot/css/atg-ui/table.css index b9d0cd6..94b54f2 100644 --- a/TWASys-App/wwwroot/css/atg-ui/table.css +++ b/TWASys-App/wwwroot/css/atg-ui/table.css @@ -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 { diff --git a/TWASys-App/wwwroot/css/pages/login.css b/TWASys-App/wwwroot/css/pages/login.css index 8598da5..9f8ca04 100644 --- a/TWASys-App/wwwroot/css/pages/login.css +++ b/TWASys-App/wwwroot/css/pages/login.css @@ -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); - } \ No newline at end of file + } + +.main-login a { + color: #454545; + font-size: .85rem; + font-weight: 600 +} \ No newline at end of file diff --git a/TWASys-App/wwwroot/css/site.css b/TWASys-App/wwwroot/css/site.css index 8d213ef..114c32e 100644 --- a/TWASys-App/wwwroot/css/site.css +++ b/TWASys-App/wwwroot/css/site.css @@ -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**********************/ \ No newline at end of file +/*******************End Page**********************/ + + +/*********Login Form**********/ +.c_validation{ + margin-bottom: 15px !important +} diff --git a/TWASys-App/wwwroot/js/js-page/10001.js b/TWASys-App/wwwroot/js/js-page/10001.js index 6b8873a..08def02 100644 --- a/TWASys-App/wwwroot/js/js-page/10001.js +++ b/TWASys-App/wwwroot/js/js-page/10001.js @@ -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) { diff --git a/TWASys-App/wwwroot/js/js-page/6101.js b/TWASys-App/wwwroot/js/js-page/6101.js index 78630e7..881c2d1 100644 --- a/TWASys-App/wwwroot/js/js-page/6101.js +++ b/TWASys-App/wwwroot/js/js-page/6101.js @@ -1,4 +1,5 @@ -import ASpinButton from '/js/libs/js-ASpinButton.js'; +import ASpinButton from '/js/libs/js-ASpinButton.js'; +import ASlideDown from '/js/libs/js-ASlideDown.js'; import AButton from '/js/libs/js-AButton.js'; import AMultiTag from '/js/libs/js-AMultiTag.js'; import AModal from '/js/libs/js-AModal.js'; @@ -7,275 +8,264 @@ import ASelect from '/js/libs/js-ASelect.js'; import AOverlay from '/js/libs/js-AOverlay.js'; import AWizard from '/js/libs/js-AWizard.js'; import AAutoFill from '/js/libs/js-AAutoFill.js'; +import ATable from '/js/libs/js-ATable.js'; -const tmp = `
-
-

Storage Server

-
-
- Add New -
- -
- Test -
-
-
-
-
-
-
-
Information Storage Configuration
-
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
-
Microsoft 365 Connnector
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
Physical Server Connnector
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
Server Authenicator
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
Storage Data Summary
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
-
-
-
-
- - -
-
-
-
Tab C
-
-
+const tmp = ` +
+
+

Storage Server

+
+
+ Add New +
+ +
+ Test +
-
`; - - +
+
+
+
+
+
Information Storage Configuration
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
Microsoft 365 Connnector
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
Physical Server Connnector
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
Server Authenicator
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
Storage Data Summary
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+
+
+ +
+
+
+
Tab C
+
+
+
+
+`; const lay1 = `
@@ -288,389 +278,304 @@ window.L6101 = function () { window.app.loadCSS(asyncStyleSheets); 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; - 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')); + let tbSS = null; + let eleSS = new ASlideDown(document.querySelectorAll(".aslidedown")); + let pr1 = new Promise(async function (resolve, reject) { + const response = await fetch("/Storage/CheckStorageInit", { + method: 'GET', + headers: { + 'Accept': 'application/json' + } + }); + const data = await response.json(); + if (data.Status == 1) { + if (data.Message == "has") { + eleSS.get(0).disable_Close(); + eleSS.get(1).enable_Open(); + eleSS.get(2).enable_Open(); + } else { + eleSS.get(0).enable_Open(); + eleSS.get(1).disable_Close(); + eleSS.get(2).disable_Close(); + var ele1 = new ASpinButton(document.getElementById("totalSize")); + var ele2 = new AMultiTag(document.getElementById("listStorage")); + const $v = id => (document.getElementById(id)?.value ?? '').trim(); + var slider = new AModal(tmp); + slider.createModal("CustomForm", "slider-right"); + var Scrollbar = window.Scrollbar; + 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(".awStorageConnector")); + var as = new ASelect(slider.CustomContainer.querySelectorAll(".aselect")); + + var asIdType = as.get(0); + wrd1.on("onBeforeBack", (evt) => { + mScroll.scrollTo(0, 0); + }); + tabs.on("changed", (e) => { + if (e.tabIndex == 1) { + if (tbSS == null) { + tbSS = new ATable(document.querySelector(".storageTb"), 10); + tbSS.labelID = "idStorageServer"; + tbSS.SetScrollBarY(400); + tbSS.AddHeader("Storage Name", "180px", "180px", "storageName"); + tbSS.AddHeader("Storage Type", "180px", "180px", "typeName"); + tbSS.AddHeader("Controller Name", "180px", "180px", "controllerID"); + tbSS.AddHeader("Create Date", "240px", "240px", "createDate"); + tbSS.IsCheckBox(true); + tbSS.LoadDataUrl("/Storage/GetStorage"); + } else { + // tb.RefreshCurrentPage(); + } - const i = 0; - as.get(1).multiSelectedItem.forEach((item) => { - fd.append(`ValidationDomains[${i}].IdValidationDomain`, item.getAttribute("data-value")); - }); + } + + }); + 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 () => { - fd.append('SocketN', $v('socketN')); - fd.append('CpuName', $v('cpuName')); - fd.append('TotalRam', $v('totalRam')); + const fd = new FormData(); + fd.append('StorageTypeID', asIdType.getSelectedItem()?.id ?? ''); + fd.append('ControllerName', $v('controllerName')); + fd.append('StorageName', $v('storageName')); - 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 + 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 (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 { + wrd1.isStopNextPage = false; + } + switch (asIdType.getSelectedItem().vSearch) { + 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`, { + method: 'GET', + headers: { + 'Accept': 'application/json' + } + }); + const data = await response.json(); + if (data) { + const autoF = new AAutoFill(document.querySelector(".awStorageConnector")); + autoF.fill(data); + } + }); + break; + } + } 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; + } })(); - - } - break; - } - } - }); - wrd1.on("onBeforeNext", (evt) => { - mScroll.scrollTo(0, 0); - if (evt.indexPage == 0) { - 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 { - wrd1.isStopNextPage = false; - } - switch (asIdType.getSelectedItem().vSearch) { - 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`, { - method: 'GET', - headers: { - 'Accept': 'application/json' + (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; } - }); - const data = await response.json(); - if (data) { - const autoF = new AAutoFill(document.querySelector(".awStorageConnector")); - autoF.fill(data); - } + })(); + } + + }, true); + var asVD = as.get(1); + ele2.on("btnAdd_Click", (e) => { + asIdType.lockElement(); + asVD.lockElement(); + slider.showModal(); + wrd1.renderTab(); + + 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) { + var obj = JSON.parse(ev.currentTarget.responseText); + var data = JSON.parse(obj.data); + if (data != null && data.length > 0) { + asIdType.element.removeAll(); + for (var i = 0; i < data.length; i++) { + asIdType.element.insertAdjacentHTML("beforeend", ``); + } + asIdType.updateItem(); + asIdType.unlockElement(); + + } + } + } + }; + xhr.addEventListener("readystatechange", f, false); + xhr.send(); }); - break; + 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) { + var obj = JSON.parse(ev.currentTarget.responseText); + var data = JSON.parse(obj.data); + if (data != null && data.length > 0) { + asVD.element.removeAll(); + for (var i = 0; i < data.length; i++) { + asVD.element.insertAdjacentHTML("beforeend", ``); + } + asVD.updateItem(); + asVD.unlockElement(); + } + } + } + }; + xhr.addEventListener("readystatechange", f, false); + xhr.send(); + }); + + }); + + let eleAddStorage = document.getElementById("btAddStorage"); + let asAddStorage = new AButton(eleAddStorage); + asAddStorage.on("click_btAddStorage", (e) => { + const xhr = new XMLHttpRequest(); + xhr.open("POST", "/Storage/AddStorageServer"); + xhr.setRequestHeader('Accept', 'application/json; charset=UTF-8'); + var data = { + "Name": document.getElementById("inpType").value + }; + + var f = function (ev) { + if (ev.currentTarget.readyState == 4) { + if (ev.currentTarget.status == 200) { + var obj = JSON.parse(ev.currentTarget.responseText); + if (ev.Status == 0) { + m.AModalOK.title("Message Error", "mess-error"); + m.AModalOK.message(ev.Message); + } else { + m.AModalOK.title("Message", "mess-success"); + m.AModalOK.message("Row Insert Success!"); + } + m.showModal(); + } + } + + }; + xhr.addEventListener("readystatechange", f, false); + xhr.send(JSON.stringify(data)); + }); + + let btSaveST = new AButton(document.getElementById("btSaveST")); + btSaveST.on("click_btSaveST", (evt) => { + const listC = tbSS.absRows.querySelectorAll("input[type=checkbox][rowCheck]:checked"); + listC.forEach((el) => { + const rowST = tbSS.data[el.closest("tr").getAttribute("data-id")]; + ele2.addItem(rowST.idStorageServer, rowST.storageName, rowST, null); + }); + btSaveST.RemoveLoading(evt); + slider.removeModal(); + }); + } - } 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); - ele2.on("btnAdd_Click", (e) => { - asIdType.lockElement(); - asVD.lockElement(); - slider.showModal(); - wrd1.renderTab(); - - 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) { - var obj = JSON.parse(ev.currentTarget.responseText); - var data = JSON.parse(obj.data); - if (data != null && data.length > 0) { - asIdType.element.removeAll(); - for (var i = 0; i < data.length; i++) { - asIdType.element.insertAdjacentHTML("beforeend", ``); - } - asIdType.updateItem(); - asIdType.unlockElement(); - - } - } - } - }; - xhr.addEventListener("readystatechange", f, false); - xhr.send(); - }); - 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) { - var obj = JSON.parse(ev.currentTarget.responseText); - var data = JSON.parse(obj.data); - if (data != null && data.length > 0) { - asVD.element.removeAll(); - for (var i = 0; i < data.length; i++) { - asVD.element.insertAdjacentHTML("beforeend", ``); - } - asVD.updateItem(); - asVD.unlockElement(); - } - } - } - }; - xhr.addEventListener("readystatechange", f, false); - xhr.send(); - }); - }); - Waves.attach('.btn-effect', ['waves-float']); Waves.init({ duration: 1000, delay: 200 }); - let eleAddStorage = document.getElementById("btAddStorage"); - let asAddStorage = new AButton(eleAddStorage); - asAddStorage.on("click_btAddStorage", (e) => { - const xhr = new XMLHttpRequest(); - xhr.open("POST", "/Storage/AddStorageServer"); - xhr.setRequestHeader('Accept', 'application/json; charset=UTF-8'); - var data = { - "Name": document.getElementById("inpType").value - }; - - var f = function (ev) { - if (ev.currentTarget.readyState == 4) { - if (ev.currentTarget.status == 200) { - var obj = JSON.parse(ev.currentTarget.responseText); - if (ev.Status == 0) { - m.AModalOK.title("Message Error", "mess-error"); - m.AModalOK.message(ev.Message); - } else { - m.AModalOK.title("Message", "mess-success"); - m.AModalOK.message("Row Insert Success!"); - } - m.showModal(); - } - } - - }; - xhr.addEventListener("readystatechange", f, false); - xhr.send(JSON.stringify(data)); - }); - - //var btnAdd = document.getElementById("btAdd"); - - //var tabs = new ATab(document.querySelector(".atabs"), document.querySelector(".tabcontents")); - //var tb = new ATable(document.querySelector(".c-table"), 10); - //var btUpdate = new AButton(document.getElementById("btUpdate")); - //var btn = new AButton(btnAdd); - //var m = new AModal(null); - //var mU = new AModal(null); - //var btBack = document.getElementById("btBack"); - //btBack.addEventListener("click", (e) => { - // tabs.selectedTab(0); - //}) - //let promise = new Promise(function (resolve, reject) { - // tb.AddHeader("ID", "120px", "", "IdTypeStorageServer"); - // tb.AddHeader("Storage Type Name", "", "240px", "TypeName"); - // tb.AddHeader("Action", "180px", "", "Action", function (id, obj) { - // var ac = document.createElement("div"); - // ac.classList.add("d-f", "j-c-center"); - // var d = document.createElement("button"); - // d.classList.add("btn", "btn-warning", "mr-2"); - // var ico = document.createElement("span"); - // ico.classList.add("atg", "atg-pencil"); - // d.appendChild(ico); - // d.addEventListener("click", ((e) => { updateClick.call(tabs, e, id, obj); })); - // ac.appendChild(d); - // d = document.createElement("button"); - // d.classList.add("btn", "btn-danger"); - // var ico = document.createElement("span"); - // ico.classList.add("atg", "atg-x"); - // d.appendChild(ico); - // ac.appendChild(d); - // return ac; - // }); - // tb.SetScrollBarY(300); - // tb.IsCheckBox(true); - // tb.LoadDataUrl("/Storage/GetTypeStorage"); - //}); - - //m.overlay.setIndex(2101); - //m.createModal("OK"); - //m.on("OK", () => { - // btn.RemoveLoading(btnAdd); - // tb.RefreshPage(1, true); - //}); - //m.on("Close", () => { btn.RemoveLoading(btnAdd); }); - //btn.on("click_btAdd", function (e) { - // const xhr = new XMLHttpRequest(); - // xhr.open("POST", "/Storage/AddType"); - // xhr.setRequestHeader('Content-type', 'application/json; charset=UTF-8'); - // var data = { - // "Name": document.getElementById("inpType").value - // }; - // var f = function (ev) { - // if (ev.currentTarget.readyState == 4) { - // if (ev.currentTarget.status == 200) { - // var obj = JSON.parse(ev.currentTarget.responseText); - // if (ev.Status == 0) { - // m.AModalOK.title("Message Error", "mess-error"); - // m.AModalOK.message(ev.Message); - // } else { - // m.AModalOK.title("Message", "mess-success"); - // m.AModalOK.message("Row Insert Success!"); - // } - // m.showModal(); - // } - // } - - // }; - // xhr.addEventListener("readystatechange", f, false); - // xhr.send(JSON.stringify(data)); - //}); - - //tabs.lockTabs.push(1); - - //mU.overlay.setIndex(2101); - //mU.createModal("OK"); - //mU.on("OK", () => { - // btUpdate.RemoveLoading(document.getElementById("btUpdate")); - // tabs.selectedTab(0); - // tb.RefreshCurrentPage(); - //}); - //mU.on("Close", () => { btn.RemoveLoading(document.getElementById("btUpdate")); }); - - //btUpdate.on("click_btUpdate", (evt) => { - // var inp = document.getElementById("inpEType"); - // var inpID = document.getElementById("inpEID"); - // if (inpID.value != "") { - // const xhr = new XMLHttpRequest(); - // xhr.open("POST", "/Storage/UpdateType"); - // xhr.setRequestHeader('Content-type', 'application/json; charset=UTF-8'); - // var data = { - // "ID": inpID.value, - // "Name": inp.value - // }; - // var f = function (ev) { - // if (ev.currentTarget.readyState == 4) { - // if (ev.currentTarget.status == 200) { - // var obj = JSON.parse(ev.currentTarget.responseText); - // if (ev.Status == 0) { - // mU.AModalOK.title("Message Error", "mess-error"); - // mU.AModalOK.message(ev.Message); - // } else { - // mU.AModalOK.title("Message", "mess-success"); - // mU.AModalOK.message("Row Update Success!"); - // } - // mU.showModal(); - // } - // } - - // }; - // xhr.addEventListener("readystatechange", f, false); - // xhr.send(JSON.stringify(data)); - // } - //}); - - //var btSearch = new AButton(document.getElementById("btSearch")); - //btSearch.on("click_btSearch", function (evt) { - // var fr = new FormData(); - // fr.append("keyword", document.getElementById("inpKey").value); - // tb.LoadDataFirst(fr); - // btSearch.RemoveLoading(evt); - //}); } -//function updateClick(e, id, obj) { -// this.enableTab(1); -// this.selectedTab(1); -// var inp = document.getElementById("inpEType"); -// var inpID = document.getElementById("inpEID"); -// inp.value = obj.TypeName; -// inpID.value = obj.IdTypeStorageServer; -//} - - window.AScript.set("6101", true); \ No newline at end of file diff --git a/TWASys-App/wwwroot/js/js-page/asyncLayout.js b/TWASys-App/wwwroot/js/js-page/asyncLayout.js index fabbb93..a278393 100644 --- a/TWASys-App/wwwroot/js/js-page/asyncLayout.js +++ b/TWASys-App/wwwroot/js/js-page/asyncLayout.js @@ -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); - - - } } diff --git a/TWASys-App/wwwroot/js/js-page/asyncLoginLayout.js b/TWASys-App/wwwroot/js/js-page/asyncLoginLayout.js index ca60052..fb4658d 100644 --- a/TWASys-App/wwwroot/js/js-page/asyncLoginLayout.js +++ b/TWASys-App/wwwroot/js/js-page/asyncLoginLayout.js @@ -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(); + } } diff --git a/TWASys-App/wwwroot/js/libs/js-AAnimation.js b/TWASys-App/wwwroot/js/libs/js-AAnimation.js index e050374..b3f2c81 100644 --- a/TWASys-App/wwwroot/js/libs/js-AAnimation.js +++ b/TWASys-App/wwwroot/js/libs/js-AAnimation.js @@ -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); diff --git a/TWASys-App/wwwroot/js/libs/js-ADropdown.js b/TWASys-App/wwwroot/js/libs/js-ADropdown.js index 33f1a33..cdd0421 100644 --- a/TWASys-App/wwwroot/js/libs/js-ADropdown.js +++ b/TWASys-App/wwwroot/js/libs/js-ADropdown.js @@ -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"); diff --git a/TWASys-App/wwwroot/js/libs/js-AMenu.js b/TWASys-App/wwwroot/js/libs/js-AMenu.js index a510f57..f3e4c03 100644 --- a/TWASys-App/wwwroot/js/libs/js-AMenu.js +++ b/TWASys-App/wwwroot/js/libs/js-AMenu.js @@ -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 => { diff --git a/TWASys-App/wwwroot/js/libs/js-AModal.js b/TWASys-App/wwwroot/js/libs/js-AModal.js index d9375d8..76db7d0 100644 --- a/TWASys-App/wwwroot/js/libs/js-AModal.js +++ b/TWASys-App/wwwroot/js/libs/js-AModal.js @@ -52,7 +52,9 @@ export default class AModal extends window.AObject { showModal() { this.overlay.showOverlay(); } - + removeModal() { + this.overlay.removeOverlay(); + } } class AModalOK { diff --git a/TWASys-App/wwwroot/js/libs/js-AMultiTag.js b/TWASys-App/wwwroot/js/libs/js-AMultiTag.js index 1352c44..6d1924e 100644 --- a/TWASys-App/wwwroot/js/libs/js-AMultiTag.js +++ b/TWASys-App/wwwroot/js/libs/js-AMultiTag.js @@ -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 = ``; + p.appendChild(close); return p; } } \ No newline at end of file diff --git a/TWASys-App/wwwroot/js/libs/js-ASelect.js b/TWASys-App/wwwroot/js/libs/js-ASelect.js index a06e688..7f8b693 100644 --- a/TWASys-App/wwwroot/js/libs/js-ASelect.js +++ b/TWASys-App/wwwroot/js/libs/js-ASelect.js @@ -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, diff --git a/TWASys-App/wwwroot/js/libs/js-ASlideDown.js b/TWASys-App/wwwroot/js/libs/js-ASlideDown.js new file mode 100644 index 0000000..84668de --- /dev/null +++ b/TWASys-App/wwwroot/js/libs/js-ASlideDown.js @@ -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(); + } + } +} \ No newline at end of file diff --git a/TWASys-App/wwwroot/js/libs/js-AWizard.js b/TWASys-App/wwwroot/js/libs/js-AWizard.js index eb9ac1a..bc11a61 100644 --- a/TWASys-App/wwwroot/js/libs/js-AWizard.js +++ b/TWASys-App/wwwroot/js/libs/js-AWizard.js @@ -33,7 +33,14 @@ export default class AWizard extends ATab { Cancel
`; - + + 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; diff --git a/TWASys-App/wwwroot/js/libs/js-AbsTable.js b/TWASys-App/wwwroot/js/libs/js-AbsTable.js index ff5c267..ceb9868 100644 --- a/TWASys-App/wwwroot/js/libs/js-AbsTable.js +++ b/TWASys-App/wwwroot/js/libs/js-AbsTable.js @@ -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]; } diff --git a/TWASys-App/wwwroot/js/libs/js-core.js b/TWASys-App/wwwroot/js/libs/js-core.js index 51284d7..bc96e3e 100644 --- a/TWASys-App/wwwroot/js/libs/js-core.js +++ b/TWASys-App/wwwroot/js/libs/js-core.js @@ -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); } }