ts-glitter 16.2.4 → 16.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@ import contollers = require('./controllers');
10
10
  import public_contollers = require('./api-public/controllers');
11
11
  import database from './modules/database';
12
12
  import {SaasScheme} from './services/saas-table-check';
13
+
13
14
  import db from './modules/database';
14
15
  import {createBucket, listBuckets} from './modules/AWSLib';
15
16
  import {Live_source} from './live_source';
@@ -41,6 +42,7 @@ import {Manager} from "./api-public/services/manager.js";
41
42
  import {SitemapStream, streamToPromise} from "sitemap";
42
43
  import {Readable} from "stream";
43
44
  import AWS from "aws-sdk";
45
+ import {extractCols, extractProds, SeoConfig} from "./seo-config.js";
44
46
 
45
47
  export const app = express();
46
48
  const logger = new Logger();
@@ -122,80 +124,10 @@ async function createAppRoute() {
122
124
  }
123
125
  }
124
126
 
125
- function extractCols(data: {
126
- value: {
127
- code: string;
128
- array: { code: string }[];
129
- }[];
130
- updated_at: Date;
131
- }) {
132
- const items: any = [];
133
- const updated_at = new Date(data.updated_at).toISOString().replace(/\.\d{3}Z$/, '+00:00');
134
- data.value.map((item: any) => {
135
- items.push({
136
- code: item.code,
137
- updated_at,
138
- seo_title: item.seo_title,
139
- seo_image: item.seo_image,
140
- seo_content: item.seo_content,
141
- });
142
- if (item.array && item.array.length > 0) {
143
- item.array.map((child: any) => {
144
- items.push({
145
- code: child.code,
146
- updated_at,
147
- seo_title: child.seo_title,
148
- seo_image: child.seo_image,
149
- seo_content: child.seo_content,
150
- });
151
- });
152
- }
153
- });
154
- return items;
155
- }
156
-
157
- function extractProds(data: any) {
158
- const items: any = [];
159
- data.map((item: any) => {
160
- const code = (() => {
161
- try {
162
- return item.content.seo.domain;
163
- } catch (error) {
164
- return '';
165
- }
166
- })();
167
- const updated_at = new Date(item.updated_time).toISOString().replace(/\.\d{3}Z$/, '+00:00');
168
- items.push({code, updated_at});
169
- });
170
- return items;
171
- }
172
127
 
173
128
  // 信任代理
174
129
  app.set('trust proxy', true);
175
130
 
176
- // 判斷現在時間是否在 start 和 end 之間的函數
177
- function isCurrentTimeWithinRange(data: {
178
- startDate: string;
179
- startTime: string;
180
- endDate?: string;
181
- endTime?: string
182
- }): boolean {
183
- const now = new Date();
184
- now.setTime(now.getTime() + 8 * 3600 * 1000);
185
- // 組合 start 的完整日期時間
186
- const startDateTime = new Date(`${data.startDate}T${data.startTime}`);
187
-
188
- // 若 endDate 或 endTime 為 undefined,視為無期限
189
- const hasEnd = data.endDate && data.endTime;
190
- const endDateTime = hasEnd ? new Date(`${data.endDate}T${data.endTime}`) : null;
191
-
192
- // 判斷現在時間是否在範圍內
193
- if (hasEnd) {
194
- return now >= startDateTime && now <= endDateTime!;
195
- } else {
196
- return now >= startDateTime;
197
- }
198
- }
199
131
 
