ttvtlb's picture
Tạo một hệ thống quản lý công việc, người dùng có thể thêm task, đánh dấu tác vụ ưu tiên, báo cáo kpi hàng ngày
b1a9ea7 verified
class TaskForm extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
.task-form {
@apply bg-white rounded-lg shadow-md p-6 mb-6;
}
.form-title {
@apply text-xl font-semibold text-gray-800 mb-4;
}
.form-group {
@apply mb-4;
}
label {
@apply block text-sm font-medium text-gray-700 mb-1;
}
input, textarea, select {
@apply w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500;
}
.priority-options {
@apply grid grid-cols-3 gap-2 mt-2;
}
.priority-option {
@apply flex items-center justify-center p-2 border rounded-md cursor-pointer;
}
.priority-option.selected {
@apply border-blue-500 bg-blue-50 text-blue-600;
}
.submit-btn {
@apply w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md transition-colors duration-200;
}
</style>
<div class="task-form">
<h3 class="form-title">Add New Task</h3>
<form id="taskForm">
<div class="form-group">
<label for="taskTitle">Task Title</label>
<input type="text" id="taskTitle" required>
</div>
<div class="form-group">
<label for="taskDescription">Description</label>
<textarea id="taskDescription" rows="3"></textarea>
</div>
<div class="form-group">
<label for="dueDate">Due Date</label>
<input type="date" id="dueDate" required>
</div>
<div class="form-group">
<label>Priority</label>
<div class="priority-options">
<div class="priority-option" data-value="low">Low</div>
<div class="priority-option" data-value="medium">Medium</div>
<div class="priority-option selected" data-value="high">High</div>
</div>
<input type="hidden" id="priority" value="high">
</div>
<button type="submit" class="submit-btn">Add Task</button>
</form>
</div>
`;
// Priority selection
this.shadowRoot.querySelectorAll('.priority-option').forEach(option => {
option.addEventListener('click', () => {
this.shadowRoot.querySelectorAll('.priority-option').forEach(opt =>
opt.classList.remove('selected')
);
option.classList.add('selected');
this.shadowRoot.getElementById('priority').value = option.dataset.value;
});
});
// Form submission
this.shadowRoot.getElementById('taskForm').addEventListener('submit', (e) => {
e.preventDefault();
const newTask = {
title: this.shadowRoot.getElementById('taskTitle').value,
description: this.shadowRoot.getElementById('taskDescription').value,
dueDate: this.shadowRoot.getElementById('dueDate').value,
priority: this.shadowRoot.getElementById('priority').value,
completed: false
};
this.dispatchEvent(new CustomEvent('task-added', { detail: newTask }));
this.shadowRoot.getElementById('taskForm').reset();
});
}
}
customElements.define('task-form', TaskForm);