create_base_frontend.py
7.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/usr/bin/env python3
"""
Create frontend JavaScript file for base configuration.
"""
import sys
import os
import argparse
import re
from pathlib import Path
# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent.parent))
def create_base_frontend_js(tenant_id: str, api_port: int = 6002, output_file: str = "frontend/static/js/app_base.js"):
"""
Create frontend JavaScript file for base configuration.
Args:
tenant_id: Tenant ID
api_port: API port
output_file: Output file path
"""
# Read original app.js
original_file = Path(__file__).parent.parent / "frontend/static/js/app.js"
if not original_file.exists():
print(f"ERROR: Original frontend file not found: {original_file}")
return 1
with open(original_file, 'r', encoding='utf-8') as f:
content = f.read()
# Replace API_BASE_URL
api_url = f"http://localhost:{api_port}"
content = content.replace(
"const API_BASE_URL = 'http://120.76.41.98:6002';",
f"const API_BASE_URL = '{api_url}';"
)
# Add tenant_id constant at the beginning
content = content.replace(
"const API_BASE_URL =",
f"const TENANT_ID = '{tenant_id}';\nconst API_BASE_URL ="
)
# Update facets for base configuration
base_facets = ''' const facets = [
{
"field": "category_keyword",
"size": 15,
"type": "terms"
},
{
"field": "vendor_keyword",
"size": 15,
"type": "terms"
},
{
"field": "tags_keyword",
"size": 10,
"type": "terms"
},
{
"field": "min_price",
"type": "range",
"ranges": [
{"key": "0-50", "to": 50},
{"key": "50-100", "from": 50, "to": 100},
{"key": "100-200", "from": 100, "to": 200},
{"key": "200+", "from": 200}
]
}
];'''
# Find and replace facets definition (multiline match)
facets_pattern = r'const facets = \[.*?\];'
content = re.sub(facets_pattern, base_facets, content, flags=re.DOTALL)
# Update fetch to include tenant_id header
content = content.replace(
"headers: {\n 'Content-Type': 'application/json',\n },",
f"headers: {{\n 'Content-Type': 'application/json',\n 'X-Tenant-ID': TENANT_ID,\n }},"
)
# Replace hits with results throughout
content = re.sub(r'\bdata\.hits\b', 'data.results', content)
content = re.sub(r'!data\.hits', '!data.results', content)
# Replace hit loop with product loop
content = re.sub(
r'data\.hits\.forEach\(\(hit\) => \{',
'data.results.forEach((product) => {',
content
)
# Remove source extraction lines
content = re.sub(r'const source = hit\._source;\s*\n', '', content)
content = re.sub(r'const score = hit\._custom_score \|\| hit\._score;\s*\n', 'const score = product.relevance_score;\n', content)
# Replace all source. references with product.
content = re.sub(r'\bsource\.', 'product.', content)
# Replace specific field names for base configuration
# imageUrl -> image_url
content = re.sub(r'product\.imageUrl', 'product.image_url', content)
# name -> title
content = re.sub(r'product\.name', 'product.title', content)
content = re.sub(r'product\.enSpuName', 'product.title', content)
# categoryName -> category
content = re.sub(r'product\.categoryName', 'product.category', content)
# brandName -> vendor
content = re.sub(r'product\.brandName', 'product.vendor', content)
# price -> price (already correct)
# Remove moq and quantity fields (not in base config)
content = re.sub(r'<div class="product-moq">.*?</div>\s*\n', '', content, flags=re.DOTALL)
content = re.sub(r'<div class="product-quantity">.*?</div>\s*\n', '', content, flags=re.DOTALL)
# Add stock and variants display
# Find the product-price div and add stock info after it
stock_info = ''' <div class="product-stock">
${product.in_stock ? '<span style="color: green;">In Stock</span>' : '<span style="color: red;">Out of Stock</span>'}
${product.variants && product.variants.length > 0 ? `<span style="color: #666; font-size: 0.9em;">(${product.variants.length} variants)</span>` : ''}
</div>
'''
content = re.sub(
r'(<div class="product-price">.*?</div>\s*\n)',
r'\1' + stock_info,
content,
flags=re.DOTALL
)
# Update price display format
content = re.sub(
r'\$\{product\.price \? `\$\{product\.price\} ₽` : \'N/A\'\}',
'${product.price ? `$${product.price.toFixed(2)}` : \'N/A\'}',
content
)
# Add compare_at_price if exists
content = re.sub(
r'(\$\{product\.price \? `\$\$\{product\.price\.toFixed\(2\)\}` : \'N/A\'\})',
r'\1${product.compare_at_price && product.compare_at_price > product.price ? `<span style="text-decoration: line-through; color: #999; font-size: 0.9em; margin-left: 8px;">$${product.compare_at_price.toFixed(2)}</span>` : \'\'}',
content
)
# Update product-meta to use base config fields
content = re.sub(
r'<div class="product-meta">\s*\$\{product\.category \? escapeHtml\(product\.category\) : \'\'\}\s*\$\{product\.vendor \? \' \| \' \+ escapeHtml\(product\.vendor\) : \'\'\}\s*</div>',
'<div class="product-meta">${product.vendor ? escapeHtml(product.vendor) : \'\'}${product.product_type ? \' | \' + escapeHtml(product.product_type) : \'\'}${product.category ? \' | \' + escapeHtml(product.category) : \'\'}</div>',
content
)
# Remove create_time display (not in base config)
content = re.sub(
r'\$\{product\.create_time \? `.*?</div>\s*` : \'\'\}',
'',
content,
flags=re.DOTALL
)
# Add tags display if exists
tags_display = ''' ${product.tags ? `
<div class="product-tags">
Tags: ${escapeHtml(product.tags)}
</div>
` : ''}'''
# Add tags before closing product-card div
content = re.sub(
r'(</div>\s*</div>\s*`;\s*\n\s*\}\);)',
tags_display + r'\n </div>\n `;\n });',
content,
count=1
)
# Update displayFacets for base configuration field names
content = re.sub(
r"facet\.field === 'categoryName_keyword'",
"facet.field === 'category_keyword'",
content
)
content = re.sub(
r"facet\.field === 'brandName_keyword'",
"facet.field === 'vendor_keyword'",
content
)
content = re.sub(
r"facet\.field === 'supplierName_keyword'",
"facet.field === 'tags_keyword'",
content
)
# Write output file
output_path = Path(__file__).parent.parent / output_file
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f"Created base frontend JavaScript: {output_path}")
return 0
def main():
parser = argparse.ArgumentParser(description='Create frontend JavaScript for base configuration')
parser.add_argument('--tenant-id', default='1', help='Tenant ID')
parser.add_argument('--api-port', type=int, default=6002, help='API port')
parser.add_argument('--output', default='frontend/static/js/app_base.js', help='Output file')
args = parser.parse_args()
return create_base_frontend_js(args.tenant_id, args.api_port, args.output)
if __name__ == '__main__':
sys.exit(main())