200
132
  export async function createAPP(dd: any) {
201
133
  const html = String.raw;
@@ -222,8 +154,18 @@ export async function createAPP(dd: any) {
222
154
  req.headers['g-app'] = appName;
223
155
  const start = new Date().getTime();
224
156
  console.log(`getPageInfo==>`, (new Date().getTime() - start) / 1000);
225
-
226
- let [customCode, FBCode, store_info, language_label] = await Promise.all([new User(appName).getConfigV2({
157
+ //SEO內容
158
+ let seo_content: string[] = []
159
+ let [
160
+ customCode,
161
+ FBCode,
162
+ store_info,
163
+ language_label,
164
+ check_schema,
165
+ brandAndMemberType,
166
+ login_config,
167
+ ip_country
168
+ ] = await Promise.all([new User(appName).getConfigV2({
227
169
  key: 'ga4_config',
228
170
  user_id: 'manager',
229
171
  }), new User(appName).getConfigV2({
@@ -235,57 +177,20 @@ export async function createAPP(dd: any) {
235
177
  }), new User(appName).getConfigV2({
236
178
  key: 'language-label',
237
179
  user_id: 'manager',
238
- })])
180
+ }), ApiPublic.createScheme(appName),
181
+ App.checkBrandAndMemberType(appName), new User(req.get('g-app') as string, req.body.token).getConfigV2({
182
+ key: 'login_config',
183
+ user_id: 'manager',
184
+ }), User.ipInfo((req.query.ip || req.headers['x-real-ip'] || req.ip) as string)])
239
185
  //取得多國語言
240
- const language = (() => {
241
- function checkIncludes(lan: string) {
242
- return store_info.language_setting.support.includes(lan);
243
- }
244
-
245
- function checkEqual(lan: string) {
246
- return `${req.query.page}`.startsWith(`${lan}/`) || req.query.page === lan;
247
- }
248
-
249
- function replace(lan: string) {
250
- if (req.query.page === lan) {
251
- req.query.page = '';
252
- } else {
253
- req.query.page = `${req.query.page}`.replace(lan + '/', '');
254
- }
255
- }
256
-
257
- if (checkEqual('en') && checkIncludes('en-US')) {
258
- replace('en');
259
- return `en-US`;
260
- } else if (checkEqual('cn') && checkIncludes('zh-CN')) {
261
- replace('cn');
262
- return `zh-CN`;
263
- } else if (checkEqual('tw') && checkIncludes('zh-TW')) {
264
- replace('tw');
265
- return `zh-TW`;
266
- } else {
267
- return store_info.language_setting.def;
268
- }
269
- })();
270
- console.log(`req.query.page===>`, req.query.page);
186
+ const language: any = await SeoConfig.language(store_info, req)
271
187
  //插入瀏覽紀錄
272
188
  Monitor.insertHistory({
273
189
  req_type: 'file',
274
190
  req: req,
275
191
  });
276
- console.log(`insertHistory==>`, (new Date().getTime() - start) / 1000);
277
- //確認資料庫是否存在
278
- await ApiPublic.createScheme(appName);
279
- console.log(`createScheme==>`, (new Date().getTime() - start) / 1000);
280
- //確認SAAS用戶資訊
281
- const brandAndMemberType = await App.checkBrandAndMemberType(appName);
282
- console.log(`brandAndMemberType==>`, (new Date().getTime() - start) / 1000);
283
- //取得Login config
284
- const login_config = await new User(req.get('g-app') as string, req.body.token).getConfigV2({
285
- key: 'login_config',
286
- user_id: 'manager',
287
- });
288
- //取得頁面資訊
192
+ console.log(`req.query.page==>`, req.query.page)
193
+ //取得SEO頁面資訊
289
194
  let data = await Seo.getPageInfo(appName, req.query.page as string, language);
290
195
  //首頁SEO
291
196
  let home_page_data = await (async () => {
@@ -295,61 +200,34 @@ export async function createAPP(dd: any) {
295
200
  return await Seo.getPageInfo(appName, 'index', language);
296
201
  }
297
202
  })();
203
+ console.log(`req.query.page==>`, req.query.page)
298
204
  if (data && data.page_config) {
299
205
  data.page_config = data.page_config ?? {};
300
206
  const d = data.page_config.seo ?? {};
301
- if (data.page_type === 'article' && data.page_config.template_type === 'product') {
302
- const product_domain = (req.query.page as string).split('/')[1];
303
- const pd = await new Shopping(appName, undefined).getProduct(
304
- product_domain
305
- ? {
306
- page: 0,
307
- limit: 1,
308
- domain: decodeURIComponent(product_domain),
309
- language: language,
310
- }
311
- : {
312
- page: 0,
313
- limit: 1,
314
- id: req.query.product_id as string,
315
- language: language,
316
- }
317
- );
318
-
319
- if (pd.data.content) {
320
- pd.data.content.language_data = pd.data.content.language_data ?? {};
321
- const productSeo = (pd.data.content.language_data[language] && pd.data.content.language_data[language].seo) || (pd.data.content.seo ?? {});
322
- data = await Seo.getPageInfo(appName, data.config.homePage, language);
323
- data.page_config = data.page_config ?? {};
324
- data.page_config.seo = data.page_config.seo ?? {};
325
- data.page_config.seo.title = productSeo.title;
326
- data.page_config.seo.image = pd.data.content.preview_image[0];
327
- data.page_config.seo.content = productSeo.content;
328
- } else {
329
- data = await Seo.getPageInfo(appName, data.config.homePage, language);
330
- }
331
- } else if (data.page_type === 'article' && data.page_config.template_type === 'blog') {
332
- req.query.article = req.query.article || (req.query.page as any).split('/')[1];
333
- let query = [`(content->>'$.type'='article')`, `(content->>'$.tag'='${req.query.article}')`];
334
- const article: any = await new UtDatabase(appName, `t_manager_post`).querySql(query, {
335
- page: 0,
336
- limit: 1,
337
- });
338
- data = await Seo.getPageInfo(appName, data.config.homePage, language);
339
- data.page_config = data.page_config ?? {};
340
- data.page_config.seo = data.page_config.seo ?? {};
341
- if (article.data[0]) {
342
- if (article.data[0].content.language_data && article.data[0].content.language_data[language]) {
343
- data.page_config.seo.title = article.data[0].content.language_data[language].seo.title;
344
- data.page_config.seo.content = article.data[0].content.language_data[language].seo.content;
345
- data.page_config.seo.keywords = article.data[0].content.language_data[language].seo.keywords;
346
- } else {
347
- data.page_config.seo.title = article.data[0].content.seo.title;
348
- data.page_config.seo.content = article.data[0].content.seo.content;
349
- data.page_config.seo.keywords = article.data[0].content.seo.keywords;
350
- }
351
-
352
- }
207
+ console.log(`req.query.page`)
208
+ //商品搜索
209
+ if (`${req.query.page}`.startsWith('products/')) {
210
+ await SeoConfig.productSEO({
211
+ data,
212
+ language,
213
+ appName,
214
+ product_id: req.query.product_id as any,
215
+ page: (req.query.page) as any
216
+ })
217
+ } else if (`${req.query.page}`.startsWith('blogs/')) {
218
+ //網誌搜索
219
+ await SeoConfig.articleSeo({
220
+ article: req.query.article as any,
221
+ page: req.query.page as any,
222
+ language, appName, data
223
+ })
224
+ } else if (`${req.query.page}`.startsWith('pages/')) {
225
+ //頁面搜索
226
+ await SeoConfig.articleSeo({
227
+ article: req.query.article as any,
228
+ page: req.query.page as any,
229
+ language, appName, data
230
+ })
353
231
  } else if (d.type !== 'custom') {
354
232
  data = home_page_data;
355
233
  }
@@ -380,183 +258,119 @@ export async function createAPP(dd: any) {
380
258
  localStorage.setItem('distributionCode','');
381
259
  `;
382
260
  }
261
+ //分銷連結頁面SEO
383
262
  if ((req.query.page as string).split('/')[0] === 'distribution' && (req.query.page as string).split('/')[1]) {
384
- const redURL = new URL(`https://127.0.0.1${req.url}`);
385
-
386
- const rec = await db.query(
387
- `SELECT *
388
- FROM \`${appName}\`.t_recommend_links
389
- WHERE content ->>'$.link' = ?;
390
- `,
391
- [(req.query.page as string).split('/')[1]]
392
- );
393
- const page = rec[0] && rec[0].content ? rec[0].content : {status: false};
394
-
395
- if (page.status && isCurrentTimeWithinRange(page)) {
396
- let query = [`(content->>'$.type'='article')`, `(content->>'$.tag'='${page.redirect.split('/')[2]}')`];
397
- const article: any = await new UtDatabase(appName, `t_manager_post`).querySql(query, {
398
- page: 0,
399
- limit: 1,
400
- });
401
- data = await Seo.getPageInfo(appName, data.config.homePage, language);
402
- data.page_config = data.page_config ?? {};
403
- data.page_config.seo = data.page_config.seo ?? {};
404
- if (article.data[0]) {
405
- if (article.data[0].content.language_data[language]) {
406
- data.page_config.seo.title = article.data[0].content.language_data[language].seo.title;
407
- data.page_config.seo.content = article.data[0].content.language_data[language].seo.content;
408
- data.page_config.seo.keywords = article.data[0].content.language_data[language].seo.keywords;
409
- } else {
410
- data.page_config.seo.title = article.data[0].content.seo.title;
411
- data.page_config.seo.content = article.data[0].content.seo.content;
412
- data.page_config.seo.keywords = article.data[0].content.seo.keywords;
413
- }
414
-
415
- }
416
- distribution_code = `
417
- localStorage.setItem('distributionCode','${page.code}');
418
- location.href = '${link_prefix ? `/` : ``}${link_prefix}${page.redirect}${redURL.search}';
419
- `;
420
- } else {
421
- distribution_code = `
422
- location.href = '/';
423
- `;
424
- }
263
+ distribution_code = await SeoConfig.distributionSEO({
264
+ appName: appName,
265
+ url: req.url,
266
+ page: req.query.page as string,
267
+ link_prefix: link_prefix,
268
+ data,
269
+ language
270
+ })
425
271
  }
272
+ //分類頁面SEO
426
273
  if ((req.query.page as string).split('/')[0] === 'collections' && (req.query.page as string).split('/')[1]) {
427
- const cols =
428
- (
429
- await Manager.getConfig({
430
- appName: appName,
431
- key: 'collection',
432
- language: language,
433
- })
434
- )[0] ?? {};
435
- const colJson = extractCols(cols);
436
- const urlCode = decodeURI((req.query.page as string).split('/')[1]);
437
- const colData = colJson.find((item: { code: string }) => item.code === urlCode);
438
- if (colData) {
439
- data.page_config.seo.title = colData.seo_title;
440
- data.page_config.seo.content = colData.seo_content;
441
- data.page_config.seo.keywords = colData.seo_keywords;
442
- }
274
+ await SeoConfig.collectionSeo({appName, language, data, page: req.query.page as string})
275
+ }
276
+ //FB像素
277
+ if (FBCode) {
278
+ seo_content.push(SeoConfig.fbCode(FBCode))
443
279
  }
444
- return html`${(() => {
445
- const d = data.page_config.seo;
446
- const home_seo = home_page_data.page_config.seo;
447
- return html`
448
- <head>
449
- ${(() => {
450
- if (req.query.type === 'editor') {
451
- return html`<title>SHOPNEX後台系統</title>
452
- <link rel="canonical" href="/index"/>
453
- <meta name="keywords" content="SHOPNEX,電商平台"/>
454
- <link
455
- id="appImage"
456
- rel="shortcut icon"
457
- href="https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/size1440_s*px$_sas0s9s0s1sesas0_1697354801736-Glitterlogo.png"
458
- type="image/x-icon"
459
- />
460
- <link
461
- rel="icon"
462
- href="https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/size1440_s*px$_sas0s9s0s1sesas0_1697354801736-Glitterlogo.png"
463
- type="image/png"
464
- sizes="128x128"
465
- />
466
- <meta property="og:image"
467
- content="https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1718778766524-shopnex_banner.jpg"/>
468
- <meta property="og:title" content="SHOPNEX後台系統"/>
469
- <meta
470
- name="description"
471
- content="SHOPNEX電商開店平台,零抽成、免手續費。提供精美模板和豐富插件,操作簡單,3分鐘內快速打造專屬商店。購物車、金物流、SEO行銷、資料分析一站搞定。支援APP上架,並提供100%客製化設計,立即免費體驗30天。"
472
- />
473
- <meta
474
- name="og:description"
475
- content="SHOPNEX電商開店平台,零抽成、免手續費。提供精美模板和豐富插件,操作簡單,3分鐘內快速打造專屬商店。購物車、金物流、SEO行銷、資料分析一站搞定。支援APP上架,並提供100%客製化設計,立即免費體驗30天。"
476
- />`;
477
- } else {
478
- return html`<title>${d.title ?? '尚未設定標題'}</title>
479
- <link
480
- rel="canonical"
481
- href="${(() => {
482
- if (data.tag === 'index') {
483
- return `https://${brandAndMemberType.domain}`;
484
- } else {
485
- return `https://${brandAndMemberType.domain}/${data.tag}`;
486
- }
487
- })()}"
488
- />
489
- ${data.tag !== req.query.page ? `<meta name="robots" content="noindex">` : ``}
490
- <meta name="keywords"
491
- content="${(d.keywords ?? '尚未設定關鍵字').replace(/"/g, '&quot;')}"/>
492
- <link id="appImage" rel="shortcut icon"
493
- href="${d.logo || home_seo.logo || ''}" type="image/x-icon"/>
494
- <link rel="icon" href="${d.logo || home_seo.logo || ''}"
495
- type="image/png" sizes="128x128"/>
496
- <meta property="og:image" content="${d.image || home_seo.image || ''}"/>
497
- <meta property="og:title"
498
- content="${(d.title ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"/>
499
- <meta name="description"
500
- content="${(d.content ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"/>
501
- <meta name="og:description"
502
- content="${(d.content ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"/>`;
503
- }
504
- })()}
505
- ${d.code ?? ''}
506
- ${(() => {
507
- if (req.query.type === 'editor') {
508
- return ``;
509
- } else {
510
- return `${(data.config.globalStyle ?? [])
511
- .map((dd: any) => {
512
- try {
513
- if (dd.data.elem === 'link') {
514
- return html`
515
- <link
516
- type="text/css"
517
- rel="stylesheet"
518
- href="${dd.data.attr.find((dd: any) => {
519
- return dd.attr === 'href';
520
- }).value}"
521
- />`;
522
- }
523
- } catch (e) {
524
- return ``;
525
- }
526
- })
527
- .join('')}`;
528
- }
529
- })()}
530
- </head>
280
+ return {
281
+ head: (() => {
282
+ const d = data.page_config.seo;
283
+ const home_seo = home_page_data.page_config.seo;
284
+ return html`
285
+ ${(() => {
286
+ if (req.query.type === 'editor') {
287
+ return SeoConfig.editorSeo;
288
+ } else {
289
+ return html`<title>${d.title || '尚未設定標題'}</title>
290
+ <link
291
+ rel="canonical"
292
+ href="${(() => {
293
+ if (data.tag === 'index') {
294
+ return `https://${brandAndMemberType.domain}`;
295
+ } else {
296
+ return `https://${brandAndMemberType.domain}/${data.tag}`;
297
+ }
298
+ })()}"
299
+ />
300
+ ${data.tag !== req.query.page ? `<meta name="robots" content="noindex">` : `<meta name="robots" content="index, follow"/>`}
301
+ <meta name="keywords"
302
+ content="${(d.keywords || '尚未設定關鍵字').replace(/"/g, '&quot;')}"/>
303
+ <link id="appImage" rel="shortcut icon"
304
+ href="${d.logo || home_seo.logo || ''}" type="image/x-icon"/>
305
+ <link rel="icon" href="${d.logo || home_seo.logo || ''}"
306
+ type="image/png" sizes="128x128"/>
307
+ <meta property="og:image" content="${d.image || home_seo.image || ''}"/>
308
+ <meta property="og:title"
309
+ content="${(d.title ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"/>
310
+ <meta name="description"
311
+ content="${(d.content ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"/>
312
+ <meta name="og:description"
313
+ content="${(d.content ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"/>`;
314
+ }
315
+ })()}
316
+ ${d.code ?? ''}
317
+ ${(() => {
318
+ if (req.query.type === 'editor') {
319
+ return ``;
320
+ } else {
321
+ return `${(data.config.globalStyle ?? [])
322
+ .map((dd: any) => {
323
+ try {
324
+ if (dd.data.elem === 'link') {
325
+ return html`
326
+ <link
327
+ type="text/css"
328
+ rel="stylesheet"
329
+ href="${dd.data.attr.find((dd: any) => {
330
+ return dd.attr === 'href';
331
+ }).value}"
332
+ />`;
333
+ }
334
+ } catch (e) {
335
+ return ``;
336
+ }
337
+ })
338
+ .join('')}`;
339
+ }
340
+ })()}
531
341
  `;
532
- })()}
533
- <script>
534
- ${d.custom_script ?? ''};
535
- window.login_config = ${JSON.stringify(login_config)};
536
- window.appName = '${appName}';
537
- window.glitterBase = '${brandAndMemberType.brand}';
538
- window.memberType = '${brandAndMemberType.memberType}';
539
- window.glitterBackend = '${config.domain}';
540
- window.preloadData = ${JSON.stringify(preload)
342
+ })()+`<script>
343
+ ${[
344
+ d.custom_script ?? '',
345
+ `window.login_config = ${JSON.stringify(login_config)};`,
346
+ `window.appName = '${appName}';`,
347
+ `window.glitterBase = '${brandAndMemberType.brand}';`,
348
+ `window.memberType = '${brandAndMemberType.memberType}';`,
349
+ `window.glitterBackend = '${config.domain}';`,
350
+ `window.preloadData = ${JSON.stringify(preload)
541
351
  .replace(/<\/script>/g, 'sdjuescript_prepand')
542
- .replace(/<script>/g, 'sdjuescript_prefix')};
543
- window.preloadData = JSON.parse(JSON.stringify(window.preloadData).replace(/sdjuescript_prepand/g, '</s' + 'cript>').replace(/sdjuescript_prefix/g, '<s' + 'cript>'))
544
- window.glitter_page = '${req.query.page}';
545
- window.store_info = ${JSON.stringify(store_info)};
546
- window.server_execute_time = ${(new Date().getTime() - start) / 1000};
547
- window.language = '${language}';
548
- ${distribution_code};
549
- window.ip_country = '${(await User.ipInfo((req.query.ip || req.headers['x-real-ip'] || req.ip) as string)).country || 'TW'}';
550
- window.currency_covert = ${JSON.stringify(await Shopping.currencyCovert((req.query.base || 'TWD') as string))};
551
- window.language_list = ${JSON.stringify(language_label.label)};
352
+ .replace(/<script>/g, 'sdjuescript_prefix')};`,
353
+ `window.glitter_page = '${req.query.page}';`,
354
+ `window.store_info = ${JSON.stringify(store_info)};`,
355
+ `window.server_execute_time = ${(new Date().getTime() - start) / 1000};`,
356
+ `window.language = '${language}';`,
357
+ `${distribution_code}`,
358
+ `window.ip_country = '${(ip_country).country || 'TW'}';`,
359
+ `window.currency_covert = ${JSON.stringify(await Shopping.currencyCovert((req.query.base || 'TWD') as string))};`,
360
+ `window.language_list = ${JSON.stringify(language_label.label)};`
361
+ ].map((dd) => {
362
+ return dd.trim()
363
+ }).filter((dd) => {
364
+ return dd
365
+ }).join(';\n')}
552
366
  </script>
553
367
  ${[
554
- {src: 'glitterBundle/GlitterInitial.js', type: 'module'},
555
- {src: 'glitterBundle/module/html-generate.js', type: 'module'},
556
- {src: 'glitterBundle/html-component/widget.js', type: 'module'},
557
- {src: 'glitterBundle/plugins/trigger-event.js', type: 'module'},
558
- {src: 'api/pageConfig.js', type: 'module'},
559
- ]
368
+ {src: 'glitterBundle/GlitterInitial.js', type: 'module'},
369
+ {src: 'glitterBundle/module/html-generate.js', type: 'module'},
370
+ {src: 'glitterBundle/html-component/widget.js', type: 'module'},
371
+ {src: 'glitterBundle/plugins/trigger-event.js', type: 'module'},
372
+ {src: 'api/pageConfig.js', type: 'module'},
373
+ ]
560
374
  .map((dd) => {
561
375
  return html`
