656 lines
22 KiB
HTML
656 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="vi">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Ghi nhận điểm - Worker App</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.4.0/css/all.min.css">
|
|
<style>
|
|
:root {
|
|
--primary-color: #2563eb;
|
|
--primary-dark: #1d4ed8;
|
|
--secondary-color: #64748b;
|
|
--success-color: #10b981;
|
|
--warning-color: #f59e0b;
|
|
--danger-color: #ef4444;
|
|
--background-color: #f8fafc;
|
|
--card-background: #ffffff;
|
|
--text-primary: #1e293b;
|
|
--text-secondary: #64748b;
|
|
--border-color: #e2e8f0;
|
|
}
|
|
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background-color: var(--background-color);
|
|
color: var(--text-primary);
|
|
line-height: 1.6;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
.header {
|
|
background: var(--card-background);
|
|
border-bottom: 1px solid var(--border-color);
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 100;
|
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.header-content {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 1rem;
|
|
max-width: 480px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.back-button {
|
|
background: none;
|
|
border: none;
|
|
color: var(--primary-color);
|
|
font-size: 1.25rem;
|
|
cursor: pointer;
|
|
padding: 0.5rem;
|
|
border-radius: 0.5rem;
|
|
transition: background-color 0.2s;
|
|
}
|
|
|
|
.back-button:hover {
|
|
background-color: #f1f5f9;
|
|
}
|
|
|
|
.header-title {
|
|
font-size: 1.125rem;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.container {
|
|
max-width: 480px;
|
|
margin: 0 auto;
|
|
background: var(--card-background);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.content {
|
|
padding: 1rem;
|
|
padding-bottom: 100px;
|
|
}
|
|
|
|
.info-card {
|
|
background: linear-gradient(135deg, #dbeafe, #bfdbfe);
|
|
border: 1px solid var(--primary-color);
|
|
border-radius: 0.75rem;
|
|
padding: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.info-title {
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
color: var(--primary-color);
|
|
margin-bottom: 0.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.info-text {
|
|
font-size: 0.875rem;
|
|
color: #1e40af;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.form-label {
|
|
display: block;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
margin-bottom: 0.5rem;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.form-label.required::after {
|
|
content: " *";
|
|
color: var(--danger-color);
|
|
}
|
|
|
|
.form-input {
|
|
width: 100%;
|
|
padding: 0.75rem;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 0.5rem;
|
|
font-size: 1rem;
|
|
background: white;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.form-input:focus {
|
|
outline: none;
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
|
|
}
|
|
|
|
.form-textarea {
|
|
min-height: 80px;
|
|
resize: vertical;
|
|
}
|
|
|
|
.form-select {
|
|
appearance: none;
|
|
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6,9 12,15 18,9'%3e%3c/polyline%3e%3c/svg%3e");
|
|
background-repeat: no-repeat;
|
|
background-position: right 0.75rem center;
|
|
background-size: 1em;
|
|
padding-right: 2.5rem;
|
|
}
|
|
|
|
.file-upload {
|
|
border: 2px dashed var(--border-color);
|
|
border-radius: 0.75rem;
|
|
padding: 2rem 1rem;
|
|
text-align: center;
|
|
transition: all 0.2s;
|
|
background: #fafafa;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.file-upload:hover {
|
|
border-color: var(--primary-color);
|
|
background: #f0f8ff;
|
|
}
|
|
|
|
.file-upload.dragover {
|
|
border-color: var(--primary-color);
|
|
background: var(--primary-color);
|
|
color: white;
|
|
}
|
|
|
|
.file-upload-icon {
|
|
font-size: 2rem;
|
|
color: var(--secondary-color);
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.file-upload.dragover .file-upload-icon {
|
|
color: white;
|
|
}
|
|
|
|
.file-upload-text {
|
|
font-size: 0.875rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.file-upload.dragover .file-upload-text {
|
|
color: white;
|
|
}
|
|
|
|
.file-preview {
|
|
display: none;
|
|
margin-top: 1rem;
|
|
padding: 1rem;
|
|
background: #f8f9fa;
|
|
border-radius: 0.5rem;
|
|
border: 1px solid var(--border-color);
|
|
}
|
|
|
|
.file-preview.show {
|
|
display: block;
|
|
}
|
|
|
|
.file-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
padding: 0.75rem;
|
|
background: white;
|
|
border-radius: 0.5rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.file-item:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.file-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
background: var(--primary-color);
|
|
border-radius: 0.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: white;
|
|
}
|
|
|
|
.file-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.file-name {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.file-size {
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.file-remove {
|
|
background: none;
|
|
border: none;
|
|
color: var(--danger-color);
|
|
cursor: pointer;
|
|
padding: 0.5rem;
|
|
border-radius: 0.25rem;
|
|
transition: background-color 0.2s;
|
|
}
|
|
|
|
.file-remove:hover {
|
|
background-color: #fee2e2;
|
|
}
|
|
|
|
.submit-button {
|
|
width: 100%;
|
|
background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
|
|
color: white;
|
|
border: none;
|
|
padding: 1rem;
|
|
border-radius: 0.75rem;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.submit-button:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 15px rgba(37, 99, 235, 0.3);
|
|
}
|
|
|
|
.submit-button:disabled {
|
|
opacity: 0.6;
|
|
cursor: not-allowed;
|
|
transform: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.points-estimate {
|
|
background: #f0f9ff;
|
|
border: 1px solid #0ea5e9;
|
|
border-radius: 0.75rem;
|
|
padding: 1rem;
|
|
margin-top: 1rem;
|
|
display: none;
|
|
}
|
|
|
|
.points-estimate.show {
|
|
display: block;
|
|
}
|
|
|
|
.estimate-title {
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
color: #0369a1;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.estimate-text {
|
|
font-size: 0.875rem;
|
|
color: #0369a1;
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.content {
|
|
padding: 0.75rem;
|
|
}
|
|
|
|
.file-upload {
|
|
padding: 1.5rem 0.75rem;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<!-- Header -->
|
|
<header class="header">
|
|
<div class="header-content">
|
|
<button class="back-button" onclick="goBack()">
|
|
<i class="fas fa-arrow-left"></i>
|
|
</button>
|
|
<h1 class="header-title">Ghi nhận điểm</h1>
|
|
<div style="width: 2.5rem;"></div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Content -->
|
|
<div class="content">
|
|
<!-- Info Card -->
|
|
<div class="info-card">
|
|
<h3 class="info-title">
|
|
<i class="fas fa-info-circle"></i>
|
|
Cách thức ghi nhận điểm
|
|
</h3>
|
|
<p class="info-text">
|
|
Chụp ảnh hóa đơn mua hàng và gửi cho chúng tôi để nhận điểm thưởng.
|
|
Mỗi 100,000 VNĐ sẽ được tích 1 điểm. Điểm sẽ được cập nhật trong vòng 1-2 ngày làm việc.
|
|
</p>
|
|
</div>
|
|
|
|
<form id="pointsForm" onsubmit="submitForm(event)">
|
|
<!-- Purchase Date -->
|
|
<div class="form-group">
|
|
<label class="form-label required">Ngày mua hàng</label>
|
|
<input type="date"
|
|
class="form-input"
|
|
id="purchaseDate"
|
|
required
|
|
max=""
|
|
onchange="validateForm()">
|
|
</div>
|
|
|
|
<!-- Store Location -->
|
|
<div class="form-group">
|
|
<label class="form-label required">Cửa hàng mua</label>
|
|
<select class="form-input form-select" id="storeLocation" required onchange="validateForm()">
|
|
<option value="">Chọn cửa hàng</option>
|
|
<option value="hcm-district1">TP.HCM - Quận 1</option>
|
|
<option value="hcm-district3">TP.HCM - Quận 3</option>
|
|
<option value="hcm-tanbinh">TP.HCM - Tân Bình</option>
|
|
<option value="hcm-binhthanh">TP.HCM - Bình Thạnh</option>
|
|
<option value="hanoi-hoankiem">Hà Nội - Hoàn Kiếm</option>
|
|
<option value="hanoi-dongda">Hà Nội - Đống Đa</option>
|
|
<option value="danang-haichau">Đà Nẵng - Hải Châu</option>
|
|
<option value="other">Cửa hàng khác</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Other Store -->
|
|
<div class="form-group" id="otherStoreGroup" style="display: none;">
|
|
<label class="form-label">Tên cửa hàng khác</label>
|
|
<input type="text"
|
|
class="form-input"
|
|
id="otherStore"
|
|
placeholder="Nhập tên cửa hàng">
|
|
</div>
|
|
|
|
<!-- Invoice Number -->
|
|
<div class="form-group">
|
|
<label class="form-label">Số hóa đơn</label>
|
|
<input type="text"
|
|
class="form-input"
|
|
id="invoiceNumber"
|
|
placeholder="Nhập số hóa đơn (nếu có)"
|
|
onchange="validateForm()">
|
|
</div>
|
|
|
|
<!-- Total Amount -->
|
|
<div class="form-group">
|
|
<label class="form-label required">Tổng giá trị đơn hàng (VNĐ)</label>
|
|
<input type="number"
|
|
class="form-input"
|
|
id="totalAmount"
|
|
placeholder="0"
|
|
min="0"
|
|
step="1000"
|
|
required
|
|
oninput="calculatePoints(); validateForm()">
|
|
</div>
|
|
|
|
<!-- Points Estimate -->
|
|
<div class="points-estimate" id="pointsEstimate">
|
|
<div class="estimate-title">Điểm dự kiến nhận được</div>
|
|
<div class="estimate-text" id="estimateText">0 điểm</div>
|
|
</div>
|
|
|
|
<!-- Products Purchased -->
|
|
<div class="form-group">
|
|
<label class="form-label">Sản phẩm đã mua</label>
|
|
<textarea class="form-input form-textarea"
|
|
id="products"
|
|
placeholder="Mô tả các sản phẩm đã mua (tùy chọn)"
|
|
rows="3"></textarea>
|
|
</div>
|
|
|
|
<!-- Invoice Images -->
|
|
<div class="form-group">
|
|
<label class="form-label required">Hình ảnh hóa đơn</label>
|
|
<div class="file-upload"
|
|
onclick="document.getElementById('fileInput').click()"
|
|
ondrop="handleDrop(event)"
|
|
ondragover="handleDragOver(event)"
|
|
ondragenter="handleDragEnter(event)"
|
|
ondragleave="handleDragLeave(event)">
|
|
<div class="file-upload-icon">
|
|
<i class="fas fa-camera"></i>
|
|
</div>
|
|
<div class="file-upload-text">
|
|
<strong>Chụp ảnh hoặc chọn file</strong><br>
|
|
<span>JPG, PNG tối đa 5MB mỗi file</span>
|
|
</div>
|
|
<input type="file"
|
|
id="fileInput"
|
|
accept="image/*"
|
|
multiple
|
|
style="display: none;"
|
|
onchange="handleFileSelect(event)">
|
|
</div>
|
|
<div class="file-preview" id="filePreview">
|
|
<div id="fileList"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Additional Notes -->
|
|
<div class="form-group">
|
|
<label class="form-label">Ghi chú thêm</label>
|
|
<textarea class="form-input form-textarea"
|
|
id="notes"
|
|
placeholder="Ghi chú thêm về đơn hàng (tùy chọn)"
|
|
rows="3"></textarea>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<button type="submit" class="submit-button" id="submitButton" disabled>
|
|
<i class="fas fa-paper-plane"></i>
|
|
Gửi yêu cầu ghi nhận điểm
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let selectedFiles = [];
|
|
|
|
// Set max date to today
|
|
document.getElementById('purchaseDate').max = new Date().toISOString().split('T')[0];
|
|
|
|
function goBack() {
|
|
window.history.back();
|
|
}
|
|
|
|
function validateForm() {
|
|
const purchaseDate = document.getElementById('purchaseDate').value;
|
|
const storeLocation = document.getElementById('storeLocation').value;
|
|
const totalAmount = document.getElementById('totalAmount').value;
|
|
const hasFiles = selectedFiles.length > 0;
|
|
|
|
const isValid = purchaseDate && storeLocation && totalAmount && hasFiles;
|
|
document.getElementById('submitButton').disabled = !isValid;
|
|
}
|
|
|
|
function calculatePoints() {
|
|
const totalAmount = document.getElementById('totalAmount').value;
|
|
const pointsEstimate = document.getElementById('pointsEstimate');
|
|
const estimateText = document.getElementById('estimateText');
|
|
|
|
if (totalAmount && totalAmount > 0) {
|
|
const points = Math.floor(totalAmount / 100000);
|
|
estimateText.textContent = `${points} điểm`;
|
|
pointsEstimate.classList.add('show');
|
|
} else {
|
|
pointsEstimate.classList.remove('show');
|
|
}
|
|
}
|
|
|
|
// Store location handling
|
|
document.getElementById('storeLocation').addEventListener('change', function() {
|
|
const otherStoreGroup = document.getElementById('otherStoreGroup');
|
|
if (this.value === 'other') {
|
|
otherStoreGroup.style.display = 'block';
|
|
document.getElementById('otherStore').required = true;
|
|
} else {
|
|
otherStoreGroup.style.display = 'none';
|
|
document.getElementById('otherStore').required = false;
|
|
}
|
|
validateForm();
|
|
});
|
|
|
|
// File upload handling
|
|
function handleFileSelect(event) {
|
|
const files = Array.from(event.target.files);
|
|
addFiles(files);
|
|
}
|
|
|
|
function handleDrop(event) {
|
|
event.preventDefault();
|
|
const fileUpload = document.querySelector('.file-upload');
|
|
fileUpload.classList.remove('dragover');
|
|
|
|
const files = Array.from(event.dataTransfer.files);
|
|
addFiles(files);
|
|
}
|
|
|
|
function handleDragOver(event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
function handleDragEnter(event) {
|
|
event.preventDefault();
|
|
const fileUpload = document.querySelector('.file-upload');
|
|
fileUpload.classList.add('dragover');
|
|
}
|
|
|
|
function handleDragLeave(event) {
|
|
event.preventDefault();
|
|
const fileUpload = document.querySelector('.file-upload');
|
|
fileUpload.classList.remove('dragover');
|
|
}
|
|
|
|
function addFiles(files) {
|
|
files.forEach(file => {
|
|
if (file.type.startsWith('image/')) {
|
|
if (file.size <= 5 * 1024 * 1024) { // 5MB limit
|
|
selectedFiles.push(file);
|
|
} else {
|
|
alert(`File "${file.name}" quá lớn. Vui lòng chọn file dưới 5MB.`);
|
|
}
|
|
} else {
|
|
alert(`File "${file.name}" không phải là hình ảnh hợp lệ.`);
|
|
}
|
|
});
|
|
|
|
updateFilePreview();
|
|
validateForm();
|
|
}
|
|
|
|
function updateFilePreview() {
|
|
const filePreview = document.getElementById('filePreview');
|
|
const fileList = document.getElementById('fileList');
|
|
|
|
if (selectedFiles.length > 0) {
|
|
filePreview.classList.add('show');
|
|
fileList.innerHTML = '';
|
|
|
|
selectedFiles.forEach((file, index) => {
|
|
const fileItem = document.createElement('div');
|
|
fileItem.className = 'file-item';
|
|
fileItem.innerHTML = `
|
|
<div class="file-icon">
|
|
<i class="fas fa-image"></i>
|
|
</div>
|
|
<div class="file-info">
|
|
<div class="file-name">${file.name}</div>
|
|
<div class="file-size">${formatFileSize(file.size)}</div>
|
|
</div>
|
|
<button type="button" class="file-remove" onclick="removeFile(${index})">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
`;
|
|
fileList.appendChild(fileItem);
|
|
});
|
|
} else {
|
|
filePreview.classList.remove('show');
|
|
}
|
|
}
|
|
|
|
function removeFile(index) {
|
|
selectedFiles.splice(index, 1);
|
|
updateFilePreview();
|
|
validateForm();
|
|
}
|
|
|
|
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 submitForm(event) {
|
|
event.preventDefault();
|
|
|
|
if (selectedFiles.length === 0) {
|
|
alert('Vui lòng chọn ít nhất một hình ảnh hóa đơn.');
|
|
return;
|
|
}
|
|
|
|
const submitButton = document.getElementById('submitButton');
|
|
submitButton.disabled = true;
|
|
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Đang gửi...';
|
|
|
|
// Simulate form submission
|
|
setTimeout(() => {
|
|
alert('Yêu cầu ghi nhận điểm đã được gửi thành công!\n\nChúng tôi sẽ xem xét và cập nhật điểm cho bạn trong vòng 1-2 ngày làm việc.');
|
|
window.history.back();
|
|
}, 2000);
|
|
}
|
|
|
|
function showToast(message, type = 'info') {
|
|
const toast = document.createElement('div');
|
|
toast.className = `fixed top-20 left-1/2 transform -translate-x-1/2 px-4 py-2 rounded-lg z-50 transition-all duration-300 ${
|
|
type === 'success' ? 'bg-green-500' : 'bg-blue-500'
|
|
} text-white`;
|
|
toast.textContent = message;
|
|
document.body.appendChild(toast);
|
|
|
|
setTimeout(() => {
|
|
toast.style.opacity = '0';
|
|
setTimeout(() => {
|
|
document.body.removeChild(toast);
|
|
}, 300);
|
|
}, 3000);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |