Compare commits

..

3 Commits

Author SHA1 Message Date
978411c9ec Merge branch 'main' of https://git.pnkr.asia/DungTT/ManagerAccount 2026-04-22 17:03:29 +07:00
61c4415ff7 push 2026-04-22 16:59:13 +07:00
1408294922 import 2026-04-22 16:57:48 +07:00
5 changed files with 1070 additions and 1410 deletions

34
.env Normal file
View File

@@ -0,0 +1,34 @@
# AccManager Backend Configuration
# Application
NODE_ENV=production
# Host port exposed by docker compose
APP_PORT=3000
# Image used for server pull deployment
DOCKER_IMAGE=toiiiiday/accmanager:1.0.3
# Container app port
PORT=3000
# SQL Server Configuration
DB_SERVER=172.20.235.176
DB_USER=sa
DB_PASSWORD=robotics@2022
DB_NAME=AccManager
DB_ENCRYPT=false
DB_TRUST_CERTIFICATE=true
DB_CONNECT_TIMEOUT=30000
# Security
BCRYPT_ROUNDS=12
# Email Verification (SMTP)
APP_BASE_URL=https://accrobot.pnkr.asia/
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=robotics.gitlab.2fa@gmail.com
SMTP_PASS=jaljalhreomqruqo
SMTP_FROM=robotics.gitlab.2fa@gmail.com

File diff suppressed because it is too large Load Diff

View File

@@ -89,18 +89,21 @@ BEGIN
AssetId INT PRIMARY KEY IDENTITY(1,1),
AssetCode NVARCHAR(100) NOT NULL UNIQUE,
AssetName NVARCHAR(255) NOT NULL,
Category NVARCHAR(100),
Brand NVARCHAR(100),
Model NVARCHAR(255),
SerialNumber NVARCHAR(100),
Quantity INT NOT NULL DEFAULT 1,
Quantity INT NOT NULL DEFAULT 0,
ImportInPeriod INT NOT NULL DEFAULT 0,
ExportInPeriod INT NOT NULL DEFAULT 0,
EndingBalance INT NOT NULL DEFAULT 0,
Unit NVARCHAR(50),
Department NVARCHAR(100),
Project NVARCHAR(150),
Location NVARCHAR(150),
Custodian NVARCHAR(100),
Borrower NVARCHAR(255),
ExportedBy NVARCHAR(100),
PurchaseDate DATE NULL,
PurchasePrice DECIMAL(18,2) NULL,
WarrantyUntil DATE NULL,
Status NVARCHAR(30) NOT NULL DEFAULT 'in_use',
Notes NVARCHAR(MAX),
CreatedBy INT NULL,
@@ -111,6 +114,16 @@ BEGIN
PRINT 'Table AssetInventory created successfully.';
END
IF COL_LENGTH('dbo.AssetInventory', 'Borrower') IS NULL
BEGIN
ALTER TABLE AssetInventory ADD Borrower NVARCHAR(255) NULL;
END
IF COL_LENGTH('dbo.AssetInventory', 'ExportedBy') IS NULL
BEGIN
ALTER TABLE AssetInventory ADD ExportedBy NVARCHAR(100) NULL;
END
-- ===========================================
-- 5. CREATE AUDIT LOG TABLE
-- ===========================================
@@ -132,6 +145,7 @@ END
-- ===========================================
-- 6. CREATE INDEXES
-- 6. CREATE INDEXES
-- ===========================================
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_Users_Username')
BEGIN
@@ -158,10 +172,21 @@ BEGIN
CREATE INDEX IX_AssetInventory_Status ON AssetInventory(Status);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_AssetInventory_AssetCode')
BEGIN
CREATE INDEX IX_AssetInventory_AssetCode ON AssetInventory(AssetCode);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_AssetInventory_Status')
BEGIN
CREATE INDEX IX_AssetInventory_Status ON AssetInventory(Status);
END
PRINT 'Indexes created successfully.';
-- ===========================================
-- 7. INSERT INITIAL DATA
-- 7. INSERT INITIAL DATA
-- ===========================================
-- Check if admin user exists
@@ -186,6 +211,7 @@ END
-- ===========================================
-- 8. DISPLAY DATABASE INFORMATION
-- 8. DISPLAY DATABASE INFORMATION
-- ===========================================
PRINT '';
PRINT '========================================';

File diff suppressed because it is too large Load Diff

View File