562
376
  <script src="/${link_prefix && `${link_prefix}/`}${dd.src}"
@@ -571,96 +385,39 @@ export async function createAPP(dd: any) {
571
385
  const link = dd.fun.replace(`TriggerEvent.setEventRouter(import.meta.url, '.`, 'official_event');
572
386
  return link.substring(0, link.length - 2);
573
387
  })
574
- .map((dd: any) => {
575
- return html`
576
- <script src="/${link_prefix && `${link_prefix}/`}${dd}"
577
- type="module"></script>`;
578
- })
388
+ .map((dd: any) =>
389
+ html`
390
+ <script src="/${link_prefix && `${link_prefix}/`}${dd}"
391
+ type="module"></script>`)
579
392
  .join('')}
580
- </head>
581
393
  ${(() => {
582
- if (req.query.type === 'editor') {
583
- return ``;
584
- } else {
585
- return html`
586
- ${(customCode.ga4 || [])
587
- .map((dd: any) => {
588
- return html`<!-- Google tag (gtag.js) -->
589
- <script async
590
- src="https://www.googletagmanager.com/gtag/js?id=${dd.code}"></script>
591
- <script>
592
- window.dataLayer = window.dataLayer || [];
593
-
594
- function gtag() {
595
- dataLayer.push(arguments);
596
- }
597
-
598
- gtag('js', new Date());
599
-
600
- gtag('config', '${dd.code}');
601
- </script>`;
602
- })
603
- .join('')}
604
- ${(customCode.g_tag || [])
605
- .map((dd: any) => {
606
- return html`<!-- Google tag (gtag.js) -->
607
- <!-- Google Tag Manager -->
608
- <script>
609
- (function (w, d, s, l, i) {
610
- w[l] = w[l] || [];
611
- w[l].push({
612
- 'gtm.start': new Date().getTime(),
613
- event: 'gtm.js',
614
- });
615
- var f = d.getElementsByTagName(s)[0],
616
- j = d.createElement(s),
617
- dl = l != 'dataLayer' ? '&l=' + l : '';
618
- j.async = true;
619
- j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
620
- f.parentNode.insertBefore(j, f);
621
- })(window, document, 'script', 'dataLayer', '${dd.code}');
622
- </script>
623
- <!-- End Google Tag Manager -->`;
624
- })
625
- .join('')}
626
- ${FBCode && FBCode.pixel
627
- ? html`<!-- Meta Pixel Code -->
628
- <script>
629
- !(function (f, b, e, v, n, t, s) {
630
- if (f.fbq) return;
631
- n = f.fbq = function () {
632
- n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);
633
- };
634
- if (!f._fbq) f._fbq = n;
635
- n.push = n;
636
- n.loaded = !0;
637
- n.version = '2.0';
638
- n.queue = [];
639
- t = b.createElement(e);
640
- t.async = !0;
641
- t.src = v;
642
- s = b.getElementsByTagName(e)[0];
643
- s.parentNode.insertBefore(t, s);
644
- })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
645
- fbq('init', '${FBCode.pixel}');
646
- fbq('track', 'PageView');
647
- </script>
648
- <noscript><img height="1" width="1" style="display:none"
649
- src="https://www.facebook.com/tr?id=617830100580621&ev=PageView&noscript=1"/>
650
- </noscript>
651
- <!-- End Meta Pixel Code -->`
652
- : ''}
394
+ if (req.query.type === 'editor') {
395
+ return ``;
396
+ } else {
397
+ return html`
398
+ ${SeoConfig.gA4(customCode.ga4)}
399
+ ${SeoConfig.gTag(customCode.g_tag)}
400
+ ${seo_content.map((dd) => {
401
+ return dd.trim()
402
+ }).join('\n')}
653
403
  `;
654
- }
655
- })()}
656
- `;
404
+ }
405
+ })()}`,
406
+ body:``
407
+ }
408
+
657
409
  } else {
658
- console.log(`brandAndMemberType==>redirect`);
659
- return await Seo.redirectToHomePage(appName, req);
410
+ return {
411
+ head:await Seo.redirectToHomePage(appName, req),
412
+ body:``
413
+ }
660
414
  }
661
415
  } catch (e: any) {
662
416
  console.error(e);
663
- return `${e}`;
417
+ return {
418
+ head:``,
419
+ body:`${e}`
420
+ }
664
421
  }
665
422
  },
666
423
  sitemap: async (req, resp) => {
@@ -694,13 +451,30 @@ export async function createAPP(dd: any) {
694
451
  )
695
452
  )[0] ?? {};
696
453
 
697
- const products = await db.query(
698
- `SELECT *
699
- FROM \`${appName}\`.t_manager_post
700
- WHERE JSON_EXTRACT(content, '$.type') = 'product';
701
- `,
702
- []
703
- );
454
+ const language_setting=(await new User(appName).getConfigV2({
455
+ key: 'store-information',
456
+ user_id: 'manager',
457
+ })).language_setting;
458
+
459
+ const product=(await new Shopping(appName).getProduct( {
460
+ page: 0,
461
+ limit: 100000,
462
+ collection: '',
463
+ accurate_search_text: false,
464
+ accurate_search_collection: true,
465
+ min_price: undefined,
466
+ max_price: undefined,
467
+ status: undefined,
468
+ channel: undefined,
469
+ id_list: undefined,
470
+ order_by: 'order by id desc',
471
+ with_hide_index: undefined,
472
+ is_manger: true,
473
+ productType: 'product',
474
+ filter_visible: 'true',
475
+ language: 'zh-TW',
476
+ currency_code: 'TWD'
477
+ })).data
704
478
  // 創建 SitemapStream
