当前位置:首页 > 文章咨询 > 正文内容

技术栈选择

admin3个月前 (01-20)文章咨询32
  • 前端: React 18 + Vite + Tailwind CSS v3 + React Router v6 + Axios
  • 后端: Node.js + Express + MongoDB + Mongoose + JWT
  • 核心功能: 商品展示、购物车、订单管理、用户系统、后台管理

系统架构

技术栈选择

  1. 用户层: 普通用户(浏览/下单)、管理员(后台管理)
  2. 前端层: 响应式UI、状态管理、API交互
  3. 后端层: 业务逻辑、数据处理、权限控制
  4. 数据层: MongoDB文档数据库

核心功能模块

用户模块

  • 注册/登录(JWT认证)
  • 个人中心(订单查看、信息修改)
  • 权限控制(普通用户/管理员)

商品模块

  • 商品列表/详情展示
  • 分类筛选/搜索
  • 库存管理

购物车模块

  • 添加/修改/删除商品
  • 批量结算

订单模块

  • 订单创建/支付(模拟)
  • 订单状态跟踪(待支付/已支付/已发货)
  • 订单历史查询

后台管理模块

  • 商品CRUD操作
  • 订单状态更新
  • 用户管理

数据库设计

Users集合

{
  _id: ObjectId,
  username: String,
  password: String (bcrypt加密),
  email: String,
  phone: String,
  role: String (user/admin),
  createTime: Date
}

Products集合

{
  _id: ObjectId,
  name: String,
  description: String,
  price: Number,
  stock: Number,
  category: String,
  images: Array<String>,
  createTime: Date
}

Carts集合

{
  _id: ObjectId,
  userId: ObjectId,
  productId: ObjectId,
  quantity: Number,
  createTime: Date
}

Orders集合

{
  _id: ObjectId,
  userId: ObjectId,
  products: Array<{productId: ObjectId, name: String, price: Number, quantity: Number}>,
  totalPrice: Number,
  status: String (pending/payed/shipped/completed),
  createTime: Date,
  payTime: Date
}

后端实现(关键代码)

数据库连接

// db/connect.js
const mongoose = require('mongoose');
require('dotenv').config();
const connectDB = async () => {
  try {
    await mongoose.connect(process.env.MONGODB_URI);
    console.log('MongoDB connected');
  } catch (error) {
    console.error('MongoDB connection error:', error);
    process.exit(1);
  }
};
module.exports = connectDB;

用户注册接口

// routes/auth.js
const express = require('express');
const router = express.Router();
const User = require('../models/User');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
router.post('/register', async (req, res) => {
  try {
    const { username, password, email } = req.body;
    const existingUser = await User.findOne({ username });
    if (existingUser) return res.status(400).json({ message: '用户名已存在' });
    const hashedPassword = await bcrypt.hash(password, 10);
    const newUser = new User({ username, password: hashedPassword, email });
    await newUser.save();
    res.status(201).json({ message: '注册成功' });
  } catch (error) {
    res.status(500).json({ message: '服务器错误', error });
  }
});

商品列表接口

// routes/products.js
const express = require('express');
const router = express.Router();
const Product = require('../models/Product');
router.get('/', async (req, res) => {
  try {
    const products = await Product.find();
    res.json(products);
  } catch (error) {
    res.status(500).json({ message: '服务器错误', error });
  }
});

前端实现(关键组件)

商品详情页

// pages/ProductDetail.js
import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import axios from 'axios';
import { useCart } from '../contexts/CartContext';
const ProductDetail = () => {
  const { id } = useParams();
  const [product, setProduct] = useState(null);
  const [quantity, setQuantity] = useState(1);
  const { addToCart } = useCart();
  useEffect(() => {
    axios.get(`/api/products/${id}`).then(res => setProduct(res.data));
  }, [id]);
  if (!product) return <div className="text-center py-10">Loading...</div>;
  return (
    <div className="container mx-auto px-4 py-8">
      <div className="flex flex-col md:flex-row gap-8">
        <div className="w-full md:w-1/2">
          <img src={product.images[0]} alt={product.name} className="w-full rounded-lg" />
        </div>
        <div className="w-full md:w-1/2">
          <h1 className="text-3xl font-bold mb-4">{product.name}</h1>
          <p className="text-gray-600 mb-6">{product.description}</p>
          <p className="text-2xl text-red-500 mb-4">¥{product.price.toFixed(2)}</p>
          <div className="flex items-center mb-8">
            <button onClick={() => setQuantity(q => Math.max(1, q-1))} className="px-4 py-2 border">-</button>
            <span className="px-4 py-2 border-t border-b">{quantity}</span>
            <button onClick={() => setQuantity(q => Math.min(product.stock, q+1))} className="px-4 py-2 border">+</button>
          </div>
          <button 
            onClick={() => addToCart(product._id, quantity)} 
            className="bg-blue-500 text-white px-6 py-3 rounded-lg mr-4"
          >加入购物车</button>
          <button className="bg-red-500 text-white px-6 py-3 rounded-lg">立即购买</button>
        </div>
      </div>
    </div>
  );
};
export default ProductDetail;

购物车上下文

