Khôi phục về commit dee59dc37cb80dffb88b8e5fa3c9a896173119d9
#21
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
- FIX-STATUS.md +0 -41
- debug_export.html +0 -47
- excel-fix-100px.js +0 -149
- 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
.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*
|
FIX-STATUS.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
| 1 |
-
# ✅ FIX HOÀN THÀNH: Phí giao hàng, lắp đặt, cọc được thêm vào Excel
|
| 2 |
-
|
| 3 |
-
## ĐÃ SỬA
|
| 4 |
-
|
| 5 |
-
**File: `qr-payment.js`** - phiên bản v1043
|
| 6 |
-
|
| 7 |
-
### Thay đổi chính:
|
| 8 |
-
|
| 9 |
-
1. **Hàm `_doExportExcel`** - Thêm dòng phí vào Excel:
|
| 10 |
-
- Sau khi in danh sách sản phẩm
|
| 11 |
-
- Thêm các dòng phí: `⊕ Phí giao hàng`, `⊕ Phí lắp đặt`, `⊕ Phí bốc xếp`
|
| 12 |
-
- Cập nhật công thức tổng: `SUM(I{firstItem}:I{lastItem})+SUM(I{feeStart}:I{feeEnd})`
|
| 13 |
-
|
| 14 |
-
2. **Hàm `parsePrompt`** - Cải thiện parsing chi phí:
|
| 15 |
-
- Nhận diện từ khóa: `giao`, `giao hàng`, `ship`, `lắp`, `lắp đặt`, `bốc xếp`
|
| 16 |
-
- Tự động gán nhãn phí phù hợp
|
| 17 |
-
|
| 18 |
-
## CÁCH ÁP DỤNG
|
| 19 |
-
|
| 20 |
-
Do rate limit, bạn cần **thủ công rebuild Space**:
|
| 21 |
-
|
| 22 |
-
1. Vào https://huggingface.co/spaces/bep40/V.AISTUDIO/settings
|
| 23 |
-
2. Chọn tab **Builder**
|
| 24 |
-
3. Nhấn **Rebuild** hoặc **Restart**
|
| 25 |
-
|
| 26 |
-
Hoặc chờ 1-2 phút để Space tự động cập nhật.
|
| 27 |
-
|
| 28 |
-
## KIỂM TRA
|
| 29 |
-
|
| 30 |
-
Sau khi rebuild, mở Space và thử:
|
| 31 |
-
1. Thêm sản phẩm vào giỏ
|
| 32 |
-
2. Nhập vào ô yêu cầu: `giao 200k, lắp 300k, cọc 5tr`
|
| 33 |
-
3. Nhấn nút **⚡ Áp dụng**
|
| 34 |
-
4. Nhấn **Xuất Excel** - file Excel sẽ có các dòng:
|
| 35 |
-
- ⊕ Phí giao hàng: 200,000đ
|
| 36 |
-
- ⊕ Phí lắp đặt: 300,000đ
|
| 37 |
-
- Cọc: 5,000,000đ
|
| 38 |
-
- Còn lại: tổng cộng - cọc
|
| 39 |
-
|
| 40 |
-
---
|
| 41 |
-
PR #24 đã merge vào main.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
excel-fix-100px.js
DELETED
|
@@ -1,149 +0,0 @@
|
|
| 1 |
-
/**
|
| 2 |
-
* V.AI STUDIO - Excel Export v1102
|
| 3 |
-
* FIX: Hình ảnh 100x100px trong Excel
|
| 4 |
-
*/
|
| 5 |
-
(function(){
|
| 6 |
-
'use strict';
|
| 7 |
-
|
| 8 |
-
function fmt(n){
|
| 9 |
-
if(n==null||n==='')return'0đ';
|
| 10 |
-
var num=typeof n==='string'?parseFloat(n.replace(/[^\d.-]/g,'')):Number(n);
|
| 11 |
-
if(isNaN(num))return'0đ';
|
| 12 |
-
return num.toLocaleString('vi-VN')+'đ';
|
| 13 |
-
}
|
| 14 |
-
|
| 15 |
-
async function fetchImageArrayBuffer(url){
|
| 16 |
-
if(!url||!url.startsWith('http')) return null;
|
| 17 |
-
try{
|
| 18 |
-
var r = await fetch(url,{mode:'cors'});
|
| 19 |
-
if(r.ok) return await r.arrayBuffer();
|
| 20 |
-
}catch(e){}
|
| 21 |
-
try{
|
| 22 |
-
var r2 = await fetch('https://api.allorigins.win/raw?url=' + encodeURIComponent(url));
|
| 23 |
-
if(r2.ok) return await r2.arrayBuffer();
|
| 24 |
-
}catch(e){}
|
| 25 |
-
return null;
|
| 26 |
-
}
|
| 27 |
-
|
| 28 |
-
function getOrderCode(){
|
| 29 |
-
var n = document.getElementById('quoteName')?.value || '';
|
| 30 |
-
var h = window.location.hash;
|
| 31 |
-
var today = new Date(), dd=today.getDate().toString().padStart(2,'0'), mm=(today.getMonth()+1).toString().padStart(2,'0'), yy=today.getFullYear().toString().slice(-2);
|
| 32 |
-
var ini='';
|
| 33 |
-
if(n && n.trim()){
|
| 34 |
-
n.trim().split(/\s+/).forEach(function(w){
|
| 35 |
-
if(w && /[A-Z]/.test(w.charAt(0).toUpperCase())) ini += w.charAt(0).toUpperCase();
|
| 36 |
-
});
|
| 37 |
-
}
|
| 38 |
-
return 'VAS'+(ini||'X')+dd+mm+yy;
|
| 39 |
-
}
|
| 40 |
-
|
| 41 |
-
window.exportExcel = async function(){
|
| 42 |
-
var cart = window.cart || [];
|
| 43 |
-
if(!cart.length){alert('Giỏ trống!');return;}
|
| 44 |
-
|
| 45 |
-
if(typeof ExcelJS === 'undefined'){
|
| 46 |
-
var s = document.createElement('script');
|
| 47 |
-
s.src = 'https://cdn.jsdelivr.net/npm/exceljs@4.4.0/dist/exceljs.min.js';
|
| 48 |
-
document.head.appendChild(s);
|
| 49 |
-
await new Promise(function(r){s.onload=r});
|
| 50 |
-
}
|
| 51 |
-
|
| 52 |
-
try{
|
| 53 |
-
var code = getOrderCode();
|
| 54 |
-
var wb = new ExcelJS.Workbook(), ws = wb.addWorksheet('Báo giá');
|
| 55 |
-
|
| 56 |
-
// Column 2 width 15 for 100px image
|
| 57 |
-
ws.columns = [
|
| 58 |
-
{width:6},{width:15},{width:30},{width:15},
|
| 59 |
-
{width:22},{width:8},{width:15},{width:15},{width:18},{width:16}
|
| 60 |
-
];
|
| 61 |
-
|
| 62 |
-
// Header title
|
| 63 |
-
ws.mergeCells('A1:J1');
|
| 64 |
-
ws.getCell('A1').value = 'BẢNG BÁO GIÁ';
|
| 65 |
-
ws.getCell('A1').font = {bold:true, size:18, color:{argb:'FFDB9815'}};
|
| 66 |
-
ws.getCell('A1').alignment = {horizontal:'center'};
|
| 67 |
-
ws.getRow(1).height = 30;
|
| 68 |
-
|
| 69 |
-
// Table header
|
| 70 |
-
var hr = ws.getRow(3);
|
| 71 |
-
['STT','Hình','Tên sản phẩm','Mã SP','Thông tin','SL','Đơn giá','Giá CK','Thành tiền','Ghi chú'].forEach(function(h,i){
|
| 72 |
-
var c = hr.getCell(i+1);
|
| 73 |
-
c.value = h;
|
| 74 |
-
c.font = {bold:true, color:{argb:'FFFFFFFF'}, size:9};
|
| 75 |
-
c.fill = {type:'pattern', pattern:'solid', fgColor:{argb:'FF003F62'}};
|
| 76 |
-
c.alignment = {horizontal:'center', vertical:'middle'};
|
| 77 |
-
});
|
| 78 |
-
hr.height = 20;
|
| 79 |
-
|
| 80 |
-
// Items with 100x100px images
|
| 81 |
-
var firstRow = 5;
|
| 82 |
-
await Promise.all(cart.map(async function(c, i){
|
| 83 |
-
var p = window.D && D[c.idx] ? D[c.idx] : null;
|
| 84 |
-
var row = ws.getRow(firstRow + i);
|
| 85 |
-
row.height = 120; // 100px + padding
|
| 86 |
-
|
| 87 |
-
var bgColor = i % 2 === 0 ? 'FFF8FAFC' : 'FFFFFFFF';
|
| 88 |
-
|
| 89 |
-
row.getCell(1).value = i+1;
|
| 90 |
-
row.getCell(1).alignment = {horizontal:'center', vertical:'middle'};
|
| 91 |
-
|
| 92 |
-
// IMAGE 100x100px
|
| 93 |
-
if((p && p.image) || c.image){
|
| 94 |
-
var imgUrl = p?.image || c.image;
|
| 95 |
-
var imgBuf = await fetchImageArrayBuffer(imgUrl);
|
| 96 |
-
if(imgBuf){
|
| 97 |
-
try{
|
| 98 |
-
wb.addImage(wb.addImage({buffer:imgBuf, extension:'png'}),
|
| 99 |
-
{tl:{col:1, row:firstRow+i-1}, ext:{width:100, height:100}});
|
| 100 |
-
}catch(e){}
|
| 101 |
-
}
|
| 102 |
-
}
|
| 103 |
-
|
| 104 |
-
row.getCell(3).value = c.name || (p?p.name||p.n:'') || '';
|
| 105 |
-
row.getCell(3).font = {bold:true, size:9};
|
| 106 |
-
row.getCell(4).value = c.sku || (p?p.sku||p.model:'') || '';
|
| 107 |
-
row.getCell(6).value = Number(c.qty||1);
|
| 108 |
-
row.getCell(7).value = Number(c.priceNum||(p?p.priceNum:0)||0);
|
| 109 |
-
row.getCell(7).numFmt = '#,##0"đ"';
|
| 110 |
-
row.getCell(8).value = Number(c.priceNum||(p?p.priceNum:0)||0);
|
| 111 |
-
row.getCell(8).numFmt = '#,##0"đ"';
|
| 112 |
-
row.getCell(9).value = Number(c.priceNum||(p?p.priceNum:0)||0) * Number(c.qty||1);
|
| 113 |
-
row.getCell(9).numFmt = '#,##0"đ"';
|
| 114 |
-
|
| 115 |
-
for(var ci=1; ci<=10; ci++){
|
| 116 |
-
row.getCell(ci).fill = {type:'pattern', pattern:'solid', fgColor:{argb:bgColor}};
|
| 117 |
-
}
|
| 118 |
-
}));
|
| 119 |
-
|
| 120 |
-
var lastRow = firstRow + cart.length - 1;
|
| 121 |
-
// Total row
|
| 122 |
-
ws.getCell('A'+(lastRow+2)).value = 'TỔNG CỘNG';
|
| 123 |
-
ws.getCell('A'+(lastRow+2)).font = {bold:true, size:13, color:{argb:'FFFFFFFF'}};
|
| 124 |
-
ws.getCell('A'+(lastRow+2)).fill = {type:'pattern', pattern:'solid', fgColor:{argb:'FF003F62'}};
|
| 125 |
-
ws.getCell('I'+(lastRow+2)).value = {formula:'SUM(I'+firstRow+':I'+lastRow+')'};
|
| 126 |
-
ws.getCell('I'+(lastRow+2)).numFmt = '#,##0"đ"';
|
| 127 |
-
ws.getCell('I'+(lastRow+2)).font = {bold:true, size:14, color:{argb:'FFF0B840'}};
|
| 128 |
-
|
| 129 |
-
wb.calcProperties.fullCalcOnLoad = true;
|
| 130 |
-
var buf = await wb.xlsx.writeBuffer();
|
| 131 |
-
var blob = new Blob([buf], {type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
|
| 132 |
-
var url = URL.createObjectURL(blob);
|
| 133 |
-
var a = document.createElement('a');
|
| 134 |
-
a.href = url;
|
| 135 |
-
a.download = code + '.xlsx';
|
| 136 |
-
document.body.appendChild(a);
|
| 137 |
-
a.click();
|
| 138 |
-
setTimeout(function(){ document.body.removeChild(a); URL.revokeObjectURL(url); }, 30000);
|
| 139 |
-
|
| 140 |
-
console.log('[VAI] Excel export OK - hình ảnh 100px');
|
| 141 |
-
if(typeof showToast === 'function') showToast('✅ Excel OK - Hình ảnh 100px');
|
| 142 |
-
|
| 143 |
-
}catch(e){
|
| 144 |
-
console.error('[VAI] Excel error:', e);
|
| 145 |
-
alert('Lỗi: '+e.message);
|
| 146 |
-
}
|
| 147 |
-
};
|
| 148 |
-
|
| 149 |
-
console.log('[VAI v1102] Excel fix loaded - 100px images ready');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|