705
479
  const stream = new SitemapStream({hostname: `https://${domain}`});
706
480
 
@@ -730,20 +504,51 @@ export async function createAPP(dd: any) {
730
504
  .map((d2: any) => {
731
505
  return {url: `https://${domain}/${d2.url}`, changefreq: 'weekly'}
732
506
  }),
733
- ...extractCols(cols)
734
- .filter((item: any) => {
735
- return item.code
736
- })
737
- .map((item: { code: string; updated_at: string }) => {
738
- return {url: `https://${domain}/collections/${item.code}`, changefreq: 'weekly'}
739
- }),
740
- ...extractProds(products)
741
- .filter((item: any) => {
742
- return item.code
743
- })
744
- .map((item: { code: string; updated_at: string }) => {
745
- return {url: `https://${domain}/products/${item.code}`, changefreq: 'weekly'}
507
+ ...(()=>{
508
+ let array:string[]=[];
509
+ extractCols(cols)
510
+ .map((item:any) => {
511
+ array=array.concat((language_setting.support).map((d1:any)=>{
512
+ const seo=(item.language_data && item.language_data[d1] && item.language_data[d1].seo && item.language_data[d1].seo.domain) || item.code || item.title
513
+ if(d1===language_setting.def){
514
+ return {url: `https://${domain}/collections/${seo}`, changefreq: 'weekly'}
515
+ }else if(d1==='zh-TW'){
516
+ return {url: `https://${domain}/tw/collections/${seo}`, changefreq: 'weekly'}
517
+ }else if(d1==='zh-CN'){
518
+ return {url: `https://${domain}/cn/collections/${seo}`, changefreq: 'weekly'}
519
+ }else if(d1==='en-US'){
520
+ return {url: `https://${domain}/en/collections/${seo}`, changefreq: 'weekly'}
521
+ }else{
522
+ return {url: `https://${domain}/${d1}/collections/${seo}`, changefreq: 'weekly'}
523
+ }
524
+ }))
525
+ })
526
+ console.log(array)
527
+ return array
528
+ })(),
529
+ ...(()=>{
530
+ let array:string[]=[];
531
+ product.map((dd:any)=>{
532
+ dd=dd.content;
533
+ array=array.concat((language_setting.support).map((d1:any)=>{
534
+ // console.log(`products=>`,dd)
535
+ const seo=(dd.language_data && dd.language_data[d1] && dd.language_data[d1].seo && dd.language_data[d1].seo.domain) || dd.seo.domain
536
+ if(d1===language_setting.def){
537
+ return {url: `https://${domain}/products/${seo}`, changefreq: 'weekly'}
538
+ }else if(d1==='zh-TW'){
539
+ return {url: `https://${domain}/tw/products/${seo}`, changefreq: 'weekly'}
540
+ }else if(d1==='zh-CN'){
541
+ return {url: `https://${domain}/cn/products/${seo}`, changefreq: 'weekly'}
542
+ }else if(d1==='en-US'){
543
+ return {url: `https://${domain}/en/products/${seo}`, changefreq: 'weekly'}
544
+ }else{
545
+ return {url: `https://${domain}/${d1}/products/${seo}`, changefreq: 'weekly'}
546
+ }
547
+ }))
746
548
  })
549
+
550
+ return array
551
+ })()
747
552
  ]).pipe(stream)).then((data: any) =>
748
553
  data.toString()
749
554
  );