📅 Day 5:订单提交与支付模拟

✅ 今日目标:

  • 创建 OrderOrderItem 模型
  • 实现从购物车生成订单的功能
  • 模拟支付流程(成功/失败页面)
  • 添加订单状态跟踪(如“待付款”、“已发货”等)
  • 提交 Git 版本记录进度

🧩 功能概览

页面 功能
/Checkout/Index.cshtml 确认订单信息
/Checkout/Success.cshtml 支付成功页面
/Checkout/Failed.cshtml 支付失败页面
/Orders/Index.cshtml 我的订单列表
数据库模型 Order, OrderItem

🛠️ 知识点预览

技术 内容
数据模型 Order 表示订单,OrderItem 表示订单中的商品
购物车转订单 将 Session 中的购物车数据保存为订单
支付模拟 使用按钮或自动跳转模拟支付结果
用户身份验证 只有登录用户才能下单
UI 设计 Bootstrap + Razor Pages 构建订单确认页

🧱 第一步:创建订单相关模型

Models 文件夹中创建以下两个类:

✅ Order.cs

using System.ComponentModel.DataAnnotations;

namespace ECommercePlatform.Models
{
    public enum OrderStatus
    {
        Pending,
        Paid,
        Shipped,
        Completed,
        Cancelled
    }

    public class Order
    {
        public int Id { get; set; }

        [Required]
        public string UserId { get; set; } = string.Empty;

        public DateTime OrderDate { get; set; } = DateTime.Now;

        public decimal TotalAmount { get; set; }

        public OrderStatus Status { get; set; } = OrderStatus.Pending;

        public List<OrderItem> Items { get; set; } = new();
    }
}

✅ OrderItem.cs

namespace ECommercePlatform.Models
{
    public class OrderItem
    {
        public int Id { get; set; }

        public int ProductId { get; set; }

        public string ProductName { get; set; } = string.Empty;

        public decimal Price { get; set; }

        public int Quantity { get; set; }

        public decimal TotalPrice => Price * Quantity;

        public int OrderId { get; set; }

        public Order Order { get; set; } = null!;
    }
}

🧰 第二步:更新数据库上下文

打开 ApplicationDbContext.cs 并添加以下代码:

public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }

然后执行迁移命令:

dotnet ef migrations add AddOrderAndOrderItem
dotnet ef database update

🛒 第三步:创建订单服务逻辑

✅ 创建 Services/IOrderService.cs

using ECommercePlatform.Models;

public interface IOrderService
{
    Task<int> CreateOrderFromCart(string userId, IList<CartItem> cartItems);
    Task<IList<Order>> GetOrdersByUser(string userId);
    Task<Order?> GetOrderById(int id, string userId);
}

✅ 创建 Services/OrderService.cs

using Microsoft.AspNetCore.Identity;
using ECommercePlatform.Models;
using ECommercePlatform.Services;

public class OrderService : IOrderService
{
    private readonly ApplicationDbContext _context;
    private readonly UserManager<IdentityUser> _userManager;

    public OrderService(ApplicationDbContext context, UserManager<IdentityUser> userManager)
    {
        _context = context;
        _userManager = userManager;
    }

    public async Task<int> CreateOrderFromCart(string userId, IList<CartItem> cartItems)
    {
        if (cartItems.Count == 0) throw new ArgumentException("购物车为空");

        var order = new Order
        {
            UserId = userId,
            OrderDate = DateTime.Now,
            TotalAmount = cartItems.Sum(i => i.TotalPrice),
            Items = cartItems.Select(i => new OrderItem
            {
                ProductId = i.ProductId,
                ProductName = i.Name,
                Price = i.Price,
                Quantity = i.Quantity
            }).ToList()
        };

        _context.Orders.Add(order);
        await _context.SaveChangesAsync();

        return order.Id;
    }

    public async Task<IList<Order>> GetOrdersByUser(string userId)
    {
        return await _context.Orders
            .Include(o => o.Items)
            .Where(o => o.UserId == userId)
            .OrderByDescending(o => o.OrderDate)
            .ToListAsync();
    }

    public async Task<Order?> GetOrderById(int id, string userId)
    {
        return await _context.Orders
            .Include(o => o.Items)
            .FirstOrDefaultAsync(o => o.Id == id && o.UserId == userId);
    }
}

注册服务到 Program.cs

builder.Services.AddScoped<IOrderService, OrderService>();

📋 第四步:创建订单确认页面(Checkout/Index)

✅ Checkout/Index.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;
using ECommercePlatform.Services;
using ECommercePlatform.Models;

namespace ECommercePlatform.Pages.Checkout
{
    [Authorize]
    public class IndexModel : PageModel
    {
        private readonly IShoppingCartService _cartService;
        private readonly UserManager<IdentityUser> _userManager;

        public IndexModel(IShoppingCartService cartService, UserManager<IdentityUser> userManager)
        {
            _cartService = cartService;
            _userManager = userManager;
        }

