trả/mượn vtth

This commit is contained in:
2026-06-30 09:51:32 +07:00
parent f00734deb8
commit 4b1296c8f8
6 changed files with 2588 additions and 132 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -244,7 +244,8 @@ BEGIN
ConsumableName NVARCHAR(255) NOT NULL, ConsumableName NVARCHAR(255) NOT NULL,
Unit NVARCHAR(50) NULL, Unit NVARCHAR(50) NULL,
ExportQuantity INT NOT NULL DEFAULT 1, ExportQuantity INT NOT NULL DEFAULT 1,
RecipientName NVARCHAR(100) NOT NULL, RecipientUserId INT NULL,
RecipientName NVARCHAR(100) NULL,
ProjectName NVARCHAR(150) NULL, ProjectName NVARCHAR(150) NULL,
ExportedByName NVARCHAR(100) NOT NULL, ExportedByName NVARCHAR(100) NOT NULL,
ExportNote NVARCHAR(1000) NULL, ExportNote NVARCHAR(1000) NULL,
@@ -287,6 +288,16 @@ BEGIN
ALTER TABLE ConsumableExportHistory ADD RecipientName NVARCHAR(100) NULL; ALTER TABLE ConsumableExportHistory ADD RecipientName NVARCHAR(100) NULL;
END END
IF COL_LENGTH('dbo.ConsumableExportHistory', 'RecipientUserId') IS NULL
BEGIN
ALTER TABLE ConsumableExportHistory ADD RecipientUserId INT NULL;
END
IF COL_LENGTH('dbo.ConsumableExportHistory', 'RecipientName') IS NOT NULL
BEGIN
ALTER TABLE ConsumableExportHistory ALTER COLUMN RecipientName NVARCHAR(100) NULL;
END
IF COL_LENGTH('dbo.ConsumableExportHistory', 'ProjectName') IS NULL IF COL_LENGTH('dbo.ConsumableExportHistory', 'ProjectName') IS NULL
BEGIN BEGIN
ALTER TABLE ConsumableExportHistory ADD ProjectName NVARCHAR(150) NULL; ALTER TABLE ConsumableExportHistory ADD ProjectName NVARCHAR(150) NULL;
@@ -358,6 +369,25 @@ BEGIN
FOREIGN KEY (ConsumableId) REFERENCES ConsumableInventory(ConsumableId) ON DELETE CASCADE; FOREIGN KEY (ConsumableId) REFERENCES ConsumableInventory(ConsumableId) ON DELETE CASCADE;
END END
UPDATE exports
SET RecipientUserId = matchedUser.UserId
FROM ConsumableExportHistory exports
CROSS APPLY (
SELECT TOP 1 users.UserId
FROM Users users
WHERE NULLIF(LTRIM(RTRIM(exports.ProjectName)), '') IS NULL
AND (
LOWER(LTRIM(RTRIM(ISNULL(users.FullName, '')))) = LOWER(LTRIM(RTRIM(ISNULL(exports.RecipientName, ''))))
OR LOWER(LTRIM(RTRIM(ISNULL(users.Username, '')))) = LOWER(LTRIM(RTRIM(ISNULL(exports.RecipientName, ''))))
)
ORDER BY CASE
WHEN LOWER(LTRIM(RTRIM(ISNULL(users.FullName, '')))) = LOWER(LTRIM(RTRIM(ISNULL(exports.RecipientName, '')))) THEN 0
ELSE 1
END,
users.UserId
) matchedUser
WHERE exports.RecipientUserId IS NULL;
IF NOT EXISTS ( IF NOT EXISTS (
SELECT 1 SELECT 1
FROM sys.foreign_key_columns fkc FROM sys.foreign_key_columns fkc
@@ -374,6 +404,88 @@ BEGIN
FOREIGN KEY (CreatedBy) REFERENCES Users(UserId) ON DELETE SET NULL; FOREIGN KEY (CreatedBy) REFERENCES Users(UserId) ON DELETE SET NULL;
END END
-- ===========================================
-- 6B. CREATE CONSUMABLE RETURN HISTORY TABLE
-- ===========================================
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'ConsumableReturnHistory')
BEGIN
CREATE TABLE ConsumableReturnHistory (
ReturnHistoryId INT PRIMARY KEY IDENTITY(1,1),
ExportHistoryId INT NOT NULL,
ConsumableId INT NOT NULL,
ReturnQuantity INT NOT NULL DEFAULT 1,
ReturnedByName NVARCHAR(100) NOT NULL,
ReturnNote NVARCHAR(1000) NULL,
PreviousExportInPeriod INT NOT NULL DEFAULT 0,
NextExportInPeriod INT NOT NULL DEFAULT 0,
PreviousEndingBalance INT NOT NULL DEFAULT 0,
NextEndingBalance INT NOT NULL DEFAULT 0,
CreatedBy INT NULL,
ReturnedDate DATETIME NOT NULL DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())),
CreatedDate DATETIME NOT NULL DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())),
UpdatedDate DATETIME NOT NULL DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())),
FOREIGN KEY (ExportHistoryId) REFERENCES ConsumableExportHistory(ExportHistoryId) ON DELETE CASCADE,
FOREIGN KEY (CreatedBy) REFERENCES Users(UserId) ON DELETE SET NULL
);
PRINT 'Table ConsumableReturnHistory created successfully.';
END
-- ===========================================
-- 6C. CREATE CONSUMABLE BORROW REQUESTS TABLE
-- ===========================================
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'ConsumableBorrowRequests')
BEGIN
CREATE TABLE ConsumableBorrowRequests (
BorrowRequestId INT PRIMARY KEY IDENTITY(1,1),
ConsumableId INT NOT NULL,
RequestType NVARCHAR(20) NOT NULL DEFAULT 'borrow',
BorrowerName NVARCHAR(100) NOT NULL,
BorrowQuantity INT NOT NULL DEFAULT 1,
Unit NVARCHAR(50) NULL,
BorrowDate DATE NOT NULL DEFAULT (CAST(DATEADD(HOUR, 7, SYSUTCDATETIME()) AS DATE)),
RequestStatus NVARCHAR(20) NOT NULL DEFAULT 'pending',
RequestNote NVARCHAR(500) NULL,
RejectReason NVARCHAR(1000) NULL,
ExportHistoryId INT NULL,
CreatedBy INT NULL,
ProcessedBy INT NULL,
ProcessedByName NVARCHAR(100) NULL,
ProcessedDate DATETIME NULL,
CreatedDate DATETIME NOT NULL DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())),
UpdatedDate DATETIME NOT NULL DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())),
FOREIGN KEY (ConsumableId) REFERENCES ConsumableInventory(ConsumableId) ON DELETE CASCADE,
FOREIGN KEY (CreatedBy) REFERENCES Users(UserId) ON DELETE SET NULL
);
PRINT 'Table ConsumableBorrowRequests created successfully.';
END
IF COL_LENGTH('dbo.ConsumableBorrowRequests', 'RequestType') IS NULL
BEGIN
ALTER TABLE ConsumableBorrowRequests
ADD RequestType NVARCHAR(20) NOT NULL CONSTRAINT DF_ConsumableBorrowRequests_RequestType DEFAULT('borrow');
END
UPDATE ConsumableBorrowRequests
SET RequestType = 'borrow'
WHERE RequestType IS NULL OR LTRIM(RTRIM(RequestType)) = '';
DECLARE @ConsumableBorrowProcessedByFk NVARCHAR(128);
SELECT TOP 1 @ConsumableBorrowProcessedByFk = fk.name
FROM sys.foreign_keys fk
INNER JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
INNER JOIN sys.columns c
ON c.object_id = fkc.parent_object_id
AND c.column_id = fkc.parent_column_id
WHERE fk.parent_object_id = OBJECT_ID('dbo.ConsumableBorrowRequests')
AND c.name = 'ProcessedBy';
IF @ConsumableBorrowProcessedByFk IS NOT NULL
BEGIN
DECLARE @DropConsumableBorrowProcessedByFkSql NVARCHAR(MAX) =
N'ALTER TABLE ConsumableBorrowRequests DROP CONSTRAINT ' + QUOTENAME(@ConsumableBorrowProcessedByFk);
EXEC sp_executesql @DropConsumableBorrowProcessedByFkSql;
END
-- =========================================== -- ===========================================
-- 7. CREATE ASSET DEPARTMENTS TABLE -- 7. CREATE ASSET DEPARTMENTS TABLE
-- =========================================== -- ===========================================
@@ -441,8 +553,7 @@ BEGIN
CreatedDate DATETIME DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())), CreatedDate DATETIME DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())),
UpdatedDate DATETIME DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())), UpdatedDate DATETIME DEFAULT (DATEADD(HOUR, 7, SYSUTCDATETIME())),
FOREIGN KEY (AssetId) REFERENCES AssetInventory(AssetId) ON DELETE CASCADE, FOREIGN KEY (AssetId) REFERENCES AssetInventory(AssetId) ON DELETE CASCADE,
FOREIGN KEY (CreatedBy) REFERENCES Users(UserId) ON DELETE SET NULL, FOREIGN KEY (CreatedBy) REFERENCES Users(UserId) ON DELETE SET NULL
FOREIGN KEY (ProcessedBy) REFERENCES Users(UserId) ON DELETE SET NULL
); );
PRINT 'Table AssetBorrowRequests created successfully.'; PRINT 'Table AssetBorrowRequests created successfully.';
END END
@@ -502,13 +613,6 @@ BEGIN
ALTER TABLE AssetBorrowRequests ADD ProcessedDate DATETIME NULL; ALTER TABLE AssetBorrowRequests ADD ProcessedDate DATETIME NULL;
END END
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_AssetBorrowRequests_ProcessedBy')
BEGIN
ALTER TABLE AssetBorrowRequests
ADD CONSTRAINT FK_AssetBorrowRequests_ProcessedBy
FOREIGN KEY (ProcessedBy) REFERENCES Users(UserId) ON DELETE SET NULL;
END
UPDATE AssetBorrowRequests UPDATE AssetBorrowRequests
SET RequestType = ISNULL(NULLIF(LTRIM(RTRIM(RequestType)), ''), 'borrow'); SET RequestType = ISNULL(NULLIF(LTRIM(RTRIM(RequestType)), ''), 'borrow');
@@ -805,6 +909,56 @@ BEGIN
CREATE INDEX IX_ConsumableExportHistory_ExportedDate ON ConsumableExportHistory(ExportedDate DESC); CREATE INDEX IX_ConsumableExportHistory_ExportedDate ON ConsumableExportHistory(ExportedDate DESC);
END END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableExportHistory_RecipientUserId')
BEGIN
CREATE INDEX IX_ConsumableExportHistory_RecipientUserId ON ConsumableExportHistory(RecipientUserId);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableReturnHistory_ExportHistoryId')
BEGIN
CREATE INDEX IX_ConsumableReturnHistory_ExportHistoryId ON ConsumableReturnHistory(ExportHistoryId);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableReturnHistory_ConsumableId')
BEGIN
CREATE INDEX IX_ConsumableReturnHistory_ConsumableId ON ConsumableReturnHistory(ConsumableId);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableReturnHistory_ReturnedDate')
BEGIN
CREATE INDEX IX_ConsumableReturnHistory_ReturnedDate ON ConsumableReturnHistory(ReturnedDate DESC);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableBorrowRequests_ConsumableId')
BEGIN
CREATE INDEX IX_ConsumableBorrowRequests_ConsumableId ON ConsumableBorrowRequests(ConsumableId);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableBorrowRequests_CreatedBy')
BEGIN
CREATE INDEX IX_ConsumableBorrowRequests_CreatedBy ON ConsumableBorrowRequests(CreatedBy);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableBorrowRequests_RequestStatus')
BEGIN
CREATE INDEX IX_ConsumableBorrowRequests_RequestStatus ON ConsumableBorrowRequests(RequestStatus);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableBorrowRequests_CreatedDate')
BEGIN
CREATE INDEX IX_ConsumableBorrowRequests_CreatedDate ON ConsumableBorrowRequests(CreatedDate DESC);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableBorrowRequests_RequestType')
BEGIN
CREATE INDEX IX_ConsumableBorrowRequests_RequestType ON ConsumableBorrowRequests(RequestType);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_ConsumableBorrowRequests_ExportHistoryId')
BEGIN
CREATE INDEX IX_ConsumableBorrowRequests_ExportHistoryId ON ConsumableBorrowRequests(ExportHistoryId);
END
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'UX_AssetDepartments_DepartmentName') IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'UX_AssetDepartments_DepartmentName')
BEGIN BEGIN
CREATE UNIQUE INDEX UX_AssetDepartments_DepartmentName ON AssetDepartments(DepartmentName); CREATE UNIQUE INDEX UX_AssetDepartments_DepartmentName ON AssetDepartments(DepartmentName);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -391,11 +391,11 @@
</div> </div>
</div> </div>
<!-- Export Consumable Modal --> <!-- Borrow / Export Consumable Modal -->
<div class="modal-backdrop fixed inset-0 z-[100] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="consumableExportModal"> <div class="modal-backdrop fixed inset-0 z-[100] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="consumableExportModal">
<div class="modal-content w-full max-w-lg bg-white rounded-xl shadow-2xl border border-slate-200 overflow-hidden m-4"> <div class="modal-content w-full max-w-lg 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 flex items-center justify-between bg-slate-50"> <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">Xuất vật tư tiêu hao</h3> <h3 id="consumableExportModalTitle" class="text-base font-extrabold text-slate-900">Mượn / xuất vật tư tiêu hao</h3>
<button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeConsumableExportModal()"> <button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeConsumableExportModal()">
<span class="material-symbols-outlined">close</span> <span class="material-symbols-outlined">close</span>
</button> </button>
@@ -412,14 +412,14 @@
<input type="number" id="consumableExportCurrentEndingInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly> <input type="number" id="consumableExportCurrentEndingInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div> </div>
<div> <div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Xuất cho</label> <label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Hình thức</label>
<select id="consumableExportTargetTypeInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" required> <select id="consumableExportTargetTypeInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" required>
<option value="user">Người dùng</option> <option value="user">Mượn cho người dùng</option>
<option value="project">Dự án</option> <option value="project">Xuất cho dự án</option>
</select> </select>
</div> </div>
<div> <div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Số lượng xuất</label> <label id="consumableExportQuantityLabel" class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Số lượng mượn</label>
<input type="number" id="consumableExportQuantityInput" min="1" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" value="1" required> <input type="number" id="consumableExportQuantityInput" min="1" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" value="1" required>
</div> </div>
<div id="consumableExportProjectField" class="hidden"> <div id="consumableExportProjectField" class="hidden">
@@ -443,13 +443,197 @@
<input type="text" id="consumableExportRoleInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly> <input type="text" id="consumableExportRoleInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div> </div>
<div class="md:col-span-2"> <div class="md:col-span-2">
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Ghi chú xuất</label> <label id="consumableExportNoteLabel" class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Ghi chú mượn</label>
<textarea id="consumableExportNoteInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 h-20 resize-none" placeholder="Nhập mục đích sử dụng hoặc ghi chú bàn giao"></textarea> <textarea id="consumableExportNoteInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 h-20 resize-none" placeholder="Nhập mục đích sử dụng hoặc ghi chú bàn giao"></textarea>
</div> </div>
</div> </div>
<div class="flex gap-3 pt-2"> <div class="flex gap-3 pt-2">
<button type="button" class="flex-1 px-4 py-2 text-xs font-bold text-slate-600 border border-slate-200 rounded-lg" onclick="closeConsumableExportModal()">Hủy</button> <button type="button" class="flex-1 px-4 py-2 text-xs font-bold text-slate-600 border border-slate-200 rounded-lg" onclick="closeConsumableExportModal()">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">Xác nhận xuất</button> <button id="consumableExportSubmitBtn" type="submit" class="flex-1 px-4 py-2 bg-primary hover:bg-primary-dim text-on-primary rounded-lg text-xs font-bold">Xác nhận mượn</button>
</div>
</form>
</div>
</div>
<!-- Consumable Borrow Request Modal -->
<div class="modal-backdrop fixed inset-0 z-[125] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="consumableBorrowRequestModal">
<div class="modal-content w-full max-w-lg bg-white rounded-xl shadow-2xl border border-slate-200 overflow-visible m-4">
<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">Tạo đơn mượn vật tư tiêu hao</h3>
<button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeConsumableBorrowRequestModal()">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<form id="consumableBorrowRequestForm" class="p-6 space-y-4 relative">
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Người tạo đơn</label>
<input type="text" id="consumableBorrowRequesterInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Vật tư cần mượn</label>
<div id="consumableBorrowProductPicker" class="relative z-[135]">
<input type="hidden" id="consumableBorrowProductInput">
<button
type="button"
id="consumableBorrowProductDisplayBtn"
class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 text-left flex items-center justify-between gap-2 bg-white"
>
<span id="consumableBorrowProductDisplayText" class="flex-1 min-w-0 truncate text-slate-600">-- Chọn vật tư --</span>
<span class="material-symbols-outlined text-base text-slate-400">expand_more</span>
</button>
<div
id="consumableBorrowProductDropdown"
class="hidden absolute left-0 right-0 w-full max-w-full mt-1 bg-white border border-slate-200 rounded-lg shadow-xl z-[145] overflow-hidden"
>
<div class="p-2 border-b border-slate-100">
<input
type="text"
id="consumableBorrowProductSearchInput"
class="w-full border border-slate-200 rounded-md text-sm py-2 px-2.5"
placeholder="Tìm theo mã, tên hoặc model vật tư..."
autocomplete="off"
>
</div>
<div id="consumableBorrowProductList" class="overflow-auto" style="max-height: 240px; overscroll-behavior: contain;"></div>
</div>
</div>
</div>
<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">Tồn hiện tại</label>
<input type="number" id="consumableBorrowCurrentStockInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Đơn vị</label>
<input type="text" id="consumableBorrowUnitInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Số lượng mượn</label>
<input type="number" id="consumableBorrowQuantityInput" min="1" value="1" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" required>
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Ngày mượn</label>
<input type="date" id="consumableBorrowDateInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" required>
</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="consumableBorrowNoteInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 h-20 resize-none" placeholder="Nhập mục đích sử dụng hoặc ghi chú"></textarea>
</div>
</div>
<p class="text-xs text-slate-500">Tồn kho chỉ được trừ sau khi Asset/Admin chấp nhận đơn.</p>
<div class="flex gap-3 pt-2">
<button type="button" class="flex-1 px-4 py-2 text-xs font-bold text-slate-600 border border-slate-200 rounded-lg" onclick="closeConsumableBorrowRequestModal()">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">Gửi đơn mượn</button>
</div>
</form>
</div>
</div>
<!-- Consumable Borrow Requests List Modal -->
<div class="modal-backdrop fixed inset-0 z-[125] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="consumableBorrowRequestsModal">
<div class="modal-content w-full max-w-7xl 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">
<div>
<h3 id="consumableBorrowRequestsModalTitle" class="text-base font-extrabold text-slate-900">Đơn mượn vật tư của tôi</h3>
<p id="consumableBorrowRequestsModalSubtitle" class="text-xs text-slate-500 mt-0.5">Theo dõi trạng thái các đơn đã gửi.</p>
</div>
<button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeConsumableBorrowRequestsModal()">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<div class="p-6 pt-4 overflow-auto">
<div class="rounded-xl border border-slate-200 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse" style="min-width: 1450px;">
<thead class="bg-slate-50 border-b border-slate-200">
<tr>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Mã đơn</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Người tạo</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Vật tư</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Loại đơn</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500 text-right">Số lượng</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Ngày</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Trạng thái</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Ghi chú</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Người xử lý</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Lý do từ chối</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500 text-right">Hành động</th>
</tr>
</thead>
<tbody id="consumableBorrowRequestsTableBody" class="divide-y divide-slate-100">
<tr><td colspan="11" class="px-4 py-8 text-sm text-center text-slate-500">Chưa có đơn mượn/trả vật tư.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Reject Consumable Borrow/Return Request Modal -->
<div class="modal-backdrop fixed inset-0 z-[150] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="consumableRequestRejectModal" style="z-index: 150;">
<div class="modal-content w-full max-w-lg 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 flex items-center justify-between bg-slate-50">
<h3 id="consumableRequestRejectModalTitle" class="text-base font-extrabold text-slate-900">Từ chối đơn vật tư</h3>
<button type="button" class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeConsumableRequestRejectModal()">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<form id="consumableRequestRejectForm" class="p-6 space-y-4">
<input type="hidden" id="consumableRequestRejectIdInput">
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Lý do từ chối</label>
<textarea id="consumableRequestRejectReasonInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 h-24 resize-none" placeholder="Nhập lý do để người tạo đơn biết..." required></textarea>
</div>
<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 hover:bg-slate-50" onclick="closeConsumableRequestRejectModal()">Đóng</button>
<button type="submit" class="flex-1 px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg text-xs font-bold">Xác nhận từ chối</button>
</div>
</form>
</div>
</div>
<!-- Return Consumable Modal -->
<div class="modal-backdrop fixed inset-0 z-[130] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="consumableReturnModal">
<div class="modal-content w-full max-w-lg 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 flex items-center justify-between bg-slate-50">
<h3 id="consumableReturnModalTitle" class="text-base font-extrabold text-slate-900">Hoàn trả vật tư về kho</h3>
<button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeConsumableReturnModal()">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<form id="consumableReturnForm" class="p-6 space-y-4">
<input type="hidden" id="consumableReturnExportHistoryIdInput">
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Vật tư</label>
<input type="text" id="consumableReturnConsumableInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div>
<div>
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Nơi đang nhận</label>
<input type="text" id="consumableReturnDestinationInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div>
<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">Số lượng chưa trả</label>
<input type="number" id="consumableReturnRemainingInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div>
<div>
<label id="consumableReturnQuantityLabel" class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Số lượng trả kho</label>
<input type="number" id="consumableReturnQuantityInput" min="1" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3" value="1" required>
</div>
<div class="md:col-span-2">
<label id="consumableReturnActorLabel" class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Người nhận lại kho</label>
<input type="text" id="consumableReturnActorInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 bg-slate-50" readonly>
</div>
<div class="md:col-span-2">
<label class="text-[10px] font-bold uppercase text-slate-500 tracking-widest block mb-1">Ghi chú trả</label>
<textarea id="consumableReturnNoteInput" class="w-full border border-slate-200 rounded-lg text-sm py-2.5 px-3 h-20 resize-none" placeholder="Nhập tình trạng hoặc ghi chú khi nhận lại"></textarea>
</div>
</div>
<p id="consumableReturnHelpText" class="text-xs text-slate-500">Khi xác nhận, số lượng này sẽ được cộng lại vào tồn kho ngay.</p>
<div class="flex gap-3 pt-2">
<button type="button" class="flex-1 px-4 py-2 text-xs font-bold text-slate-600 border border-slate-200 rounded-lg" onclick="closeConsumableReturnModal()">Hủy</button>
<button id="consumableReturnSubmitBtn" type="submit" class="flex-1 px-4 py-2 bg-primary hover:bg-primary-dim text-on-primary rounded-lg text-xs font-bold">Xác nhận trả kho</button>
</div> </div>
</form> </form>
</div> </div>
@@ -459,7 +643,7 @@
<div class="modal-backdrop fixed inset-0 z-[110] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="consumableExportHistoryModal" style="z-index: 124;"> <div class="modal-backdrop fixed inset-0 z-[110] flex items-center justify-center bg-black/40 backdrop-blur-sm" id="consumableExportHistoryModal" style="z-index: 124;">
<div class="modal-content w-full max-w-6xl 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="modal-content w-full max-w-6xl 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"> <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">Lịch sử xuất vật tư tiêu hao</h3> <h3 class="text-base font-extrabold text-slate-900">Lịch sử mượn / xuất / trả vật tư</h3>
<button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeConsumableExportHistoryModal()"> <button class="p-1.5 rounded-lg hover:bg-slate-200 text-slate-400 transition-colors" onclick="closeConsumableExportHistoryModal()">
<span class="material-symbols-outlined">close</span> <span class="material-symbols-outlined">close</span>
</button> </button>
@@ -467,22 +651,25 @@
<div class="p-6 pt-4 overflow-auto"> <div class="p-6 pt-4 overflow-auto">
<div class="rounded-xl border border-slate-200 overflow-hidden"> <div class="rounded-xl border border-slate-200 overflow-hidden">
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="w-full text-left border-collapse" style="min-width: 1100px;"> <table class="w-full text-left border-collapse" style="min-width: 1500px;">
<thead class="bg-slate-50 border-b border-slate-200"> <thead class="bg-slate-50 border-b border-slate-200">
<tr> <tr>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Ngày giờ</th> <th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Ngày giờ</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Vật tư</th> <th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Vật tư</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Số lượng</th> <th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Nơi nhận</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Người nhận</th> <th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500 text-right">Đã xuất</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Dự án nhận</th> <th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500 text-right">Đã trả</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500 text-right">Còn lại</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Trạng thái</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Người xuất</th> <th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Người xuất</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Tồn trước/sau</th> <th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Tồn trước/sau</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Ghi chú</th> <th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500">Ghi chú</th>
<th class="px-4 py-2.5 text-[10px] font-bold uppercase tracking-wider text-slate-500 text-right">Thao tác</th>
</tr> </tr>
</thead> </thead>
<tbody id="consumableExportHistoryTableBody" class="divide-y divide-slate-100"> <tbody id="consumableExportHistoryTableBody" class="divide-y divide-slate-100">
<tr> <tr>
<td colspan="8" class="px-4 py-8 text-sm text-center text-slate-500">Chưa có dữ liệu lịch sử xuất vật tư.</td> <td colspan="11" class="px-4 py-8 text-sm text-center text-slate-500">Chưa có dữ liệu lịch sử mượn / xuất vật tư.</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -323,6 +323,6 @@
</div> </div>
</main> </main>
<script src="../js/app.js?v=20260515-5"></script> <script src="../js/app.js?v=20260630-1"></script>
</body> </body>
</html> </html>