~cytrogen/blog-public

blog-public/posts/41a3.html -rw-r--r-- 148.2 KiB
88eebf3dCytrogen Deploy 2026-02-19 08:34:27 4 days ago
                                                                                
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
<!DOCTYPE html><html lang="zh" data-theme="dark"><head><meta charset="utf-8"><meta name="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>IBM 全栈开发【13・上】:全栈应用程序开发者毕业设计 · Cytrogen 的个人博客</title><meta name="description" content="本文是 IBM 全栈开发毕业设计项目的实战笔记(上篇),旨在对已有的“Best Cars”汽车经销商应用进行功能增强。内容分为三大模块:首先,对 React 前端进行体验优化,包括将静态下拉菜单改为动态搜索框并美化UI;接着,使用 Node.js、Express 和 MongoDB 从零构建一个全新的、容器化的汽车库存后端微服务;最后,开发新的 React 前端组件,与后端服务集成,实现按品牌、型号、年份等多条件筛选汽车库存的动态功能。这篇笔记全面展示了在一个真实全-stack项目中进行功能迭代、构建新服务并完成前后端集成的完整流程。"><link rel="icon" href="../favicon.png"><link rel="canonical" href="https://cytrogen.icu/posts/41a3.html"><link rel="webmention" href="https://webmention.io/cytrogen.icu/webmention"><link rel="me" href="https://m.otter.homes/@Cytrogen"><link rel="me" href="https://github.com/cytrogen"><meta name="fediverse:creator" content="@Cytrogen@m.otter.homes"><link rel="preload" href="../fonts/opensans-regular-latin.woff2" as="font" type="font/woff2" crossorigin="anonymous"><style>@font-face {
  font-family: 'Open Sans';
  src: url('../fonts/opensans-regular-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  size-adjust: 107%;
  ascent-override: 97%;
  descent-override: 25%;
  line-gap-override: 0%;
}
</style><script>(function() {
  try {
    // 优先级:用户选择 > 系统偏好 > 默认浅色
    const saved = localStorage.getItem('theme');
    const theme = saved || 
      (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
    
    document.documentElement.setAttribute('data-theme', theme);
    document.documentElement.style.colorScheme = theme;
  } catch (error) {
    // 失败时使用默认主题,不阻塞渲染
    document.documentElement.setAttribute('data-theme', 'light');
  }
})();
</script><link rel="stylesheet" href="../css/ares.css"><script data-netlify-skip-bundle="true">(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const theme = document.documentElement.getAttribute('data-theme');
    const pageWrapper = document.getElementById('page-wrapper');
    if (pageWrapper && theme) {
      pageWrapper.setAttribute('data-theme', theme);
    }
  });
})();