        public IList<CartItem> CartItems { get; set; } = new List<CartItem>();
        public decimal TotalPrice { get; set; }

        public async Task<IActionResult> OnGetAsync()
        {
            CartItems = _cartService.GetCartItems();
            TotalPrice = _cartService.GetTotalPrice();

            if (CartItems.Count == 0)
            {
                return RedirectToPage("/Cart/Index");
            }

            return Page();
        }

        public async Task<IActionResult> OnPostAsync()
        {
            var user = await _userManager.GetUserAsync(User);
            if (user == null) return NotFound();

            var cartItems = _cartService.GetCartItems();
            if (cartItems.Count == 0) return BadRequest();

            // 创建订单
            var orderService = HttpContext.RequestServices.GetService<IOrderService>();
            var orderId = await orderService.CreateOrderFromCart(user.Id, cartItems);

            // 清空购物车
            _cartService.ClearCart();

            return RedirectToPage("/Checkout/Success", new { id = orderId });
        }
    }
}

✅ Checkout/Index.cshtml

@page
@model ECommercePlatform.Pages.Checkout.IndexModel

<h2>确认订单</h2>

<table class="table">
    <thead>
        <tr>
            <th>名称</th>
            <th>单价</th>
            <th>数量</th>
            <th>总价</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.CartItems)
        {
            <tr>
                <td>@item.Name</td>
                <td>$@item.Price</td>
                <td>@item.Quantity</td>
                <td>$@item.TotalPrice</td>
            </tr>
        }
    </tbody>
</table>

<h4>总计:$@Model.TotalPrice</h4>

<form method="post">
    <button type="submit" class="btn btn-success">立即支付</button>
</form>

✅ 第五步:创建支付成功页面(Checkout/Success)

✅ Success.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;

namespace ECommercePlatform.Pages.Checkout
{
    public class SuccessModel : PageModel
    {
        public void OnGet(int id)
        {
            // 这里可以显示订单编号或详细信息
        }
    }
}

✅ Success.cshtml

@page
@model ECommercePlatform.Pages.Checkout.SuccessModel

<h2>✅ 支付成功!</h2>
<p>您的订单已提交。订单号:@Request.Query["id"]</p>
<a asp-page="/Orders/Index" class="btn btn-primary">查看我的订单</a>

❌ 第六步:创建支付失败页面(Checkout/Failed)

✅ Failed.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;

namespace ECommercePlatform.Pages.Checkout
{
    public class FailedModel : PageModel
    {
        public void OnGet()
        {
        }
    }
}

✅ Failed.cshtml

@page
@model ECommercePlatform.Pages.Checkout.FailedModel

<h2>❌ 支付失败</h2>
<p>请返回重新尝试支付。</p>
<a asp-page="/Cart/Index" class="btn btn-warning">返回购物车</a>

📦 第七步:创建我的订单页面(Orders/Index)

✅ Orders/Index.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;
using ECommercePlatform.Services;
using ECommercePlatform.Models;
using Microsoft.AspNetCore.Identity;

namespace ECommercePlatform.Pages.Orders
{
    [Authorize]
    public class IndexModel : PageModel
    {
        private readonly IOrderService _orderService;
        private readonly UserManager<IdentityUser> _userManager;

        public IndexModel(IOrderService orderService, UserManager<IdentityUser> userManager)
        {
            _orderService = orderService;
            _userManager = userManager;
        }

        public IList<Order> Orders { get; set; } = new List<Order>();

        public async Task OnGetAsync()
        {
            var user = await _userManager.GetUserAsync(User);
            if (user != null)
            {
                Orders = await _orderService.GetOrdersByUser(user.Id);
            }
        }
    }
}

✅ Orders/Index.cshtml

@page
@model ECommercePlatform.Pages.Orders.IndexModel

<h2>我的订单</h2>

@if (Model.Orders.Count == 0)
{
    <p>暂无订单。</p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>订单号</th>
                <th>日期</th>
                <th>总金额</th>
                <th>状态</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var order in Model.Orders)
            {
                <tr>
                    <td>@order.Id</td>
                    <td>@order.OrderDate.ToShortDateString()</td>
                    <td>$@order.TotalAmount</td>
                    <td>@order.Status</td>
                    <td><a asp-page="/Orders/Details" asp-route-id="@order.Id" class="btn btn-info btn-sm">查看详情</a></td>
                </tr>
            }
        </tbody>
    </table>
}

📦 第八步:提交 Git 版本

git add .
git commit -m "Day5: Added order submission and payment simulation with order status tracking"

📝 今日总结

今天你完成了:

✅ 创建 OrderOrderItem 模型
✅ 实现从购物车生成订单的功能
✅ 模拟支付流程(成功/失败页面)
✅ 订单状态跟踪(Pending、Paid、Shipped 等)
✅ 提交版本控制记录


📆 明日计划(Day6)

我们将进入 后台管理系统开发阶段

  • 创建管理员页面
  • 实现商品管理(CRUD)
  • 实现订单管理(查看、状态变更)
  • 权限控制(仅管理员可见)
Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