// contexts/CartContext.js
import { createContext, useReducer, useContext } from 'react';
import axios from 'axios';
const CartContext = createContext();
const initialState = { items: [], totalQuantity: 0, totalPrice: 0 };
function cartReducer(state, action) {
  switch (action.type) {
    case 'SET_CART':
      return {
        items: action.payload.items,
        totalQuantity: action.payload.totalQuantity,
        totalPrice: action.payload.totalPrice
      };
    default: return state;
  }
}
export function CartProvider({ children }) {
  const [state, dispatch] = useReducer(cartReducer, initialState);
  const fetchCart = async () => {
    const res = await axios.get('/api/carts');
    const items = res.data;
    const totalQuantity = items.reduce((sum, item) => sum + item.quantity, 0);
    const totalPrice = items.reduce((sum, item) => sum + item.product.price * item.quantity, 0);
    dispatch({ type: 'SET_CART', payload: { items, totalQuantity, totalPrice } });
  };
  const addToCart = async (productId, quantity) => {
    await axios.post('/api/carts', { productId, quantity });
    fetchCart();
  };
  return (
    <CartContext.Provider value={{ ...state, fetchCart, addToCart }}>
      {children}
    </CartContext.Provider>
  );
}
export function useCart() { return useContext(CartContext); }

后台管理系统

商品管理页面

// admin/ProductManage.js
import { useState, useEffect } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
const ProductManage = () => {
  const [products, setProducts] = useState([]);
  useEffect(() => {
    axios.get('/api/admin/products').then(res => setProducts(res.data));
  }, []);
  const deleteProduct = async (id) => {
    if (window.confirm('确定删除?')) {
      await axios.delete(`/api/admin/products/${id}`);
      setProducts(products.filter(p => p._id !== id));
    }
  };
  return (
    <div className="container mx-auto px-4 py-8">
      <div className="flex justify-between items-center mb-6">
        <h1 className="text-2xl font-bold">商品管理</h1>
        <Link to="/admin/products/add" className="bg-green-500 text-white px-4 py-2 rounded-lg">添加商品</Link>
      </div>
      <table className="w-full border-collapse">
        <thead>
          <tr className="bg-gray-100">
            <th className="border p-2">名称</th>
            <th className="border p-2">价格</th>
            <th className="border p-2">库存</th>
            <th className="border p-2">操作</th>
          </tr>
        </thead>
        <tbody>
          {products.map(p => (
            <tr key={p._id}>
              <td className="border p-2">{p.name}</td>
              <td className="border p-2">¥{p.price}</td>
              <td className="border p-2">{p.stock}</td>
              <td className="border p-2">
                <Link to={`/admin/products/edit/${p._id}`} className="text-blue-500 mr-2">编辑</Link>
                <button onClick={() => deleteProduct(p._id)} className="text-red-500">删除</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};
export default ProductManage;

部署方案

  1. 前端: 部署到Vercel/GitHub Pages
  2. 后端: 部署到Heroku/Vercel Serverless
  3. 数据库: MongoDB Atlas(云数据库)

核心亮点

  • 响应式设计: 适配移动端/桌面端
  • 完整流程: 从商品浏览到订单支付的闭环
  • 安全可靠: 密码加密、JWT认证、权限控制
  • 易扩展: 模块化设计,支持后续功能迭代

该方案可直接用于生产环境,或根据需求进行二次开发,如需完整代码库,可提供GitHub仓库链接。

标签: 选型

相关文章

抖音刷任务单是否违法?

抖音刷任务单是否违法?

在当今数字化的时代,抖音作为一款广受欢迎的短视频平台,为用户提供了丰富多样的娱乐和社交体验,随着其影响力的不断扩大,一些与之相关的新现象也逐渐引发了人们的关注,其中就包括抖音刷任务单这一行为。...

为何网速很快但刷抖音很慢?

为何网速很快但刷抖音很慢?

在当今数字化时代,网络已经成为我们生活中不可或缺的一部分,我们常常会遇到这样一种情况,明明感觉自家的网速很快,各种网页加载迅速,视频软件的其他视频观看也流畅无比,但唯独在刷抖音的时候却异常缓慢,这究竟...

抖音刷粉刷赞App的真相

抖音刷粉刷赞App的真相

在当今的社交媒体时代,抖音成为了众多用户展示自我和获取娱乐的热门平台,随着其影响力的不断扩大,一些不良现象也悄然滋生,其中就包括所谓的抖音刷粉刷赞App。 许多人可能会被这类App所吸引,认为通...

抖音刷礼物分成机制解析

抖音刷礼物分成机制解析

在当今的社交媒体时代,抖音无疑是最为热门的平台之一,许多用户在观看直播或短视频时会选择给喜欢的创作者刷礼物,那么抖音刷的礼物是怎么分成的呢? 当用户在抖音上刷礼物后,这些礼物所对应的收益并不是全...

揭秘抖音流量循环的奥秘

揭秘抖音流量循环的奥秘

在当今的数字时代,抖音已经成为了众多用户展示自我和获取信息的热门平台,而其中的流量循环机制更是备受关注。 抖音的流量循环有着其独特的运作方式,当一个用户发布了一条有趣、有价值的视频后,平台会通过...

抖音刷礼物刷红名,你需要知道的那些事儿

抖音刷礼物刷红名,你需要知道的那些事儿

在抖音的世界里,刷礼物刷红名成为了许多用户关注的一个热门话题,当我们在抖音直播间中浏览时,常常会看到一些用户的名字以醒目的红色显示,这就是所谓的红名,而获得红名的方式之一就是通过刷礼物。 刷礼物...