trả/mượn vtth
This commit is contained in:
1158
backend/server.js
1158
backend/server.js
File diff suppressed because it is too large
Load Diff
@@ -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
1169
public/js/app.js
1169
public/js/app.js
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user