当前位置: 首页 > news >正文

从 0 到 1:Vue3+Django打造现代化宠物商城系统(含AI智能顾问)

🐾 从 0 到 1:Vue3+Django打造现代化宠物商城系统(含AI智能顾问)

项目亮点:前后端分离架构 + AI智能咨询 + 完整电商功能 + 现代化UI设计

技术栈:Vue3 + Element Plus + Django + MySQL + LongCat AI

GitHub地址:https://github.com/Smartloe/PetMarketplaceSystem

📖 前言

作为一名全栈开发者,我一直想做一个集成AI功能的电商项目来实践现代Web开发技术。经过几个月的开发,终于完成了这个吉祥宠物商城系统

这不仅仅是一个普通的电商网站,更是一个融合了AI智能顾问的现代化宠物服务平台。用户可以在购买宠物用品的同时,获得专业的AI宠物护理建议。

🎯 项目概览

核心功能特色

  • 🤖 AI宠物顾问:基于LongCat模型,24小时在线提供专业宠物咨询
  • 🛍️ 完整电商功能:商品浏览、购物车、订单管理、支付集成
  • 🎨 现代化UI:Element Plus + 自定义设计系统,支持响应式布局
  • 🔐 安全认证:JWT无状态认证 + 权限控制
  • 📊 数据可视化:销售统计、用户行为分析

技术架构

前端:Vue3 + Element Plus + Vuex + Vue Router
后端:Django + DRF + JWT + MySQL
AI服务:LongCat API集成
支付:支付宝/微信/银联

🏗️ 系统架构设计

整体架构图

外部服务
数据存储层
业务逻辑层
API网关层
前端层
LongCat AI API
支付网关
MySQL数据库
媒体文件存储
用户管理模块
商品管理模块
订单交易模块
AI咨询模块
Django REST Framework
JWT认证中间件
CORS跨域处理
Vue3 SPA应用
Element Plus UI
Vuex状态管理
Vue Router路由

项目目录结构

PetMarketplaceSystem/
├── frontstage/pet_shop/          # Vue3前端
│   ├── src/
│   │   ├── views/                # 页面组件
│   │   │   ├── Home.vue          # 首页
│   │   │   ├── AIPetExpert.vue   # AI顾问
│   │   │   ├── CommodityList.vue # 商品列表
│   │   │   └── ShoppingCart.vue  # 购物车
│   │   ├── components/           # 公共组件
│   │   ├── store/                # Vuex状态管理
│   │   └── api/                  # API接口
│   └── package.json
│
└── backstage/pet_shop/           # Django后端├── accounts/                 # 用户管理├── commodity/                # 商品管理├── trade/                    # 交易订单├── customer_operation/       # 用户操作├── index/                    # AI咨询└── pyproject.toml

💻 核心功能实现

1. AI智能顾问实现

这是项目的最大亮点,我们集成了LongCat AI模型来提供专业的宠物咨询服务。

