FIX V2: Thêm phí giao hàng lắp đặt vào Excel
#25
by bep40 - opened
This view is limited to 50 files because it contains too many changes. See the raw diff here.
- .gitattributes +0 -102
- .github/workflows/auto-sync.yml +0 -48
- .rebuild +1 -1
- APPLY_EXCEL_FIX.md +51 -32
- debug_export.html +0 -47
- grob-price-fix.js +0 -87
- grob_img/grob_p1.jpeg +0 -0
- grob_img/grob_p10.jpeg +0 -3
- grob_img/grob_p100.jpeg +0 -0
- grob_img/grob_p101.jpeg +0 -3
- grob_img/grob_p102.jpeg +0 -3
- grob_img/grob_p103.jpeg +0 -0
- grob_img/grob_p104.jpeg +0 -0
- grob_img/grob_p105.jpeg +0 -0
- grob_img/grob_p106.jpeg +0 -3
- grob_img/grob_p107.jpeg +0 -0
- grob_img/grob_p108.jpeg +0 -0
- grob_img/grob_p109.jpeg +0 -3
- grob_img/grob_p11.jpeg +0 -3
- grob_img/grob_p110.jpeg +0 -3
- grob_img/grob_p111.jpeg +0 -3
- grob_img/grob_p112.jpeg +0 -0
- grob_img/grob_p113.jpeg +0 -0
- grob_img/grob_p114.jpeg +0 -0
- grob_img/grob_p115.jpeg +0 -0
- grob_img/grob_p116.jpeg +0 -0
- grob_img/grob_p117.jpeg +0 -0
- grob_img/grob_p118.jpeg +0 -3
- grob_img/grob_p119.jpeg +0 -3
- grob_img/grob_p12.jpeg +0 -0
- grob_img/grob_p120.jpeg +0 -3
- grob_img/grob_p121.jpeg +0 -0
- grob_img/grob_p122.jpeg +0 -0
- grob_img/grob_p123.jpeg +0 -0
- grob_img/grob_p124.jpeg +0 -0
- grob_img/grob_p125.jpeg +0 -3
- grob_img/grob_p126.jpeg +0 -0
- grob_img/grob_p127.jpeg +0 -0
- grob_img/grob_p128.jpeg +0 -0
- grob_img/grob_p129.jpeg +0 -0
- grob_img/grob_p13.jpeg +0 -0
- grob_img/grob_p130.jpeg +0 -3
- grob_img/grob_p131.jpeg +0 -3
- grob_img/grob_p132.jpeg +0 -3
- grob_img/grob_p133.jpeg +0 -3
- grob_img/grob_p134.jpeg +0 -3
- grob_img/grob_p135.jpeg +0 -0
- grob_img/grob_p136.jpeg +0 -0
- grob_img/grob_p137.jpeg +0 -0
- grob_img/grob_p138.jpeg +0 -0
.gitattributes
DELETED
|
@@ -1,102 +0,0 @@
|
|
| 1 |
-
grob_img/grob_p10.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
grob_img/grob_p101.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 3 |
-
grob_img/grob_p102.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
grob_img/grob_p106.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
grob_img/grob_p109.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
grob_img/grob_p11.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
grob_img/grob_p110.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
grob_img/grob_p111.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
grob_img/grob_p118.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
grob_img/grob_p119.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
grob_img/grob_p120.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
grob_img/grob_p125.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
grob_img/grob_p130.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
grob_img/grob_p131.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
grob_img/grob_p132.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
grob_img/grob_p133.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
grob_img/grob_p134.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
grob_img/grob_p140.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
grob_img/grob_p141.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
grob_img/grob_p166.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
grob_img/grob_p17.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
grob_img/grob_p174.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
grob_img/grob_p175.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
grob_img/grob_p177.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
grob_img/grob_p178.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
grob_img/grob_p179.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
grob_img/grob_p180.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
grob_img/grob_p183.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
grob_img/grob_p184.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
grob_img/grob_p185.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
grob_img/grob_p186.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
grob_img/grob_p19.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
grob_img/grob_p199.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
grob_img/grob_p2.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
grob_img/grob_p201.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 36 |
-
grob_img/grob_p21.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
-
grob_img/grob_p23.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
-
grob_img/grob_p24.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 39 |
-
grob_img/grob_p28.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 40 |
-
grob_img/grob_p29.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 41 |
-
grob_img/grob_p3.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 42 |
-
grob_img/grob_p30.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 43 |
-
grob_img/grob_p31.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 44 |
-
grob_img/grob_p32.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 45 |
-
grob_img/grob_p33.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 46 |
-
grob_img/grob_p34.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 47 |
-
grob_img/grob_p35.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 48 |
-
grob_img/grob_p36.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 49 |
-
grob_img/grob_p37.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 50 |
-
grob_img/grob_p38.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 51 |
-
grob_img/grob_p39.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 52 |
-
grob_img/grob_p40.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 53 |
-
grob_img/grob_p41.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 54 |
-
grob_img/grob_p42.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 55 |
-
grob_img/grob_p43.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 56 |
-
grob_img/grob_p44.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 57 |
-
grob_img/grob_p45.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 58 |
-
grob_img/grob_p46.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 59 |
-
grob_img/grob_p47.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 60 |
-
grob_img/grob_p48.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 61 |
-
grob_img/grob_p49.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 62 |
-
grob_img/grob_p50.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 63 |
-
grob_img/grob_p51.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 64 |
-
grob_img/grob_p52.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 65 |
-
grob_img/grob_p53.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 66 |
-
grob_img/grob_p54.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 67 |
-
grob_img/grob_p55.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 68 |
-
grob_img/grob_p56.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 69 |
-
grob_img/grob_p57.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 70 |
-
grob_img/grob_p58.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 71 |
-
grob_img/grob_p59.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 72 |
-
grob_img/grob_p6.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 73 |
-
grob_img/grob_p60.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 74 |
-
grob_img/grob_p61.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 75 |
-
grob_img/grob_p62.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 76 |
-
grob_img/grob_p63.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 77 |
-
grob_img/grob_p64.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 78 |
-
grob_img/grob_p65.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 79 |
-
grob_img/grob_p66.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 80 |
-
grob_img/grob_p67.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 81 |
-
grob_img/grob_p68.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 82 |
-
grob_img/grob_p69.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 83 |
-
grob_img/grob_p7.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 84 |
-
grob_img/grob_p70.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 85 |
-
grob_img/grob_p71.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 86 |
-
grob_img/grob_p72.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 87 |
-
grob_img/grob_p73.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 88 |
-
grob_img/grob_p74.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 89 |
-
grob_img/grob_p76.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 90 |
-
grob_img/grob_p77.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 91 |
-
grob_img/grob_p78.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 92 |
-
grob_img/grob_p79.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 93 |
-
grob_img/grob_p8.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 94 |
-
grob_img/grob_p80.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 95 |
-
grob_img/grob_p82.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 96 |
-
grob_img/grob_p83.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 97 |
-
grob_img/grob_p84.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 98 |
-
grob_img/grob_p85.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 99 |
-
grob_img/grob_p88.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 100 |
-
grob_img/grob_p9.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 101 |
-
grob_img/grob_p97.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 102 |
-
grob_img/grob_p98.jpeg filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.github/workflows/auto-sync.yml
DELETED
|
@@ -1,48 +0,0 @@
|
|
| 1 |
-
name: Auto-Sync Products
|
| 2 |
-
|
| 3 |
-
on:
|
| 4 |
-
schedule:
|
| 5 |
-
# Chạy hàng ngày lúc midnight UTC (8:00 AM Việt Nam)
|
| 6 |
-
- cron: '0 0 * * *'
|
| 7 |
-
workflow_dispatch:
|
| 8 |
-
inputs:
|
| 9 |
-
dry_run:
|
| 10 |
-
description: 'Chỉ kiểm tra mà không cập nhật'
|
| 11 |
-
type: boolean
|
| 12 |
-
default: false
|
| 13 |
-
target_space:
|
| 14 |
-
description: 'Không gian target (vai-avatar2 hoặc both)'
|
| 15 |
-
type: choice
|
| 16 |
-
options:
|
| 17 |
-
- vai-avatar2
|
| 18 |
-
- both
|
| 19 |
-
|
| 20 |
-
jobs:
|
| 21 |
-
sync-products:
|
| 22 |
-
runs-on: ubuntu-latest
|
| 23 |
-
steps:
|
| 24 |
-
- name: Checkout code
|
| 25 |
-
uses: actions/checkout@v4
|
| 26 |
-
|
| 27 |
-
- name: Setup Python
|
| 28 |
-
uses: actions/setup-python@v5
|
| 29 |
-
with:
|
| 30 |
-
python-version: '3.11'
|
| 31 |
-
|
| 32 |
-
- name: Install dependencies
|
| 33 |
-
run: |
|
| 34 |
-
pip install huggingface_hub
|
| 35 |
-
|
| 36 |
-
- name: Run sync products
|
| 37 |
-
env:
|
| 38 |
-
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 39 |
-
run: |
|
| 40 |
-
echo "Starting product auto-sync..."
|
| 41 |
-
python3 sync_products.py
|
| 42 |
-
|
| 43 |
-
if [ $? -eq 0 ]; then
|
| 44 |
-
echo "✅ Sync completed successfully"
|
| 45 |
-
else
|
| 46 |
-
echo "❌ Sync failed"
|
| 47 |
-
exit 1
|
| 48 |
-
fi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.rebuild
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
2026-07-
|
|
|
|
| 1 |
+
2026-07-03T08:05:09+00:00
|
APPLY_EXCEL_FIX.md
CHANGED
|
@@ -1,32 +1,51 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
| 3 |
-
##
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
-
|
| 10 |
-
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
## Cách
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
2.
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hướng dẫn áp dụng Fix Excel Download - CẬP NHẬT 2026
|
| 2 |
+
|
| 3 |
+
## Vấn đề
|
| 4 |
+
File Excel chỉ tải được 1 lần, lần 2+ thất bại vì `URL.revokeObjectURL()` được gọi sau 60s.
|
| 5 |
+
|
| 6 |
+
## 🎯 GIẢI PHÁP HOÀN HẢO - Fix v2.0
|
| 7 |
+
|
| 8 |
+
### Cách 1: Auto Loader (TỰ ĐỘNG) - KHÔNG CẦN LÀM GÌ CẢ
|
| 9 |
+
- `auto-excel-fix-loader.js` tự động tải `vai-excel-fix-v2.js` khi trang mở
|
| 10 |
+
- Script đã được tích hợp sẵn trong index.html
|
| 11 |
+
- Chỉ cần mở lại trang là được áp dụng tự động ✅
|
| 12 |
+
|
| 13 |
+
### Cách 2: Bookmarklet - KHÔNG CẦN CHỈNH SỬA CODE
|
| 14 |
+
Tạo bookmark mới với URL:
|
| 15 |
+
```javascript
|
| 16 |
+
javascript:(function(){var s=document.createElement('script');s.src='/vai-excel-fix-v2.js?v='+Date.now();s.onload=function(){alert('✅ Excel Fix v2.0 đã tải!\nBạn có thể tải Excel bao nhiêu lần tùy thích!');};document.head.appendChild(s);})();
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
### Cách 3: Thêm script tag vào index.html (TỰ ĐỘNG)
|
| 20 |
+
Thêm đoạn sau vào trước thẻ `</body>`:
|
| 21 |
+
```html
|
| 22 |
+
<!-- V.AI STUDIO Excel Multi-Download Fix v2.0 -->
|
| 23 |
+
<script src="vai-excel-fix-v2.js?v=2026"></script>
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
## Test
|
| 27 |
+
1. Mở Space V.AISTUDIO
|
| 28 |
+
2. Tạo báo giá (lập báo giá) → Click 💾 Excel → tải ✅
|
| 29 |
+
3. Click 💾 Excel NGAY → tải tiếp tục ✅
|
| 30 |
+
4. Click nhiều lần nữa → luôn tải được ✅
|
| 31 |
+
5. Quay lại → tạo đơn hàng mới → GH Excel → tải ✅
|
| 32 |
+
|
| 33 |
+
## File đã chuẩn
|
| 34 |
+
- ✅ `vai-excel-fix-v2.js` - Script fix chính (mới nhất)
|
| 35 |
+
- ✅ `auto-excel-fix-loader.js` - Tự động tải fix
|
| 36 |
+
- ✅ `vai-quote-excel-order-fix-v1050.js` - Backup (nếu v2 không tải được)
|
| 37 |
+
|
| 38 |
+
## Điều kiện áp dụng
|
| 39 |
+
- Cần có thư viện ExcelJS (đã có trong index.html):
|
| 40 |
+
```html
|
| 41 |
+
<script src="https://cdn.jsdelivr.net/npm/exceljs@4.4.0/dist/exceljs.min.js"></script>
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
## Changelog v2.0
|
| 45 |
+
- Thay đổi cách quản lý blob URL: registry toàn cục
|
| 46 |
+
- Patch URL.revokeObjectURL: không revoke khi chưa unload
|
| 47 |
+
- Hỗ trợ cả Quote modal và Order modal
|
| 48 |
+
- Toast thông báo khi xuất thành công/thất bại
|
| 49 |
+
|
| 50 |
+
---
|
| 51 |
+
*Cập nhật: 14-07-2026 - ML Intern - Fix Excel multi-download hoàn hảo*
|
debug_export.html
DELETED
|
@@ -1,47 +0,0 @@
|
|
| 1 |
-
<!DOCTYPE html>
|
| 2 |
-
<html lang="vi"><head><meta charset="utf-8"/>
|
| 3 |
-
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
| 4 |
-
<title>VAI Export Debug</title>
|
| 5 |
-
<script src="https://cdn.jsdelivr.net/npm/exceljs@4.4.0/dist/exceljs.min.js"></script>
|
| 6 |
-
<style>body{font-family:system-ui;padding:16px;background:#f5f7fa}textarea{width:100%;height:120px;font-size:16px;padding:10px;border:2px solid #003f62;border-radius:8px}button{margin-top:12px;width:100%;padding:14px;font-size:18px;background:#003f62;color:#fff;border:0;border-radius:10px;font-weight:700}#log{margin-top:16px;white-space:pre-wrap;background:#fff;border:1px solid #ccc;border-radius:8px;padding:12px;font-size:13px;max-height:40vh;overflow:auto}</style>
|
| 7 |
-
</head><body>
|
| 8 |
-
<h2>VAI Export Debug</h2>
|
| 9 |
-
<p>Nhập prompt rồi bấm nút. File sẽ có đủ dòng phí. Log hiển thị bên dưới.</p>
|
| 10 |
-
<textarea id="prompt">Malloca ck 35%, giao hàng 200k, lắp đặt 500k, cọc 5tr, ghi chú: giao thứ 7</textarea>
|
| 11 |
-
<button id="go">Xuất Excel Test</button>
|
| 12 |
-
<div id="log">Log sẽ hiện ở đây...</div>
|
| 13 |
-
<script>
|
| 14 |
-
function L(s){var el=document.getElementById('log');el.textContent+=("\n"+s);el.scrollTop=el.scrollHeight;console.log(s);}
|
| 15 |
-
document.getElementById('go').addEventListener('click',async function(){
|
| 16 |
-
L("ExcelJS loaded: "+(typeof ExcelJS!=='undefined'));
|
| 17 |
-
var txt=document.getElementById('prompt').value.trim();
|
| 18 |
-
L("Prompt: "+txt);
|
| 19 |
-
var fees=[];var deposit=0;var note='';
|
| 20 |
-
var m1=txt.match(/giao hàng\s*([\d.,]+)\s*(k|tr|triệu|đ|nghìn)?/i);
|
| 21 |
-
if(m1){var v=parseFloat(m1[1].replace(/[.,]/g,''));var u=(m1[2]||'').toLowerCase();if(u==='k')v*=1000;if(u==='tr'||u==='triệu')v*=1e6;fees.push({label:'Phí giao hàng',amount:v});}
|
| 22 |
-
var m2=txt.match(/lắp đặt\s*([\d.,]+)\s*(k|tr|triệu|đ|nghìn)?/i);
|
| 23 |
-
if(m2){var v=parseFloat(m2[1].replace(/[.,]/g,''));var u=(m2[2]||'').toLowerCase();if(u==='k')v*=1000;if(u==='tr'||u==='triệu')v*=1e6;fees.push({label:'Phí lắp đặt',amount:v});}
|
| 24 |
-
var m3=txt.match(/cọc\s*([\d.,]+)\s*(k|tr|triệu|đ|nghìn)?/i);
|
| 25 |
-
if(m3){var v=parseFloat(m3[1].replace(/[.,]/g,''));var u=(m3[2]||'').toLowerCase();if(u==='k')v*=1000;if(u==='tr'||u==='triệu')v*=1e6;deposit=v;}
|
| 26 |
-
var mn=txt.match(/ghi chú\s*[::]?\s*(.+)$/i);
|
| 27 |
-
if(mn)note=mn[1].trim();
|
| 28 |
-
L("Parsed fees: "+JSON.stringify(fees)+" deposit="+deposit+" note="+note);
|
| 29 |
-
if(typeof ExcelJS==='undefined'){L("ERROR: ExcelJS not loaded - check network/CDN");return;}
|
| 30 |
-
try{
|
| 31 |
-
var wb=new ExcelJS.Workbook();var ws=wb.addWorksheet('BaoGia');
|
| 32 |
-
ws.addRow(['BẢNG BÁO GIÁ']);
|
| 33 |
-
ws.addRow([]);
|
| 34 |
-
ws.addRow(['1','SP Test','MH800TC',1,7350000,4777500,4777500]);
|
| 35 |
-
fees.forEach(function(f){ws.addRow([' '+f.label, f.amount]);L("ROW: "+f.label+" "+f.amount);});
|
| 36 |
-
var total=4777500+fees.reduce(function(a,f){return a+f.amount;},0);
|
| 37 |
-
ws.addRow(['TỔNG CỘNG', total]);
|
| 38 |
-
if(deposit>0){ws.addRow(['Đã cọc',deposit]);ws.addRow(['CÒN LẠI',total-deposit]);}
|
| 39 |
-
if(note)ws.addRow(['Ghi chú: '+note]);
|
| 40 |
-
var buf=await wb.xlsx.writeBuffer();
|
| 41 |
-
var blob=new Blob([buf],{type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
|
| 42 |
-
var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='VAI_debug.xlsx';a.click();
|
| 43 |
-
L("FILE DOWNLOADED OK. Dòng phí: "+(fees.length>0?'CÓ':'KHÔNG'));
|
| 44 |
-
}catch(e){L("EXPORT ERROR: "+e.message);}
|
| 45 |
-
});
|
| 46 |
-
</script>
|
| 47 |
-
</body></html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grob-price-fix.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
| 1 |
-
/**
|
| 2 |
-
* V.AI STUDIO — Grob Price Fix
|
| 3 |
-
* ==============================
|
| 4 |
-
* Fixes incorrect prices from the catalogue-based PDF price list.
|
| 5 |
-
* Fixed as of July 2026 per Grob Vietnam catalogue.
|
| 6 |
-
*/
|
| 7 |
-
(function() {
|
| 8 |
-
'use strict';
|
| 9 |
-
if (window.__GROB_PRICE_FIX__) return;
|
| 10 |
-
window.__GROB_PRICE_FIX__ = true;
|
| 11 |
-
|
| 12 |
-
const PRICE_FIXES = {
|
| 13 |
-
// 0203 | Grob | Bản lề inox - cánh/phủ bì 203mm: 0đ -> 67.000đ
|
| 14 |
-
'0203': { p: '67.000đ', pn: 67000 },
|
| 15 |
-
// 0280 | Grob | Khay chia thìa dĩa nhựa - cánh/phủ bì 280mm: 885.000đ -> 965.000đ
|
| 16 |
-
'0280': { p: '965.000đ', pn: 965000 },
|
| 17 |
-
// 0290 | Grob | Khay chia thìa dĩa nhựa - cánh/phủ bì 290mm: 965.000đ -> 1.018.000đ
|
| 18 |
-
'0290': { p: '1.018.000đ', pn: 1018000 },
|
| 19 |
-
};
|
| 20 |
-
|
| 21 |
-
function patchProduct(prod) {
|
| 22 |
-
if (!prod) return;
|
| 23 |
-
var name = prod.n || prod.name || '';
|
| 24 |
-
for (var code in PRICE_FIXES) {
|
| 25 |
-
if (name.indexOf(code) === 0 && name.indexOf('Grob') !== -1) {
|
| 26 |
-
var fix = PRICE_FIXES[code];
|
| 27 |
-
if (prod.p) prod.p = fix.p;
|
| 28 |
-
if (prod.pn !== undefined) prod.pn = fix.pn;
|
| 29 |
-
if (prod.price) prod.price = fix.p;
|
| 30 |
-
if (prod.priceNum !== undefined) prod.priceNum = fix.pn;
|
| 31 |
-
return true;
|
| 32 |
-
}
|
| 33 |
-
}
|
| 34 |
-
return false;
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
// Patch after D is populated
|
| 38 |
-
function patchD() {
|
| 39 |
-
if (typeof window.D !== 'undefined' && Array.isArray(window.D)) {
|
| 40 |
-
var patched = 0;
|
| 41 |
-
window.D.forEach(function(p) {
|
| 42 |
-
if (patchProduct(p)) patched++;
|
| 43 |
-
});
|
| 44 |
-
if (patched > 0) {
|
| 45 |
-
console.log('[Grob Price Fix] Patched ' + patched + ' product(s) in D');
|
| 46 |
-
// Also sync prices for items already in cart
|
| 47 |
-
patchCart();
|
| 48 |
-
if (typeof window.refreshUI === 'function') window.refreshUI();
|
| 49 |
-
}
|
| 50 |
-
}
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
// Sync Grob prices in cart (localStorage)
|
| 54 |
-
function patchCart() {
|
| 55 |
-
try {
|
| 56 |
-
var cart = JSON.parse(localStorage.getItem('malloca_cart') || '[]');
|
| 57 |
-
if (!Array.isArray(cart) || !cart.length) return;
|
| 58 |
-
var changed = false;
|
| 59 |
-
cart.forEach(function(item) {
|
| 60 |
-
if (patchProduct(item)) changed = true;
|
| 61 |
-
});
|
| 62 |
-
if (changed) {
|
| 63 |
-
localStorage.setItem('malloca_cart', JSON.stringify(cart));
|
| 64 |
-
window.cart = cart;
|
| 65 |
-
console.log('[Grob Price Fix] Synced prices in cart');
|
| 66 |
-
}
|
| 67 |
-
} catch(e) {}
|
| 68 |
-
}
|
| 69 |
-
|
| 70 |
-
// Try patching at various intervals as data loads
|
| 71 |
-
function onReady() {
|
| 72 |
-
setTimeout(patchD, 200);
|
| 73 |
-
setTimeout(patchD, 500);
|
| 74 |
-
setTimeout(patchD, 1000);
|
| 75 |
-
setTimeout(patchD, 2000);
|
| 76 |
-
setTimeout(patchD, 3000);
|
| 77 |
-
setTimeout(patchD, 5000);
|
| 78 |
-
}
|
| 79 |
-
|
| 80 |
-
if (document.readyState === 'loading') {
|
| 81 |
-
document.addEventListener('DOMContentLoaded', onReady);
|
| 82 |
-
} else {
|
| 83 |
-
onReady();
|
| 84 |
-
}
|
| 85 |
-
|
| 86 |
-
console.log('[Grob Price Fix] Loaded: 02.03=67k, 02.80=965k, 02.90=1,018k');
|
| 87 |
-
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grob_img/grob_p1.jpeg
DELETED
|
Binary file (80 kB)
|
|
|
grob_img/grob_p10.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p100.jpeg
DELETED
|
Binary file (51.6 kB)
|
|
|
grob_img/grob_p101.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p102.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p103.jpeg
DELETED
|
Binary file (42 kB)
|
|
|
grob_img/grob_p104.jpeg
DELETED
|
Binary file (20 kB)
|
|
|
grob_img/grob_p105.jpeg
DELETED
|
Binary file (56.2 kB)
|
|
|
grob_img/grob_p106.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p107.jpeg
DELETED
|
Binary file (96 kB)
|
|
|
grob_img/grob_p108.jpeg
DELETED
|
Binary file (86.7 kB)
|
|
|
grob_img/grob_p109.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p11.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p110.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p111.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p112.jpeg
DELETED
|
Binary file (54 kB)
|
|
|
grob_img/grob_p113.jpeg
DELETED
|
Binary file (76.2 kB)
|
|
|
grob_img/grob_p114.jpeg
DELETED
|
Binary file (92.9 kB)
|
|
|
grob_img/grob_p115.jpeg
DELETED
|
Binary file (92.9 kB)
|
|
|
grob_img/grob_p116.jpeg
DELETED
|
Binary file (40.1 kB)
|
|
|
grob_img/grob_p117.jpeg
DELETED
|
Binary file (21.9 kB)
|
|
|
grob_img/grob_p118.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p119.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p12.jpeg
DELETED
|
Binary file (89.4 kB)
|
|
|
grob_img/grob_p120.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p121.jpeg
DELETED
|
Binary file (61.4 kB)
|
|
|
grob_img/grob_p122.jpeg
DELETED
|
Binary file (58.4 kB)
|
|
|
grob_img/grob_p123.jpeg
DELETED
|
Binary file (59.5 kB)
|
|
|
grob_img/grob_p124.jpeg
DELETED
|
Binary file (59.5 kB)
|
|
|
grob_img/grob_p125.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p126.jpeg
DELETED
|
Binary file (33.6 kB)
|
|
|
grob_img/grob_p127.jpeg
DELETED
|
Binary file (64.2 kB)
|
|
|
grob_img/grob_p128.jpeg
DELETED
|
Binary file (41.2 kB)
|
|
|
grob_img/grob_p129.jpeg
DELETED
|
Binary file (51.6 kB)
|
|
|
grob_img/grob_p13.jpeg
DELETED
|
Binary file (98 kB)
|
|
|
grob_img/grob_p130.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p131.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p132.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p133.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p134.jpeg
DELETED
Git LFS Details
|
grob_img/grob_p135.jpeg
DELETED
|
Binary file (48.5 kB)
|
|
|
grob_img/grob_p136.jpeg
DELETED
|
Binary file (67.4 kB)
|
|
|
grob_img/grob_p137.jpeg
DELETED
|
Binary file (24.3 kB)
|
|
|
grob_img/grob_p138.jpeg
DELETED
|
Binary file (52.9 kB)
|
|
|