type
Post
status
Published
date
Feb 8, 2026
slug
nextjs-shopping-platform-011
summary
tags
Next.js
category
编程学习
icon
password
1. Section Intro
In this section, we will continue on with the admin area. We have the overview page and the orders, now we want to be able to manage products, including create, read, update and delete as well as implement product images.
在本节中,我们将继续开发管理区域。我们已经有了概览页面和订单,现在我们希望能够管理产品,包括创建、读取、更新和删除,以及实现产品图片功能。
First we'll get the products and display them in the admin area.
首先,我们将获取产品并在管理区域中显示它们。
Then we'll add the ability to delete products. We'll re-use the delete dialog component that we used for the orders.
然后,我们将添加删除产品的功能。我们将重用之前用于订单的删除对话框组件。
Then we want to be able to create products. We'll create an action, add the form with a slugify option so we can get a slug from the title.
然后,我们希望能够创建产品。我们将创建一个操作,添加带有slugify选项的表单,这样我们就可以从标题生成slug。
We'll be using Uploadthing as our image upload service, so we have to configure that.
我们将使用Uploadthing作为我们的图片上传服务,所以我们需要配置它。
Then we'll implement the image uploading in the create form.
然后,我们将在创建表单中实现图片上传功能。
We're also going to have an is featured option and featured products can have a banner that will show on the homepage.
我们还将有一个is featured(精选)选项,精选产品可以有一个横幅,将显示在首页上。
Lastly, we'll add the ability to update products.
最后,我们将添加更新产品的功能。
2. Get Products For Admin Page 获取管理员页面产品列表
We now want to list all of the products in the admin area. We are going to have an action that not only gets the products but also filters them by category, price and ratings, etc. So I want to take this step by step and explain what we are doing.
我们现在希望在管理区域列出所有产品。我们将创建一个操作,不仅可以获取产品,还可以按类别、价格和评分等进行筛选。因此,我将逐步讲解我们正在做什么。
Let's start off by creating the page and the action.
让我们从创建页面和操作开始。
Create a new file at
app/admin/products/page.tsx and add the following:在
app/admin/products/page.tsx 创建一个新文件并添加以下内容:Now you should be able to go to
http://localhost:3000/admin/products and see the page. It should just say, "Products" at the top.现在你应该能够访问
http://localhost:3000/admin/products 并看到页面。页面顶部应该只显示 "Products"。There are a few search params that we want to pass into the
AdminProductsPage component and set some variables depending on those values. Add the following:我们希望在
AdminProductsPage 组件中传递一些搜索参数,并根据这些值设置一些变量。添加以下内容:Be sure to import the
requireAdmin function at the top of the file:确保在文件顶部导入
requireAdmin 函数:From the search params, we want to get the query, category and page. The query is the search term that we are looking for in the product name. If it is empty, we want to get all the products. If category is empty, we want to get all the products. If page is empty, we want to get the first page.
从搜索参数中,我们希望获取 query(查询)、category(类别)和 page(页码)。query 是我们在产品名称中搜索的关键词。如果为空,我们希望获取所有产品。如果 category 为空,我们希望获取所有产品。如果 page 为空,我们希望获取第一页。
Start The Action 开始创建操作
Next, let's create the action to get all the products. Open the file
lib/actions/products.action.ts and let's start by creating the function signature, meaning the parameters that we want to pass in and their types.接下来,让我们创建获取所有产品的操作。打开文件
lib/actions/products.action.ts,首先创建函数签名,即我们要传入的参数及其类型。Add the following:
添加以下内容:
So it will take in the following parameters:
因此,它将接受以下参数:
- query - A search term to look for in product names.
- query - 用于在产品名称中搜索的关键词。
- limit - The maximum number of products to retrieve per page (defaulted to PAGE_SIZE).
- limit - 每页检索的最大产品数量(默认为 PAGE_SIZE)。
- page - The current page number, used for pagination.
- page - 当前页码,用于分页。
- category - The category to filter products by.
- category - 用于筛选产品的类别。
We need to import the
PAGE_SIZE constant from the lib/constants/index.ts file:我们需要从
lib/constants/index.ts 文件导入 PAGE_SIZE 常量:Now, let's add the following to find the products:
现在,让我们添加以下内容来查找产品:
We are using the
skip and take methods to paginate the results. We are skipping (page - 1) * limit products and taking limit products. This is how we can get the products for the current page.我们使用
skip 和 take 方法来对结果进行分页。我们跳过 (page - 1) * limit 个产品,并获取 limit 个产品。这就是我们如何获取当前页面产品的方法。Handle pagination 处理分页
In order to have pagination, we need to get the total number of products. Add this to the function:
为了实现分页,我们需要获取产品的总数。将此添加到函数中:
Now just return an object with the
data and the total pages:现在只需返回一个包含
data 和总页数的对象:Here is the entire action for now:
这是目前完整的操作代码:
Now let's bring this into our page. Open the
app/admin/products/page.tsx file and add the following imports:现在让我们将其引入到页面中。打开
app/admin/products/page.tsx 文件并添加以下导入:We are bringing in the
getAllProducts action and the formatCurrency and formatId functions from the lib/utils file as well as the Link component from next/link.我们引入了
getAllProducts 操作,以及来自 lib/utils 文件的 formatCurrency 和 formatId 函数,还有来自 next/link 的 Link 组件。Add the following right above the return statement and under the other variables:
在 return 语句上方和其他变量下方添加以下内容:
We are then calling the
getAllProducts function with the search text and the page number. We are also logging the products to the console.然后我们调用
getAllProducts 函数,传入搜索文本和页码。我们还将产品记录到控制台。Now when you go to the page, you should see the products and total pages in the console. This should be in your terminal not in the browser because we are rendering this on the server.
现在当你访问页面时,你应该能在控制台中看到产品和总页数。这应该显示在你的终端中,而不是浏览器中,因为我们是在服务器端渲染的。
Now that we are able to fetch the products, let's add a table to the page with the data in the next lesson.
现在我们已经能够获取产品了,在下一课中,让我们向页面添加一个表格来展示数据。
3. Display Products 展示产品
In the last lesson, we were able to create an action to get all the products and then have them log in the console from the page we created. Now we want to display them in the page.
在上一课中,我们成功创建了一个操作来获取所有产品,并在我们创建的页面中将它们记录到控制台。现在我们希望在页面中展示这些产品。
Add the following imports to the top of the
app/admin/products/page.tsx file:将以下导入添加到
app/admin/products/page.tsx 文件的顶部:Let's add a button to create a product at the top. It won't do anything yet, but we will add the functionality soon:
让我们在顶部添加一个创建产品的按钮。它暂时还不会执行任何操作,但我们很快就会添加功能:
Now under the first ending
</div> add another div with the Table component from ShadCN. The entire page should look like this:现在在第一个结束的
</div> 下方添加另一个包含 ShadCN 的 Table 组件的 div。整个页面应该如下所示:We are just mapping over the products and displaying them in the table. We also added a button to edit the product, which we will work on later. I put a comment where the delete dialog will go for now. You should also see the pagination as long as you have more products than the PAGE_SIZE. To test, change the
PAGE_SIZE in the constant/index.ts file to a smaller number, like 2.我们只是遍历产品并将它们显示在表格中。我们还添加了一个编辑产品的按钮,稍后我们会处理这个功能。我在删除对话框将要放置的位置添加了一个注释。只要你的产品数量超过 PAGE_SIZE,你就应该能看到分页组件。要进行测试,可以将
constant/index.ts 文件中的 PAGE_SIZE 改为一个较小的数字,比如 2。4. Delete Products From Admin Area 从管理区域删除产品
Now let's add the delete functionality. We need an action to delete the product. Let's open the
lib/actions/product.action.ts file and add the following:现在让我们添加删除功能。我们需要一个操作来删除产品。让我们打开
lib/actions/product.action.ts 文件并添加以下内容:We check to see if the product exists and if it does, we delete it and revalidate the path. This will update the products page after the product has been deleted.
我们检查产品是否存在,如果存在,则删除它并重新验证路径。这将在产品删除后更新产品页面。
We already created a component at
components/shared/delete-dialog.tsx that we can use to delete the product. Let's import it and use it in the page.我们已经在
components/shared/delete-dialog.tsx 创建了一个组件,可以用来删除产品。让我们导入它并在页面中使用。Go into
app/admin/products/page.tsx and import both the delete dialog and the action:进入
app/admin/products/page.tsx 并导入删除对话框和操作:Noe replace the comment with the actual delete dialog. Right under the edit button, add the following:
现在用实际的删除对话框替换注释。在编辑按钮正下方,添加以下内容:
Now when you click the delete button, it will open the dialog and ask you to confirm that you want to delete the product. If you click yes, it will delete the product and revalidate the path.
现在当你点击删除按钮时,它会打开对话框并询问你是否确认要删除该产品。如果你点击是,它将删除产品并重新验证路径。
5. Create & Update Product Actions 创建和更新产品操作
We want to be able to create and update products. Products are created by admins and they will have images associated with them. However, I want to first just be able to create and update products without images. Then once we get the form working, we will integrate image uploading with "Uploadthing".
我们希望能够创建和更新产品。产品由管理员创建,并且会有与之关联的图片。然而,我想先能够在没有图片的情况下创建和更新产品。然后一旦表单正常工作,我们将使用 "Uploadthing" 集成图片上传功能。
Zod Schema Zod 模式
Let's start by creating the Zod schema.
让我们从创建 Zod 模式开始。
Open the
lib/validator.ts file. We already have an insertProductSchema schema. Let's create another one called updateProductSchema right below it.打开
lib/validator.ts 文件。我们已经有一个 insertProductSchema 模式。让我们在它下面创建另一个名为 updateProductSchema 的模式。All we need to do is extend the
insertProductSchema schema with the id field. We also need to add the id field to the insertProductSchema schema.我们所需要做的就是用
id 字段扩展 insertProductSchema 模式。我们还需要将 id 字段添加到 insertProductSchema 模式中。Open the
lib/actions/product.actions.ts file and import the updateProductSchema schema:打开
lib/actions/product.actions.ts 文件并导入 updateProductSchema 模式:Product Default Values 产品默认值
I am also going to add a constant for the product form default values. Open the
lib/constants/index.ts file and add the following constant:我还将为产品表单默认值添加一个常量。打开
lib/constants/index.ts 文件并添加以下常量:Create Product Action 创建产品操作
Let's create the action to create a product. In the
lib/actions/product.actions.ts file and add the following function:让我们创建创建产品的操作。在
lib/actions/product.actions.ts 文件中添加以下函数:This code is simple. We are validating the product using the
insertProductSchema schema. If the validation is successful, we are creating the product using the Prisma client. We are also revalidating the /admin/products page to update the products list.这段代码很简单。我们使用
insertProductSchema 模式验证产品。如果验证成功,我们使用 Prisma 客户端创建产品。我们还重新验证 /admin/products 页面以更新产品列表。Update Product Action 更新产品操作
While we're in the action file, let's also add the update product action.
既然我们在操作文件中,让我们也添加更新产品操作。
Add the following function to the
lib/actions/product.actions.ts file:将以下函数添加到
lib/actions/product.actions.ts 文件中:We are finding, validating and updating the product using the Prisma client. We are also revalidating the
/admin/products page to update the products list.我们使用 Prisma 客户端查找、验证和更新产品。我们还重新验证
/admin/products 页面以更新产品列表。Now that we have the actions, let's start to work on the pages and forms.
现在我们已经有了操作,让我们开始处理页面和表单。
6. Create Product Page & Form 创建产品页面
Now let's work on the page and UI to create a new product.
现在让我们来开发创建新产品的页面和用户界面。
Create a file at
app/admin/products/create/page.tsx with the following code:
在 app/admin/products/create/page.tsx 路径下创建一个文件,并添加以下代码:If you go to the admin products page, you should be able to click on the button and see the heading. You can also go to the
/admin/products/create page and see the heading.
如果您访问管理员产品页面,应该能够点击按钮并看到标题。您也可以直接访问 /admin/products/create 页面来查看标题。Product Form 产品表单
Let's start on the product form. Create a file at
components/shared/admin/product-form and add the following code for now:
让我们开始创建产品表单。在 components/shared/admin/product-form 路径下创建一个文件,并暂时添加以下代码:Now bring it into the
app/admin/products/create/page.tsx file:
现在将其引入到 app/admin/products/create/page.tsx 文件中:and embed it:
并嵌入它:
We are passing in a type of
Create to the form. This can be either Create or Update.
我们向表单传递了一个类型为 Create 的参数。这个参数可以是 Create 或 Update。You should see the text
Form on the page.
您应该能在页面上看到 Form 文本。Let's add all of the imports:
让我们添加所有的导入:
Lot's of imports here. We have a bunch of ui components from ShadCN, a few hooks, a few actions, a few types, a few constants, a few validators, a few libraries, and a few components.
这里有很多导入。我们从 ShadCN 引入了一堆 UI 组件,一些钩子,一些动作,一些类型,一些常量,一些验证器,一些库和一些组件。
Let's add a few parameters to the
ProductForm component and also init the router and toast:
让我们给 ProductForm 组件添加一些参数,并初始化 router 和 toast:It is taking in a type, which will be either
Create or Update, a product, and a productId. We will use this to determine whether we are creating a new product or updating an existing product.
它接收一个类型参数(可以是 Create 或 Update)、一个产品对象和一个产品 ID。我们将使用这些参数来确定我们是在创建新产品还是在更新现有产品。We are going to use React Hook Form, so let's create a form:
我们将使用 React Hook Form,所以让我们创建一个表单:
We are using the
useForm hook from React Hook Form. We are passing in the schema we want to use, the default values, and the resolver. We are using the zodResolver from @hookform/resolvers/zod to resolve the schema. We are using the type parameter to determine whether we are creating a new product or updating an existing product. We are using the product parameter to determine the default values. We are using the productId parameter to determine whether we are creating a new product or updating an existing product.
我们使用 React Hook Form 中的 useForm 钩子。我们传入了要使用的模式、默认值和解析器。我们使用 @hookform/resolvers/zod 中的 zodResolver 来解析模式。我们使用 type 参数来确定我们是在创建新产品还是在更新现有产品。我们使用 product 参数来确定默认值。我们使用 productId 参数来确定我们是在创建新产品还是在更新现有产品。Now we want to assemble the form with a bunch of fields. These are the fields we want to show in the form:
现在我们想要组装一个包含多个字段的表单。这些是我们希望在表单中显示的字段:
- Name 名称
- Slug (with a button to generate the slug from the name) 别名(带有一个从名称生成别名的按钮)
- Category 类别
- Brand 品牌
- Price 价格
- Stock 库存
- Images (We will add this later) 图片(我们稍后会添加)
- Featured (Is the image featured?) (We will add this later) 精选(图片是否精选?)(我们稍后会添加)
- Description 描述
- Button to submit the form 提交表单的按钮
It will be a two colum layout. So we will have a div wrapped around every two fields.
这将是一个两列布局。因此,我们会在每两个字段周围包裹一个 div。
Let's add the form to the return statement with the divs that will hold the fields. We will use comments to map everything out:
让我们将表单和容纳字段的 div 添加到 return 语句中。我们将使用注释来规划所有内容:
I added the custom class
upload-field to the divs that will hold image uploads because for some reason the button text is white on the white background. So we will add an override class to the button to make it black.
我将自定义类 upload-field 添加到将容纳图片上传的 div 上,因为由于某种原因,按钮文本在白色背景上是白色的。所以我们将为按钮添加一个覆盖类,使其变成黑色。In the next lesson, we will add the form fields.
在下一课中,我们将添加表单字段。
7. Form Fields & Slugify
Create Product Page 创建产品页面
Now let's work on the page and UI to create a new product.
现在让我们来创建一个用于添加新产品的页面和用户界面。
Slugify 网址友好化处理
We are going to have slugs for the product which are a URL-friendly version of the product name. We're going to use a package called
slugify that will convert names to slugs.
我们将为产品添加网址友好的 slug(短链接),它是产品名称的 URL 友好版本。我们将使用一个名为 slugify 的包来将名称转换为 slug。Install the package with the following command:
使用以下命令安装该包:
Name & Slug Fields 名称与 Slug 字段
In the first div, we will have the name and the slug:
在第一个 div 中,我们将包含名称和 slug 字段:
Let's add the button to generate the slug:
让我们添加生成 slug 的按钮:
We are using the
slugify library to generate the slug from the name. We are using the form.getValues method to get the value of the name field. We are using the form.setValue method to set the value of the slug field.
我们正在使用 slugify 库从产品名称生成 slug。我们使用 form.getValues 方法获取名称字段的值,使用 form.setValue 方法设置 slug 字段的值。Category & Brand Fields 类别与品牌字段
Let's add the next set of fields:
让我们添加下一组字段:
Price & Stock Fields 价格与库存字段
Now, let's add the price and stock fields:
现在,让我们添加价格和库存字段:
Description Field 描述字段
We are going to skip the image field for now and add the description and the submit button.
我们暂时跳过图片字段,先添加描述和提交按钮。
We need to install the ShadCN Textarea component. In your terminal, enter the following command:
我们需要安装 ShadCN Textarea 组件。在终端中输入以下命令:
Add the following for the description:
为描述字段添加以下内容:
Now add the submit button:
现在添加提交按钮:
Alright, now that we added the form fields, in the next lesson, we will add the submit handler.
好了,现在我们已经添加了表单字段,在下一课中,我们将添加提交处理程序。
8. Create Product Form Submission
Create Product Handler 创建产品处理程序
We have most of our product form ready. We do still need the images and the is featured field, but we will get to those later.
我们的产品表单大部分已经准备好了。我们仍然需要图片和精选字段,但稍后会处理这些内容。
Let's create the handler for the create product form. In the
components/shared/admin/product-form.tsx file, add the following code above the return statement:让我们为创建产品表单创建处理程序。在
components/shared/admin/product-form.tsx 文件中,在 return 语句上方添加以下代码:We are just calling the appropriate action based on the type and the productId. We are also using the router to navigate to the admin products page after the product is created or updated.
我们只是根据类型和 productId 调用适当的操作。在产品创建或更新后,我们还使用路由器导航到管理产品页面。
Add the handler to the form:
将处理程序添加到表单:
If you try and submit the form with nothing filled in, you will see all your error messages.
如果您尝试在不填写任何内容的情况下提交表单,您将看到所有错误消息。
If you fill them all in you'll notice it is not submitting. This is because the
insertProductSchema schema need the images, banner and isFeatured fields to be set.如果您全部填写完毕,您会注意到它没有提交。这是因为
insertProductSchema 模式需要设置 images、banner 和 isFeatured 字段。Since we are not using those fields yet, Let's open the
lib/validator.ts file and comment out the following lines:由于我们还没有使用这些字段,让我们打开
lib/validator.ts 文件并注释掉以下行:Now if you try and submit the form, it should work.
现在如果您尝试提交表单,它应该可以工作了。
You will see the product in the admin products area and on the home page. It will not have an image yet. Let's fix that next.
您将在管理产品区域和首页看到该产品。它还没有图片。让我们接下来解决这个问题。
9. Uploadthing Configuration
Image Upload 图片上传
We are going to use the
uploadthing library to handle the image uploading. Uploadthing is a file uploading service that offers features like middleware support, file type validation, and custom metadata, making it an great choice for secure and efficient file handling. The free teir that we're using is very generous and the paid teir is only 10 bucks per month. They aren't sponsoring or anything like that. I just think it's a good solution for image uploads.我们将使用
uploadthing库来处理图片上传。Uploadthing是一个文件上传服务,提供中间件支持、文件类型验证和自定义元数据等功能,使其成为安全高效文件处理的绝佳选择。我们使用的免费套餐非常慷慨,付费套餐每月只需10美元。他们并没有赞助什么,我只是认为这是一个很好的图片上传解决方案。Go to https://uploadthing.com/ and sign in with Github. Then click on the "Create an app" button and name your app. Then from the dashboard, click on the "API Keys" option and copy the token, secret and the app id (Find this in the URL) and past them in your
.env file.访问https://uploadthing.com/并使用Github登录。然后点击"Create an app"按钮并为您的应用命名。然后从仪表板中,点击"API Keys"选项,复制token、secret和app id(在URL中找到),并将它们粘贴到您的
.env文件中。They should look something like this:
它们应该看起来像这样:
We need to install the following packages:
我们需要安装以下包:
All the code that we are about to write comes from the uploadthing documentation.
我们即将编写的所有代码都来自uploadthing文档。
We need to create a new file at
app/api/uploadthing/core.ts and add the following code:我们需要在
app/api/uploadthing/core.ts创建一个新文件,并添加以下代码:This code creates a file router for the uploadthing library. It also creates a middleware that checks if the user is authenticated. If the user is not authenticated, it throws an error. It also returns the user id in the metadata. This metadata is then passed to the
onUploadComplete callback.这段代码为uploadthing库创建了一个文件路由器。它还创建了一个中间件来检查用户是否已通过身份验证。如果用户未通过身份验证,它会抛出一个错误。它还在元数据中返回用户id。然后这个元数据会传递给
onUploadComplete回调函数。Create The Route 创建路由
Now we will use the
ourFileRouter to create a route for the uploadthing library. Create a file at app/api/uploadthing/route.ts with the following code:现在我们将使用
ourFileRouter为uploadthing库创建一个路由。在app/api/uploadthing/route.ts创建一个文件,并添加以下代码:We are exporting the
GET and POST routes for the uploadthing library. This works similar to how we created the routes for the next auth library. So the route /api/uploadthing will be used to upload images.我们正在为uploadthing库导出
GET和POST路由。这与我们为next auth库创建路由的方式类似。所以/api/uploadthing路由将用于上传图片。Generate Components 生成组件
Now we are going to generate some pre-configured components that we can use to upload images.
现在我们将生成一些预配置的组件,我们可以用它们来上传图片。
Create a file named
lib/uploadthing.ts with the following code:创建一个名为
lib/uploadthing.ts的文件,并添加以下代码:We are exporting the
UploadButton and UploadDropzone components from the uploadthing library with the OurFileRouter type. You can import them directly in the file where you want to use them.我们正在从
uploadthing库导出带有OurFileRouter类型的UploadButton和UploadDropzone组件。您可以在想要使用它们的文件中直接导入它们。Add Domain To Config 将域名添加到配置
When we use images from 3rd party websites, we need to add the domain to the
next.config.mjs file.当我们使用来自第三方网站的图片时,我们需要将域名添加到
next.config.mjs文件中。Add the following code to the
next.config.mjs file:将以下代码添加到
next.config.mjs文件中:10. Add Image Uploads 添加图片上传功能
A couple lessons ago, we commented out some fields in the
lib/validators.ts file in the insertProductSchema. We want to uncomment the images field so that we can upload images to our products.几节课前,我们在
lib/validators.ts 文件的 insertProductSchema 中注释掉了一些字段。现在我们要取消注释 images 字段,以便我们可以为产品上传图片。So it should look like this:
所以它应该像这样:
Now let's open the
components/shared/admin/product-form.tsx file and add the image field. We also want to preview the image.现在让我们打开
components/shared/admin/product-form.tsx 文件并添加图片字段。我们还想要预览图片。Import the
UploadButton component from the file we created earlier:从我们之前创建的文件中导入
UploadButton 组件:Right above the return statement, add the following:
在 return 语句正上方,添加以下内容:
This will allow us to access the images array from the form.
这将允许我们从表单中访问图片数组。
Replace the image comment in the return statement with the following:
用以下内容替换 return 语句中的图片注释:
We created an area for the uploaded images to be displayed. We map over the images and display them. We also added a button to upload images using the
UploadButton component. We also added a onClientUploadComplete function that will be called when the upload is complete. When the upload is complete, we will add the new image to the images array to be sent to the database. On error, we will show a toast message.我们创建了一个用于显示已上传图片的区域。我们遍历图片并显示它们。我们还添加了一个使用
UploadButton 组件上传图片的按钮。我们还添加了一个 onClientUploadComplete 函数,该函数将在上传完成时调用。当上传完成时,我们将把新图片添加到图片数组中以发送到数据库。如果出错,我们将显示一个提示消息。You may notice that you can't see the "Choose File" text. This is why I added the custom class of
upload-field to the div.您可能会注意到看不到"选择文件"的文字。这就是为什么我向 div 添加了自定义类
upload-field。Open your
assets/styles/globals.css file and add the following:打开您的
assets/styles/globals.css 文件并添加以下内容:That should fix the issue.
这应该可以解决问题。
Now try adding a new product and uploading an image. You should see the image in the preview area.
现在尝试添加一个新产品并上传一张图片。您应该能在预览区域看到图片。
11. Product Cleanup 产品清理
Right now, our sample products are still using a local path to the image. We need to change that to a public path. So we are going to delete all existing products and re-add them.
目前,我们的示例产品仍在使用本地图片路径。我们需要将其更改为公共路径。因此,我们将删除所有现有产品并重新添加它们。
I am attaching the images for the products in this lesson. But you can also just get them from your
public/images/sample-products folder.我在本课中附上了产品图片。但您也可以直接从
public/images/sample-products 文件夹中获取它们。Here are the products to add right now. We are not going to add one and two just yet because I want them to be featured and we don't have that option yet.
以下是现在要添加的产品。我们暂时不添加第一和第二个产品,因为我希望它们成为精选产品,但我们还没有这个功能。
- name: Polo Sporting Stretch Shirt
- category: Mens Dress Shirts
- description: Classic Polo style with modern comfort
- price: 59.99
- brand: Polo
- stock: 500
- 名称:Polo Sporting Stretch Shirt
- 类别:男士正装衬衫
- 描述:经典Polo风格,兼具现代舒适感
- 价格:59.99
- 品牌:Polo
- 库存:500
Upload the images
p1-1.jpg and p1-2.jpg.上传图片
p1-1.jpg 和 p1-2.jpg。- name: Brooks Brothers Long Sleeved Shirt
- category: Mens Dress Shirts
- description: Timeless style and premium comfort
- price: 85.99
- brand: Brooks Brothers
- stock: 500
- 名称:Brooks Brothers Long Sleeved Shirt
- 类别:男士正装衬衫
- 描述:永恒风格,极致舒适
- 价格:85.99
- 品牌:Brooks Brothers
- 库存:500
Upload the images
p2-1.jpg and p2-2.jpg.上传图片
p2-1.jpg 和 p2-2.jpg。- name: Tommy Hilfiger Classic Fit Dress Shirt
- category: Mens Dress Shirts
- description: A perfect blend of sophistication and comfort
- price: 99.95
- brand: Tommy Hilfiger
- stock: 500
- 名称:Tommy Hilfiger Classic Fit Dress Shirt
- 类别:男士正装衬衫
- 描述:精致与舒适的完美融合
- 价格:99.95
- 品牌:Tommy Hilfiger
- 库存:500
Upload the images
p3-1.jpg and p3-2.jpg.上传图片
p3-1.jpg 和 p3-2.jpg。- name: Calvin Klein Slim Fit Stretch Shirt
- category: Mens Dress Shirts
- description: Streamlined design with flexible stretch fabric
- price: 99.95
- brand: Calvin Klein
- stock: 500
- 名称:Calvin Klein Slim Fit Stretch Shirt
- 类别:男士正装衬衫
- 描述:流线型设计,弹性舒适面料
- 价格:99.95
- 品牌:Calvin Klein
- 库存:500
Upload the images
p4-1.jpg and p4-2.jpg.上传图片
p4-1.jpg 和 p4-2.jpg。- name: Polo Ralph Lauren Oxford Shirt
- category: Mens Dress Shirts
- description: Iconic Polo design with refined oxford fabric
- price: 79.99
- brand: Polo
- stock: 0
- 名称:Polo Ralph Lauren Oxford Shirt
- 类别:男士正装衬衫
- 描述:标志性Polo设计,精致牛津面料
- 价格:79.99
- 品牌:Polo
- 库存:0
Upload the images
p5-1.jpg and p5-2.jpg.上传图片
p5-1.jpg 和 p5-2.jpg。- name: Polo Classic Pink Hoodie
- category: Mens Sweatshirts
- description: Soft, stylish, and perfect for laid-back days
- price: 99.99
- brand: Polo
- stock: 500
- 名称:Polo Classic Pink Hoodie
- 类别:男士卫衣
- 描述:柔软时尚,完美适配休闲时光
- 价格:99.99
- 品牌:Polo
- 库存:500
Upload the images
p6-1.jpg and p6-2.jpg.上传图片
p6-1.jpg 和 p6-2.jpg。All products should now have an Uploadthing URL for the images in the array. The images should be shown all around the site.
所有产品现在都应该在数组中拥有 Uploadthing 的图片 URL。图片应该在整个网站上都能显示出来。
12. Is-Featured and Banner Image 精选产品和横幅图片
Now that we can add products, I want to add a new field that will allow us to mark a product as featured and add a banner image. I will add a download of the banner images with this lesson. You can also get them from the public image folder or the repository.
既然我们可以添加产品了,我想添加一个新字段,让我们可以将产品标记为精选产品并添加横幅图片。我将在本课中添加横幅图片的下载。您也可以从公共图片文件夹或代码仓库中获取它们。
We will have a checkbox to mark a product as featured and if it is checked, it will display an image upload for the banner.
我们将有一个复选框来将产品标记为精选产品,如果选中它,就会显示横幅图片的上传功能。
Go into the
lib/validators.ts file and make sure you uncomment the isFeatured and banner fields:进入
lib/validators.ts 文件,确保取消注释 isFeatured 和 banner 字段:Open the
components/shared/admin/product-form.tsx file and add the following above the return statement:打开
components/shared/admin/product-form.tsx 文件,并在 return 语句上方添加以下内容:Go to where you have the "isFeatured" comment. It should be below the image and above the description.
找到您有 "isFeatured" 注释的位置。它应该在图片下方和描述上方。
Add the following
div element:添加以下
div 元素:We are using the
watch method to get the value of the isFeatured and banner fields. We are also using the UploadButton component from the uploadthing package to upload the banner image.我们使用
watch 方法来获取 isFeatured 和 banner 字段的值。我们还使用 uploadthing 包中的 UploadButton 组件来上传横幅图片。Now you should have the option to set a product to featured ans add a banner. You can test it out by creating a featrued product and a banner. In the next lesson, we will be able to update products.
现在您应该有将产品设置为精选产品并添加横幅的选项了。您可以通过创建一个精选产品和横幅来测试它。在下一课中,我们将能够更新产品。
13. Update Product Form 更新产品表单
We can add new products through the admin panel. Now we want to update existing products. We have the update action and we have the product form. One other thing we need is an action to get the product by id.
我们可以通过管理面板添加新产品。现在我们想要更新现有产品。我们已经有了更新操作和产品表单。我们还需要一个通过id获取产品的操作。
Open the
lib/actions/product.action.ts file and add the following function:
打开 lib/actions/product.action.ts 文件并添加以下函数:Create a new file at
app/admin/products/[id]/page.tsx. This will be the update page.
在 app/admin/products/[id]/page.tsx 创建一个新文件。这将是更新页面。Add the following code:
添加以下代码:
Now click on the edit button on a product in the admin dashboard and you should see the update form with the values. Go ahead and change something like the stock and save and the product should be updated.
现在点击管理面板中某个产品的编辑按钮,你应该能看到带有值的更新表单。继续修改一些内容,比如库存,然后保存,产品就应该被更新了。
📎 参考文章
- 一些引用
- 引用文章
欢迎您在底部评论区留言,一起交流~
Loading...