后端AI接口实现
# index/views.py
import json
import requests
from django.http import StreamingHttpResponse
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated@api_view(['POST'])
@permission_classes([IsAuthenticated])
def ai_pet_consult(request):"""AI宠物顾问咨询接口"""user_message = request.data.get('message', '')conversation_id = request.data.get('conversation_id', '')# 构建AI请求headers = {'Authorization': f'Bearer {settings.LONGCAT_API_KEY}','Content-Type': 'application/json'}payload = {"model": "longchat-7b-16k","messages": [{"role": "system","content": "你是一位专业的宠物顾问,专门为宠物主人提供护理建议..."},{"role": "user", "content": user_message}],"stream": True,"max_tokens": 1000}def generate_response():"""流式响应生成器"""try:response = requests.post(settings.LONGCAT_API_URL,headers=headers,json=payload,stream=True,timeout=30)for line in response.iter_lines():if line:line_str = line.decode('utf-8')if line_str.startswith('data: '):data_str = line_str[6:]if data_str.strip(':yield f"data: {json.dumps({'type': 'end'})}\n\n"breaktry:data = json.loads(data_str)content = data['choices'][0]['delta'].get('content', '')if content:yield f"data: {json.dumps({'type': 'message', 'content': content})}\n\n"except json.JSONDecodeError:continueexcept Exception as e:yield f"data: {json.dumps({'type': 'error', 'message': str(e)})}\n\n"return StreamingHttpResponse(generate_response(),content_type='text/event-stream')
前端AI对话组件
<!-- AIPetExpert.vue -->
<template><div class="ai-chat-container"><div class="chat-header"><h2>🤖 AI宠物顾问</h2><p>专业的宠物护理建议,24小时在线服务</p></div><div class="chat-messages" ref="messagesContainer"><div v-for="(message, index) in messages" :key="index":class="['message', message.type]"><div class="message-content"><div class="message-text" v-html="formatMessage(message.content)"></div><div class="message-time">{{ message.timestamp }}</div></div></div><!-- AI正在输入指示器 --><div v-if="isAITyping" class="message ai typing"><div class="typing-indicator"><span></span><span></span><span></span></div></div></div><div class="chat-input"><el-inputv-model="userInput"placeholder="请输入您的问题,比如:我的猫咪不吃饭怎么办?"@keyup.enter="sendMessage":disabled="isLoading"><template #append><el-button @click="sendMessage" :loading="isLoading"type="primary">发送</el-button></template></el-input></div></div>
</template><script>
import { ref, reactive, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import api from '@/api'export default {name: 'AIPetExpert',setup() {const userInput = ref('')const messages = reactive([])const isLoading = ref(false)const isAITyping = ref(false)const messagesContainer = ref(null)// 发送消息const sendMessage = async () => {if (!userInput.value.trim() || isLoading.value) returnconst userMessage = userInput.value.trim()// 添加用户消息messages.push({type: 'user',content: userMessage,timestamp: new Date().toLocaleTimeString()})userInput.value = ''isLoading.value = trueisAITyping.value = truetry {// 调用AI接口const response = await fetch('/api/ai-pet-consult/', {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': `Bearer ${localStorage.getItem('access_token')}`},body: JSON.stringify({message: userMessage,conversation_id: generateConversationId()})})const reader = response.body.getReader()let aiMessage = {type: 'ai',content: '',timestamp: new Date().toLocaleTimeString()}messages.push(aiMessage)isAITyping.value = false// 处理流式响应while (true) {const { done, value } = await reader.read()if (done) breakconst chunk = new TextDecoder().decode(value)const lines = chunk.split('\n')for (const line of lines) {if (line.startsWith('data: ')) {try {const data = JSON.parse(line.slice(6))if (data.type === 'message') {aiMessage.content += data.contentawait nextTick()scrollToBottom()} else if (data.type === 'end') {isLoading.value = falsereturn}} catch (e) {console.error('解析AI响应失败:', e)}}}}} catch (error) {console.error('AI咨询失败:', error)ElMessage.error('AI服务暂时不可用,请稍后重试')messages.pop() // 移除失败的消息} finally {isLoading.value = falseisAITyping.value = false}}// 滚动到底部const scrollToBottom = () => {nextTick(() => {if (messagesContainer.value) {messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight}})}// 格式化消息内容const formatMessage = (content) => {return content.replace(/\n/g, '<br>').replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>').replace(/\*(.*?)\*/g, '<em>$1</em>')}// 生成对话IDconst generateConversationId = () => {return 'conv_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9)}return {userInput,messages,isLoading,isAITyping,messagesContainer,sendMessage,formatMessage}}
}
</script><style scoped>
.ai-chat-container {max-width: 800px;margin: 0 auto;height: 600px;display: flex;flex-direction: column;border: 1px solid #e4e7ed;border-radius: 8px;overflow: hidden;
}.chat-header {background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);color: white;padding: 20px;text-align: center;
}.chat-messages {flex: 1;overflow-y: auto;padding: 20px;background: #f8f9fa;
}.message {margin-bottom: 15px;display: flex;
}.message.user {justify-content: flex-end;
}.message.ai {justify-content: flex-start;
}.message-content {max-width: 70%;padding: 12px 16px;border-radius: 18px;position: relative;
}.message.user .message-content {background: #409eff;color: white;
}.message.ai .message-content {background: white;border: 1px solid #e4e7ed;
}.typing-indicator {display: flex;gap: 4px;padding: 12px 16px;
}.typing-indicator span {width: 8px;height: 8px;border-radius: 50%;background: #409eff;animation: typing 1.4s infinite ease-in-out;
}.typing-indicator span:nth-child(2) {animation-delay: 0.2s;
}.typing-indicator span:nth-child(3) {animation-delay: 0.4s;
}@keyframes typing {0%, 80%, 100% {transform: scale(0.8);opacity: 0.5;}40% {transform: scale(1);opacity: 1;}
}.chat-input {padding: 20px;background: white;border-top: 1px solid #e4e7ed;
}
</style>

2. 商品管理系统

后端商品模型设计
# commodity/models.py
from django.db import modelsclass CommodityCategories(models.Model):"""商品分类模型"""name = models.CharField(max_length=30, verbose_name="分类名")code = models.CharField(max_length=30, verbose_name="分类code")desc = models.TextField(verbose_name="分类描述")category_type = models.IntegerField(choices=((1, "一级类目"), (2, "二级类目"), (3, "三级类目")))parent_category = models.ForeignKey("self", null=True, blank=True, on_delete=models.CASCADE)is_tab = models.BooleanField(default=False, verbose_name="是否导航")add_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")class Meta:verbose_name = "商品类别"verbose_name_plural = verbose_nameclass CommodityInfos(models.Model):"""商品信息模型"""category = models.ForeignKey(CommodityCategories, on_delete=models.CASCADE, verbose_name="商品类目")goods_sn = models.CharField(max_length=50, default="", verbose_name="商品唯一货号")name = models.CharField(max_length=100, verbose_name="商品名")click_num = models.IntegerField(default=0, verbose_name="点击数")sold_num = models.IntegerField(default=0, verbose_name="商品销售量")fav_num = models.IntegerField(default=0, verbose_name="收藏数")goods_num = models.IntegerField(default=0, verbose_name="库存数")market_price = models.FloatField(default=0, verbose_name="市场价格")shop_price = models.FloatField(default=0, verbose_name="本店价格")goods_brief = models.TextField(max_length=500, verbose_name="商品简短描述")goods_desc = models.TextField(verbose_name="商品详情")ship_free = models.BooleanField(default=True, verbose_name="是否承担运费")goods_front_image = models.ImageField(upload_to="goods/images/", null=True, blank=True, verbose_name="封面图")is_new = models.BooleanField(default=False, verbose_name="是否新品")is_hot = models.BooleanField(default=False, verbose_name="是否热销")add_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")class Meta:verbose_name = '商品信息'verbose_name_plural = verbose_name
前端商品列表组件
<!-- CommodityList.vue -->
<template><div class="commodity-list"><!-- 筛选栏 --><div class="filter-bar"><el-row :gutter="20"><el-col :span="6"><el-select v-model="filters.category" placeholder="选择分类" @change="loadProducts"><el-option label="全部分类" value=""></el-option><el-option v-for="category in categories" :key="category.id":label="category.name" :value="category.id"></el-option></el-select></el-col><el-col :span="6"><el-select v-model="filters.ordering" placeholder="排序方式" @change="loadProducts"><el-option label="默认排序" value=""></el-option><el-option label="价格从低到高" value="shop_price"></el-option><el-option label="价格从高到低" value="-shop_price"></el-option><el-option label="销量最高" value="-sold_num"></el-option><el-option label="最新上架" value="-add_time"></el-option></el-select></el-col><el-col :span="12"><el-inputv-model="filters.search"placeholder="搜索商品名称"@keyup.enter="loadProducts"><template #append><el-button @click="loadProducts" icon="Search">搜索</el-button></template></el-input></el-col></el-row></div><!-- 商品网格 --><div class="products-grid" v-loading="loading"><div v-for="product in products" :key="product.id"class="product-card"@click="goToDetail(product.id)"><div class="product-image"><img :src="getImageUrl(product.goods_front_image)" :alt="product.name"><div class="product-badges"><span v-if="product.is_new" class="badge new">新品</span><span v-if="product.is_hot" class="badge hot">热销</span></div></div><div class="product-info"><h3 class="product-name">{{ product.name }}</h3><p class="product-brief">{{ product.goods_brief }}</p><div class="product-price"><span class="current-price">¥{{ product.shop_price }}</span><span v-if="product.market_price > product.shop_price" class="original-price">¥{{ product.market_price }}</span></div><div class="product-stats"><span>销量: {{ product.sold_num }}</span><span>库存: {{ product.goods_num }}</span></div><div class="product-actions"><el-button type="primary" size="small"@click.stop="addToCart(product)":loading="addingToCart[product.id]">加入购物车</el-button><el-button size="small"@click.stop="toggleFavorite(product)":class="{ 'is-favorited': product.is_favorited }"><el-icon><Star /></el-icon></el-button></div></div></div></div><!-- 分页 --><div class="pagination-wrapper"><el-paginationv-model:current-page="currentPage":page-size="pageSize":total="total"layout="prev, pager, next, jumper, total"@current-change="handlePageChange"/></div></div>
</template><script>
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { Star } from '@element-plus/icons-vue'
import api from '@/api'export default {name: 'CommodityList',components: { Star },setup() {const router = useRouter()const products = ref([])const categories = ref([])const loading = ref(false)const currentPage = ref(1)const pageSize = ref(12)const total = ref(0)const addingToCart = reactive({})const filters = reactive({category: '',ordering: '',search: ''})// 加载商品列表const loadProducts = async () => {loading.value = truetry {const params = {page: currentPage.value,page_size: pageSize.value,...filters}const { data } = await api.get('/commodity/goods/', { params })products.value = data.resultstotal.value = data.count} catch (error) {ElMessage.error('加载商品失败')} finally {loading.value = false}}// 加载分类const loadCategories = async () => {try {const { data } = await api.get('/commodity/categories/')categories.value = data.results} catch (error) {console.error('加载分类失败:', error)}}// 添加到购物车const addToCart = async (product) => {addingToCart[product.id] = truetry {await api.post('/trade/shopping-carts/', {goods: product.id,nums: 1})ElMessage.success('已添加到购物车')} catch (error) {ElMessage.error('添加失败,请先登录')} finally {addingToCart[product.id] = false}}// 切换收藏const toggleFavorite = async (product) => {try {if (product.is_favorited) {await api.delete(`/customer-operation/user-favs/${product.fav_id}/`)product.is_favorited = falseElMessage.success('已取消收藏')} else {const { data } = await api.post('/customer-operation/user-favs/', {goods: product.id})product.is_favorited = trueproduct.fav_id = data.idElMessage.success('已添加收藏')}} catch (error) {ElMessage.error('操作失败,请先登录')}}// 跳转到详情页const goToDetail = (productId) => {router.push(`/commodity/detail/${productId}`)}// 获取图片URLconst getImageUrl = (imagePath) => {if (!imagePath) return '/img/default-product.png'return imagePath.startsWith('http') ? imagePath : `${api.defaults.baseURL}${imagePath}`}// 分页处理const handlePageChange = (page) => {currentPage.value = pageloadProducts()}onMounted(() => {loadCategories()loadProducts()})return {products,categories,loading,currentPage,pageSize,total,filters,addingToCart,loadProducts,addToCart,toggleFavorite,goToDetail,getImageUrl,handlePageChange}}
}
</script><style scoped>
.commodity-list {padding: 20px;max-width: 1200px;margin: 0 auto;
}.filter-bar {margin-bottom: 30px;padding: 20px;background: white;border-radius: 8px;box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}.products-grid {display: grid;grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));gap: 20px;margin-bottom: 30px;
}.product-card {background: white;border-radius: 12px;overflow: hidden;box-shadow: 0 4px 12px rgba(0,0,0,0.1);transition: transform 0.3s ease, box-shadow 0.3s ease;cursor: pointer;
}.product-card:hover {transform: translateY(-5px);box-shadow: 0 8px 25px rgba(0,0,0,0.15);
}.product-image {position: relative;height: 200px;overflow: hidden;
}.product-image img {width: 100%;height: 100%;object-fit: cover;
}.product-badges {position: absolute;top: 10px;left: 10px;
}.badge {display: inline-block;padding: 4px 8px;border-radius: 12px;font-size: 12px;color: white;margin-right: 5px;
}.badge.new {background: #67c23a;
}.badge.hot {background: #f56c6c;
}.product-info {padding: 15px;
}.product-name {font-size: 16px;font-weight: 600;margin: 0 0 8px 0;color: #303133;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
}.product-brief {font-size: 14px;color: #909399;margin: 0 0 12px 0;height: 40px;overflow: hidden;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;
}.product-price {margin-bottom: 10px;
}.current-price {font-size: 18px;font-weight: 600;color: #f56c6c;
}.original-price {font-size: 14px;color: #909399;text-decoration: line-through;margin-left: 8px;
}.product-stats {font-size: 12px;color: #909399;margin-bottom: 15px;
}.product-stats span {margin-right: 15px;
}.product-actions {display: flex;justify-content: space-between;align-items: center;
}.is-favorited {color: #f56c6c;
}.pagination-wrapper {display: flex;justify-content: center;margin-top: 30px;
}
</style>

3. 购物车与订单系统

购物车状态管理
// store/modules/cart.js
import api from '@/api'const state = {items: [],total: 0,loading: false
}const mutations = {SET_CART_ITEMS(state, items) {state.items = itemsstate.total = items.reduce((sum, item) => sum + (item.goods.shop_price * item.nums), 0)},UPDATE_ITEM_QUANTITY(state, { itemId, quantity }) {const item = state.items.find(item => item.id === itemId)if (item) {item.nums = quantitystate.total = state.items.reduce((sum, item) => sum + (item.goods.shop_price * item.nums), 0)}},REMOVE_ITEM(state, itemId) {state.items = state.items.filter(item => item.id !== itemId)state.total = state.items.reduce((sum, item) => sum + (item.goods.shop_price * item.nums), 0)},SET_LOADING(state, loading) {state.loading = loading}
}const actions = {// 获取购物车async fetchCart({ commit }) {commit('SET_LOADING', true)try {const { data } = await api.get('/trade/shopping-carts/')commit('SET_CART_ITEMS', data.results)} catch (error) {console.error('获取购物车失败:', error)} finally {commit('SET_LOADING', false)}},// 添加到购物车async addToCart({ dispatch }, { goodsId, quantity = 1 }) {try {await api.post('/trade/shopping-carts/', {goods: goodsId,nums: quantity})await dispatch('fetchCart')return true} catch (error) {throw error}},// 更新数量async updateQuantity({ commit }, { itemId, quantity }) {try {await api.patch(`/trade/shopping-carts/${itemId}/`, {nums: quantity})commit('UPDATE_ITEM_QUANTITY', { itemId, quantity })} catch (error) {throw error}},// 删除商品async removeItem({ commit }, itemId) {try {await api.delete(`/trade/shopping-carts/${itemId}/`)commit('REMOVE_ITEM', itemId)} catch (error) {throw error}},// 清空购物车async clearCart({ commit }) {try {await api.delete('/trade/shopping-carts/clear/')commit('SET_CART_ITEMS', [])} catch (error) {throw error}}
}const getters = {cartItemCount: state => state.items.reduce((sum, item) => sum + item.nums, 0),cartTotal: state => state.total,cartItems: state => state.items
}export default {namespaced: true,state,mutations,actions,getters
}

🎨 UI设计系统

设计理念

我们采用了温暖的宠物主题色彩,营造亲切友好的购物氛围:

/* design-system.css */
:root {/* 主色调 - 温暖橙色系 */--primary-color: #ff6b35;--primary-light: #ff8c69;--primary-dark: #e55a2b;/* 辅助色 */--secondary-color: #4ecdc4;--accent-color: #45b7d1;--success-color: #96ceb4;--warning-color: #feca57;--error-color: #ff6b6b;/* 中性色 */--text-primary: #2c3e50;--text-secondary: #7f8c8d;--text-light: #bdc3c7;--background: #f8f9fa;--surface: #ffffff;--border: #e9ecef;/* 阴影 */--shadow-sm: 0 2px 4px rgba(0,0,0,0.1);--shadow-md: 0 4px 12px rgba(0,0,0,0.15);--shadow-lg: 0 8px 25px rgba(0,0,0,0.2);/* 圆角 */--radius-sm: 4px;--radius-md: 8px;--radius-lg: 12px;--radius-xl: 16px;/* 间距 */--spacing-xs: 4px;--spacing-sm: 8px;--spacing-md: 16px;--spacing-lg: 24px;--spacing-xl: 32px;
}/* 通用按钮样式 */
.pet-btn {padding: var(--spacing-sm) var(--spacing-md);border: none;border-radius: var(--radius-md);font-weight: 500;cursor: pointer;transition: all 0.3s ease;display: inline-flex;align-items: center;gap: var(--spacing-xs);
}.pet-btn-primary {background: var(--primary-color);color: white;
}.pet-btn-primary:hover {background: var(--primary-dark);transform: translateY(-2px);box-shadow: var(--shadow-md);
}/* 卡片样式 */
.pet-card {background: var(--surface);border-radius: var(--radius-lg);box-shadow: var(--shadow-sm);overflow: hidden;transition: all 0.3s ease;
}.pet-card:hover {transform: translateY(-4px);box-shadow: var(--shadow-lg);
}/* 玻璃拟态效果 */
.glass-effect {background: rgba(255, 255, 255, 0.25);backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.18);
}/* 渐变背景 */
.gradient-bg {background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
}/* 响应式网格 */
.responsive-grid {display: grid;grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));gap: var(--spacing-lg);
}/* 动画效果 */
@keyframes fadeInUp {from {opacity: 0;transform: translateY(30px);}to {opacity: 1;transform: translateY(0);}
}.fade-in-up {animation: fadeInUp 0.6s ease-out;
}/* 加载动画 */
@keyframes pulse {0%, 100% {opacity: 1;}50% {opacity: 0.5;}
}.loading-pulse {animation: pulse 2s infinite;
}

🔐 安全与认证

JWT认证实现

# authentication.py
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
from django.contrib.auth.models import AnonymousUserclass CustomJWTAuthentication(JWTAuthentication):"""自定义JWT认证"""def authenticate(self, request):header = self.get_header(request)if header is None:return Noneraw_token = self.get_raw_token(header)if raw_token is None:return Nonetry:validated_token = self.get_validated_token(raw_token)user = self.get_user(validated_token)return (user, validated_token)except TokenError:return Nonedef get_user(self, validated_token):"""获取用户信息"""try:user_id = validated_token['user_id']user = User.objects.get(id=user_id)return userexcept User.DoesNotExist:return AnonymousUser()

权限控制

# permissions.py
from rest_framework import permissionsclass IsOwnerOrReadOnly(permissions.BasePermission):"""只有所有者可以编辑"""def has_object_permission(self, request, view, obj):# 读权限对所有人开放if request.method in permissions.SAFE_METHODS:return True# 写权限只给所有者return obj.user == request.userclass IsAuthenticatedOrReadOnlyLimited(permissions.BasePermission):"""未登录用户只能查看有限内容"""def has_permission(self, request, view):if request.method in permissions.SAFE_METHODS:return Truereturn request.user and request.user.is_authenticateddef has_object_permission(self, request, view, obj):if request.method in permissions.SAFE_METHODS:# 未登录用户只能查看部分商品if not request.user.is_authenticated:return hasattr(obj, 'is_preview_allowed') and obj.is_preview_allowedreturn Truereturn request.user and request.user.is_authenticated

📊 性能优化

前端优化策略

  1. 路由懒加载
const routes = [{path: '/',name: 'Home',component: () => import('@/views/Home.vue')},{path: '/ai-expert',name: 'AIPetExpert',component: () => import('@/views/AIPetExpert.vue')}
]
  1. 图片懒加载
<template><img v-lazy="product.image" :alt="product.name"class="product-image"/>
</template>
  1. 组件缓存
<template><keep-alive include="CommodityList,UserCenter"><router-view /></keep-alive>
</template>

后端优化策略

  1. 数据库查询优化
# 使用select_related减少查询次数
def get_queryset(self):return CommodityInfos.objects.select_related('category').prefetch_related('images').filter(is_active=True)
  1. 分页优化
# settings.py
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination','PAGE_SIZE': 12
}
  1. 缓存策略
from django.core.cache import cachedef get_hot_products():cache_key = 'hot_products'products = cache.get(cache_key)if products is None:products = CommodityInfos.objects.filter(is_hot=True).order_by('-sold_num')[:6]cache.set(cache_key, products, 300)  # 缓存5分钟return products

🚀 部署与运维

Docker部署

# Dockerfile
FROM python:3.10-slimWORKDIR /app# 安装系统依赖
RUN apt-get update && apt-get install -y \gcc \default-libmysqlclient-dev \&& rm -rf /var/lib/apt/lists/*# 安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt# 复制项目文件
COPY . .# 收集静态文件
RUN python manage.py collectstatic --noinputEXPOSE 8000CMD ["gunicorn", "pet_shop.wsgi:application", "--bind", "0.0.0.0:8000"]
# docker-compose.yml
version: '3.8'services:db:image: mysql:8.0environment:MYSQL_DATABASE: pet_shopMYSQL_ROOT_PASSWORD: passwordvolumes:- mysql_data:/var/lib/mysqlports:- "3306:3306"backend:build: ./backstage/pet_shopdepends_on:- dbenvironment:- MYSQL_HOST=db- MYSQL_PASSWORD=passwordports:- "8000:8000"frontend:build: ./frontstage/pet_shopports:- "80:80"volumes:mysql_data:

Nginx配置

server {listen 80;server_name your-domain.com;# 前端静态文件location / {root /var/www/pet-shop/dist;try_files $uri $uri/ /index.html;}# 后端APIlocation /api/ {proxy_pass http://127.0.0.1:8000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}# 媒体文件location /media/ {alias /var/www/pet-shop/media/;expires 30d;}# 静态文件location /static/ {alias /var/www/pet-shop/static/;expires 30d;}
}

📈 项目亮点与创新

1. AI集成创新

  • 流式响应:实现了类似ChatGPT的打字机效果
  • 上下文管理:智能截断历史消息,避免token超限
  • 错误容错:网络异常时的优雅降级处理

2. 用户体验优化

  • 响应式设计:完美适配桌面和移动端
  • 加载状态:丰富的loading动画和骨架屏
  • 交互反馈:hover效果、点击反馈、状态提示

3. 技术架构优势

  • 模块化设计:前后端完全分离,便于团队协作
  • 可扩展性:支持水平扩展和微服务改造
  • 安全性:JWT认证 + 权限控制 + 输入验证

4. 开发效率提升

  • 代码复用:组件化开发,提高开发效率
  • API文档:Swagger自动生成,便于前后端协作
  • 环境配置:Docker一键部署,简化运维工作

💡 技术总结

通过这个项目,我深度实践了现代Web开发的最佳实践:

  1. 前后端分离:Vue3 + Django REST API的组合提供了极佳的开发体验
  2. AI集成:学会了如何在Web应用中集成第三方AI服务
  3. 状态管理:Vuex的使用让复杂状态管理变得简单
  4. UI设计:Element Plus + 自定义设计系统打造了现代化界面
  5. 性能优化:从前端路由懒加载到后端数据库查询优化
  6. 部署运维:Docker容器化部署简化了运维工作

这个项目不仅是技术的实践,更是对电商业务流程的深度理解。希望能为同样在学习全栈开发的朋友们提供一些参考和启发。

🔗 相关链接

  • GitHub仓库:https://github.com/Smartloe/PetMarketplaceSystem
  • 在线演示:(待部署)
  • 技术文档:项目README.md
  • API文档:http://localhost:8000/swagger/

如果这个项目对你有帮助,欢迎给个Star⭐️支持一下!

有任何问题或建议,欢迎在评论区交流讨论!

http://www.dtcms.com/a/605965.html

相关文章:

  • 支持向量机(SVM)在脑电情绪识别中的学术解析与研究进展
  • dj网站建设广州有做虚拟货币网站
  • 音视频学习(七十):SVC编码
  • 营销型网站建设 ppt百度竞价广告怎么投放
  • 基于CNN-BiLSTM的室内WiFi指纹定位方法研究
  • Java八股文-01
  • 2025年11月13日 AI快讯
  • 凡科网站建设样品图seo优化关键词是什么意思
  • 力扣3703. 移除K-平衡子字符串
  • 美团龙猫大模型LongCat-Flash总结
  • C语言反编译器 | 探索C语言反编译技术的原理与应用
  • 不用wordpress建站开网站做代发
  • EDI二次开发 - 实现个性化需求的创新
  • 【AI软件开发设计】AutoDS-Free:卖家如何用 AI 搭一套零费用的代发系统?
  • 深圳网站建设服务清单建站哪家好就要用兴田德润
  • LMDeploy Docker部署FP8量化模型的详细指南
  • 网站建设的总体目标温州网站建设风格
  • 几种web鉴权方式对比
  • 网站asp木马删除胖子马wordpress模板:q8免费版
  • Modbus03功能码读取
  • 2025.11.12 力扣每日一题
  • wordpress 架站 电子书石家庄网站推广
  • 有没有哪个网站可以做LCM模组阜宁县住房与城乡建设局网站
  • 天硕SSD自主主控技术解析:如何实现工业级宽温域下的高可靠存储
  • 牛客周赛round117--------题解1
  • 锂电池 SOC 估计技术综述:成熟算法、新颖突破与车企应用实践
  • 玄机-第八章 内存马分析-java01-nacos
  • 教育平台oss做视频网站网站横幅怎么更换
  • C语言程序编译器 | 提升C语言编程效率的工具与技巧
  • 网站建设 类型泰州seo