@@ -197,126 +197,3 @@
</div>
</div>
</div>
<!-- Add/Edit Asset Modal -->
<div class="modal-backdrop fixed inset-0 z-[100] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="assetModal">
<div class="modal-content w-full max-w-2xl bg-white rounded-xl shadow-2xl border border-slate-200 overflow-hidden m-4 flex flex-col" style="max-height: calc(100vh - 2rem);">
<div class="px-6 py-4 border-b border-slate-100 flex items-center justify-between bg-slate-50">
<h3 class="text-base font-extrabold text-slate-900">Biểu mẫu tài sản</h3>
<button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeAssetModal()">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<form id="assetForm" class="p-6 space-y-4 overflow-y-auto">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Mã tài sản</label>
<input type="text" id="assetCodeInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" required placeholder="TS-001">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Tên tài sản</label>
<input type="text" id="assetNameInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" required placeholder="Laptop Dell Latitude 5440">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Danh mục</label>
<input type="text" id="assetCategoryInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="Thiết bị CNTT">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Trạng thái</label>
<select id="assetStatusInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3">
<option value="in_use">Đang sử dụng</option>
<option value="in_stock">Trong kho</option>
<option value="maintenance">Bảo trì</option>
<option value="disposed">Thanh lý</option>
</select>
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Hãng</label>
<input type="text" id="assetBrandInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="Dell">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Model</label>
<input type="text" id="assetModelInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="Latitude 5440">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Số serial</label>
<input type="text" id="assetSerialInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="SN123...">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Số lượng</label>
<input type="number" id="assetQuantityInput" min="1" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" value="1">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Đơn vị</label>
<input type="text" id="assetUnitInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="cái">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Phòng ban</label>
<input type="text" id="assetDepartmentInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="Kỹ thuật">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Vị trí</label>
<input type="text" id="assetLocationInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="Kho A">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Người phụ trách</label>
<input type="text" id="assetCustodianInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="Nguyễn Văn A">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Ngày mua</label>
<input type="date" id="assetPurchaseDateInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3">
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Giá mua</label>
<input type="number" id="assetPriceInput" min="0" step="0.01" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" placeholder="0">
</div>
<div class="md:col-span-2">
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Hạn bảo hành</label>
<input type="date" id="assetWarrantyUntilInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3">
</div>
<div class="md:col-span-2">
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Ghi chú</label>
<textarea id="assetNotesInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 h-20 resize-none" placeholder="Thông tin bổ sung"></textarea>
</div>
</div>
<div class="flex gap-3 pt-2 sticky bottom-0 bg-white pb-1">
<button type="button" class="flex-1 px-4 py-2 text-xs font-bold text-slate-600 border border-slate-200 rounded-lg" onclick="closeAssetModal()">Hủy</button>
<button type="submit" class="flex-1 px-4 py-2 bg-primary hover:bg-primary-dim text-on-primary rounded-lg text-xs font-bold">Lưu tài sản</button>
</div>
</form>
</div>
</div>
<!-- View Asset Modal -->
<div class="modal-backdrop fixed inset-0 z-[100] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="viewAssetModal">
<div class="modal-content w-full max-w-2xl bg-white rounded-xl shadow-2xl border border-slate-200 overflow-hidden m-4 flex flex-col" style="max-height: calc(100vh - 2rem);">
<div class="px-6 py-4 border-b border-slate-100 flex items-center justify-between bg-slate-50">
<h3 class="text-base font-extrabold text-slate-900">Chi tiết tài sản</h3>
<button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeViewAssetModal()">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<div id="assetDetailsContent" class="p-6 grid grid-cols-1 md:grid-cols-2 gap-3 text-sm text-slate-700 overflow-y-auto"></div>
<div class="p-6 pt-3 flex gap-3 border-t border-slate-100 bg-white">
<button type="button" class="flex-1 px-4 py-2 text-xs font-bold text-slate-600 border border-slate-200 rounded-lg" onclick="closeViewAssetModal()">Đóng</button>
<button type="button" class="flex-1 px-4 py-2 bg-primary hover:bg-primary-dim text-on-primary rounded-lg text-xs font-bold edit-asset-from-view">Sửa</button>
</div>
</div>
</div>
<!-- Delete Asset Modal -->
<div class="modal-backdrop fixed inset-0 z-[100] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="deleteAssetModal">
<div class="modal-content w-full max-w-md bg-white rounded-xl shadow-2xl border border-slate-200 overflow-hidden m-4">
<div class="px-6 py-4 border-b border-slate-100 bg-red-50 flex items-center gap-3">
<span class="material-symbols-outlined text-red-600 text-2xl">warning</span>
<h3 class="text-base font-extrabold text-red-700">Xóa tài sản</h3>
</div>
<div class="p-6">
<p class="text-sm text-slate-600 mb-6">Bạn có chắc muốn xóa tài sản <strong id="deleteAssetName">-</strong>? Hành động này không thể hoàn tác.</p>
<div class="flex gap-3">
<button type="button" class="flex-1 px-4 py-2 text-xs font-bold text-slate-600 border border-slate-200 rounded-lg" onclick="closeDeleteAssetModal()">Hủy</button>
<button type="button" class="flex-1 px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg text-xs font-bold confirm-delete-asset">Xóa</button>
</div>
</div>
</div>
</div>