Spaces:
Running
Running
Fix search: strip . - space from queries for SKU matching, add cleaned SKU to search index
Browse files- index.html +10 -4
index.html
CHANGED
|
@@ -712,25 +712,31 @@ function nVN(s){return s.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]
|
|
| 712 |
const SYN={'ke':['gia'],'gia':['ke'],'bat':['chen'],'chen':['bat'],'xoong':['noi'],'noi':['xoong'],'dao':['thot'],'thot':['dao'],'ray':['truot'],'truot':['ray'],'khoa':['lock'],'lock':['khoa'],'bon':['chau'],'chau':['bon'],'ro':['gia','ke']};
|
| 713 |
|
| 714 |
function smartSearch(query,text){
|
| 715 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
| 716 |
if(text.includes(query))return true;
|
| 717 |
// 2. Split into words, ALL must match (any order)
|
| 718 |
let words=query.split(/\s+/).filter(w=>w);
|
| 719 |
if(!words.length)return true;
|
| 720 |
let matched=0;
|
| 721 |
for(let w of words){
|
| 722 |
-
|
|
|
|
| 723 |
// Try synonym
|
| 724 |
let hit=false;
|
| 725 |
if(SYN[w]){for(let s of SYN[w]){if(text.includes(s)){hit=true;break;}}}
|
| 726 |
if(hit){matched++;continue;}
|
| 727 |
}
|
| 728 |
-
// All words must match
|
| 729 |
return matched===words.length;
|
| 730 |
}
|
| 731 |
function buildSearchIndex(p){
|
| 732 |
-
// Only index product-specific content, NOT generic category names
|
| 733 |
let parts=[p.name,p.sku,p.model,p.brand,p.price];
|
|
|
|
|
|
|
|
|
|
| 734 |
if(p.feats&&p.feats.length)parts.push(p.feats.join(' '));
|
| 735 |
if(p.specs){Object.entries(p.specs).forEach(([k,v])=>{parts.push(k);parts.push(String(v))})}
|
| 736 |
// AI semantic keywords based on product name
|
|
|
|
| 712 |
const SYN={'ke':['gia'],'gia':['ke'],'bat':['chen'],'chen':['bat'],'xoong':['noi'],'noi':['xoong'],'dao':['thot'],'thot':['dao'],'ray':['truot'],'truot':['ray'],'khoa':['lock'],'lock':['khoa'],'bon':['chau'],'chau':['bon'],'ro':['gia','ke']};
|
| 713 |
|
| 714 |
function smartSearch(query,text){
|
| 715 |
+
// Strip . - space from query for SKU matching
|
| 716 |
+
let cleanQ=query.replace(/[.\- ]/g,'');
|
| 717 |
+
let cleanT=text.replace(/[.\- ]/g,'');
|
| 718 |
+
// 1. Exact substring on cleaned versions
|
| 719 |
+
if(cleanT.includes(cleanQ))return true;
|
| 720 |
if(text.includes(query))return true;
|
| 721 |
// 2. Split into words, ALL must match (any order)
|
| 722 |
let words=query.split(/\s+/).filter(w=>w);
|
| 723 |
if(!words.length)return true;
|
| 724 |
let matched=0;
|
| 725 |
for(let w of words){
|
| 726 |
+
let cw=w.replace(/[.\-]/g,'');
|
| 727 |
+
if(text.includes(w)||cleanT.includes(cw)){matched++;continue;}
|
| 728 |
// Try synonym
|
| 729 |
let hit=false;
|
| 730 |
if(SYN[w]){for(let s of SYN[w]){if(text.includes(s)){hit=true;break;}}}
|
| 731 |
if(hit){matched++;continue;}
|
| 732 |
}
|
|
|
|
| 733 |
return matched===words.length;
|
| 734 |
}
|
| 735 |
function buildSearchIndex(p){
|
|
|
|
| 736 |
let parts=[p.name,p.sku,p.model,p.brand,p.price];
|
| 737 |
+
// Add cleaned SKU/model (no . - space) for search
|
| 738 |
+
if(p.sku)parts.push(p.sku.replace(/[.\- ]/g,''));
|
| 739 |
+
if(p.model)parts.push(p.model.replace(/[.\- ]/g,''));
|
| 740 |
if(p.feats&&p.feats.length)parts.push(p.feats.join(' '));
|
| 741 |
if(p.specs){Object.entries(p.specs).forEach(([k,v])=>{parts.push(k);parts.push(String(v))})}
|
| 742 |
// AI semantic keywords based on product name
|