</script><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 8.1.1"><link rel="alternate" href="atom.xml" title="Cytrogen 的个人博客" type="application/atom+xml">
</head><body><div id="page-wrapper"><a class="skip-link" href="#main-content">跳到主要内容</a><div class="wrap"><header><a class="logo-link" href="../index.html"><img src="../favicon.png" alt="logo"></a><div class="h-card visually-hidden"><img class="u-photo" src="https://cytrogen.icu/favicon.png" alt="Cytrogen"><a class="p-name u-url u-uid" href="https://cytrogen.icu">Cytrogen</a><p class="p-note">Cytrogen 的个人博客,Cytrogen's Blog</p><a class="u-url" rel="me noopener" target="_blank" href="https://m.otter.homes/@Cytrogen">Mastodon</a><a class="u-url" rel="me noopener" target="_blank" href="https://github.com/cytrogen">GitHub</a></div><nav class="site-nav"><div class="nav-main"><div class="nav-primary"><ul class="nav-list hidden-mobile"><li class="nav-item"><a class="nav-link" href="../index.html">首页</a></li></ul><div class="nav-tools"><div class="language-menu"><button class="language-toggle" type="button"><svg class="icon icon-globe" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855A7.97 7.97 0 0 0 10.855 12H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z"></path></svg><span>中文</span></button><div class="language-dropdown"></div></div></div><div class="nav-controls"><div class="more-menu hidden-mobile"><button class="more-toggle" type="button"><span>更多</span><svg class="icon icon-chevron-down" width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 8.825c-.2 0-.4-.1-.5-.2l-3.3-3.3c-.3-.3-.3-.8 0-1.1s.8-.3 1.1 0l2.7 2.7 2.7-2.7c.3-.3.8-.3 1.1 0s.3.8 0 1.1l-3.3 3.3c-.1.1-.3.2-.5.2z"></path></svg></button><div class="more-dropdown"><ul class="dropdown-list"><li class="dropdown-item"><a class="nav-link" href="../archives/index.html">归档</a></li><li class="dropdown-item"><a class="nav-link" href="../categories/index.html">分类</a></li><li class="dropdown-item"><a class="nav-link" href="../tags/index.html">标签</a></li><li class="dropdown-item"><a class="nav-link" href="../about/index.html">关于</a></li><li class="dropdown-item"><a class="nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></div><div class="theme-switcher"><button class="theme-toggle" type="button" role="switch" aria-pressed="false" aria-label="切换主题"><div class="theme-icon moon-icon"><svg class="icon icon-moon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z"></path></svg></div><div class="theme-icon sun-icon"><svg class="icon icon-sun" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"></path></svg></div></button></div><details class="mobile-menu-details hidden-desktop"><summary class="hamburger-menu" aria-label="nav.menu"><svg class="icon icon-bars" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"></path></svg><span class="menu-text">nav.menu</span></summary><div class="mobile-menu-dropdown"><ul class="mobile-nav-list"><li class="mobile-nav-item"><a class="mobile-nav-link" href="../index.html">首页</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../archives/index.html">归档</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../categories/index.html">分类</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../tags/index.html">标签</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../about/index.html">关于</a></li><li class="mobile-nav-item"><a class="mobile-nav-link" href="../sitemap/index.html">领地地图</a></li></ul></div></details></div></div></div></nav></header><main class="container" id="main-content" tabindex="-1"><div class="post"><article class="post-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="author-avatar u-photo" src="../favicon.png" alt="Cytrogen"><span class="p-name">Cytrogen</span><a class="u-url" href="https://cytrogen.icu">https://cytrogen.icu</a></div><a class="post-permalink u-url u-uid visually-hidden" href="https://cytrogen.icu/posts/41a3.html">永久链接</a><div class="p-summary visually-hidden"><p>近期在学习 IBM 全栈应用开发微学士课程,故此记录学习笔记。</p></div><div class="visually-hidden"><a class="p-category" href="../categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/">编程笔记</a><a class="p-category" href="../tags/JavaScript/">JavaScript</a><a class="p-category" href="../tags/IBM/">IBM</a><a class="p-category" href="../tags/HTML/">HTML</a><a class="p-category" href="../tags/Node-js/">Node.js</a><a class="p-category" href="../tags/Express-js/">Express.js</a><a class="p-category" href="../tags/React-js/">React.js</a></div><h1 class="post-title p-name">IBM 全栈开发【13・上】:全栈应用程序开发者毕业设计</h1><div class="post-info"><time class="post-date dt-published" datetime="2024-07-07T04:00:00.000Z">7/7/2024</time><time class="dt-updated visually-hidden" datetime="2026-02-09T17:16:54.717Z"></time></div><div class="post-content e-content"><html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程,故此记录学习笔记。</p>
<span id="more"></span>
<p>恭喜您成功完成 IBM 全栈软件开发人员专业证书的所有前面课程!现在是通过完成期末考试来检验您的新技能的时候了。</p>
<p>您将通过考试,了解自己在 PC 各门课程中学到的知识。现在,您应该已经熟练掌握了以下主题:</p>
<ul>
<li>云计算的核心概念</li>
<li>网页开发语言,包括 HTML、CSS 和 JavaScript</li>
<li>Git 和 GitHub</li>
<li>Node.JS、Express 和 React</li>
<li>容器</li>
<li>Python</li>
<li>数据库概念和相关技术,如 SQL 和 Django</li>
<li>微服务和无服务器计算</li>
</ul>
<p>这是 IBM 全栈软件开发人员专业证书的最后一门课程。它将测试您迄今为止所掌握的知识和技能。本课程包含分级期末考试,涵盖 PC 中各种课程的内容。</p>
<p>您将就以下主题接受评估:核心云计算概念;HTML、CSS、JavaScript 和 Python 等语言;Node.JS、Express 和 React 等框架;以及 Docker、Kubernetes、OpenShift、SQL、Django、微服务和 Serverless 等后端技术。</p>
<p>在学习本课程之前,请确保您已完成 IBM 全栈开发人员专业证书中的所有先前课程。</p>
<h1 id="通过附加功能丰富汽车经销商门户网站"><a class="markdownIt-Anchor" href="#通过附加功能丰富汽车经销商门户网站"></a> 通过附加功能丰富汽车经销商门户网站</h1>
<p>该课程从模块开始:通过三个实验丰富汽车经销商门户网站的附加功能。</p>
<p>在「全栈应用程序开发项目」(可见 <a href="/posts/fa4d.html">文章</a>)中,您创建了一个汽车经销商应用程序,需要开发前端页面、用户管理、构建数据库操作动作、创建后端服务以及配置 CI / CD 管道。前端使用的技术包括 HTML、CSS、JavaScript 和 React,后端使用的技术包括 Django、Node.JS、NoSQL(Mongo)、容器化、IBM 代码引擎、Python 和 Kubernetes。</p>
<p>通过汽车经销商应用程序,我们可以根据经销商的 ID 查看所有经销商的详细信息和评论,还可以注册、登录为用户,并在注册或登录后为特定经销商添加新的评论,方法是将 <code>About</code><code>Contact Us</code> 等静态页面整合到一起。</p>
<p>用户注册和登录功能也是在为端点和 Django 视图配置了 Express-Mongo 后端微服务后实现的。还集成了一个情感分析微服务来分析评论。也实现了各种功能,如显示经销商列表、详细信息和评论,在 Django 应用程序中添加新的经销商评论。最后,将 CI / CD Linting 服务集成到应用程序中,并部署到 Kubernetes 上。</p>
<p>在本课程中,您将从增强同一个汽车经销商应用程序开始。改进的重点是前端方面,然后通过添加新的微服务转移到后端,最后在后续实验中将其与前端集成。</p>
<p>强烈建议先完成全栈应用程序开发项目课程,然后再学习本课程,因为本模块的实验是增强已建应用程序的一部分。虽然这些内容不属于评分标准的一部分,但它们对于增强你的理解和技能仍然很有价值。</p>
<h2 id="概述"><a class="markdownIt-Anchor" href="#概述"></a> 概述</h2>
<p>作为毕业设计项目的一部分,您已经成功创建并测试了 <code>Car Dealerships website</code>,确保其符合预期功能。这包括允许用户查看所有经销商的详细信息、查看对特定经销商的现有评论,以及在作为注册用户登录后发布对特定经销商的新评论。</p>
<p>完成上述工作后,下一步就是增强应用程序的功能。这涉及到应用程序的前端和后端方面。如下所述,您将分三部分实施这些增强功能:</p>
<ol>
<li>
<p>前端改进</p>
<ul>
<li><code>Dealerships</code> 页面上的 <code>States</code> 下拉菜单转换为可搜索文本框,使用户能够通过输入搜索字符串来筛选经销商。</li>
<li>改进应用程序主页上导航栏和经销商按钮的配色方案,以及 <code>Dealerships Review</code> 页面上审查面板和审查图标的颜色。</li>
<li>微调经销商审查面板的视觉元素,对字体大小和字体对齐方式等方面进行调整。</li>
</ul>
</li>
<li>
<p>汽车库存后端服务</p>
<ul>
<li>使用 MongoDB 和 Node.JS 服务器建立一个新的后端微型服务,专门用于获取与汽车库存相关的各种详细信息。</li>
<li>将新创建的微服务与 Django 应用程序的后端集成,并验证后端服务器的成功启动。</li>
</ul>
</li>
<li>
<p>汽车库存服务的前端开发</p>
<ul>
<li>开发前端组件,并将其与 <a href="#%E7%AC%AC-2-%E9%83%A8%E5%88%86%E6%B1%BD%E8%BD%A6%E5%BA%93%E5%AD%98%E5%90%8E%E7%AB%AF%E6%9C%8D%E5%8A%A1">第 2 部分:汽车库存后端服务</a> 中开发的后端汽车库存微服务集成。</li>
<li>创建一个按 <strong>品牌</strong><strong>型号</strong><strong>年份</strong><strong>里程</strong><strong>价格</strong> 选择汽车的选项。</li>
<li>对 Django 应用程序与集成的汽车库存服务生成的输出进行全面测试。</li>
</ul>
</li>
</ol>
<h2 id="前端改进"><a class="markdownIt-Anchor" href="#前端改进"></a> 前端改进</h2>
<h4 id="将-dealerships-页面上的-states-下拉菜单转换为可搜索文本框"><a class="markdownIt-Anchor" href="#将-dealerships-页面上的-states-下拉菜单转换为可搜索文本框"></a><code>Dealerships</code> 页面上的 <code>States</code> 下拉菜单转换为可搜索文本框</h4>
<ol>
<li>访问 <code>frontend/src/components/Dealers/Dealers.jsx</code> 文件。</li>
<li>您会注意到,经销商下拉菜单的代码是在 <code>&lt;select&gt;</code> 下拉菜单元素中显示的:<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">&lt;select name=<span class="string">"state"</span> id=<span class="string">"state"</span> onChange={<span class="function">(<span class="params">e</span>) =&gt;</span> <span class="title function_">filterDealers</span>(e.<span class="property">target</span>.<span class="property">value</span>)}&gt;</span><br><span class="line">&lt;/select&gt;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>用包含以下属性的 <code>&lt;input&gt;</code> 字段取代现有的 <code>&lt;select&gt;</code> 元素:
<ul>
<li>用户可在文本框中输入搜索州。</li>
<li>根据输入的搜索查询过滤显示的经销商,并与州匹配。</li>
<li>当输入框失去焦点时,将显示的经销商重置为原始列表。</li>
</ul>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;input type=<span class="string">"text"</span> placeholder=<span class="string">"Search states..."</span> onChange={handleInputChange} onBlur={handleLostFocus} value={searchQuery} /&gt;</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
<p>观察输入元素中的函数。现在,让我们创建它们。</p>
<ol>
<li>创建一个名为 <code>handleInputChange</code> 的新函数,用于管理输入更改,并根据输入的状态查询过滤经销商。<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">handleInputChange</span> = (<span class="params">event</span>) =&gt; {</span><br><span class="line">  <span class="keyword">const</span> query = event.<span class="property">target</span>.<span class="property">value</span>;</span><br><span class="line">  <span class="title function_">setSearchQuery</span>(query);</span><br><span class="line">  <span class="keyword">const</span> filtered = originalDealers.<span class="title function_">filter</span>(<span class="function"><span class="params">dealer</span> =&gt;</span></span><br><span class="line">    dealer.<span class="property">state</span>.<span class="title function_">toLowerCase</span>().<span class="title function_">includes</span>(query.<span class="title function_">toLowerCase</span>())</span><br><span class="line">  );</span><br><span class="line">  <span class="title function_">setDealersList</span>(filtered);</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>每次输入框内的值发生变化时,都会触发该函数。</li>
<li>它会检索用户在输入框中输入的当前值,并将其作为查询存储在 <code>setSearchQuery</code> 变量中,用于筛选经销商。</li>
<li>系统会生成一个新数组,其中只包含状态与输入的查询相匹配的经销商。</li>
<li>通过将查询和经销商状态转换为小写,使其大小写不敏感,从而确保用户获得更友好的搜索体验。</li>
<li>然后,该函数将显示与输入的状态查询相匹配的经销商。</li>
</ul>
</li>
<li>总之,<code>handleInputChange</code> 函数可根据用户在搜索栏中的输入动态过滤经销商列表。它实时更新显示的经销商列表,为用户提供响应式搜索功能。</li>
<li>创建 <code>handleLostFocus</code> 函数,以确保当用户将搜索输入留空并点击或滑动标签离开时,经销商列表会重置为原始列表。<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">handleLostFocus</span> = (<span class="params"></span>) =&gt; {</span><br><span class="line">  <span class="keyword">if</span> (!searchQuery) {</span><br><span class="line">    <span class="title function_">setDealersList</span>(originalDealers);</span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>该函数在执行时验证 <code>searchQuery</code> 状态是否为空。</li>
<li>如果 <code>searchQuery</code> 确实为空,它就会将经销商列表恢复到开始搜索前的原始状态。</li>
<li><code>handleLostFocus</code> 函数在用户点击输入框外或标签页离开输入框时调用,由 <code>onBlur</code> 事件触发。</li>
</ul>
</li>
<li>将此代码与之前定义的其他状态变量一起添加:<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> [searchQuery, setSearchQuery] = <span class="title function_">useState</span>(<span class="string">''</span>);</span><br></pre></td></tr></tbody></table></figure>
<ul>
<li>这将利用 <code>useState</code> 钩子创建一个名为 <code>searchQuery</code> 的状态变量和一个相应的函数 <code>setSearchQuery</code> 来更新其值。</li>
<li><code>searchQuery</code> 状态变量实时保存用户在搜索输入框中输入的值。当用户在搜索栏中输入时,该状态变量会通过调用 <code>setSearchQuery</code> 进行更新,并触发组件的重新渲染,以反映对搜索查询所做的任何更改。</li>
</ul>
</li>
<li>初始化和设置状态变量,用于管理原始经销商列表。
<ul>
<li>添加以下代码,初始化 <code>dealersList</code><code>searchQuery</code><code>states</code> 变量及其设置函数:<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> [originalDealers, setOriginalDealers] = <span class="title function_">useState</span>([]);</span><br></pre></td></tr></tbody></table></figure>
在这段代码中,状态变量 <code>originalDealers</code> 及其设置函数 <code>setOriginalDealers</code> 用于跟踪和更新原始经销商列表。</li>
<li>将下面的代码放在 <code>getDealers</code> 函数中更新其他状态(<code>setStates</code><code>setDealersList</code>)的地方。<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">setOriginalDealers</span>(all_dealers);</span><br></pre></td></tr></tbody></table></figure>
这一行用从应用程序接口获取的所有经销商数组设置状态变量 <code>originalDealers</code>,用于存储过滤前的原始经销商列表。</li>
</ul>
</li>
<li>确保保存所有更改。</li>
<li>运行以下命令来构建应用程序的客户端:<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /home/project/xrwvm-fullstack_developer_capstone/server/frontend</span><br><span class="line">npm run build</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>访问经销商详细信息页面,测试应用程序的输出。</li>
<li>请观察用于经销商搜索的搜索框的外观,它取代了之前的下拉框。</li>
<li>输入搜索查询,例如 <code>Texas</code>,搜索该州来进行测试。</li>
</ol>
<h4 id="更改应用程序的配色方案"><a class="markdownIt-Anchor" href="#更改应用程序的配色方案"></a> 更改应用程序的配色方案</h4>
<p>在本节中,您将了解在以下区域更改应用程序配色方案的步骤:</p>
<ul>
<li>
<p>与应用程序主页有关的方面,包括:</p>
<ol>
<li>更改导航栏的背景颜色。</li>
<li>修改 <code>View Dealerships</code> 按钮的背景颜色。</li>
</ol>
</li>
<li>
<p><code>Dealership Review</code> 页面有关的方面包括:</p>
<ol>
<li>调整与 <code>Review</code> 面板相关的背景颜色。</li>
<li>自定义与 <code>Review</code> 图标相关的悬浮边框。</li>
</ol>
</li>
</ul>
<ol>
<li>
<p><strong>更改导航栏的背景颜色</strong></p>
<ol>
<li>打开文件 <code>frontend/static/Home.html</code></li>
<li>您将看到以下代码片段,它将当前的深绿色背景添加到应用程序中的导航栏:<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">nav</span> <span class="attr">class</span>=<span class="string">"navbar navbar-expand-lg navbar-light"</span> <span class="attr">style</span>=<span class="string">{{backgroundColor:</span>"<span class="attr">darkturquoise</span>",<span class="attr">height:</span>"<span class="attr">1in</span>"}}&gt;</span></span><br></pre></td></tr></tbody></table></figure>
</li>
<li>用您喜欢的颜色(如 <code>mediumspringgreen</code>)代替它,以修改页眉的背景颜色。<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">nav</span> <span class="attr">class</span>=<span class="string">"navbar navbar-expand-lg navbar-light"</span> <span class="attr">style</span>=<span class="string">"background-color:mediumspringgreen; height: 1in;"</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
</li>
<li>保存更改。</li>
<li>运行提供的命令构建客户端并显示上述更改:<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run build</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>刷新应用页面。</li>
<li>观察导航栏背景的变化。</li>
</ol>
</li>
<li>
<p><strong>修改 <code>View Dealerships</code> 按钮的背景颜色</strong></p>
<ol>
<li>以下代码表示应用程序主页上 <code>View Dealerships</code> 按钮的背景颜色:<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"/dealers"</span> <span class="attr">class</span>=<span class="string">"btn"</span> <span class="attr">style</span>=<span class="string">"background-color: aqua;margin:10px"</span>&gt;</span>View Dealerships<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
</li>
<li>将其调整为您喜欢的颜色(例如,<code>plum</code>,一种紫色)。<figure class="highlight html"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"/dealers"</span> <span class="attr">class</span>=<span class="string">"btn"</span> <span class="attr">style</span>=<span class="string">"background-color: plum; margin:10px"</span>&gt;</span>View Dealerships<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
</li>
<li>请观察 <code>View Dealerships</code> 按钮的最新配色方案。</li>
</ol>
</li>
<li>
<p><strong>调整与 <code>Review</code> 面板相关的背景颜色</strong></p>
<ol>
<li><code>Dealers.css</code> 文件中的样式是为应用程序中的 <code>Dealerships</code><code>Reviews</code> 面板定制的。<code>review_panel</code> 类包含用于设计经销商审查面板样式的代码。</li>
<li>请注意,它的边框是纯灰色的。<figure class="highlight css"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">border</span>: solid grey;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>调整代码,使其具有纯紫色边框:<figure class="highlight css"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">border</span>: solid purple;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>你会发现 <code>Review</code> 面板的边框变成了纯紫色,外观也发生了变化。</li>
</ol>
</li>
<li>
<p><strong>自定义与 <code>Review</code> 图标相连的悬浮边框</strong></p>
<ol>
<li>当用户将鼠标悬停在 <code>Review</code> 图标上时,<code>.review_icon:hover</code> 类将为其应用样式。</li>
<li>请注意,悬停时它的背景是纯浅灰色。<figure class="highlight css"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">border</span>: solid lightgray;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>将颜色调整为黑色色调,边框变细(如 2 像素),以便在悬停时呈现出鲜明而纤细的背景外观。<figure class="highlight css"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">border</span>: <span class="number">2px</span> solid <span class="number">#080808</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>观察修改后的图标,它带有细细的黑色边框,悬停时会显示出明显的存在感。</li>
</ol>
</li>
</ol>
<h4 id="更改应用程序的外观和感觉"><a class="markdownIt-Anchor" href="#更改应用程序的外观和感觉"></a> 更改应用程序的外观和感觉</h4>
<p>在本节中,您将学习如何改进应用程序中 <code>Dealer Review</code> 面板的视觉效果。</p>
<p>其中包括:</p>
<ul>
<li>调整字体大小</li>
<li>确保字体对齐正确,以改善整体外观</li>
</ul>
<ol>
<li>
<p><strong>调整字体大小</strong></p>
<ol>
<li><code>.reviewer</code> 类定义了用户评论的样式。</li>
<li>当前字体大小设置为小。</li>
<li>将字体大小调整到特定值(例如 18 像素),以放大 <code>Review</code> 文本,提高可读性。<figure class="highlight css"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">font-size</span>: <span class="number">18px</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
</li>
<li>
<p><strong>确保字体对齐正确,改善整体外观</strong></p>
<ol>
<li>文本对齐属性并未被指定。</li>
<li>因此,浏览器的默认文本对齐方式(通常为左对齐)会被应用,从而产生左对齐的 <code>Review</code> 文本。</li>
<li>将文本居中,以确保 <code>User reviews</code> 显示在 <code>Review</code> 窗格的中心。<figure class="highlight css"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">text-align</span>: center;</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
</li>
</ol>
<h2 id="汽车库存后端服务"><a class="markdownIt-Anchor" href="#汽车库存后端服务"></a> 汽车库存后端服务</h2>
<h4 id="使用-mongodb-和-nodejs-开发新的后端汽车库存微服务"><a class="markdownIt-Anchor" href="#使用-mongodb-和-nodejs-开发新的后端汽车库存微服务"></a> 使用 MongoDB 和 Node.JS 开发新的后端汽车库存微服务</h4>
<ol>
<li>
<p>打开一个新的终端窗口,导航到 <code>xrwvm-fullstack_developer_capstone/server</code> 目录。<br>
生成一个名为 <code>carsInventory</code> 的新目录。</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> carsInventory</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>执行以下命令,初始化一个新的 Node.JS 项目,并在 <code>carsInvent</code> 目录下创建 <code>package.json</code> 文件:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm init</span><br></pre></td></tr></tbody></table></figure>
<p>将以下应用程序依赖项添加到 <code>package.json</code> 中:</p>
<figure class="highlight json"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"> <span class="attr">"cors"</span><span class="punctuation">:</span> <span class="string">"^2.8.5"</span><span class="punctuation">,</span>    </span><br><span class="line"><span class="attr">"express"</span><span class="punctuation">:</span> <span class="string">"^4.18.2"</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">"mongodb"</span><span class="punctuation">:</span> <span class="string">"^6.3.0"</span><span class="punctuation">,</span></span><br><span class="line"><span class="attr">"mongoose"</span><span class="punctuation">:</span> <span class="string">"^8.0.1"</span></span><br></pre></td></tr></tbody></table></figure>
<p>这些依赖项对于启用 CORS(跨源资源共享)、处理网络应用程序路由和中间件(Express)、与 MongoDB 交互(MongoDB 驱动程序)以及在使用 MongoDB 的 Node.JS 应用程序中提供便捷的数据建模方式(Mongoose)至关重要。</p>
<p>每个依赖关系中版本号前的 <code>^</code> 符号允许在运行 <code>npm install</code> 命令时安装兼容的未来更新。</p>
<p><code>name</code> 设置为 <code>carsInventory</code>,将 <code>main</code> 的值设置为 <code>app.js</code>。这样,<code>package.json</code> 文件看起来应该与下面相似:</p>
<figure class="highlight json"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"> <span class="punctuation">{</span></span><br><span class="line">  <span class="attr">"name"</span><span class="punctuation">:</span> <span class="string">"carsInventory"</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"version"</span><span class="punctuation">:</span> <span class="string">"1.0.0"</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"description"</span><span class="punctuation">:</span> <span class="string">""</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"main"</span><span class="punctuation">:</span> <span class="string">"app.js"</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"scripts"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">     <span class="attr">"test"</span><span class="punctuation">:</span> <span class="string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span></span><br><span class="line">  <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"author"</span><span class="punctuation">:</span> <span class="string">""</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"license"</span><span class="punctuation">:</span> <span class="string">"ISC"</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">"dependencies"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line">    <span class="attr">"cors"</span><span class="punctuation">:</span> <span class="string">"^2.8.5"</span><span class="punctuation">,</span>    </span><br><span class="line">    <span class="attr">"express"</span><span class="punctuation">:</span> <span class="string">"^4.18.2"</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">"mongodb"</span><span class="punctuation">:</span> <span class="string">"^6.3.0"</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">"mongoose"</span><span class="punctuation">:</span> <span class="string">"^8.0.1"</span></span><br><span class="line">  <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></tbody></table></figure>
<p>执行命令安装这些依赖项:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>在名为 <code>inventory.js</code> 的文件中设置 MongoDB schema。现在,您将使用 <code>mongoose</code> 库为名为 <code>cars</code> 的集合建立 MongoDB schema。<br>
这将用于创建一个与 MongoDB 数据库交互的 <code>mongoose</code> 模型,使应用程序能够以更有条理、更有组织的方式对汽车文档执行 CRUD 操作。<br>
schema 应定义汽车文件的结构,其中应包括以下字段及其数据类型:</p>
<ul>
<li><code>dealer_id</code><code>Number</code></li>
<li><code>make</code><code>String</code></li>
<li><code>model</code><code>String</code></li>
<li><code>bodyType</code><code>String</code></li>
<li><code>year</code><code>Number</code></li>
<li><code>mileage</code><code>Number</code></li>
<li><code>price</code><code>Number</code></li>
</ul>
<p>模型将被命名为 <code>cars</code>,与所连接的 MongoDB 数据库中的 <code>cars</code> 集合相对应。MongoDB 模型将以此名称导出。</p>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> { <span class="title class_">Int32</span> } = <span class="built_in">require</span>(<span class="string">'mongodb'</span>);</span><br><span class="line"><span class="keyword">const</span> mongoose = <span class="built_in">require</span>(<span class="string">'mongoose'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Schema</span> = mongoose.<span class="property">Schema</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> cars = <span class="keyword">new</span> <span class="title class_">Schema</span>({</span><br><span class="line">  <span class="attr">dealer_id</span>: {</span><br><span class="line">    <span class="attr">type</span>: <span class="title class_">Number</span>,</span><br><span class="line">    <span class="attr">required</span>: <span class="literal">true</span></span><br><span class="line">  },</span><br><span class="line">  <span class="attr">make</span>: {</span><br><span class="line">    <span class="attr">type</span>: <span class="title class_">String</span>,</span><br><span class="line">    <span class="attr">required</span>: <span class="literal">true</span></span><br><span class="line">  },</span><br><span class="line">  <span class="attr">model</span>: {</span><br><span class="line">    <span class="attr">type</span>: <span class="title class_">String</span>,</span><br><span class="line">    <span class="attr">required</span>: <span class="literal">true</span></span><br><span class="line">  },</span><br><span class="line">  <span class="attr">bodyType</span>: {</span><br><span class="line">    <span class="attr">type</span>: <span class="title class_">String</span>,</span><br><span class="line">    <span class="attr">required</span>: <span class="literal">true</span></span><br><span class="line">  },</span><br><span class="line">  <span class="attr">year</span>: {</span><br><span class="line">    <span class="attr">type</span>: <span class="title class_">Number</span>,</span><br><span class="line">    <span class="attr">required</span>: <span class="literal">true</span></span><br><span class="line">  },</span><br><span class="line">  <span class="attr">mileage</span>: {</span><br><span class="line">    <span class="attr">type</span>: <span class="title class_">Number</span>,</span><br><span class="line">    <span class="attr">required</span>: <span class="literal">true</span></span><br><span class="line">  },</span><br><span class="line">  <span class="attr">price</span>: {</span><br><span class="line">    <span class="attr">type</span>: <span class="title class_">Number</span>,</span><br><span class="line">    <span class="attr">required</span>: <span class="literal">true</span></span><br><span class="line">  }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = mongoose.<span class="title function_">model</span>(<span class="string">'cars'</span>, cars);</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>获取包含汽车库存和相关详细信息的 JSON 数据集。<br>
首先创建一个名为 <code>data</code> 的文件夹并导航进入:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> data</span><br><span class="line"><span class="built_in">cd</span> data</span><br></pre></td></tr></tbody></table></figure>
<p>下载汽车库存数据集:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBM-CD0321EN-SkillsNetwork/labs/v2/m6/car_records.json</span><br></pre></td></tr></tbody></table></figure>
<p>检查文件,发现每个汽车对象都有以下字段:</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make, model, bodyType, year, dealer_id, mileage, price</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>返回 <code>carsInvent</code> 目录,创建更多文件。</p>
<p>建立具有后端端点功能的 Node.JS 服务器。首先创建一个名为 <code>app.js</code> 的文件:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> app.js</span><br></pre></td></tr></tbody></table></figure>
<p>它应具备以下功能:</p>
<ul>
<li>设置与 MongoDB 集成的 Express 服务器</li>
<li>从文件 <code>car_records.json</code> 中读取数据</li>
<li>建立与 MongoDB 的连接</li>
<li>定义根 API 端点 <code>/</code>,当访问根 API 时,它会响应一条欢迎访问 Mongoose API 消息</li>
<li>定义以下六个端点,用于根据各种条件查询汽车:
<ul>
<li><code>cars/:id</code> 端点,可根据指定的经销商 ID 从 MongoDB 集合中检索并返回汽车文档</li>
<li><code>/carsbymake/:id/:make</code> 端点,可根据经销商 ID 和汽车品牌检索并返回汽车文档</li>
<li><code>/carsbymake/:id/:model</code> 端点,可根据经销商 ID 和车型检索并返回汽车文档</li>
<li><code>/carsbymaxmileage/:id/:mileage</code> 端点,可根据经销商 ID 和里程限制检索并返回汽车文件,如下所示:
<ul>
<li>里程数:
<ul>
<li>小于或等于 50000</li>
<li>50000 至 100000</li>
<li>100000 至 150000</li>
<li>150000 至 200000</li>
<li>大于 200000</li>
</ul>
</li>
</ul>
</li>
<li><code>/carsbyprice/:id/:price</code> 端点,可根据经销商 ID 和价格约束检索并返回汽车文件,如下所示:
<ul>
<li>价格:
<ul>
<li>小于或等于 20000</li>
<li>20000 至 40000</li>
<li>40000 至 60000</li>
<li>60000 至 80000</li>
<li>大于 80000</li>
</ul>
</li>
</ul>
</li>
<li><code>/carsbymake/:id/:year</code> 端点,可根据经销商 ID 和最低年份约束检索并返回汽车文件</li>
</ul>
</li>
<li><code>3050</code> 端口启动服务器。</li>
</ul>
<figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*jshint esversion: 8 */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> express = <span class="built_in">require</span>(<span class="string">'express'</span>);</span><br><span class="line"><span class="keyword">const</span> mongoose = <span class="built_in">require</span>(<span class="string">'mongoose'</span>);</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"><span class="keyword">const</span> cors = <span class="built_in">require</span>(<span class="string">'cors'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="title function_">express</span>();</span><br><span class="line"><span class="keyword">const</span> port = <span class="number">3050</span>;</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">cors</span>());</span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">urlencoded</span>({ <span class="attr">extended</span>: <span class="literal">false</span> }));</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> carsData = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(fs.<span class="title function_">readFileSync</span>(<span class="string">'car_records.json'</span>, <span class="string">'utf8'</span>));</span><br><span class="line"></span><br><span class="line">mongoose.<span class="title function_">connect</span>(<span class="string">'mongodb://mongo_db:27017/'</span>, { <span class="attr">dbName</span>: <span class="string">'dealershipsDB'</span> });</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Cars</span> = <span class="built_in">require</span>(<span class="string">'./inventory'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line">  <span class="title class_">Cars</span>.<span class="title function_">deleteMany</span>({}).<span class="title function_">then</span>(<span class="function">() =&gt;</span> {</span><br><span class="line">    <span class="title class_">Cars</span>.<span class="title function_">insertMany</span>(carsData.<span class="property">cars</span>);</span><br><span class="line">  });</span><br><span class="line">} <span class="keyword">catch</span> (error) {</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">error</span>(error);</span><br><span class="line">  <span class="comment">// Handle errors properly here</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">'/'</span>, <span class="title function_">async</span> (req, res) =&gt; {</span><br><span class="line">  res.<span class="title function_">send</span>(<span class="string">'Welcome to the Mongoose API'</span>);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">'/cars/:id'</span>, <span class="title function_">async</span> (req, res) =&gt; {</span><br><span class="line">  <span class="keyword">try</span> {</span><br><span class="line">    <span class="keyword">const</span> documents = <span class="keyword">await</span> <span class="title class_">Cars</span>.<span class="title function_">find</span>({<span class="attr">dealer_id</span>: req.<span class="property">params</span>.<span class="property">id</span>});</span><br><span class="line">    res.<span class="title function_">json</span>(documents);</span><br><span class="line">  } <span class="keyword">catch</span> (error) {</span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">json</span>({ <span class="attr">error</span>: <span class="string">'Error fetching reviews'</span> });</span><br><span class="line">  }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">'/carsbymake/:id/:make'</span>, <span class="title function_">async</span> (req, res) =&gt; {</span><br><span class="line">  <span class="keyword">try</span> {</span><br><span class="line">    <span class="keyword">const</span> documents = <span class="keyword">await</span> <span class="title class_">Cars</span>.<span class="title function_">find</span>({<span class="attr">dealer_id</span>: req.<span class="property">params</span>.<span class="property">id</span>, <span class="attr">make</span>: req.<span class="property">params</span>.<span class="property">make</span>});</span><br><span class="line">    res.<span class="title function_">json</span>(documents);</span><br><span class="line">  } <span class="keyword">catch</span> (error) {</span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">json</span>({ <span class="attr">error</span>: <span class="string">'Error fetching reviews by car make and model'</span> });</span><br><span class="line">  }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">'/carsbymodel/:id/:model'</span>, <span class="title function_">async</span> (req, res) =&gt; {</span><br><span class="line">  <span class="keyword">try</span> {</span><br><span class="line">    <span class="keyword">const</span> documents = <span class="keyword">await</span> <span class="title class_">Cars</span>.<span class="title function_">find</span>({ <span class="attr">dealer_id</span>: req.<span class="property">params</span>.<span class="property">id</span>, <span class="attr">model</span>: req.<span class="property">params</span>.<span class="property">model</span> });</span><br><span class="line">    res.<span class="title function_">json</span>(documents);</span><br><span class="line">  } <span class="keyword">catch</span> (error) {</span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">json</span>({ <span class="attr">error</span>: <span class="string">'Error fetching dealers by ID'</span> });</span><br><span class="line">  }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">'/carsbymaxmileage/:id/:mileage'</span>, <span class="title function_">async</span> (req, res) =&gt; {</span><br><span class="line">  <span class="keyword">try</span> {</span><br><span class="line">    <span class="keyword">let</span> mileage = <span class="built_in">parseInt</span>(req.<span class="property">params</span>.<span class="property">mileage</span>)</span><br><span class="line">    <span class="keyword">let</span> condition = {}</span><br><span class="line">    <span class="keyword">if</span>(mileage === <span class="number">50000</span>) {</span><br><span class="line">      condition = { $lte : mileage}</span><br><span class="line">    } <span class="keyword">else</span> <span class="keyword">if</span> (mileage === <span class="number">100000</span>){</span><br><span class="line">      condition = { $lte : mileage, $gt : <span class="number">50000</span>}</span><br><span class="line">    } <span class="keyword">else</span> <span class="keyword">if</span> (mileage === <span class="number">150000</span>){</span><br><span class="line">      condition = { $lte : mileage, $gt : <span class="number">100000</span>}</span><br><span class="line">    } <span class="keyword">else</span> <span class="keyword">if</span> (mileage === <span class="number">200000</span>){</span><br><span class="line">      condition = { $lte : mileage, $gt : <span class="number">150000</span>}</span><br><span class="line">    } <span class="keyword">else</span> {</span><br><span class="line">      condition = { $gt : <span class="number">200000</span>}</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">const</span> documents = <span class="keyword">await</span> <span class="title class_">Cars</span>.<span class="title function_">find</span>({ <span class="attr">dealer_id</span>: req.<span class="property">params</span>.<span class="property">id</span>, mileage : condition });</span><br><span class="line">    res.<span class="title function_">json</span>(documents);</span><br><span class="line">  } <span class="keyword">catch</span> (error) {</span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">json</span>({ <span class="attr">error</span>: <span class="string">'Error fetching dealers by ID'</span> });</span><br><span class="line">  }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">'/carsbyprice/:id/:price'</span>, <span class="title function_">async</span> (req, res) =&gt; {</span><br><span class="line">  <span class="keyword">try</span> {</span><br><span class="line">    <span class="keyword">let</span> price = <span class="built_in">parseInt</span>(req.<span class="property">params</span>.<span class="property">price</span>)</span><br><span class="line">    <span class="keyword">let</span> condition = {}</span><br><span class="line">    <span class="keyword">if</span>(price === <span class="number">20000</span>) {</span><br><span class="line">      condition = { $lte : price}</span><br><span class="line">    } <span class="keyword">else</span> <span class="keyword">if</span> (price=== <span class="number">40000</span>){</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"\n \n \n "</span>+ price)  </span><br><span class="line">      condition = { $lte : price, $gt : <span class="number">20000</span>}</span><br><span class="line">    } <span class="keyword">else</span> <span class="keyword">if</span> (price === <span class="number">60000</span>){</span><br><span class="line">      condition = { $lte : price, $gt : <span class="number">40000</span>}</span><br><span class="line">    } <span class="keyword">else</span> <span class="keyword">if</span> (price === <span class="number">80000</span>){</span><br><span class="line">      condition = { $lte : price, $gt : <span class="number">60000</span>}</span><br><span class="line">    } <span class="keyword">else</span> {</span><br><span class="line">      condition = { $gt : <span class="number">80000</span>}</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">const</span> documents = <span class="keyword">await</span> <span class="title class_">Cars</span>.<span class="title function_">find</span>({ <span class="attr">dealer_id</span>: req.<span class="property">params</span>.<span class="property">id</span>, price : condition });</span><br><span class="line">    res.<span class="title function_">json</span>(documents);</span><br><span class="line">  } <span class="keyword">catch</span> (error) {</span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">json</span>({ <span class="attr">error</span>: <span class="string">'Error fetching dealers by ID'</span> });</span><br><span class="line">  }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">'/carsbyyear/:id/:year'</span>, <span class="title function_">async</span> (req, res) =&gt; {</span><br><span class="line">  <span class="keyword">try</span> {</span><br><span class="line">    <span class="keyword">const</span> documents = <span class="keyword">await</span> <span class="title class_">Cars</span>.<span class="title function_">find</span>({ <span class="attr">dealer_id</span>: req.<span class="property">params</span>.<span class="property">id</span>, year : { $gte :req.<span class="property">params</span>.<span class="property">year</span> }});</span><br><span class="line">    res.<span class="title function_">json</span>(documents);</span><br><span class="line">  } <span class="keyword">catch</span> (error) {</span><br><span class="line">    res.<span class="title function_">status</span>(<span class="number">500</span>).<span class="title function_">json</span>({ <span class="attr">error</span>: <span class="string">'Error fetching dealers by ID'</span> });</span><br><span class="line">  }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(port, <span class="function">() =&gt;</span> {</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Server is running on http://localhost:<span class="subst">${port}</span>`</span>);</span><br><span class="line">});</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>为 Node.JS 应用程序创建 Docker 镜像。首先创建 <code>Dockerfile</code></p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> Dockerfile</span><br></pre></td></tr></tbody></table></figure>
<p>添加以下内容:</p>
<ul>
<li>基础 Docker 镜像:<code>node:18.12.1-bullseye-slim</code></li>
<li>安装 <code>9.1.3</code> 版本的 <code>npm</code></li>
<li>从当前目录内添加 <code>package.json</code><code>app.js</code><code>car_records.json</code> 到 Docker 镜像的根目录</li>
<li>复制当前目录的所有文件到 Docker 镜像</li>
<li>让容器监听 3050 端口</li>
<li>将容器启动时要运行的默认命令指定为 <code>node app.js</code></li>
</ul>
<figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> node:<span class="number">18.12</span>.<span class="number">1</span>-bullseye-slim</span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> npm install -g npm@9.1.3</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ADD</span><span class="language-bash"> package.json .</span></span><br><span class="line"><span class="keyword">ADD</span><span class="language-bash"> app.js .</span></span><br><span class="line"><span class="keyword">ADD</span><span class="language-bash"> data/car_records.json .</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> . .</span></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> npm install</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">EXPOSE</span> <span class="number">3050</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">CMD</span><span class="language-bash"> [ <span class="string">"node"</span>, <span class="string">"app.js"</span> ]</span></span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>为运行两个服务(MongoDB 容器和 Node.JS 应用程序)设置 Docker Compose 配置文件。<br>
创建 Docker Compose 配置 YAML 文件(<code>docker-compose.yml</code>):</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> docker-compose.yml</span><br></pre></td></tr></tbody></table></figure>
<p>添加内容:</p>
<figure class="highlight yaml"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">'3.9'</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="comment"># Mongodb service</span></span><br><span class="line">  <span class="attr">mongo_db:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">carsInventory_container</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">mongo:latest</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="number">27018</span><span class="string">:27017</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">mongo_data:/data/db</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># Node api service</span></span><br><span class="line">  <span class="attr">api:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nodeapp</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="number">3050</span><span class="string">:3050</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">mongo_db</span></span><br><span class="line"></span><br><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="attr">mongo_data:</span> {}</span><br></pre></td></tr></tbody></table></figure>
<p>构建 Docker 应用:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker build . -t nodeapp</span><br></pre></td></tr></tbody></table></figure>
<p>执行以下命令启动服务器:</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up</span><br></pre></td></tr></tbody></table></figure>
<p>启动服务器并验证汽车库存服务的根端点是否显示了 <code>Welcome to the Mongoose API</code> 的消息。</p>
</li>
</ol>
<h4 id="将微服务与-django-应用程序后端集成并成功启动后端服务器"><a class="markdownIt-Anchor" href="#将微服务与-django-应用程序后端集成并成功启动后端服务器"></a> 将微服务与 Django 应用程序后端集成,并成功启动后端服务器</h4>
<ol>
<li>
<p>导航至 <code>xrwvm-fullstack_developer_capstone/server</code> 目录。如果 Django 服务器已在运行,则停止该服务器。</p>
</li>
<li>
<p><code>.env</code> 文件中插入汽车库存服务端点的 URL(上一节已复制)。</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">searchcars_url='your end'</span><br></pre></td></tr></tbody></table></figure>
<blockquote>
<p>不要添加尾端的 <code>\</code></p>
</blockquote>
</li>
<li>
<p><code>restapis.py</code> 中加入执行以下功能的代码:</p>
<ol>
<li>
<p><code>.env</code> 文件中获取 URL。</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">searchcars_url = os.getenv(</span><br><span class="line">    <span class="string">'searchcars_url'</span>,</span><br><span class="line">    default=<span class="string">"http://localhost:3050/"</span></span><br><span class="line">)</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>执行一个名为 <code>searchcars_request</code> 的方法,该方法具有以下功能:</p>
<ul>
<li>接受端点和变量关键字参数</li>
<li>利用提供的端点、查询参数和基本 URL 构建一个完整的请求 URL</li>
<li>执行 GET 请求并返回响应的 JSON 内容</li>
<li>处理错误(包括网络异常)并提供成功完成消息</li>
</ul>
<p>代码结构将与您之前在 Capstone 主项目中创建的 <code>get_request</code> 方法非常相似:</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">searchcars_request</span>(<span class="params">endpoint, **kwargs</span>):</span><br><span class="line">    params = <span class="string">""</span></span><br><span class="line">    <span class="keyword">if</span> (kwargs):</span><br><span class="line">    <span class="keyword">for</span> key, value <span class="keyword">in</span> kwargs.items():</span><br><span class="line">        params = params+key + <span class="string">"="</span> + value + <span class="string">"&amp;"</span></span><br><span class="line"></span><br><span class="line">        request_url = searchcars_url+endpoint+<span class="string">"?"</span>+params</span><br><span class="line"></span><br><span class="line">        <span class="built_in">print</span>(<span class="string">"GET from {} "</span>.<span class="built_in">format</span>(request_url))</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="comment"># Call get method of requests library with URL and parameters</span></span><br><span class="line">            response = requests.get(request_url)</span><br><span class="line">            <span class="keyword">return</span> response.json()</span><br><span class="line">        <span class="keyword">except</span>:</span><br><span class="line">            <span class="comment"># If any error occurs</span></span><br><span class="line">            <span class="built_in">print</span>(<span class="string">"Network exception occurred"</span>)</span><br><span class="line">        <span class="keyword">finally</span>:</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">"GET request call complete!"</span>)</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
</li>
<li>
<p><code>djangoapp/views.py</code> 文件中添加名为 <code>get_inventory</code> 的视图,以获取汽车库存。</p>
<ul>
<li>该视图应处理 HTTP 请求,提取查询参数和经销商 ID。</li>
<li>它应使用提供的参数构建一个 API 端点,并调用 <code>restapis.py</code> 中定义的 <code>searchcars_request</code> 函数来检索汽车数据。确保为 <code>searchcars_request</code> 函数加入模块导入。</li>
<li>它应返回状态为 <code>200</code> 的 JSON 响应,如果提供了经销商 ID,则返回获取的汽车。</li>
<li>如果没有经销商 ID,则应返回状态为 <code>400</code> 的 JSON 响应和 <code>Bad Request</code> 消息。</li>
</ul>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Module import</span></span><br><span class="line"><span class="keyword">from</span> .restapis <span class="keyword">import</span> get_request, analyze_review_sentiments, post_review, searchcars_request</span><br><span class="line"></span><br><span class="line"><span class="comment"># Code for the view</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_inventory</span>(<span class="params">request, dealer_id</span>):</span><br><span class="line">    data = request.GET</span><br><span class="line">    <span class="keyword">if</span> (dealer_id):</span><br><span class="line">        <span class="keyword">if</span> <span class="string">'year'</span> <span class="keyword">in</span> data:</span><br><span class="line">            endpoint = <span class="string">"/carsbyyear/"</span>+<span class="built_in">str</span>(dealer_id)+<span class="string">"/"</span>+data[<span class="string">'year'</span>]</span><br><span class="line">        <span class="keyword">elif</span> <span class="string">'make'</span> <span class="keyword">in</span> data:</span><br><span class="line">            endpoint = <span class="string">"/carsbymake/"</span>+<span class="built_in">str</span>(dealer_id)+<span class="string">"/"</span>+data[<span class="string">'make'</span>]</span><br><span class="line">        <span class="keyword">elif</span> <span class="string">'model'</span> <span class="keyword">in</span> data:</span><br><span class="line">            endpoint = <span class="string">"/carsbymodel/"</span>+<span class="built_in">str</span>(dealer_id)+<span class="string">"/"</span>+data[<span class="string">'model'</span>]</span><br><span class="line">        <span class="keyword">elif</span> <span class="string">'mileage'</span> <span class="keyword">in</span> data:</span><br><span class="line">            endpoint = <span class="string">"/carsbymaxmileage/"</span>+<span class="built_in">str</span>(dealer_id)+<span class="string">"/"</span>+data[<span class="string">'mileage'</span>]</span><br><span class="line">        <span class="keyword">elif</span> <span class="string">'price'</span> <span class="keyword">in</span> data:</span><br><span class="line">            endpoint = <span class="string">"/carsbyprice/"</span>+<span class="built_in">str</span>(dealer_id)+<span class="string">"/"</span>+data[<span class="string">'price'</span>]</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            endpoint = <span class="string">"/cars/"</span>+<span class="built_in">str</span>(dealer_id)</span><br><span class="line"></span><br><span class="line">        cars = searchcars_request(endpoint)</span><br><span class="line">        <span class="keyword">return</span> JsonResponse({<span class="string">"status"</span>: <span class="number">200</span>, <span class="string">"cars"</span>: cars})</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="keyword">return</span> JsonResponse({<span class="string">"status"</span>: <span class="number">400</span>, <span class="string">"message"</span>: <span class="string">"Bad Request"</span>})</span><br><span class="line">    <span class="keyword">return</span> JsonResponse({<span class="string">"status"</span>: <span class="number">400</span>, <span class="string">"message"</span>: <span class="string">"Bad Request"</span>})</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p><code>djangoapp/urls.py</code> 文件中包含该视图的路由。</p>
<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">path(route=<span class="string">'get_inventory/&lt;int:dealer_id&gt;'</span>, view=views.get_inventory, name=<span class="string">'get_inventory'</span>),</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>导航到 <code>xrwvm-fullstack_developer_capstone/server</code> 目录。<br>
确保 Docker Compose 服务器正在运行。如果没有,请使用 <code>docker-compose up</code> 命令启动它。</p>
</li>
<li>
<p>执行模型迁移并启动服务器。</p>
<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">python3 manage.py makemigrations</span><br><span class="line">python3 manage.py migrate</span><br><span class="line">python3 manage.py runserver</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>
<p>确保服务器启动成功且无错误。如果出现任何错误日志,请检查并根据需要处理您的代码。</p>
</li>
</ol>
<h2 id="汽车库存服务的前端开发"><a class="markdownIt-Anchor" href="#汽车库存服务的前端开发"></a> 汽车库存服务的前端开发</h2>
<h4 id="开发并集成与后端汽车库存微服务相对应的前端服务"><a class="markdownIt-Anchor" href="#开发并集成与后端汽车库存微服务相对应的前端服务"></a> 开发并集成与后端汽车库存微服务相对应的前端服务</h4>
<p>这需要创建一个 React 组件,专门用于搜索和显示汽车信息,并为该组件整合相应的路线。</p>
<ol>
<li>
<p>创建一个用于搜索和显示汽车信息的 React 组件。</p>
<ol>
<li>导航至 <code>xrwvm-fullstack_developer_capstone/server/frontend/src/components/Dealers</code> 目录,并添加名为 <code>SearchCars.jsx</code> 的新文件。</li>
<li>在该文件中加入以下内容:<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, { useState, useEffect } <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> { useParams } <span class="keyword">from</span> <span class="string">'react-router-dom'</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Header</span> <span class="keyword">from</span> <span class="string">'../Header/Header'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">SearchCars</span> = (<span class="params"></span>) =&gt; {</span><br><span class="line">  <span class="keyword">const</span> [cars, setCars] = <span class="title function_">useState</span>([]);</span><br><span class="line">  <span class="keyword">const</span> [makes, setMakes] = <span class="title function_">useState</span>([]);</span><br><span class="line">  <span class="keyword">const</span> [models, setModels] = <span class="title function_">useState</span>([]);</span><br><span class="line">  <span class="keyword">const</span> [dealer, setDealer] = <span class="title function_">useState</span>({<span class="string">"full_name"</span>:<span class="string">""</span>});</span><br><span class="line">  <span class="keyword">const</span> [message, setMessage] = <span class="title function_">useState</span>(<span class="string">"Loading Cars...."</span>);</span><br><span class="line">  <span class="keyword">const</span> { id } = <span class="title function_">useParams</span>();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> dealer_url = <span class="string">`/djangoapp/get_inventory/<span class="subst">${id}</span>`</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> fetch_url = <span class="string">`/djangoapp/dealer/<span class="subst">${id}</span>`</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">fetchDealer</span> = <span class="keyword">async</span> (<span class="params"></span>)=&gt;{</span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> <span class="title function_">fetch</span>(fetch_url, {</span><br><span class="line">      <span class="attr">method</span>: <span class="string">"GET"</span></span><br><span class="line">    });</span><br><span class="line">    <span class="keyword">const</span> retobj = <span class="keyword">await</span> res.<span class="title function_">json</span>();</span><br><span class="line">    <span class="keyword">if</span>(retobj.<span class="property">status</span> === <span class="number">200</span>) {</span><br><span class="line">      <span class="keyword">let</span> dealer = retobj.<span class="property">dealer</span>;</span><br><span class="line">      <span class="title function_">setDealer</span>({<span class="string">"full_name"</span>:dealer[<span class="number">0</span>].<span class="property">full_name</span>})</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">populateMakesAndModels</span> = (<span class="params">cars</span>)=&gt;{</span><br><span class="line">    <span class="keyword">let</span> tmpmakes = []</span><br><span class="line">    <span class="keyword">let</span> tmpmodels = []</span><br><span class="line">    cars.<span class="title function_">forEach</span>(<span class="function">(<span class="params">car</span>)=&gt;</span>{</span><br><span class="line">      tmpmakes.<span class="title function_">push</span>(car.<span class="property">make</span>)</span><br><span class="line">      tmpmodels.<span class="title function_">push</span>(car.<span class="property">model</span>)</span><br><span class="line">    })</span><br><span class="line">    <span class="title function_">setMakes</span>(<span class="title class_">Array</span>.<span class="title function_">from</span>(<span class="keyword">new</span> <span class="title class_">Set</span>(tmpmakes)));</span><br><span class="line">    <span class="title function_">setModels</span>(<span class="title class_">Array</span>.<span class="title function_">from</span>(<span class="keyword">new</span> <span class="title class_">Set</span>(tmpmodels)));</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">fetchCars</span> = <span class="keyword">async</span> (<span class="params"></span>)=&gt;{</span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> <span class="title function_">fetch</span>(dealer_url, {</span><br><span class="line">      <span class="attr">method</span>: <span class="string">"GET"</span></span><br><span class="line">    });</span><br><span class="line">    <span class="keyword">const</span> retobj = <span class="keyword">await</span> res.<span class="title function_">json</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(retobj.<span class="property">status</span> === <span class="number">200</span>) {</span><br><span class="line">      <span class="keyword">let</span> cars = <span class="title class_">Array</span>.<span class="title function_">from</span>(retobj.<span class="property">cars</span>)</span><br><span class="line">      <span class="title function_">setCars</span>(cars);</span><br><span class="line">      <span class="title function_">populateMakesAndModels</span>(cars);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">setCarsmatchingCriteria</span> = <span class="keyword">async</span>(<span class="params">matching_cars</span>)=&gt;{</span><br><span class="line">    <span class="keyword">let</span> cars = <span class="title class_">Array</span>.<span class="title function_">from</span>(matching_cars)</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"Number of matching cars "</span>+cars.<span class="property">length</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> makeIdx = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'make'</span>).<span class="property">selectedIndex</span>;</span><br><span class="line">    <span class="keyword">let</span> modelIdx = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'model'</span>).<span class="property">selectedIndex</span>;</span><br><span class="line">    <span class="keyword">let</span> yearIdx = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'year'</span>).<span class="property">selectedIndex</span>;</span><br><span class="line">    <span class="keyword">let</span> mileageIdx = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'mileage'</span>).<span class="property">selectedIndex</span>;</span><br><span class="line">    <span class="keyword">let</span> priceIdx = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'price'</span>).<span class="property">selectedIndex</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(makeIdx !== <span class="number">0</span>) {</span><br><span class="line">      <span class="keyword">let</span> currmake = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'make'</span>).<span class="property">value</span>;</span><br><span class="line">      cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">make</span> === currmake);</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">if</span>(modelIdx !== <span class="number">0</span>) {</span><br><span class="line">      <span class="keyword">let</span> currmodel = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'model'</span>).<span class="property">value</span>;</span><br><span class="line">      cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">model</span> === currmodel);</span><br><span class="line">      <span class="keyword">if</span>(cars.<span class="property">length</span> !== <span class="number">0</span>) {</span><br><span class="line">        <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'make'</span>).<span class="property">value</span> = cars[<span class="number">0</span>].<span class="property">make</span>;</span><br><span class="line">      }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(yearIdx !== <span class="number">0</span>) {</span><br><span class="line">      <span class="keyword">let</span> curryear = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'year'</span>).<span class="property">value</span>;</span><br><span class="line">      cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">year</span> &gt;= curryear);</span><br><span class="line">      <span class="keyword">if</span>(cars.<span class="property">length</span> !== <span class="number">0</span>) {</span><br><span class="line">        <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'make'</span>).<span class="property">value</span> = cars[<span class="number">0</span>].<span class="property">make</span>;</span><br><span class="line">      }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(mileageIdx !== <span class="number">0</span>) {</span><br><span class="line">      <span class="keyword">let</span> currmileage = <span class="built_in">parseInt</span>(<span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'mileage'</span>).<span class="property">value</span>);</span><br><span class="line">      <span class="keyword">if</span>(currmileage === <span class="number">50000</span>) {</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">mileage</span> &lt;= currmileage);</span><br><span class="line">      } <span class="keyword">else</span> <span class="keyword">if</span> (currmileage === <span class="number">100000</span>){</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">mileage</span> &lt;= currmileage &amp;&amp; car.<span class="property">mileage</span> &gt; <span class="number">50000</span>);</span><br><span class="line">      } <span class="keyword">else</span> <span class="keyword">if</span> (currmileage === <span class="number">150000</span>){</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">mileage</span> &lt;= currmileage &amp;&amp; car.<span class="property">mileage</span> &gt; <span class="number">100000</span>);</span><br><span class="line">      } <span class="keyword">else</span> <span class="keyword">if</span> (currmileage === <span class="number">200000</span>){</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">mileage</span> &lt;= currmileage &amp;&amp; car.<span class="property">mileage</span> &gt; <span class="number">150000</span>);</span><br><span class="line">      } <span class="keyword">else</span> {</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">mileage</span> &gt; <span class="number">200000</span>);</span><br><span class="line">      }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(priceIdx !== <span class="number">0</span>) {</span><br><span class="line">      <span class="keyword">let</span> currprice = <span class="built_in">parseInt</span>(<span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'price'</span>).<span class="property">value</span>);</span><br><span class="line">      <span class="keyword">if</span>(currprice === <span class="number">20000</span>) {</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">price</span> &lt;= currprice);</span><br><span class="line">      } <span class="keyword">else</span> <span class="keyword">if</span> (currprice === <span class="number">40000</span>){</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">price</span> &lt;= currprice &amp;&amp; car.<span class="property">price</span> &gt; <span class="number">20000</span>);</span><br><span class="line">      } <span class="keyword">else</span> <span class="keyword">if</span> (currprice === <span class="number">60000</span>){</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">price</span> &lt;= currprice &amp;&amp; car.<span class="property">price</span> &gt; <span class="number">40000</span>);</span><br><span class="line">      } <span class="keyword">else</span> <span class="keyword">if</span> (currprice === <span class="number">80000</span>){</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">price</span> &lt;= currprice &amp;&amp; car.<span class="property">price</span> &gt; <span class="number">60000</span>);</span><br><span class="line">      } <span class="keyword">else</span> {</span><br><span class="line">        cars = cars.<span class="title function_">filter</span>(<span class="function"><span class="params">car</span> =&gt;</span> car.<span class="property">price</span> &gt; <span class="number">80000</span>);</span><br><span class="line">      }</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(cars.<span class="property">length</span> === <span class="number">0</span>) {</span><br><span class="line">      <span class="title function_">setMessage</span>(<span class="string">"No cars found matching criteria"</span>);</span><br><span class="line">    }</span><br><span class="line">    <span class="title function_">setCars</span>(cars);</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> <span class="title function_">SearchCarsByMake</span> = <span class="keyword">async</span> (<span class="params"></span>)=&gt; {</span><br><span class="line">    <span class="keyword">let</span> make = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"make"</span>).<span class="property">value</span>;</span><br><span class="line">    dealer_url = dealer_url + <span class="string">"?make="</span>+make;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> <span class="title function_">fetch</span>(dealer_url, {</span><br><span class="line">      <span class="attr">method</span>: <span class="string">'GET'</span>,</span><br><span class="line">      <span class="attr">headers</span>: {</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      }})</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> retobj = <span class="keyword">await</span> res.<span class="title function_">json</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(retobj.<span class="property">status</span> === <span class="number">200</span>) {</span><br><span class="line">      <span class="title function_">setCarsmatchingCriteria</span>(retobj.<span class="property">cars</span>);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> <span class="title function_">SearchCarsByModel</span> = <span class="keyword">async</span> (<span class="params"></span>)=&gt; {</span><br><span class="line">    <span class="keyword">let</span> model = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"model"</span>).<span class="property">value</span>;</span><br><span class="line">    dealer_url = dealer_url + <span class="string">"?model="</span>+model;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> <span class="title function_">fetch</span>(dealer_url, {</span><br><span class="line">      <span class="attr">method</span>: <span class="string">'GET'</span>,</span><br><span class="line">      <span class="attr">headers</span>: {</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      }})</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> retobj = <span class="keyword">await</span> res.<span class="title function_">json</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(retobj.<span class="property">status</span> === <span class="number">200</span>) {</span><br><span class="line">      <span class="title function_">setCarsmatchingCriteria</span>(retobj.<span class="property">cars</span>);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> <span class="title function_">SearchCarsByYear</span> = <span class="keyword">async</span> (<span class="params"></span>)=&gt; {</span><br><span class="line">    <span class="keyword">let</span> year = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"year"</span>).<span class="property">value</span>;</span><br><span class="line">    <span class="keyword">if</span> (year !== <span class="string">"all"</span>) {</span><br><span class="line">      dealer_url = dealer_url + <span class="string">"?year="</span>+year;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> <span class="title function_">fetch</span>(dealer_url, {</span><br><span class="line">      <span class="attr">method</span>: <span class="string">'GET'</span>,</span><br><span class="line">      <span class="attr">headers</span>: {</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      }})</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> retobj = <span class="keyword">await</span> res.<span class="title function_">json</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(retobj.<span class="property">status</span> === <span class="number">200</span>) {</span><br><span class="line">      <span class="title function_">setCarsmatchingCriteria</span>(retobj.<span class="property">cars</span>);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> <span class="title function_">SearchCarsByMileage</span> = <span class="keyword">async</span> (<span class="params"></span>)=&gt; {</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> mileage = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"mileage"</span>).<span class="property">value</span>;</span><br><span class="line">    <span class="keyword">if</span> (mileage !== <span class="string">"all"</span>) {</span><br><span class="line">      dealer_url = dealer_url + <span class="string">"?mileage="</span>+mileage;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> <span class="title function_">fetch</span>(dealer_url, {</span><br><span class="line">      <span class="attr">method</span>: <span class="string">'GET'</span>,</span><br><span class="line">      <span class="attr">headers</span>: {</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      }})</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> retobj = <span class="keyword">await</span> res.<span class="title function_">json</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(retobj.<span class="property">status</span> === <span class="number">200</span>) {</span><br><span class="line">      <span class="title function_">setCarsmatchingCriteria</span>(retobj.<span class="property">cars</span>);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> <span class="title function_">SearchCarsByPrice</span> = <span class="keyword">async</span> (<span class="params"></span>)=&gt; {</span><br><span class="line">    <span class="keyword">let</span> price = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">"price"</span>).<span class="property">value</span>;</span><br><span class="line">    <span class="keyword">if</span>(price !== <span class="string">"all"</span>) {</span><br><span class="line">      dealer_url = dealer_url + <span class="string">"?price="</span>+price;</span><br><span class="line">    }</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> res = <span class="keyword">await</span> <span class="title function_">fetch</span>(dealer_url, {</span><br><span class="line">      <span class="attr">method</span>: <span class="string">'GET'</span>,</span><br><span class="line">      <span class="attr">headers</span>: {</span><br><span class="line">        <span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>,</span><br><span class="line">      }})</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> retobj = <span class="keyword">await</span> res.<span class="title function_">json</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(retobj.<span class="property">status</span> === <span class="number">200</span>) {</span><br><span class="line">      <span class="title function_">setCarsmatchingCriteria</span>(retobj.<span class="property">cars</span>);</span><br><span class="line">    }</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">reset</span> = (<span class="params"></span>)=&gt;{</span><br><span class="line">    <span class="keyword">const</span> selectElements = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">'select'</span>);</span><br><span class="line"></span><br><span class="line">    selectElements.<span class="title function_">forEach</span>(<span class="function">(<span class="params">select</span>) =&gt;</span> {</span><br><span class="line">      select.<span class="property">selectedIndex</span> = <span class="number">0</span>;</span><br><span class="line">    });</span><br><span class="line">    <span class="title function_">fetchCars</span>();</span><br><span class="line">  }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="title function_">useEffect</span>(<span class="function">() =&gt;</span> {</span><br><span class="line">    <span class="title function_">fetchCars</span>();</span><br><span class="line">    <span class="title function_">fetchDealer</span>();</span><br><span class="line">  },[]);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> (</span><br><span class="line">    <span class="language-xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">Header</span> /&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">h1</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginBottom:</span> '<span class="attr">20px</span>'}}&gt;</span>Cars at {dealer.full_name}<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">span</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">paddingLeft:</span> '<span class="attr">10px</span>'}}&gt;</span>Make<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">select</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">marginRight:</span> '<span class="attr">10px</span>' ,<span class="attr">paddingLeft:</span> '<span class="attr">10px</span>', <span class="attr">borderRadius</span> <span class="attr">:</span>'<span class="attr">10px</span>'}} <span class="attr">name</span>=<span class="string">"make"</span> <span class="attr">id</span>=<span class="string">"make"</span> <span class="attr">onChange</span>=<span class="string">{SearchCarsByMake}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          {makes.length === 0 ? (</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">''</span>&gt;</span>No data found<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          ):(</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;&gt;</span></span></span><br><span class="line"><span class="language-xml">              <span class="tag">&lt;<span class="name">option</span> <span class="attr">disabled</span> <span class="attr">defaultValue</span>&gt;</span> -- All -- <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">              {makes.map((make, index) =&gt; (</span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">option</span> <span class="attr">key</span>=<span class="string">{index}</span> <span class="attr">value</span>=<span class="string">{make}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                  {make}</span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">              ))}</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/&gt;</span></span></span><br><span class="line"><span class="language-xml">          )</span></span><br><span class="line"><span class="language-xml">          }</span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">span</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">paddingLeft:</span> '<span class="attr">10px</span>'}}&gt;</span>Model<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;<span class="name">select</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">marginRight:</span> '<span class="attr">10px</span>' ,<span class="attr">paddingLeft:</span> '<span class="attr">10px</span>', <span class="attr">borderRadius</span> <span class="attr">:</span>'<span class="attr">10px</span>'}} <span class="attr">name</span>=<span class="string">"model"</span> <span class="attr">id</span>=<span class="string">"model"</span> <span class="attr">onChange</span>=<span class="string">{SearchCarsByModel}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          {models.length === 0 ? (</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">''</span>&gt;</span>No data found<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          ) : (</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;&gt;</span></span></span><br><span class="line"><span class="language-xml">              <span class="tag">&lt;<span class="name">option</span> <span class="attr">disabled</span> <span class="attr">defaultValue</span>&gt;</span> -- All -- <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">              {models.map((model, index) =&gt; (</span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">option</span> <span class="attr">key</span>=<span class="string">{index}</span> <span class="attr">value</span>=<span class="string">{model}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                  {model}</span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">              ))}</span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;/&gt;</span></span></span><br><span class="line"><span class="language-xml">          )}</span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span></span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">span</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">paddingLeft:</span> '<span class="attr">10px</span>'}}&gt;</span>Year<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">select</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">marginRight:</span> '<span class="attr">10px</span>' ,<span class="attr">paddingLeft:</span> '<span class="attr">10px</span>', <span class="attr">borderRadius</span> <span class="attr">:</span>'<span class="attr">10px</span>'}} <span class="attr">name</span>=<span class="string">"year"</span> <span class="attr">id</span>=<span class="string">"year"</span> <span class="attr">onChange</span>=<span class="string">{SearchCarsByYear}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">selected</span> <span class="attr">value</span>=<span class="string">'all'</span>&gt;</span> -- All -- <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2024'</span>&gt;</span>2024 or newer<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2023'</span>&gt;</span>2023 or newer<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2022'</span>&gt;</span>2022 or newer<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2021'</span>&gt;</span>2021 or newer<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2020'</span>&gt;</span>2020 or newer<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span></span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">span</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">paddingLeft:</span> '<span class="attr">10px</span>'}}&gt;</span>Mileage<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">select</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">marginRight:</span> '<span class="attr">10px</span>' ,<span class="attr">paddingLeft:</span> '<span class="attr">10px</span>', <span class="attr">borderRadius</span> <span class="attr">:</span>'<span class="attr">10px</span>'}} <span class="attr">name</span>=<span class="string">"mileage"</span> <span class="attr">id</span>=<span class="string">"mileage"</span> <span class="attr">onChange</span>=<span class="string">{SearchCarsByMileage}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">selected</span> <span class="attr">value</span>=<span class="string">'all'</span>&gt;</span> -- All -- <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'50000'</span>&gt;</span>Under 50000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'100000'</span>&gt;</span>50000 - 100000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'150000'</span>&gt;</span>100000 - 150000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'200000'</span>&gt;</span>150000 - 200000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'200001'</span>&gt;</span>Over 200000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span></span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">span</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">paddingLeft:</span> '<span class="attr">10px</span>'}}&gt;</span>Price<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">select</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">marginRight:</span> '<span class="attr">10px</span>' ,<span class="attr">paddingLeft:</span> '<span class="attr">10px</span>', <span class="attr">borderRadius</span> <span class="attr">:</span>'<span class="attr">10px</span>'}} <span class="attr">name</span>=<span class="string">"price"</span> <span class="attr">id</span>=<span class="string">"price"</span> <span class="attr">onChange</span>=<span class="string">{SearchCarsByPrice}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">selected</span> <span class="attr">value</span>=<span class="string">'all'</span>&gt;</span> -- All -- <span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'20000'</span>&gt;</span>Under 20000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'40000'</span>&gt;</span>20000 - 40000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'60000'</span>&gt;</span>40000 - 60000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'80000'</span>&gt;</span>60000 - 80000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">option</span> <span class="attr">value</span>=<span class="string">'80001'</span>&gt;</span>Over 80000<span class="tag">&lt;/<span class="name">option</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line">        <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">style</span>=<span class="string">{{marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">paddingLeft:</span> '<span class="attr">10px</span>'}} <span class="attr">onClick</span>=<span class="string">{reset}</span>&gt;</span>Reset<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"></span><br><span class="line">      &lt;/div&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">      <span class="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">marginRight:</span> '<span class="attr">10px</span>' , <span class="attr">marginTop:</span> '<span class="attr">20px</span>'}} &gt;</span></span></span><br><span class="line"><span class="language-xml">        {cars.length === 0 ? (</span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">p</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginLeft:</span> '<span class="attr">10px</span>', <span class="attr">marginRight:</span> '<span class="attr">10px</span>', <span class="attr">marginTop:</span> '<span class="attr">20px</span>' }}&gt;</span>{message}<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        ) : (</span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            <span class="tag">&lt;<span class="name">hr</span>/&gt;</span></span></span><br><span class="line"><span class="language-xml">            {cars.map((car) =&gt; (</span></span><br><span class="line"><span class="language-xml">              <span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">key</span>=<span class="string">{car._id}</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                  <span class="tag">&lt;<span class="name">h3</span>&gt;</span>{car.make} {car.model}<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                  <span class="tag">&lt;<span class="name">p</span>&gt;</span>Year: {car.year}<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                  <span class="tag">&lt;<span class="name">p</span>&gt;</span>Mileage: {car.mileage}<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                  <span class="tag">&lt;<span class="name">p</span>&gt;</span>Price: {car.price}<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">                <span class="tag">&lt;<span class="name">hr</span>/&gt;</span></span></span><br><span class="line"><span class="language-xml">              <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">            ))}</span></span><br><span class="line"><span class="language-xml">          <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">        )}</span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  );</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">SearchCars</span>;</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
</li>
<li>
<p>为该组件添加路由并构建前端。</p>
<ol>
<li><code>frontend/src/App.js</code> 中为该组件添加导入语句和路由,将搜索路径设为 <code>/searchcars/:id</code><figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">SearchCars</span> <span class="keyword">from</span> <span class="string">"./components/Dealers/SearchCars"</span>;	</span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;<span class="title class_">Route</span> path=<span class="string">"/searchcars/:id"</span> element={<span class="language-xml"><span class="tag">&lt;<span class="name">SearchCars</span> /&gt;</span></span>} /&gt;</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>整合锚链接,将用户从特定经销商的评论页面重定向到 <code>Search Cars</code> 页面。
<ul>
<li>转到 <code>frontend/src/components/Dealers/Dealer.jsx</code>,插入一个锚元素。</li>
<li>将其标记为 <code>Search Cars</code>,并设置为点击后导航至 <code>Search Cars</code> 页面。</li>
</ul>
<figure class="highlight jsx"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;a href={<span class="string">`/searchcars/<span class="subst">${id}</span>`</span>}&gt;<span class="title class_">SearchCars</span>&lt;/a&gt;	</span><br></pre></td></tr></tbody></table></figure>
</li>
<li>构建应用程序的前端,以便部署。<figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run build</span><br></pre></td></tr></tbody></table></figure>
</li>
<li><code>djangoproj/urls.py</code> 中添加路径为 <code>searchcars/&lt;int:dealer_id&gt;</code> 的动态 URL 模式。<figure class="highlight python"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">path(<span class="string">'searchcars/&lt;int:dealer_id&gt;'</span>,TemplateView.as_view(template_name=<span class="string">"index.html"</span>)),</span><br></pre></td></tr></tbody></table></figure>
</li>
</ol>
</li>
</ol>
</body></html></div></article></div></main><footer><div class="paginator"><a class="prev" href="ed32.html">上一篇</a><a class="next" href="49c3.html">下一篇</a></div><!-- Webmention 显示区域--><div class="webmention-section webmention-empty" data-page-url="posts/41a3.html" data-full-url="https://cytrogen.icu/posts/41a3.html" data-mode="static">
              <h3 class="webmention-title">Webmentions (<span class="webmention-count">0</span>)</h3>
              <div class="webmention-list"></div>
              <span>暂无 Webmentions</span>
            </div><div class="copyright"><p class="footer-links"><a href="../friends/index.html">友链</a><span class="footer-separator"> ·</span><a href="../links/index.html">邻邦</a><span class="footer-separator"> ·</span><a href="../contact/index.html">联络</a><span class="footer-separator"> ·</span><a href="../colophon/index.html">营造记</a><span class="footer-separator"> ·</span><a href="../atom.xml">RSS订阅</a></p><p>© 2025 - 2026 <a href="https://cytrogen.icu">Cytrogen</a>, powered by <a href="https://hexo.io/" target="_blank">Hexo</a> and <a href="https://github.com/cytrogen/hexo-theme-ares" target="_blank">hexo-theme-ares</a>.</p><p><a href="https://blogscn.fun" target="_blank" rel="noopener">BLOGS·CN</a></p></div></footer></div></div><a class="back-to-top" href="#top" aria-label="返回顶部"><svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M3.293 9.707a1 1 0 010-1.414L9.586 2a2 2 0 012.828 0l6.293 6.293a1 1 0 01-1.414 1.414L11 3.414V17a1 1 0 11-2 0V3.414L2.707 9.707a1 1 0 01-1.414 0z"></path></svg></a><script>document.addEventListener('DOMContentLoaded', function() {
  const codeBlocks = document.querySelectorAll('figure.highlight');
  
  codeBlocks.forEach(block => {
    let caption = block.querySelector('figcaption');
    if (!caption) {
      caption = document.createElement('figcaption');
      block.insertBefore(caption, block.firstChild);
    }

    const info = document.createElement('div');
    info.className = 'info';
    
    const filename = caption.querySelector('span');
    if (filename) {
      filename.className = 'filename';
      info.appendChild(filename);
    }
    
    const lang = block.className.split(' ')[1];
    if (lang) {
      const langSpan = document.createElement('span');
      langSpan.className = 'lang-name';
      langSpan.textContent = lang;
      info.appendChild(langSpan);
    }

    const sourceLink = caption.querySelector('a');
    if (sourceLink) {
      sourceLink.className = 'source-link';
      info.appendChild(sourceLink);
    }

    const actions = document.createElement('div');
    actions.className = 'actions';

    const codeHeight = block.scrollHeight;
    const threshold = 300;

    if (codeHeight > threshold) {
      block.classList.add('folded');
      
      const toggleBtn = document.createElement('button');
      toggleBtn.textContent = '展开';
      toggleBtn.addEventListener('click', () => {
        block.classList.toggle('folded');
        toggleBtn.textContent = block.classList.contains('folded') ? '展开' : '折叠';
      });
      actions.appendChild(toggleBtn);
    }

    const copyBtn = document.createElement('button');
    copyBtn.textContent = '复制';
    copyBtn.addEventListener('click', async () => {
      const codeLines = block.querySelectorAll('.code .line');
      const code = Array.from(codeLines)
        .map(line => line.textContent)
        .join('\n')
        .replace(/\n\n/g, '\n');
      
      try {
        await navigator.clipboard.writeText(code);
        copyBtn.textContent = '已复制';
        copyBtn.classList.add('copied');
        
        setTimeout(() => {
          copyBtn.textContent = '复制';
          copyBtn.classList.remove('copied');
        }, 3000);
      } catch (err) {
        console.error('复制失败:', err);
        copyBtn.textContent = '复制失败';
        
        setTimeout(() => {
          copyBtn.textContent = '复制';
        }, 3000);
      }
    });
    actions.appendChild(copyBtn);

    caption.innerHTML = '';
    caption.appendChild(info);
    caption.appendChild(actions);

    const markedLines = block.getAttribute('data-marked-lines');
    if (markedLines) {
      const lines = markedLines.split(',');
      lines.forEach(range => {
        if (range.includes('-')) {
          const [start, end] = range.split('-').map(Number);
          for (let i = start; i <= end; i++) {
            const line = block.querySelector(`.line-${i}`);
            if (line) line.classList.add('marked');
          }
        } else {
          const line = block.querySelector(`.line-${range}`);
          if (line) line.classList.add('marked');
        }
      });
    }
  });
});</script><script async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" id="MathJax-script"></script><script>(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const themeToggle = document.querySelector('.theme-toggle');
    
    if (!themeToggle) return;
    
    const getCurrentTheme = () => {
      return document.documentElement.getAttribute('data-theme') || 'light';
    };
    
    const updateUI = (theme) => {
      const isDark = theme === 'dark';
      themeToggle.setAttribute('aria-pressed', isDark.toString());
    };
    
    const setTheme = (theme) => {
      document.documentElement.setAttribute('data-theme', theme);
      document.documentElement.style.colorScheme = theme;
      
      const pageWrapper = document.getElementById('page-wrapper');
      if (pageWrapper) {
        pageWrapper.setAttribute('data-theme', theme);
      }
      
      // Find and remove the temporary anti-flicker style tag if it exists.
      // This ensures the main stylesheet takes full control after the initial load.
      const antiFlickerStyle = document.getElementById('anti-flicker-style');
      if (antiFlickerStyle) {
        antiFlickerStyle.remove();
      }
      
      localStorage.setItem('theme', theme);
      updateUI(theme);
    };
    
    const toggleTheme = () => {
      const current = getCurrentTheme();
      const newTheme = current === 'light' ? 'dark' : 'light';
      setTheme(newTheme);
    };
    
    updateUI(getCurrentTheme());
    
    themeToggle.addEventListener('click', toggleTheme);
    
    if (window.matchMedia) {
      const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
      mediaQuery.addEventListener('change', function(e) {
        if (!localStorage.getItem('theme')) {
          const theme = e.matches ? 'dark' : 'light';
          setTheme(theme);
        }
      });
    }
  });
})();
</script><script src="../js/details-toggle.js" defer></script><script>(function() {
  document.addEventListener('DOMContentLoaded', function() {
    const backToTopBtn = document.querySelector('.back-to-top');
    
    if (!backToTopBtn) return;
    
    const toggleButtonVisibility = () => {
      const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
      const shouldShow = scrollTop > 200;
      
      if (shouldShow) {
        backToTopBtn.classList.add('is-visible');
      } else {
        backToTopBtn.classList.remove('is-visible');
      }
    };
    
    let ticking = false;
    const handleScroll = () => {
      if (!ticking) {
        requestAnimationFrame(() => {
          toggleButtonVisibility();
          ticking = false;
        });
        ticking = true;
      }
    };
    
    const scrollToTop = (event) => {
      event.preventDefault();
      window.scrollTo({
        top: 0,
        behavior: 'smooth'
      });
    };
    
    window.addEventListener('scroll', handleScroll);
    backToTopBtn.addEventListener('click', scrollToTop);
    
    toggleButtonVisibility();
  });
})();</script></body></html>