生成代码工程
This commit is contained in:
parent
0934be187d
commit
aab7c7387d
|
|
@ -0,0 +1,45 @@
|
|||
cmake_minimum_required(VERSION 3.14)
|
||||
project(MallSystem VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# MSVC UTF-8 support
|
||||
if (MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
# ============================================================
|
||||
# Main executable
|
||||
# ============================================================
|
||||
set(SOURCES
|
||||
src/main.cpp
|
||||
src/app.cpp
|
||||
src/product.cpp
|
||||
src/shopping_cart.cpp
|
||||
src/order.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
include/app.hpp
|
||||
include/product.hpp
|
||||
include/shopping_cart.hpp
|
||||
include/order.hpp
|
||||
)
|
||||
|
||||
add_executable(mall ${SOURCES} ${HEADERS})
|
||||
target_include_directories(mall PRIVATE include)
|
||||
|
||||
# ============================================================
|
||||
# Test executable (uses plain assert, no external dependency)
|
||||
# ============================================================
|
||||
set(TEST_SOURCES
|
||||
tests/basic_test.cpp
|
||||
src/app.cpp
|
||||
src/product.cpp
|
||||
src/shopping_cart.cpp
|
||||
src/order.cpp
|
||||
)
|
||||
|
||||
add_executable(mall_test ${TEST_SOURCES} ${HEADERS})
|
||||
target_include_directories(mall_test PRIVATE include)
|
||||
45
README.md
45
README.md
|
|
@ -1,3 +1,44 @@
|
|||
# 商城管理系统
|
||||
# MallSystem —— 简约商城系统
|
||||
|
||||
商城管理系统
|
||||
## 概述
|
||||
|
||||
使用 C++17 编写的控制台商城模拟系统,包含三大核心模块:
|
||||
|
||||
- **商品管理**(Product):商品名称、价格、库存
|
||||
- **购物车**(ShoppingCart):添加/移除商品、计算总价
|
||||
- **订单管理**(Order):从购物车生成订单、查看订单状态
|
||||
|
||||
## 构建与运行
|
||||
|
||||
```bash
|
||||
# 构建
|
||||
cmake -B build
|
||||
cmake --build build
|
||||
|
||||
# 运行主程序
|
||||
./build/mall
|
||||
|
||||
# 运行测试
|
||||
./build/mall_test
|
||||
```
|
||||
|
||||
## 工程结构
|
||||
|
||||
```
|
||||
.
|
||||
├── CMakeLists.txt
|
||||
├── README.md
|
||||
├── include/
|
||||
│ ├── app.hpp # 应用入口封装
|
||||
│ ├── product.hpp # 商品类
|
||||
│ ├── shopping_cart.hpp # 购物车类
|
||||
│ └── order.hpp # 订单类
|
||||
├── src/
|
||||
│ ├── main.cpp # 命令行入口
|
||||
│ ├── app.cpp # 应用逻辑
|
||||
│ ├── product.cpp # 商品实现
|
||||
│ ├── shopping_cart.cpp # 购物车实现
|
||||
│ └── order.cpp # 订单实现
|
||||
└── tests/
|
||||
└── basic_test.cpp # 单元测试(assert)
|
||||
```
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef MALL_APP_HPP
|
||||
#define MALL_APP_HPP
|
||||
|
||||
#include "product.hpp"
|
||||
#include "shopping_cart.hpp"
|
||||
#include "order.hpp"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* @brief 商城应用类,协调商品、购物车、订单的管理与交互。
|
||||
*/
|
||||
class App {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数,初始化预置商品。
|
||||
*/
|
||||
App();
|
||||
|
||||
/**
|
||||
* @brief 启动商城控制台交互。
|
||||
*/
|
||||
void run();
|
||||
|
||||
private:
|
||||
std::vector<Product> products_; ///< 商品库
|
||||
ShoppingCart cart_; ///< 当前购物车
|
||||
std::vector<std::unique_ptr<Order>> orders_; ///< 历史订单列表
|
||||
|
||||
/**
|
||||
* @brief 初始化预置商品数据。
|
||||
*/
|
||||
void initProducts();
|
||||
|
||||
// ---- 菜单功能 ----
|
||||
|
||||
/** @brief 显示商品列表 */
|
||||
void showProducts() const;
|
||||
|
||||
/** @brief 添加商品到购物车 */
|
||||
void addToCart();
|
||||
|
||||
/** @brief 查看购物车 */
|
||||
void showCart() const;
|
||||
|
||||
/** @brief 生成订单 */
|
||||
void checkout();
|
||||
|
||||
/** @brief 查看历史订单 */
|
||||
void showOrders() const;
|
||||
|
||||
/**
|
||||
* @brief 获取有效商品输入。
|
||||
* @return 指向选中商品的迭代器,未找到则返回 end()
|
||||
*/
|
||||
std::vector<Product>::const_iterator selectProduct() const;
|
||||
|
||||
/** @brief 打印菜单选项 */
|
||||
static void printMenu();
|
||||
};
|
||||
|
||||
#endif // MALL_APP_HPP
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef MALL_ORDER_HPP
|
||||
#define MALL_ORDER_HPP
|
||||
|
||||
#include "shopping_cart.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
|
||||
/**
|
||||
* @brief 订单状态枚举。
|
||||
*/
|
||||
enum class OrderStatus {
|
||||
Pending, ///< 待支付
|
||||
Paid, ///< 已支付
|
||||
Shipped, ///< 已发货
|
||||
Delivered, ///< 已送达
|
||||
Cancelled ///< 已取消
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 订单状态转可读字符串。
|
||||
* @param status 订单状态
|
||||
* @return 中文状态描述
|
||||
*/
|
||||
std::string orderStatusToString(OrderStatus status);
|
||||
|
||||
/**
|
||||
* @brief 订单类,由购物车生成。
|
||||
*/
|
||||
class Order {
|
||||
public:
|
||||
/**
|
||||
* @brief 默认构造函数。
|
||||
*/
|
||||
Order() = default;
|
||||
|
||||
/**
|
||||
* @brief 从购物车构造订单。
|
||||
* @param orderId 订单编号
|
||||
* @param cart 购物车(内容会被移入订单)
|
||||
*/
|
||||
explicit Order(uint64_t orderId, ShoppingCart& cart);
|
||||
|
||||
/** @brief 获取订单编号 */
|
||||
uint64_t getOrderId() const noexcept { return orderId_; }
|
||||
|
||||
/** @brief 获取订单状态 */
|
||||
OrderStatus getStatus() const noexcept { return status_; }
|
||||
|
||||
/**
|
||||
* @brief 设置订单状态。
|
||||
* @param status 新状态
|
||||
*/
|
||||
void setStatus(OrderStatus status) noexcept { status_ = status; }
|
||||
|
||||
/** @brief 获取订单创建时间(时间戳) */
|
||||
std::time_t getCreateTime() const noexcept { return createTime_; }
|
||||
|
||||
/** @brief 获取订单条目 */
|
||||
const std::vector<CartItem>& getItems() const noexcept { return items_; }
|
||||
|
||||
/** @brief 计算订单总金额 */
|
||||
double totalPrice() const;
|
||||
|
||||
/**
|
||||
* @brief 返回订单摘要字符串。
|
||||
* @return 多行描述的订单信息
|
||||
*/
|
||||
std::string toString() const;
|
||||
|
||||
private:
|
||||
uint64_t orderId_ = 0; ///< 订单编号
|
||||
OrderStatus status_ = OrderStatus::Pending; ///< 订单状态
|
||||
std::time_t createTime_ = 0; ///< 创建时间
|
||||
std::vector<CartItem> items_; ///< 商品条目
|
||||
};
|
||||
|
||||
#endif // MALL_ORDER_HPP
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef MALL_PRODUCT_HPP
|
||||
#define MALL_PRODUCT_HPP
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* @brief 商品类,表示商城中的一件商品。
|
||||
*/
|
||||
class Product {
|
||||
public:
|
||||
/**
|
||||
* @brief 默认构造函数,构造一个空商品。
|
||||
*/
|
||||
Product() = default;
|
||||
|
||||
/**
|
||||
* @brief 构造商品。
|
||||
* @param id 商品唯一编号
|
||||
* @param name 商品名称
|
||||
* @param price 商品单价(元)
|
||||
* @param stock 库存数量
|
||||
*/
|
||||
Product(uint64_t id, std::string name, double price, int stock);
|
||||
|
||||
/** @brief 获取商品编号 */
|
||||
uint64_t getId() const noexcept { return id_; }
|
||||
|
||||
/** @brief 获取商品名称 */
|
||||
const std::string& getName() const noexcept { return name_; }
|
||||
|
||||
/** @brief 获取商品单价 */
|
||||
double getPrice() const noexcept { return price_; }
|
||||
|
||||
/** @brief 获取库存数量 */
|
||||
int getStock() const noexcept { return stock_; }
|
||||
|
||||
/**
|
||||
* @brief 减少库存。
|
||||
* @param quantity 减少数量
|
||||
* @return true 扣减成功,false 库存不足
|
||||
*/
|
||||
bool reduceStock(int quantity);
|
||||
|
||||
/**
|
||||
* @brief 增加库存。
|
||||
* @param quantity 增加数量
|
||||
*/
|
||||
void addStock(int quantity);
|
||||
|
||||
/**
|
||||
* @brief 返回商品简要信息字符串。
|
||||
* @return 例如 "[#1001] 苹果 ¥5.50 (库存:20)"
|
||||
*/
|
||||
std::string toString() const;
|
||||
|
||||
private:
|
||||
uint64_t id_ = 0; ///< 商品编号
|
||||
std::string name_; ///< 商品名称
|
||||
double price_ = 0.0; ///< 单价
|
||||
int stock_ = 0; ///< 库存数量
|
||||
};
|
||||
|
||||
#endif // MALL_PRODUCT_HPP
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef MALL_SHOPPING_CART_HPP
|
||||
#define MALL_SHOPPING_CART_HPP
|
||||
|
||||
#include "product.hpp"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* @brief 购物车条目,记录商品和购买数量。
|
||||
*/
|
||||
struct CartItem {
|
||||
Product product; ///< 商品副本
|
||||
int quantity = 0; ///< 购买数量
|
||||
|
||||
/** @brief 小计金额 = 单价 × 数量 */
|
||||
double subtotal() const noexcept { return product.getPrice() * quantity; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 购物车类,管理用户选中的商品。
|
||||
*/
|
||||
class ShoppingCart {
|
||||
public:
|
||||
ShoppingCart() = default;
|
||||
|
||||
/**
|
||||
* @brief 向购物车添加商品(若已存在则累加数量)。
|
||||
* @param product 商品
|
||||
* @param quantity 数量
|
||||
*/
|
||||
void addItem(const Product& product, int quantity);
|
||||
|
||||
/**
|
||||
* @brief 从购物车移除指定商品(完全移除)。
|
||||
* @param productId 商品编号
|
||||
* @return true 移除成功,false 未找到
|
||||
*/
|
||||
bool removeItem(uint64_t productId);
|
||||
|
||||
/**
|
||||
* @brief 修改某商品的数量。
|
||||
* @param productId 商品编号
|
||||
* @param quantity 新数量(≤0 则移除)
|
||||
* @return true 修改成功
|
||||
*/
|
||||
bool updateQuantity(uint64_t productId, int quantity);
|
||||
|
||||
/** @brief 清空购物车 */
|
||||
void clear();
|
||||
|
||||
/** @brief 获取所有条目 */
|
||||
const std::vector<CartItem>& getItems() const noexcept { return items_; }
|
||||
|
||||
/**
|
||||
* @brief 计算购物车总金额。
|
||||
* @return 所有条目小计之和
|
||||
*/
|
||||
double totalPrice() const;
|
||||
|
||||
/** @brief 购物车是否为空 */
|
||||
bool isEmpty() const noexcept { return items_.empty(); }
|
||||
|
||||
/** @brief 条目数量 */
|
||||
size_t itemCount() const noexcept { return items_.size(); }
|
||||
|
||||
private:
|
||||
std::vector<CartItem> items_; ///< 购物车条目列表
|
||||
};
|
||||
|
||||
#endif // MALL_SHOPPING_CART_HPP
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
#include "app.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
App::App() {
|
||||
initProducts();
|
||||
}
|
||||
|
||||
void App::initProducts() {
|
||||
products_.emplace_back(1001, "\xe8\x8b\xb9\xe6\x9e\x9c", 5.50, 100); // 苹果
|
||||
products_.emplace_back(1002, "\xe9\xa6\x99\xe8\x95\x89", 3.20, 150); // 香蕉
|
||||
products_.emplace_back(1003, "\xe7\x89\x9b\xe5\xa5\xb6", 12.80, 80); // 牛奶
|
||||
products_.emplace_back(1004, "\xe9\x9d\xa2\xe5\x8c\x85", 8.90, 60); // 面包
|
||||
products_.emplace_back(1005, "\xe6\x97\xa5\xe8\xae\xb0\xe6\x9c\xac", 15.00, 40); // 日记本
|
||||
}
|
||||
|
||||
void App::printMenu() {
|
||||
std::cout << "\n====== \xe5\x95\x86\xe5\x9f\x8e\xe7\xb3\xbb\xe7\xbb\x9f ======\n"; // 商城系统
|
||||
std::cout << " 1. \xe6\x9f\xa5\xe7\x9c\x8b\xe5\x95\x86\xe5\x93\x81\xe5\x88\x97\xe8\xa1\xa8\n"; // 查看商品列表
|
||||
std::cout << " 2. \xe5\x8a\xa0\xe5\x85\xa5\xe8\xb4\xad\xe7\x89\xa9\xe8\xbd\xa6\n"; // 加入购物车
|
||||
std::cout << " 3. \xe6\x9f\xa5\xe7\x9c\x8b\xe8\xb4\xad\xe7\x89\xa9\xe8\xbd\xa6\n"; // 查看购物车
|
||||
std::cout << " 4. \xe4\xb8\x8b\xe5\x8d\x95\xe7\xbb\x93\xe7\xae\x97\n"; // 下单结算
|
||||
std::cout << " 5. \xe6\x9f\xa5\xe7\x9c\x8b\xe5\x8e\x86\xe5\x8f\xb2\xe8\xae\xa2\xe5\x8d\x95\n"; // 查看历史订单
|
||||
std::cout << " 0. \xe9\x80\x80\xe5\x87\xba\n"; // 退出
|
||||
std::cout << "\xe8\xaf\xb7\xe9\x80\x89\xe6\x8b\xa9: "; // 请选择
|
||||
}
|
||||
|
||||
void App::run() {
|
||||
int choice = 0;
|
||||
do {
|
||||
printMenu();
|
||||
std::cin >> choice;
|
||||
if (std::cin.fail()) {
|
||||
std::cin.clear();
|
||||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
choice = -1;
|
||||
}
|
||||
switch (choice) {
|
||||
case 1: showProducts(); break;
|
||||
case 2: addToCart(); break;
|
||||
case 3: showCart(); break;
|
||||
case 4: checkout(); break;
|
||||
case 5: showOrders(); break;
|
||||
case 0: std::cout << "\xe6\xac\xa2\xe8\xbf\x8e\xe4\xb8\x8b\xe6\xac\xa1\xe5\x85\x89\xe4\xb8\xb4!\n"; break; // 欢迎下次光临
|
||||
default: std::cout << "\xe8\xaf\xb7\xe8\xbe\x93\xe5\x85\xa5\xe6\x9c\x89\xe6\x95\x88\xe9\x80\x89\xe9\xa1\xb9 (0-5)\n"; break; // 请输入有效选项
|
||||
}
|
||||
} while (choice != 0);
|
||||
}
|
||||
|
||||
void App::showProducts() const {
|
||||
std::cout << "\n------ \xe5\x95\x86\xe5\x93\x81\xe5\x88\x97\xe8\xa1\xa8 ------\n"; // 商品列表
|
||||
for (const auto& p : products_) {
|
||||
std::cout << " " << p.toString() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Product>::const_iterator App::selectProduct() const {
|
||||
std::cout << "\xe8\xaf\xb7\xe8\xbe\x93\xe5\x85\xa5\xe5\x95\x86\xe5\x93\x81\xe7\xbc\x96\xe5\x8f\xb7: "; // 请输入商品编号
|
||||
uint64_t id;
|
||||
std::cin >> id;
|
||||
return std::find_if(products_.begin(), products_.end(),
|
||||
[id](const Product& p) { return p.getId() == id; });
|
||||
}
|
||||
|
||||
void App::addToCart() {
|
||||
showProducts();
|
||||
auto it = selectProduct();
|
||||
if (it == products_.end()) {
|
||||
std::cout << "\xe6\x9c\xaa\xe6\x89\xbe\xe5\x88\xb0\xe8\xaf\xa5\xe5\x95\x86\xe5\x93\x81\xef\xbc\x81\n"; // 未找到该商品!
|
||||
return;
|
||||
}
|
||||
std::cout << "\xe8\xaf\xb7\xe8\xbe\x93\xe5\x85\xa5\xe6\x95\xb0\xe9\x87\x8f: "; // 请输入数量
|
||||
int qty;
|
||||
std::cin >> qty;
|
||||
if (qty <= 0) {
|
||||
std::cout << "\xe6\x95\xb0\xe9\x87\x8f\xe5\xbf\x85\xe9\xa1\xbb\xe5\xa4\xa7\xe4\xba\x8e 0\xef\xbc\x81\n"; // 数量必须大于 0!
|
||||
return;
|
||||
}
|
||||
cart_.addItem(*it, qty);
|
||||
std::cout << "\xe5\xb7\xb2\xe5\x8a\xa0\xe5\x85\xa5\xe8\xb4\xad\xe7\x89\xa9\xe8\xbd\xa6\xef\xbc\x81\n"; // 已加入购物车!
|
||||
}
|
||||
|
||||
void App::showCart() const {
|
||||
if (cart_.isEmpty()) {
|
||||
std::cout << "\n\xe8\xb4\xad\xe7\x89\xa9\xe8\xbd\xa6\xe6\x98\xaf\xe7\xa9\xba\xe7\x9a\x84\xe3\x80\x82\n"; // 购物车是空的。
|
||||
return;
|
||||
}
|
||||
std::cout << "\n------ \xe8\xb4\xad\xe7\x89\xa9\xe8\xbd\xa6 ------\n"; // 购物车
|
||||
for (const auto& item : cart_.getItems()) {
|
||||
std::cout << " " << item.product.getName()
|
||||
<< " x" << item.quantity
|
||||
<< " \xEF\xBF\xA5" << std::fixed << std::setprecision(2) << item.subtotal() << "\n";
|
||||
}
|
||||
std::cout << " \xe5\x90\x88\xe8\xae\xa1: \xEF\xBF\xA5" << std::fixed << std::setprecision(2) << cart_.totalPrice() << "\n"; // 合计
|
||||
}
|
||||
|
||||
void App::checkout() {
|
||||
if (cart_.isEmpty()) {
|
||||
std::cout << "\n\xe8\xb4\xad\xc7\x89\xa9\xe8\xbd\xa6\xe4\xb8\xba\xe7\xa9\xba\xef\xbc\x8c\xe6\x97\xa0\xe6\xb3\x95\xe4\xb8\x8b\xe5\x8d\x95\xe3\x80\x82\n"; // 购物车为空,无法下单。
|
||||
return;
|
||||
}
|
||||
static uint64_t nextOrderId = 10000;
|
||||
auto order = std::make_unique<Order>(nextOrderId++, cart_);
|
||||
std::cout << "\n\xe8\xae\xa2\xe5\x8d\x95\xe5\xb7\xb2\xe7\x94\x9f\xe6\x88\x90\xef\xbc\x81\n"; // 订单已生成!
|
||||
std::cout << order->toString() << "\n";
|
||||
orders_.push_back(std::move(order));
|
||||
}
|
||||
|
||||
void App::showOrders() const {
|
||||
if (orders_.empty()) {
|
||||
std::cout << "\n\xe6\xb2\xa1\xe6\x9c\x89\xe5\x8e\x86\xe5\x8f\xb2\xe8\xae\xa2\xe5\x8d\x95\xe3\x80\x82\n"; // 没有历史订单。
|
||||
return;
|
||||
}
|
||||
for (const auto& order : orders_) {
|
||||
std::cout << order->toString() << "\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* @file main.cpp
|
||||
* @brief 商城系统命令行入口。
|
||||
*/
|
||||
|
||||
#include "app.hpp"
|
||||
|
||||
/**
|
||||
* @brief 程序主入口。
|
||||
* @return 程序退出码
|
||||
*/
|
||||
int main() {
|
||||
App app;
|
||||
app.run();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#include "order.hpp"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include <numeric>
|
||||
|
||||
std::string orderStatusToString(OrderStatus status) {
|
||||
switch (status) {
|
||||
case OrderStatus::Pending: return "\xe5\xbe\x85\xe6\x94\xaf\xe4\xbb\x98"; // 待支付
|
||||
case OrderStatus::Paid: return "\xe5\xb7\xb2\xe6\x94\xaf\xe4\xbb\x98"; // 已支付
|
||||
case OrderStatus::Shipped: return "\xe5\xb7\xb2\xe5\x8f\x91\xe8\xb4\xa7"; // 已发货
|
||||
case OrderStatus::Delivered: return "\xe5\xb7\xb2\xe9\x80\x81\xe8\xbe\xbe"; // 已送达
|
||||
case OrderStatus::Cancelled: return "\xe5\xb7\xb2\xe5\x8f\x96\xe6\xb6\x88"; // 已取消
|
||||
default: return "\xe6\x9c\xaa\xe7\x9f\xa5"; // 未知
|
||||
}
|
||||
}
|
||||
|
||||
Order::Order(uint64_t orderId, ShoppingCart& cart)
|
||||
: orderId_(orderId)
|
||||
, status_(OrderStatus::Pending)
|
||||
, createTime_(std::time(nullptr))
|
||||
{
|
||||
items_ = std::move(cart.getItems());
|
||||
cart.clear();
|
||||
}
|
||||
|
||||
double Order::totalPrice() const {
|
||||
return std::accumulate(items_.begin(), items_.end(), 0.0,
|
||||
[](double sum, const CartItem& item) {
|
||||
return sum + item.subtotal();
|
||||
});
|
||||
}
|
||||
|
||||
std::string Order::toString() const {
|
||||
std::ostringstream oss;
|
||||
char timeBuf[64] = {0};
|
||||
std::tm* tmPtr = std::localtime(&createTime_);
|
||||
if (tmPtr) {
|
||||
std::strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", tmPtr);
|
||||
}
|
||||
|
||||
oss << "\xe2\x94\x81\xe2\x94\x81\xe2\x96\xa0 \xe8\xae\xa2\xe5\x8d\x95 #" << orderId_
|
||||
<< " \xe2\x94\x81\xe2\x94\x81\xe2\x94\x81\xe2\x94\x81\xe2\x94\x81\xe2\x94\x81\xe2\x94\x81\xe2\x94\x81\n";
|
||||
oss << " \xe7\x8a\xb6\xe6\x80\x81: " << orderStatusToString(status_) << "\n";
|
||||
oss << " \xe6\x97\xb6\xe9\x97\xb4: " << timeBuf << "\n";
|
||||
oss << " \xe5\x95\x86\xe5\x93\x81:\n";
|
||||
|
||||
for (const auto& item : items_) {
|
||||
oss << " " << item.product.getName()
|
||||
<< " x" << item.quantity
|
||||
<< " \xEF\xBF\xA5" << std::fixed << std::setprecision(2) << item.subtotal()
|
||||
<< "\n";
|
||||
}
|
||||
oss << " \xe5\x90\x88\xe8\xae\xa1: \xEF\xBF\xA5" << std::fixed << std::setprecision(2) << totalPrice() << "\n";
|
||||
return oss.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#include "product.hpp"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
Product::Product(uint64_t id, std::string name, double price, int stock)
|
||||
: id_(id), name_(std::move(name)), price_(price), stock_(stock) {}
|
||||
|
||||
bool Product::reduceStock(int quantity) {
|
||||
if (quantity <= 0 || quantity > stock_) {
|
||||
return false;
|
||||
}
|
||||
stock_ -= quantity;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Product::addStock(int quantity) {
|
||||
if (quantity > 0) {
|
||||
stock_ += quantity;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Product::toString() const {
|
||||
std::ostringstream oss;
|
||||
oss << "[#" << id_ << "] " << name_
|
||||
<< " \xEF\xBF\xA5" << std::fixed << std::setprecision(2) << price_
|
||||
<< " (\xe5\xba\x93\xe5\xad\x98:" << stock_ << ")";
|
||||
return oss.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#include "shopping_cart.hpp"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
void ShoppingCart::addItem(const Product& product, int quantity) {
|
||||
if (quantity <= 0) return;
|
||||
|
||||
for (auto& item : items_) {
|
||||
if (item.product.getId() == product.getId()) {
|
||||
item.quantity += quantity;
|
||||
return;
|
||||
}
|
||||
}
|
||||
items_.push_back({product, quantity});
|
||||
}
|
||||
|
||||
bool ShoppingCart::removeItem(uint64_t productId) {
|
||||
auto it = std::find_if(items_.begin(), items_.end(),
|
||||
[productId](const CartItem& item) {
|
||||
return item.product.getId() == productId;
|
||||
});
|
||||
if (it == items_.end()) return false;
|
||||
items_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShoppingCart::updateQuantity(uint64_t productId, int quantity) {
|
||||
auto it = std::find_if(items_.begin(), items_.end(),
|
||||
[productId](const CartItem& item) {
|
||||
return item.product.getId() == productId;
|
||||
});
|
||||
if (it == items_.end()) return false;
|
||||
|
||||
if (quantity <= 0) {
|
||||
items_.erase(it);
|
||||
} else {
|
||||
it->quantity = quantity;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShoppingCart::clear() {
|
||||
items_.clear();
|
||||
}
|
||||
|
||||
double ShoppingCart::totalPrice() const {
|
||||
return std::accumulate(items_.begin(), items_.end(), 0.0,
|
||||
[](double sum, const CartItem& item) {
|
||||
return sum + item.subtotal();
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* @file basic_test.cpp
|
||||
* @brief 商城系统单元测试,使用标准库 assert,无外部依赖。
|
||||
*/
|
||||
|
||||
#include "product.hpp"
|
||||
#include "shopping_cart.hpp"
|
||||
#include "order.hpp"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
/**
|
||||
* @brief 测试商品类的构造与基本接口。
|
||||
*/
|
||||
static void testProduct() {
|
||||
Product p(1001, "Test Book", 29.99, 50);
|
||||
assert(p.getId() == 1001);
|
||||
assert(p.getName() == "Test Book");
|
||||
assert(std::abs(p.getPrice() - 29.99) < 0.001);
|
||||
assert(p.getStock() == 50);
|
||||
|
||||
assert(p.reduceStock(10) == true);
|
||||
assert(p.getStock() == 40);
|
||||
|
||||
assert(p.reduceStock(100) == false); // 库存不足
|
||||
assert(p.getStock() == 40);
|
||||
|
||||
p.addStock(5);
|
||||
assert(p.getStock() == 45);
|
||||
|
||||
// toString 不应为空
|
||||
assert(!p.toString().empty());
|
||||
std::cout << "[PASS] testProduct\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试购物车类的添加、移除、清空、总价。
|
||||
*/
|
||||
static void testShoppingCart() {
|
||||
Product p1(2001, "Item A", 10.0, 100);
|
||||
Product p2(2002, "Item B", 20.0, 100);
|
||||
|
||||
ShoppingCart cart;
|
||||
assert(cart.isEmpty());
|
||||
assert(cart.itemCount() == 0);
|
||||
assert(std::abs(cart.totalPrice() - 0.0) < 0.001);
|
||||
|
||||
cart.addItem(p1, 2);
|
||||
cart.addItem(p2, 3);
|
||||
assert(!cart.isEmpty());
|
||||
assert(cart.itemCount() == 2);
|
||||
assert(std::abs(cart.totalPrice() - (10.0*2 + 20.0*3)) < 0.001);
|
||||
|
||||
// 再次添加相同商品应累加数量
|
||||
cart.addItem(p1, 1);
|
||||
assert(cart.itemCount() == 2);
|
||||
assert(std::abs(cart.totalPrice() - (10.0*3 + 20.0*3)) < 0.001);
|
||||
|
||||
// 移除商品
|
||||
assert(cart.removeItem(2001) == true);
|
||||
assert(cart.itemCount() == 1);
|
||||
|
||||
// 修改数量
|
||||
assert(cart.updateQuantity(2002, 5) == true);
|
||||
assert(std::abs(cart.totalPrice() - 20.0*5) < 0.001);
|
||||
|
||||
// 修改不存在的商品
|
||||
assert(cart.updateQuantity(9999, 1) == false);
|
||||
|
||||
// 清空
|
||||
cart.clear();
|
||||
assert(cart.isEmpty());
|
||||
std::cout << "[PASS] testShoppingCart\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试订单类的创建与状态。
|
||||
*/
|
||||
static void testOrder() {
|
||||
Product p1(3001, "Book", 25.0, 10);
|
||||
Product p2(3002, "Pen", 3.5, 50);
|
||||
|
||||
ShoppingCart cart;
|
||||
cart.addItem(p1, 2);
|
||||
cart.addItem(p2, 4);
|
||||
|
||||
Order order(9001, cart);
|
||||
assert(order.getOrderId() == 9001);
|
||||
assert(order.getStatus() == OrderStatus::Pending);
|
||||
assert(order.getItems().size() == 2);
|
||||
assert(std::abs(order.totalPrice() - (25.0*2 + 3.5*4)) < 0.001);
|
||||
|
||||
// 确认购物车已被清空
|
||||
assert(cart.isEmpty());
|
||||
|
||||
// 修改订单状态
|
||||
order.setStatus(OrderStatus::Paid);
|
||||
assert(order.getStatus() == OrderStatus::Paid);
|
||||
|
||||
// 订单摘要不为空
|
||||
assert(!order.toString().empty());
|
||||
std::cout << "[PASS] testOrder\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测试 orderStatusToString 枚举转换。
|
||||
*/
|
||||
static void testOrderStatusString() {
|
||||
assert(orderStatusToString(OrderStatus::Pending) == "\xe5\xbe\x85\xe6\x94\xaf\xe4\xbb\x98");
|
||||
assert(orderStatusToString(OrderStatus::Delivered) == "\xe5\xb7\xb2\xe9\x80\x81\xe8\xbe\xbe");
|
||||
std::cout << "[PASS] testOrderStatusString\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 运行所有测试。
|
||||
*/
|
||||
int main() {
|
||||
testProduct();
|
||||
testShoppingCart();
|
||||
testOrder();
|
||||
testOrderStatusString();
|
||||
std::cout << "\n===== \xe5\x85\xa8\xe9\x83\xa8\xe6\xb5\x8b\xe8\xaf\x95\xe9\x80\x9a\xe8\xbf\x87! =====\n"; // 全部测试通过!
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue