构建电商模块:支付、运输与销售全解析
1. 支付模块概述
在电商系统中,支付模块是核心组成部分之一。我们构建了一个包含两种支付方式的支付模块,分别是模拟信用卡支付的卡支付方式和不涉及信用卡的静态支票支付方式。这两种支付方式均为虚拟方法,并不与任何外部支付处理器进行实际通信。
为了便于后续定制,我们通过标记服务来暴露每个支付方法。使用
payment_method
标签是一种共识,因为我们在构建整个应用程序时可以自主选择在销售模块中的实现方式。通过为每个支付方法使用相同的标签名,我们为未来的销售模块在结账过程中选择并呈现所有支付方法创造了条件。
2. 运输模块构建
2.1 运输模块概述
运输模块与支付模块一样,为电商网站的销售功能提供了基础。在即将到来的销售模块的结账过程中,运输模块将使我们能够选择运输方式。运输方式可分为静态和动态两种,静态运输方式可能意味着固定的定价或通过简单条件计算得出的价格,而动态运输方式通常意味着与外部 API 服务的连接。
2.2 运输模块涉及内容
我们将从以下几个方面构建运输模块:
- 需求
- 依赖
- 实现
- 单元测试
- 功能测试
2.3 需求分析
由于应用需求未明确指定需要实现的运输类型,我们将开发两种运输方法:动态费率运输和统一费率运输。动态费率运输用于将运输方法与实际的运输处理器(如 UPS、FedEx 等)连接,但实际上不会连接到任何外部 API。
理想情况下,我们希望通过以下接口实现:
namespace Foggyline\SalesBundle\Interface;
interface Shipment
{
function getInfo($street, $city, $country, $postcode, $amount, $qty);
function process($street, $city, $country, $postcode, $amount, $qty);
}
getInfo
方法用于获取给定订单信息的可用交付选项,而
process
方法用于处理所选的交付选项。
由于尚未开发
SalesBundle
模块,我们将使用 Symfony 控制器处理
process
方法,使用服务处理
getInfo
方法。同样,我们将通过标记的 Symfony 服务暴露
getInfo
方法,使用的标签为
shipment_method
。在结账过程中,
SalesBundle
模块将获取所有带有
shipment_method
标签的服务,并将其用于可用运输方法列表。
2.4 依赖关系
我们采用逆向构建方式,在不了解
SalesBundle
模块的情况下构建运输模块。因此,运输模块对其他模块没有严格的依赖关系。不过,先构建
SalesBundle
模块并暴露一些运输模块可以使用的接口可能会更方便。
2.5 实现步骤
2.5.1 创建新模块
使用以下命令创建名为
Foggyline\ShipmentBundle
的新模块:
php bin/console generate:bundle --namespace=Foggyline/ShipmentBundle
该命令会触发一个交互式过程,完成后会自动修改
app/AppKernel.php
和
app/config/routing.yml
文件。
2.5.2 修改路由文件
为避免与核心应用代码冲突,将
routing.yml
文件中的
prefix: /
修改为
prefix: /shipment/
。
2.5.3 创建统一费率运输服务
在
src/Foggyline/ShipmentBundle/Resources/config/services.xml
文件中定义服务:
<service id="foggyline_shipment.dynamicrate_shipment" class="Foggyline\ShipmentBundle\Service\DynamicRateShipment">
<argument type="service" id="router"/>
<tag name="shipment_method"/>
</service>
创建服务类
src/Foggyline/ShipmentBundle/Service/FlatRateShipment.php
:
namespace Foggyline\ShipmentBundle\Service;
class FlatRateShipment
{
private $router;
public function __construct(
\Symfony\Bundle\FrameworkBundle\Routing\Router $router
)
{
$this->router = $router;
}
public function getInfo($street, $city, $country, $postcode, $amount, $qty)
{
return array(
'shipment' => array(
'title' => 'Foggyline FlatRate Shipment',
'code' => 'flat_rate',
'delivery_options' => array(
'title' => 'Fixed',
'code' => 'fixed',
'price' => 9.99
),
'url_process' => $this->router->generate('foggyline_shipment_flat_rate_process'),
)
);
}
}
2.5.4 创建统一费率运输控制器和路由
在
src/Foggyline/ShipmentBundle/Resources/config/routing.xml
文件中添加路由定义:
<route id="foggyline_shipment_flat_rate_process" path="/flat_rate/process">
<default key="_controller">FoggylineShipmentBundle:FlatRate:process</default>
</route>
创建控制器文件
src/Foggyline/ShipmentBundle/Controller/FlatRateController.php
:
namespace Foggyline\ShipmentBundle\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class FlatRateController extends Controller
{
public function processAction(Request $request)
{
$transaction = md5(time() . uniqid());
return new JsonResponse(array(
'success' => $transaction
));
}
}
2.5.5 创建动态费率运输服务
在
src/Foggyline/ShipmentBundle/Resources/config/services.xml
文件中定义服务:
<service id="foggyline_shipment.dynamicrate_shipment" class="Foggyline\ShipmentBundle\Service\DynamicRateShipment">
<argument type="service" id="router"/>
<tag name="shipment_method"/>
</service>
创建服务类
src/Foggyline/ShipmentBundle/Service/DynamicRateShipment.php
:
namespace Foggyline\ShipmentBundle\Service;
class DynamicRateShipment
{
private $router;
public function __construct(
\Symfony\Bundle\FrameworkBundle\Routing\Router $router
)
{
$this->router = $router;
}
public function getInfo($street, $city, $country, $postcode, $amount, $qty)
{
return array(
'shipment' => array(
'title' => 'Foggyline DynamicRate Shipment',
'code' => 'dynamic_rate_shipment',
'delivery_options' => $this->getDeliveryOptions($street, $city, $country, $postcode, $amount, $qty),
'url_process' => $this->router->generate('foggyline_shipment_dynamic_rate_process'),
)
);
}
public function getDeliveryOptions($street, $city, $country, $postcode, $amount, $qty)
{
return array(
array(
'title' => 'Same day delivery',
'code' => 'dynamic_rate_sdd',
'price' => 9.99
),
array(
'title' => 'Standard delivery',
'code' => 'dynamic_rate_sd',
'price' => 4.99
),
);
}
}
2.5.6 创建动态费率运输控制器和路由
在
src/Foggyline/ShipmentBundle/Resources/config/routing.xml
文件中添加路由定义:
<route id="foggyline_shipment_dynamic_rate_process" path="/dynamic_rate/process">
<default key="_controller">FoggylineShipmentBundle:DynamicRate:process</default>
</route>
创建控制器文件
src/Foggyline/ShipmentBundle/Controller/DynamicRateController.php
:
namespace Foggyline\ShipmentBundle\Controller;
use Foggyline\ShipmentBundle\Entity\DynamicRate;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class DynamicRateController extends Controller
{
public function processAction(Request $request)
{
$transaction = md5(time() . uniqid());
if ($transaction) {
return new JsonResponse(array(
'success' => $transaction
));
}
return new JsonResponse(array(
'error' => 'Error occurred while processing DynamicRate shipment.'
));
}
}
2.6 单元测试
为了确保运输模块的正确性,我们需要进行单元测试。首先,在
phpunit.xml.dist
文件的
testsuites
元素下添加以下行:
<directory>src/Foggyline/ShipmentBundle/Tests</directory>
2.6.1 统一费率运输服务测试
创建测试文件
src/Foggyline/ShipmentBundle/Tests/Service/FlatRateShipmentTest.php
:
namespace Foggyline\ShipmentBundle\Tests\Service;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class FlatRateShipmentTest extends KernelTestCase
{
private $container;
private $router;
private $street = 'Masonic Hill Road';
private $city = 'Little Rock';
private $country = 'US';
private $postcode = 'AR 72201';
private $amount = 199.99;
private $qty = 7;
public function setUp()
{
static::bootKernel();
$this->container = static::$kernel->getContainer();
$this->router = $this->container->get('router');
}
public function testGetInfoViaService()
{
$shipment = $this->container->get('foggyline_shipment.flat_rate');
$info = $shipment->getInfo(
$this->street, $this->city, $this->country, $this->postcode, $this->amount, $this->qty
);
$this->validateGetInfoResponse($info);
}
public function testGetInfoViaClass()
{
$shipment = new \Foggyline\ShipmentBundle\Service\FlatRateShipment($this->router);
$info = $shipment->getInfo(
$this->street, $this->city, $this->country, $this->postcode, $this->amount, $this->qty
);
$this->validateGetInfoResponse($info);
}
public function validateGetInfoResponse($info)
{
$this->assertNotEmpty($info);
$this->assertNotEmpty($info['shipment']['title']);
$this->assertNotEmpty($info['shipment']['code']);
$this->assertNotEmpty($info['shipment']['delivery_options']);
$this->assertNotEmpty($info['shipment']['url_process']);
}
}
2.6.2 动态费率运输服务测试
创建测试文件
src/Foggyline/ShipmentBundle/Tests/Service/DynamicRateShipmentTest.php
:
namespace Foggyline\ShipmentBundle\Tests\Service;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class DynamicRateShipmentTest extends KernelTestCase
{
private $container;
private $router;
private $street = 'Masonic Hill Road';
private $city = 'Little Rock';
private $country = 'US';
private $postcode = 'AR 72201';
private $amount = 199.99;
private $qty = 7;
public function setUp()
{
static::bootKernel();
$this->container = static::$kernel->getContainer();
$this->router = $this->container->get('router');
}
public function testGetInfoViaService()
{
$shipment = $this->container->get('foggyline_shipment.dynamicrate_shipment');
$info = $shipment->getInfo(
$this->street, $this->city, $this->country, $this->postcode, $this->amount, $this->qty
);
$this->validateGetInfoResponse($info);
}
public function testGetInfoViaClass()
{
$shipment = new \Foggyline\ShipmentBundle\Service\DynamicRateShipment($this->router);
$info = $shipment->getInfo(
$this->street, $this->city, $this->country, $this->postcode, $this->amount, $this->qty
);
$this->validateGetInfoResponse($info);
}
public function validateGetInfoResponse($info)
{
$this->assertNotEmpty($info);
$this->assertNotEmpty($info['shipment']['title']);
$this->assertNotEmpty($info['shipment']['code']);
$this->assertNotEmpty($info['shipment']['url_process']);
}
}
2.7 功能测试
我们还需要对运输模块的控制器进行功能测试,以确保其响应正常。
2.7.1 统一费率运输控制器测试
创建测试文件
src/Foggyline/ShipmentBundle/Tests/Controller/FlatRateControllerTest.php
:
namespace Foggyline\ShipmentBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class FlatRateControllerTest extends WebTestCase
{
private $client;
private $router;
public function setUp()
{
$this->client = static::createClient();
$this->router = $this->client->getContainer()->get('router');
}
public function testProcessAction()
{
$this->client->request('GET', $this->router->generate('foggyline_shipment_flat_rate_process'));
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
$this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type'));
$this->assertContains('success', $this->client->getResponse()->getContent());
$this->assertNotEmpty($this->client->getResponse()->getContent());
}
}
2.7.2 动态费率运输控制器测试
创建测试文件
src/Foggyline/ShipmentBundle/Tests/Controller/DynamicRateControllerTest.php
:
namespace Foggyline\ShipmentBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class DynamicRateControllerTest extends WebTestCase
{
private $client;
private $router;
public function setUp()
{
$this->client = static::createClient();
$this->router = $this->client->getContainer()->get('router');
}
public function testProcessAction()
{
$this->client->request('GET', $this->router->generate('foggyline_shipment_dynamic_rate_process'));
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
$this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type'));
$this->assertContains('success', $this->client->getResponse()->getContent());
$this->assertNotEmpty($this->client->getResponse()->getContent());
}
}
3. 销售模块构建
3.1 销售模块概述
销售模块是构建简单而实用的电商应用程序系列模块中的最后一个。我们将在目录的基础上添加购物车和结账功能,结账过程将最终利用前面章节中定义的运输和支付服务。
3.2 销售模块涉及内容
我们将从以下几个方面构建销售模块:
- 需求
- 依赖
- 实现
- 单元测试
- 功能测试
3.3 需求分析
根据应用需求,我们需要创建以下实体来实现购物车和结账功能:
- 购物车
- 购物车商品
- 订单
- 订单商品
3.3.1 购物车实体属性
| 属性 | 数据类型 |
|---|---|
| id | 整数,自增 |
| customer_id | 字符串 |
| created_at | 日期时间 |
| modified_at | 日期时间 |
3.3.2 购物车商品实体属性
| 属性 | 数据类型 |
|---|---|
| id | 整数,自增 |
| cart_id | 整数,外键,引用类别表的 id 列 |
| product_id | 整数,外键,引用产品表的 id 列 |
| qty | 字符串 |
| unit_price | 小数 |
| created_at | 日期时间 |
| modified_at | 日期时间 |
3.3.3 订单实体属性
| 属性 | 数据类型 |
|---|---|
| id | 整数,自增 |
| customer_id | 整数,外键,引用客户表的 id 列 |
| items_price | 小数 |
| shipment_price | 小数 |
| total_price | 小数 |
| status | 字符串 |
| customer_email | 字符串 |
| customer_first_name | 字符串 |
| customer_last_name | 字符串 |
| address_first_name | 字符串 |
| address_last_name | 字符串 |
| address_country | 字符串 |
| address_state | 字符串 |
| address_city | 字符串 |
3.4 销售模块构建流程
graph LR
A[需求分析] --> B[依赖处理]
B --> C[实现功能]
C --> D[单元测试]
D --> E[功能测试]
通过以上步骤,我们可以构建一个完整的电商系统,包括支付、运输和销售模块。每个模块都有其特定的功能和实现方式,通过合理的设计和测试,我们可以确保系统的正确性和稳定性。
3.4 依赖关系
销售模块主要依赖于前面构建的支付模块和运输模块。支付模块提供了不同的支付方式,运输模块提供了多种运输方法,销售模块将在结账过程中使用这些服务。由于之前已经完成了支付和运输模块的开发,所以销售模块可以直接引用它们提供的功能。
3.5 实现步骤
3.5.1 创建销售模块
首先,我们需要创建一个新的销售模块。虽然文档中未给出具体的创建命令,但通常可以使用框架提供的工具来创建。例如,在 Symfony 框架中,可能会使用类似以下的命令:
php bin/console generate:bundle --namespace=YourNamespace/SalesBundle
这个命令会触发交互式过程,创建相关的文件和目录结构,并自动修改
app/AppKernel.php
和
app/config/routing.yml
文件,将新模块注册到应用中。
3.5.2 实现购物车功能
购物车功能是销售模块的重要组成部分,它负责管理用户选择的商品。我们需要实现以下几个主要功能:
-
添加商品到购物车
:用户在浏览商品时,可以选择将商品添加到购物车。这需要在数据库中创建购物车商品记录,关联购物车和商品。
-
更新购物车商品数量
:用户可以修改购物车中商品的数量,系统需要更新数据库中的记录。
-
删除购物车商品
:用户可以删除不需要的商品,系统需要从数据库中删除相应的记录。
以下是一个简单的购物车服务示例:
namespace YourNamespace\SalesBundle\Service;
use YourNamespace\SalesBundle\Entity\Cart;
use YourNamespace\SalesBundle\Entity\CartItem;
use YourNamespace\SalesBundle\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
class CartService
{
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function addToCart(Product $product, $qty, $customerId)
{
$cart = $this->getOrCreateCart($customerId);
$cartItem = $this->findCartItem($cart, $product);
if ($cartItem) {
$cartItem->setQty($cartItem->getQty() + $qty);
} else {
$cartItem = new CartItem();
$cartItem->setCart($cart);
$cartItem->setProduct($product);
$cartItem->setQty($qty);
$cart->addCartItem($cartItem);
$this->entityManager->persist($cartItem);
}
$this->entityManager->flush();
}
private function getOrCreateCart($customerId)
{
$cart = $this->entityManager->getRepository(Cart::class)
->findOneBy(['customer_id' => $customerId]);
if (!$cart) {
$cart = new Cart();
$cart->setCustomerId($customerId);
$this->entityManager->persist($cart);
$this->entityManager->flush();
}
return $cart;
}
private function findCartItem(Cart $cart, Product $product)
{
foreach ($cart->getCartItems() as $cartItem) {
if ($cartItem->getProduct() === $product) {
return $cartItem;
}
}
return null;
}
}
3.5.3 实现结账功能
结账功能是销售模块的核心,它涉及到支付和运输的选择。在结账过程中,用户需要选择支付方式和运输方式,系统需要根据用户的选择进行相应的处理。
以下是一个简单的结账控制器示例:
namespace YourNamespace\SalesBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use YourNamespace\SalesBundle\Service\CartService;
use YourNamespace\PaymentBundle\Service\PaymentService;
use YourNamespace\ShipmentBundle\Service\ShipmentService;
class CheckoutController extends Controller
{
private $cartService;
private $paymentService;
private $shipmentService;
public function __construct(CartService $cartService, PaymentService $paymentService, ShipmentService $shipmentService)
{
$this->cartService = $cartService;
$this->paymentService = $paymentService;
$this->shipmentService = $shipmentService;
}
public function checkoutAction(Request $request)
{
$customerId = $request->get('customer_id');
$paymentMethod = $request->get('payment_method');
$shipmentMethod = $request->get('shipment_method');
$cart = $this->cartService->getCart($customerId);
$totalAmount = $this->cartService->calculateTotalAmount($cart);
// 处理支付
$paymentResult = $this->paymentService->processPayment($paymentMethod, $totalAmount);
if (!$paymentResult) {
return new JsonResponse(['error' => 'Payment failed'], 400);
}
// 处理运输
$shipmentResult = $this->shipmentService->processShipment($shipmentMethod, $cart);
if (!$shipmentResult) {
return new JsonResponse(['error' => 'Shipment failed'], 400);
}
// 创建订单
$order = $this->createOrder($cart, $paymentMethod, $shipmentMethod);
$this->entityManager->persist($order);
$this->entityManager->flush();
return new JsonResponse(['success' => 'Checkout completed'], 200);
}
private function createOrder($cart, $paymentMethod, $shipmentMethod)
{
$order = new Order();
$order->setCustomerId($cart->getCustomerId());
$order->setItemsPrice($this->cartService->calculateItemsPrice($cart));
$order->setShipmentPrice($this->shipmentService->getShipmentPrice($shipmentMethod, $cart));
$order->setTotalPrice($this->cartService->calculateTotalAmount($cart));
$order->setStatus('Pending');
// 设置其他订单属性
foreach ($cart->getCartItems() as $cartItem) {
$orderItem = new OrderItem();
$orderItem->setOrder($order);
$orderItem->setProduct($cartItem->getProduct());
$orderItem->setQty($cartItem->getQty());
$orderItem->setUnitPrice($cartItem->getProduct()->getPrice());
$this->entityManager->persist($orderItem);
}
return $order;
}
}
3.6 单元测试
单元测试是确保销售模块功能正确性的重要手段。我们需要对购物车服务、结账控制器等关键组件进行测试。
3.6.1 购物车服务测试
以下是一个简单的购物车服务测试示例:
namespace YourNamespace\SalesBundle\Tests\Service;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use YourNamespace\SalesBundle\Service\CartService;
use YourNamespace\SalesBundle\Entity\Product;
class CartServiceTest extends KernelTestCase
{
private $cartService;
private $entityManager;
public function setUp()
{
self::bootKernel();
$this->entityManager = self::$kernel->getContainer()
->get('doctrine')
->getManager();
$this->cartService = new CartService($this->entityManager);
}
public function testAddToCart()
{
$product = new Product();
$product->setName('Test Product');
$product->setPrice(100);
$this->entityManager->persist($product);
$this->entityManager->flush();
$customerId = 1;
$qty = 2;
$this->cartService->addToCart($product, $qty, $customerId);
$cart = $this->cartService->getCart($customerId);
$this->assertCount(1, $cart->getCartItems());
$this->assertEquals($qty, $cart->getCartItems()[0]->getQty());
}
}
3.6.2 结账控制器测试
以下是一个简单的结账控制器测试示例:
namespace YourNamespace\SalesBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use YourNamespace\SalesBundle\Controller\CheckoutController;
use YourNamespace\SalesBundle\Service\CartService;
use YourNamespace\PaymentBundle\Service\PaymentService;
use YourNamespace\ShipmentBundle\Service\ShipmentService;
class CheckoutControllerTest extends WebTestCase
{
private $checkoutController;
private $cartService;
private $paymentService;
private $shipmentService;
public function setUp()
{
$client = static::createClient();
$this->cartService = $client->getContainer()->get('your_namespace.cart_service');
$this->paymentService = $client->getContainer()->get('your_namespace.payment_service');
$this->shipmentService = $client->getContainer()->get('your_namespace.shipment_service');
$this->checkoutController = new CheckoutController($this->cartService, $this->paymentService, $this->shipmentService);
}
public function testCheckoutAction()
{
$request = new Request([
'customer_id' => 1,
'payment_method' => 'credit_card',
'shipment_method' => 'flat_rate'
]);
$response = $this->checkoutController->checkoutAction($request);
$this->assertInstanceOf(JsonResponse::class, $response);
}
}
3.7 功能测试
功能测试用于验证销售模块的整体功能是否正常。我们可以使用 WebTestCase 来模拟用户的操作,测试购物车、结账等功能。
以下是一个简单的功能测试示例:
namespace YourNamespace\SalesBundle\Tests\Functional;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class SalesModuleFunctionalTest extends WebTestCase
{
public function testCheckoutFlow()
{
$client = static::createClient();
// 模拟用户添加商品到购物车
$client->request('POST', '/add-to-cart', [
'product_id' => 1,
'qty' => 2,
'customer_id' => 1
]);
$this->assertEquals(200, $client->getResponse()->getStatusCode());
// 模拟用户结账
$client->request('POST', '/checkout', [
'customer_id' => 1,
'payment_method' => 'credit_card',
'shipment_method' => 'flat_rate'
]);
$this->assertEquals(200, $client->getResponse()->getStatusCode());
}
}
4. 总结
通过以上步骤,我们成功构建了一个简单而实用的电商系统,包括支付模块、运输模块和销售模块。每个模块都有其特定的功能和实现方式,通过合理的设计和测试,我们可以确保系统的正确性和稳定性。
4.1 模块总结
| 模块 | 功能 | 实现要点 |
|---|---|---|
| 支付模块 | 提供多种支付方式,模拟支付过程 | 使用标记服务暴露支付方法,实现虚拟支付逻辑 |
| 运输模块 | 提供多种运输方式,模拟运输过程 | 创建运输服务和控制器,使用标记服务暴露运输方法,进行单元和功能测试 |
| 销售模块 | 实现购物车和结账功能,整合支付和运输服务 | 创建销售模块,实现购物车和结账逻辑,进行单元和功能测试 |
4.2 未来优化方向
- 集成真实的支付和运输 API :目前的支付和运输模块都是模拟实现,未来可以集成真实的支付和运输 API,提高系统的实用性。
- 优化用户体验 :可以添加更多的交互功能,如购物车商品数量的实时更新、结账过程的进度提示等,提高用户体验。
- 性能优化 :随着系统的发展,可能会面临性能问题。可以对数据库查询、缓存机制等进行优化,提高系统的性能。
通过不断的优化和改进,我们可以构建一个更加完善和强大的电商系统。
超级会员免费看
11万+

被折叠的 条评论
为什么被折叠?



