Spaces:
Running
Running
Upload order-store.js
Browse files- order-store.js +32 -13
order-store.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
| 1 |
/**
|
| 2 |
-
* V.AI STUDIO — Order Store v19.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
*
|
| 4 |
* CHANGES from v19.1:
|
| 5 |
* - FIX: AbortController 8s timeout cho syncFromServer tránh treo UI khi bot ngủ
|
| 6 |
-
* - FIX: Skip BẢO HÀNH X NĂM/giao thứ X notes khỏi fees/phụ phí
|
| 7 |
*
|
| 8 |
* CHANGES from v18:
|
| 9 |
* - ADD PRODUCT TO ORDER: Nút "➕ Thêm SP" trong modal sửa đơn
|
|
@@ -66,11 +70,11 @@ function syncFromServer(){
|
|
| 66 |
});
|
| 67 |
if(added>0){
|
| 68 |
saveOrders(localOrders);
|
| 69 |
-
console.log('[OS v19.
|
| 70 |
}
|
| 71 |
}).catch(function(e){
|
| 72 |
-
if(e.name==='AbortError'){console.log('[OS v19.
|
| 73 |
-
else{console.log('[OS v19.
|
| 74 |
});
|
| 75 |
}
|
| 76 |
// Sync from server 3s after page load (give bot time to wake up)
|
|
@@ -86,7 +90,7 @@ function processQueue(){
|
|
| 86 |
var q=getQueue();if(!q.length)return;
|
| 87 |
var item=q[0];
|
| 88 |
fetch(KETOAN_API+item.endpoint,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(item.payload)})
|
| 89 |
-
.then(function(r){if(r.ok){q.shift();saveQueue(q);console.log('[OS v19.
|
| 90 |
.catch(function(){item.attempts=(item.attempts||0)+1;if(item.attempts>50){q.shift();}saveQueue(q);});
|
| 91 |
}
|
| 92 |
setInterval(processQueue,30000);
|
|
@@ -187,11 +191,16 @@ function parsePrompt(text){
|
|
| 187 |
// If rest is just a number/unit, skip
|
| 188 |
if(textAfterBrand.match(/^[\d.,\s%(k|tr|trieu|m|đ|vnd)]+$/i)) return;
|
| 189 |
}
|
| 190 |
-
// ===== FIX v19.
|
| 191 |
-
|
| 192 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
var m=lo.match(/([\d.,]+)\s*(k|tr|trieu|m|nghin)?/);
|
| 194 |
-
if(m){var amt2=parseFloat(m[1].replace(/\./g,'').replace(',','.'));var u3=(m[2]||'').toLowerCase();if(u3==='k'||u3==='nghin')amt2*=1000;if(u3==='tr'||u3==='trieu'||u3==='m')amt2*=1000000;if(amt2>0){var lb=line.replace(m[0],'').trim();if(!lb||lb.length<2)lb='Phụ phí';fees.push({label:lb,amount:amt2});}}
|
| 195 |
});
|
| 196 |
return{fees:fees,deposit:deposit,discountPercent:discountPercent,note:note,itemDiscounts:itemDiscounts};
|
| 197 |
}
|
|
@@ -221,6 +230,8 @@ function openSearchModal(){var old=document.getElementById('vai-order-search-mod
|
|
| 221 |
|
| 222 |
function openOrderDetail(order){var old=document.getElementById('vai-order-detail-modal');if(old)old.remove();order=JSON.parse(JSON.stringify(order));var ov=document.createElement('div');ov.id='vai-order-detail-modal';ov.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:10000;display:flex;align-items:flex-start;justify-content:center;padding:16px;overflow-y:auto';ov.onclick=function(e){if(e.target===ov)ov.remove();};document.body.appendChild(ov);var modal=document.createElement('div');modal.style.cssText='background:#fff;border-radius:16px;max-width:750px;width:100%;max-height:92vh;overflow-y:auto';ov.appendChild(modal);
|
| 223 |
var _searchOpen=false;
|
|
|
|
|
|
|
| 224 |
function addProductToOrder(product){
|
| 225 |
var pn=product.priceNum||product.pn||0;
|
| 226 |
var item={name:product.name||product.n||'',model:product.sku||product.model||product.mod||'',brand:product.brand||'',image:product.image||product.img||product.i||'',specs:product.specs||'',info:product.info||product.thong_tin||'',dim_info:product.dim_info||product.dimension_info||'',qty:1,price:pn,discPrice:pn,total:pn,note:''};
|
|
@@ -239,6 +250,8 @@ function openOrderDetail(order){var old=document.getElementById('vai-order-detai
|
|
| 239 |
var db=[];if(typeof D!=='undefined'&&Array.isArray(D))db=D;if(typeof VAI_URL_ADDED_PRODUCTS!=='undefined'&&Array.isArray(VAI_URL_ADDED_PRODUCTS))db=db.concat(VAI_URL_ADDED_PRODUCTS);
|
| 240 |
var nq=nrm(q);var terms=nq.split(/\s+/).filter(function(t){return t.length>1;});
|
| 241 |
var scored=[];
|
|
|
|
|
|
|
| 242 |
for(var i=0;i<db.length;i++){
|
| 243 |
var p=db[i];if(!p)continue;
|
| 244 |
var name=nrm(p.name||p.n||'');var sku=nrm(p.sku||p.model||p.mod||'');var brand=nrm(p.brand||'');
|
|
@@ -339,9 +352,15 @@ function openOrderDetail(order){var old=document.getElementById('vai-order-detai
|
|
| 339 |
// Close search panel
|
| 340 |
var closeSpBtn=document.getElementById('od-sp-close');
|
| 341 |
if(closeSpBtn){closeSpBtn.onclick=function(){_searchOpen=false;render();};}
|
| 342 |
-
// Search input
|
| 343 |
var searchInput=document.getElementById('od-sp-search');
|
| 344 |
-
if(searchInput){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 345 |
// Render search results if panel is open
|
| 346 |
if(_searchOpen){renderSearchResults();}
|
| 347 |
function cc(){order.customer=document.getElementById('od-name').value;order.phone=document.getElementById('od-phone').value;order.addr=document.getElementById('od-addr').value;}
|
|
@@ -373,5 +392,5 @@ var _mO=new MutationObserver(function(){setTimeout(injectMaKHToQuote,500);});_mO
|
|
| 373 |
|
| 374 |
window.VAI_ORDERS={save:saveCurrentOrder,search:searchOrders,openSearch:openSearchModal,openDetail:openOrderDetail,getAll:getOrders,getByCode:function(c){return getOrders().find(function(o){return o.code===c;});},add:addOrder,delete:deleteOrder,confirm:confirmOrder,unconfirm:unconfirmOrder,toVAIData:orderToVAIData,loadKH:loadKhachHang,findKH:findKH,processQueue:processQueue,syncFromServer:syncFromServer};
|
| 375 |
var qLen=getQueue().length;
|
| 376 |
-
console.log('[OS v19.
|
| 377 |
})();
|
|
|
|
| 1 |
/**
|
| 2 |
+
* V.AI STUDIO — Order Store v19.3
|
| 3 |
+
*
|
| 4 |
+
* CHANGES from v19.2:
|
| 5 |
+
* - FIX: searchProducts debounce 200ms → không treo UI khi gõ tìm SP
|
| 6 |
+
* - FIX: parsePrompt fallback không đẩy text có số vào notes, thành Phụ phí
|
| 7 |
+
* - FIX: Vẫn skip BẢO HÀNH X NĂM/giao thứ X notes khỏi phụ phí
|
| 8 |
*
|
| 9 |
* CHANGES from v19.1:
|
| 10 |
* - FIX: AbortController 8s timeout cho syncFromServer tránh treo UI khi bot ngủ
|
|
|
|
| 11 |
*
|
| 12 |
* CHANGES from v18:
|
| 13 |
* - ADD PRODUCT TO ORDER: Nút "➕ Thêm SP" trong modal sửa đơn
|
|
|
|
| 70 |
});
|
| 71 |
if(added>0){
|
| 72 |
saveOrders(localOrders);
|
| 73 |
+
console.log('[OS v19.3] ☁️ Synced '+added+' orders from server. Total local: '+localOrders.length);
|
| 74 |
}
|
| 75 |
}).catch(function(e){
|
| 76 |
+
if(e.name==='AbortError'){console.log('[OS v19.3] Server sync timeout (8s) — bot sleeping, skip');}
|
| 77 |
+
else{console.log('[OS v19.3] Server sync skip (bot may be sleeping)');}
|
| 78 |
});
|
| 79 |
}
|
| 80 |
// Sync from server 3s after page load (give bot time to wake up)
|
|
|
|
| 90 |
var q=getQueue();if(!q.length)return;
|
| 91 |
var item=q[0];
|
| 92 |
fetch(KETOAN_API+item.endpoint,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(item.payload)})
|
| 93 |
+
.then(function(r){if(r.ok){q.shift();saveQueue(q);console.log('[OS v19.3] Queue sync OK: '+item.endpoint+' ('+q.length+' remaining)');if(q.length)setTimeout(processQueue,2000);}else throw new Error('HTTP '+r.status);})
|
| 94 |
.catch(function(){item.attempts=(item.attempts||0)+1;if(item.attempts>50){q.shift();}saveQueue(q);});
|
| 95 |
}
|
| 96 |
setInterval(processQueue,30000);
|
|
|
|
| 191 |
// If rest is just a number/unit, skip
|
| 192 |
if(textAfterBrand.match(/^[\d.,\s%(k|tr|trieu|m|đ|vnd)]+$/i)) return;
|
| 193 |
}
|
| 194 |
+
// ===== FIX v19.3: Skip note patterns nhưng KHÔNG chặn fee detection =====
|
| 195 |
+
var isNotePattern=false;
|
| 196 |
+
if(lo.match(/bao.hanh\s*\d+\s*(nam|thang)/)){isNotePattern=true;}
|
| 197 |
+
if(!isNotePattern&&lo.match(/giao\s+(thu|ngay)\s*\d+/)){isNotePattern=true;}
|
| 198 |
+
if(!isNotePattern&&lo.match(/\b(nam|thang)\s*(bao.hanh)/)){isNotePattern=true;}
|
| 199 |
+
if(isNotePattern)return;
|
| 200 |
+
// === End note skip ===
|
| 201 |
+
// Fallback: line with number → Phụ phí (không đẩy vào notes)
|
| 202 |
var m=lo.match(/([\d.,]+)\s*(k|tr|trieu|m|nghin)?/);
|
| 203 |
+
if(m){var amt2=parseFloat(m[1].replace(/\./g,'').replace(',','.'));var u3=(m[2]||'').toLowerCase();if(u3==='k'||u3==='nghin')amt2*=1000;if(u3==='tr'||u3==='trieu'||u3==='m')amt2*=1000000;if(amt2>0){var lb=line.replace(m[0],'').trim();if(!lb||lb.length<2)lb='Phụ phí';else lb='Phụ phí';fees.push({label:lb,amount:amt2});}}
|
| 204 |
});
|
| 205 |
return{fees:fees,deposit:deposit,discountPercent:discountPercent,note:note,itemDiscounts:itemDiscounts};
|
| 206 |
}
|
|
|
|
| 230 |
|
| 231 |
function openOrderDetail(order){var old=document.getElementById('vai-order-detail-modal');if(old)old.remove();order=JSON.parse(JSON.stringify(order));var ov=document.createElement('div');ov.id='vai-order-detail-modal';ov.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:10000;display:flex;align-items:flex-start;justify-content:center;padding:16px;overflow-y:auto';ov.onclick=function(e){if(e.target===ov)ov.remove();};document.body.appendChild(ov);var modal=document.createElement('div');modal.style.cssText='background:#fff;border-radius:16px;max-width:750px;width:100%;max-height:92vh;overflow-y:auto';ov.appendChild(modal);
|
| 232 |
var _searchOpen=false;
|
| 233 |
+
// ===== FIX v19.3: Debounce cho searchProducts =====
|
| 234 |
+
var _searchDebounceTimer=null;
|
| 235 |
function addProductToOrder(product){
|
| 236 |
var pn=product.priceNum||product.pn||0;
|
| 237 |
var item={name:product.name||product.n||'',model:product.sku||product.model||product.mod||'',brand:product.brand||'',image:product.image||product.img||product.i||'',specs:product.specs||'',info:product.info||product.thong_tin||'',dim_info:product.dim_info||product.dimension_info||'',qty:1,price:pn,discPrice:pn,total:pn,note:''};
|
|
|
|
| 250 |
var db=[];if(typeof D!=='undefined'&&Array.isArray(D))db=D;if(typeof VAI_URL_ADDED_PRODUCTS!=='undefined'&&Array.isArray(VAI_URL_ADDED_PRODUCTS))db=db.concat(VAI_URL_ADDED_PRODUCTS);
|
| 251 |
var nq=nrm(q);var terms=nq.split(/\s+/).filter(function(t){return t.length>1;});
|
| 252 |
var scored=[];
|
| 253 |
+
// Giới hạn quét: chỉ quét thực sự khi có terms
|
| 254 |
+
if(!terms.length)return[];
|
| 255 |
for(var i=0;i<db.length;i++){
|
| 256 |
var p=db[i];if(!p)continue;
|
| 257 |
var name=nrm(p.name||p.n||'');var sku=nrm(p.sku||p.model||p.mod||'');var brand=nrm(p.brand||'');
|
|
|
|
| 352 |
// Close search panel
|
| 353 |
var closeSpBtn=document.getElementById('od-sp-close');
|
| 354 |
if(closeSpBtn){closeSpBtn.onclick=function(){_searchOpen=false;render();};}
|
| 355 |
+
// Search input v19.3: debounce 200ms để tránh treo UI
|
| 356 |
var searchInput=document.getElementById('od-sp-search');
|
| 357 |
+
if(searchInput){
|
| 358 |
+
searchInput.oninput=function(){
|
| 359 |
+
if(_searchDebounceTimer)clearTimeout(_searchDebounceTimer);
|
| 360 |
+
_searchDebounceTimer=setTimeout(function(){renderSearchResults();},200);
|
| 361 |
+
};
|
| 362 |
+
searchInput.onkeydown=function(e){if(e.key==='Escape'){_searchOpen=false;render();}};
|
| 363 |
+
}
|
| 364 |
// Render search results if panel is open
|
| 365 |
if(_searchOpen){renderSearchResults();}
|
| 366 |
function cc(){order.customer=document.getElementById('od-name').value;order.phone=document.getElementById('od-phone').value;order.addr=document.getElementById('od-addr').value;}
|
|
|
|
| 392 |
|
| 393 |
window.VAI_ORDERS={save:saveCurrentOrder,search:searchOrders,openSearch:openSearchModal,openDetail:openOrderDetail,getAll:getOrders,getByCode:function(c){return getOrders().find(function(o){return o.code===c;});},add:addOrder,delete:deleteOrder,confirm:confirmOrder,unconfirm:unconfirmOrder,toVAIData:orderToVAIData,loadKH:loadKhachHang,findKH:findKH,processQueue:processQueue,syncFromServer:syncFromServer};
|
| 394 |
var qLen=getQueue().length;
|
| 395 |
+
console.log('[OS v19.3] '+getOrders().length+' orders'+(qLen?' | ⏳ '+qLen+' pending sync':'')+' | ☁️ Server sync enabled | ➕ Add product to order enabled | 🛠️ Debounce search 200ms | 🚫 Skip BH/giao thứ X notes');
|
| 396 |
})();
|