<!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><select></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"><select name=<span class="string">"state"</span> id=<span class="string">"state"</span> onChange={<span class="function">(<span class="params">e</span>) =></span> <span class="title function_">filterDealers</span>(e.<span class="property">target</span>.<span class="property">value</span>)}></span><br><span class="line"></select></span><br></pre></td></tr></tbody></table></figure>
</li>
<li>用包含以下属性的 <code><input></code> 字段取代现有的 <code><select></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"><input type=<span class="string">"text"</span> placeholder=<span class="string">"Search states..."</span> onChange={handleInputChange} onBlur={handleLostFocus} value={searchQuery} /></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>) => {</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> =></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>) => {</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"><<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>"}}></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"><<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>></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"><<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>></span>View Dealerships<span class="tag"></<span class="name">a</span>></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"><<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>></span>View Dealerships<span class="tag"></<span class="name">a</span>></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\" && 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">() =></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) => {</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) => {</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) => {</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) => {</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) => {</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) => {</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) => {</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">() =></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">"&"</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/<int:dealer_id>'</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>) => {</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>)=>{</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>)=>{</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>)=></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>)=>{</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>)=>{</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> =></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> =></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> =></span> car.<span class="property">year</span> >= 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> =></span> car.<span class="property">mileage</span> <= 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> =></span> car.<span class="property">mileage</span> <= currmileage && car.<span class="property">mileage</span> > <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> =></span> car.<span class="property">mileage</span> <= currmileage && car.<span class="property">mileage</span> > <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> =></span> car.<span class="property">mileage</span> <= currmileage && car.<span class="property">mileage</span> > <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> =></span> car.<span class="property">mileage</span> > <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> =></span> car.<span class="property">price</span> <= 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> =></span> car.<span class="property">price</span> <= currprice && car.<span class="property">price</span> > <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> =></span> car.<span class="property">price</span> <= currprice && car.<span class="property">price</span> > <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> =></span> car.<span class="property">price</span> <= currprice && car.<span class="property">price</span> > <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> =></span> car.<span class="property">price</span> > <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>)=> {</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>)=> {</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>)=> {</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>)=> {</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>)=> {</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>)=>{</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>) =></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">() =></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"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Header</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">h1</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginBottom:</span> '<span class="attr">20px</span>'}}></span>Cars at {dealer.full_name}<span class="tag"></<span class="name">h1</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<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>'}}></span>Make<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<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>></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"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">''</span>></span>No data found<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> ):(</span></span><br><span class="line"><span class="language-xml"> <span class="tag"><></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">disabled</span> <span class="attr">defaultValue</span>></span> -- All -- <span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> {makes.map((make, index) => (</span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<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>></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"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> ))}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></></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"></<span class="name">select</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<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>'}}></span>Model<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<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>></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"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">''</span>></span>No data found<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> ) : (</span></span><br><span class="line"><span class="language-xml"> <span class="tag"><></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">disabled</span> <span class="attr">defaultValue</span>></span> -- All -- <span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> {models.map((model, index) => (</span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<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>></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"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> ))}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></></span></span></span><br><span class="line"><span class="language-xml"> )}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">select</span>></span></span></span><br><span class="line"> <span class="language-xml"><span class="tag"><<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>'}}></span>Year<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"> <span class="language-xml"><span class="tag"><<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>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">selected</span> <span class="attr">value</span>=<span class="string">'all'</span>></span> -- All -- <span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2024'</span>></span>2024 or newer<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2023'</span>></span>2023 or newer<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2022'</span>></span>2022 or newer<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2021'</span>></span>2021 or newer<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'2020'</span>></span>2020 or newer<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">select</span>></span></span></span><br><span class="line"> <span class="language-xml"><span class="tag"><<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>'}}></span>Mileage<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"> <span class="language-xml"><span class="tag"><<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>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">selected</span> <span class="attr">value</span>=<span class="string">'all'</span>></span> -- All -- <span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'50000'</span>></span>Under 50000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'100000'</span>></span>50000 - 100000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'150000'</span>></span>100000 - 150000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'200000'</span>></span>150000 - 200000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'200001'</span>></span>Over 200000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">select</span>></span></span></span><br><span class="line"> <span class="language-xml"><span class="tag"><<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>'}}></span>Price<span class="tag"></<span class="name">span</span>></span></span></span><br><span class="line"> <span class="language-xml"><span class="tag"><<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>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">selected</span> <span class="attr">value</span>=<span class="string">'all'</span>></span> -- All -- <span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'20000'</span>></span>Under 20000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'40000'</span>></span>20000 - 40000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'60000'</span>></span>40000 - 60000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'80000'</span>></span>60000 - 80000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">'80001'</span>></span>Over 80000<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">select</span>></span></span></span><br><span class="line"></span><br><span class="line"> <span class="language-xml"><span class="tag"><<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>></span>Reset<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"></span><br><span class="line"> </div></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="language-xml"><span class="tag"><<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>'}} ></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"><<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>' }}></span>{message}<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> ) : (</span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">hr</span>/></span></span></span><br><span class="line"><span class="language-xml"> {cars.map((car) => (</span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">div</span> <span class="attr">key</span>=<span class="string">{car._id}</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">h3</span>></span>{car.make} {car.model}<span class="tag"></<span class="name">h3</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>Year: {car.year}<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>Mileage: {car.mileage}<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>Price: {car.price}<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">hr</span>/></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> ))}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> )}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> </div></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"><<span class="title class_">Route</span> path=<span class="string">"/searchcars/:id"</span> element={<span class="language-xml"><span class="tag"><<span class="name">SearchCars</span> /></span></span>} /></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"><a href={<span class="string">`/searchcars/<span class="subst">${id}</span>`</span>}><span class="title class_">SearchCars</span></a> </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/<int:dealer_id></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/<int:dealer_id>'</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>