Files
worker/html/design-request-create.html
2025-10-24 11:31:48 +07:00

760 lines
27 KiB
HTML

<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tạo Yêu cầu Thiết kế - EuroTile Worker</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.form-container {
max-width: 480px;
margin: 0 auto;
padding: 20px;
background: #f8fafc;
min-height: calc(100vh - 120px);
}
.form-card {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
margin-bottom: 20px;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
font-weight: 600;
color: #374151;
margin-bottom: 8px;
font-size: 14px;
}
.required {
color: #ef4444;
}
.form-input,
.form-textarea,
.form-select {
width: 100%;
padding: 12px 16px;
border: 2px solid #e5e7eb;
border-radius: 8px;
font-size: 16px;
transition: all 0.3s ease;
background: white;
}
.form-input:focus,
.form-textarea:focus,
.form-select:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
.form-textarea {
height: 100px;
resize: vertical;
font-family: inherit;
}
.file-upload-area {
border: 2px dashed #d1d5db;
border-radius: 8px;
padding: 24px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
background: #f9fafb;
}
.file-upload-area:hover {
border-color: #2563eb;
background: #eff6ff;
}
.file-upload-area.drag-over {
border-color: #2563eb;
background: #eff6ff;
}
.upload-icon {
font-size: 32px;
color: #9ca3af;
margin-bottom: 12px;
}
.upload-text {
color: #6b7280;
margin-bottom: 8px;
}
.upload-hint {
font-size: 12px;
color: #9ca3af;
}
.file-preview {
margin-top: 16px;
}
.file-item {
display: flex;
align-items: center;
padding: 12px;
background: #f3f4f6;
border-radius: 8px;
margin-bottom: 8px;
}
.file-icon {
width: 40px;
height: 40px;
background: #2563eb;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
color: white;
margin-right: 12px;
font-size: 16px;
}
.file-info {
flex: 1;
}
.file-name {
font-weight: 600;
color: #1f2937;
font-size: 14px;
margin-bottom: 4px;
}
.file-size {
color: #6b7280;
font-size: 12px;
}
.file-remove {
background: #ef4444;
color: white;
border: none;
border-radius: 50%;
width: 24px;
height: 24px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.form-actions {
display: flex;
gap: 12px;
margin-top: 32px;
}
.btn {
flex: 1;
padding: 14px 20px;
border-radius: 8px;
font-weight: 600;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
border: none;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.btn-primary {
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
color: white;
}
.btn-primary:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4);
}
.btn-secondary {
background: white;
color: #374151;
border: 2px solid #e5e7eb;
}
.btn-secondary:hover {
border-color: #2563eb;
color: #2563eb;
}
.progress-steps {
display: flex;
justify-content: center;
margin-bottom: 24px;
}
.step {
width: 32px;
height: 32px;
border-radius: 50%;
background: #e5e7eb;
color: #6b7280;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
margin: 0 8px;
position: relative;
}
.step.active {
background: #2563eb;
color: white;
}
.step.completed {
background: #10b981;
color: white;
}
.step::after {
content: '';
position: absolute;
right: -24px;
top: 50%;
transform: translateY(-50%);
width: 16px;
height: 2px;
background: #e5e7eb;
}
.step:last-child::after {
display: none;
}
.step.completed::after {
background: #10b981;
}
.error-message {
color: #ef4444;
font-size: 12px;
margin-top: 4px;
display: none;
}
.toast {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: #10b981;
color: white;
padding: 12px 24px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 1000;
display: none;
align-items: center;
gap: 8px;
}
.toast.show {
display: flex;
animation: slideDown 0.3s ease;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateX(-50%) translateY(-20px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
</style>
</head>
<body>
<div class="page-wrapper">
<!-- Header -->
<div class="header">
<a href="nha-mau.html" class="back-button">
<i class="fas fa-arrow-left"></i>
</a>
<h1 class="header-title">Tạo yêu cầu thiết kế mới</h1>
<div style="width: 32px;"></div>
</div>
<div class="form-container">
<!-- Progress Steps -->
<div class="progress-steps">
<div class="step active">1</div>
<div class="step">2</div>
<div class="step">3</div>
</div>
<!-- Form -->
<form id="design-request-form" onsubmit="submitForm(event)">
<!-- Basic Information -->
<div class="form-card">
<h3 style="font-weight: 700; font-size: 18px; color: #1f2937; margin-bottom: 20px; display: flex; align-items: center; gap: 8px;">
<i class="fas fa-info-circle" style="color: #2563eb;"></i>
Thông tin cơ bản
</h3>
<div class="form-group">
<label class="form-label">
Tên dự án/Khách hàng <span class="required">*</span>
</label>
<input
type="text"
class="form-input"
id="project-name"
placeholder="VD: Thiết kế nhà anh Minh - Quận 7"
required>
<div class="error-message" id="project-name-error">Vui lòng nhập tên dự án</div>
</div>
<div class="form-group">
<label class="form-label">
Diện tích (m²) <span class="required">*</span>
</label>
<input
type="number"
class="form-input"
id="project-area"
placeholder="VD: 120"
min="1"
required>
<div class="error-message" id="project-area-error">Vui lòng nhập diện tích hợp lệ</div>
</div>
<div class="form-group">
<label class="form-label">
Phong cách mong muốn <span class="required">*</span>
</label>
<select class="form-select" id="project-style" required>
<option value="">-- Chọn phong cách --</option>
<option value="hien-dai">Hiện đại</option>
<option value="toi-gian">Tối giản</option>
<option value="co-dien">Cổ điển</option>
<option value="scandinavian">Scandinavian</option>
<option value="industrial">Industrial</option>
<option value="tropical">Tropical</option>
<option value="luxury">Luxury</option>
<option value="khac">Khác (ghi rõ trong ghi chú)</option>
</select>
<div class="error-message" id="project-style-error">Vui lòng chọn phong cách</div>
</div>
<div class="form-group">
<label class="form-label">
Ngân sách dự kiến
</label>
<select class="form-select" id="project-budget">
<option value="">-- Chọn ngân sách --</option>
<option value="duoi-100tr">Dưới 100 triệu</option>
<option value="100-300tr">100 - 300 triệu</option>
<option value="300-500tr">300 - 500 triệu</option>
<option value="500tr-1ty">500 triệu - 1 tỷ</option>
<option value="tren-1ty">Trên 1 tỷ</option>
<option value="trao-doi">Trao đổi trực tiếp</option>
</select>
</div>
</div>
<!-- Detailed Requirements -->
<div class="form-card">
<h3 style="font-weight: 700; font-size: 18px; color: #1f2937; margin-bottom: 20px; display: flex; align-items: center; gap: 8px;">
<i class="fas fa-edit" style="color: #2563eb;"></i>
Yêu cầu chi tiết
</h3>
<div class="form-group">
<label class="form-label">
Ghi chú chi tiết <span class="required">*</span>
</label>
<textarea
class="form-textarea"
id="project-notes"
placeholder="Mô tả chi tiết về yêu cầu thiết kế, số phòng, công năng sử dụng, sở thích cá nhân..."
required></textarea>
<div class="error-message" id="project-notes-error">Vui lòng mô tả yêu cầu chi tiết</div>
</div>
<div class="form-group">
<label class="form-label">
Thông tin liên hệ
</label>
<input
type="text"
class="form-input"
id="contact-info"
placeholder="Số điện thoại, email hoặc địa chỉ (tùy chọn)">
</div>
</div>
<!-- File Upload -->
<div class="form-card">
<h3 style="font-weight: 700; font-size: 18px; color: #1f2937; margin-bottom: 20px; display: flex; align-items: center; gap: 8px;">
<i class="fas fa-cloud-upload-alt" style="color: #2563eb;"></i>
Đính kèm tài liệu
</h3>
<div class="form-group">
<label class="form-label">
Đính kèm mặt bằng/Ảnh hiện trạng
</label>
<div class="file-upload-area" onclick="document.getElementById('file-input').click()">
<input
type="file"
id="file-input"
multiple
accept="image/*,.pdf,.dwg,.jpg,.jpeg,.png"
style="display: none;"
onchange="handleFileSelect(event)">
<div class="upload-icon">
<i class="fas fa-cloud-upload-alt"></i>
</div>
<div class="upload-text">
Nhấn để chọn file hoặc kéo thả vào đây
</div>
<div class="upload-hint">
Hỗ trợ: JPG, PNG, PDF, DWG (Tối đa 10MB mỗi file)
</div>
</div>
<div class="file-preview" id="file-preview">
<!-- File previews will be inserted here -->
</div>
</div>
</div>
<!-- Form Actions -->
<div class="form-actions">
<button type="button" class="btn btn-secondary" onclick="saveDraft()">
<i class="fas fa-save"></i>
Lưu nháp
</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-paper-plane"></i>
Gửi yêu cầu
</button>
</div>
</form>
</div>
<!-- Bottom Navigation -->
<!--<div class="bottom-nav">
<a href="index.html" class="nav-item">
<i class="fas fa-home"></i>
<span>Trang chủ</span>
</a>
<a href="loyalty.html" class="nav-item">
<i class="fas fa-star"></i>
<span>Hội viên</span>
</a>
<a href="promotions.html" class="nav-item">
<i class="fas fa-tags"></i>
<span>Khuyến mãi</span>
</a>
<a href="notifications.html" class="nav-item">
<i class="fas fa-bell"></i>
<span>Thông báo</span>
</a>
<a href="account.html" class="nav-item active">
<i class="fas fa-user"></i>
<span>Cài đặt</span>
</a>
</div>-->
</div>
<!-- Toast Notification -->
<div class="toast" id="toast">
<i class="fas fa-check-circle"></i>
<span id="toast-message">Thành công!</span>
</div>
<script>
let selectedFiles = [];
let currentStep = 1;
// File upload handling
function handleFileSelect(event) {
const files = Array.from(event.target.files);
files.forEach(file => {
if (validateFile(file)) {
selectedFiles.push(file);
addFilePreview(file);
}
});
// Clear input to allow re-selecting same file
event.target.value = '';
}
function validateFile(file) {
const maxSize = 10 * 1024 * 1024; // 10MB
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'application/pdf'];
if (file.size > maxSize) {
showToast('File quá lớn. Vui lòng chọn file dưới 10MB', 'error');
return false;
}
if (!allowedTypes.includes(file.type) && !file.name.toLowerCase().endsWith('.dwg')) {
showToast('Định dạng file không được hỗ trợ', 'error');
return false;
}
return true;
}
function addFilePreview(file) {
const preview = document.getElementById('file-preview');
const fileItem = document.createElement('div');
fileItem.className = 'file-item';
const fileIcon = getFileIcon(file.type, file.name);
const fileSize = formatFileSize(file.size);
fileItem.innerHTML = `
<div class="file-icon">
<i class="${fileIcon}"></i>
</div>
<div class="file-info">
<div class="file-name">${file.name}</div>
<div class="file-size">${fileSize}</div>
</div>
<button type="button" class="file-remove" onclick="removeFile(${selectedFiles.length - 1}, this)">
<i class="fas fa-times"></i>
</button>
`;
preview.appendChild(fileItem);
}
function getFileIcon(type, name) {
if (type.startsWith('image/')) return 'fas fa-image';
if (type === 'application/pdf') return 'fas fa-file-pdf';
if (name.toLowerCase().endsWith('.dwg')) return 'fas fa-drafting-compass';
return 'fas fa-file';
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function removeFile(index, button) {
selectedFiles.splice(index, 1);
button.parentElement.remove();
// Update indices for remaining files
updateFileIndices();
}
function updateFileIndices() {
const fileItems = document.querySelectorAll('.file-remove');
fileItems.forEach((button, index) => {
button.onclick = () => removeFile(index, button);
});
}
// Drag and drop handling
const uploadArea = document.querySelector('.file-upload-area');
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.classList.add('drag-over');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('drag-over');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('drag-over');
const files = Array.from(e.dataTransfer.files);
files.forEach(file => {
if (validateFile(file)) {
selectedFiles.push(file);
addFilePreview(file);
}
});
});
// Form validation and submission
function validateForm() {
let isValid = true;
// Clear previous errors
document.querySelectorAll('.error-message').forEach(el => {
el.style.display = 'none';
});
// Validate required fields
const requiredFields = [
{ id: 'project-name', message: 'Vui lòng nhập tên dự án' },
{ id: 'project-area', message: 'Vui lòng nhập diện tích hợp lệ' },
{ id: 'project-style', message: 'Vui lòng chọn phong cách' },
{ id: 'project-notes', message: 'Vui lòng mô tả yêu cầu chi tiết' }
];
requiredFields.forEach(field => {
const input = document.getElementById(field.id);
const error = document.getElementById(field.id + '-error');
if (!input.value.trim()) {
error.textContent = field.message;
error.style.display = 'block';
input.style.borderColor = '#ef4444';
isValid = false;
} else {
input.style.borderColor = '#e5e7eb';
}
});
// Validate area is a positive number
const area = document.getElementById('project-area');
if (area.value && (isNaN(area.value) || parseFloat(area.value) <= 0)) {
const error = document.getElementById('project-area-error');
error.textContent = 'Diện tích phải là số dương';
error.style.display = 'block';
area.style.borderColor = '#ef4444';
isValid = false;
}
return isValid;
}
function submitForm(event) {
event.preventDefault();
if (!validateForm()) {
showToast('Vui lòng kiểm tra lại thông tin', 'error');
return;
}
// Simulate form submission
const submitButton = event.target.querySelector('button[type="submit"]');
const originalText = submitButton.innerHTML;
submitButton.disabled = true;
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Đang gửi...';
setTimeout(() => {
// Generate random request ID
const requestId = 'YC' + Math.random().toString().substr(2, 6).toUpperCase();
// Store request data (in real app, send to backend)
const requestData = {
id: requestId,
name: document.getElementById('project-name').value,
area: document.getElementById('project-area').value,
style: document.getElementById('project-style').value,
budget: document.getElementById('project-budget').value,
notes: document.getElementById('project-notes').value,
contact: document.getElementById('contact-info').value,
files: selectedFiles.map(f => f.name),
status: 'pending',
createdAt: new Date().toISOString()
};
localStorage.setItem('newDesignRequest', JSON.stringify(requestData));
showToast('Yêu cầu thiết kế đã được gửi thành công!');
// Redirect after delay
setTimeout(() => {
window.location.href = `design-request-detail.html?id=${requestId}`;
}, 1500);
}, 2000);
}
function saveDraft() {
const draftData = {
name: document.getElementById('project-name').value,
area: document.getElementById('project-area').value,
style: document.getElementById('project-style').value,
budget: document.getElementById('project-budget').value,
notes: document.getElementById('project-notes').value,
contact: document.getElementById('contact-info').value,
files: selectedFiles.map(f => f.name)
};
localStorage.setItem('designRequestDraft', JSON.stringify(draftData));
showToast('Đã lưu nháp thành công!');
}
function showToast(message, type = 'success') {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toast-message');
toastMessage.textContent = message;
if (type === 'error') {
toast.style.background = '#ef4444';
} else {
toast.style.background = '#10b981';
}
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
// Load draft on page load
document.addEventListener('DOMContentLoaded', function() {
const draft = localStorage.getItem('designRequestDraft');
if (draft) {
try {
const draftData = JSON.parse(draft);
if (confirm('Có bản nháp đã lưu. Bạn có muốn khôi phục không?')) {
Object.keys(draftData).forEach(key => {
if (key !== 'files') {
const input = document.getElementById('project-' + key) || document.getElementById('contact-info');
if (input && draftData[key]) {
input.value = draftData[key];
}
}
});
// Clear draft after loading
localStorage.removeItem('designRequestDraft');
}
} catch (e) {
console.error('Error loading draft:', e);
}
}
});
</script>
</body>
</html>