Python项目-校园二手物品交易平台的设计与实现(2)

源代码续:

{% extends 'base.html' %}

{% block title %}购买商品 | {{ super() }}{% endblock %}

{% block styles %}
{{ super() }}
<style>
    .item-summary {
        display: flex;
        margin-bottom: 20px;
        padding: 15px;
        border: 1px solid #dee2e6;
        border-radius: 8px;
        background-color: #f8f9fa;
    }
    .item-image {
        width: 100px;
        height: 100px;
        object-fit: cover;
        border-radius: 4px;
        margin-right: 15px;
    }
    .item-details {
        flex-grow: 1;
    }
    .item-price {
        font-size: 1.5rem;
        font-weight: bold;
        color: #ff4136;
    }
    .order-section {
        margin-top: 30px;
    }
    .order-total {
        font-size: 1.2rem;
        font-weight: bold;
        margin-top: 20px;
        padding-top: 20px;
        border-top: 1px solid #dee2e6;
    }
</style>
{% endblock %}

{% block content %}
<div class="container my-5">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <h1 class="mb-4">确认订单</h1>
            
            <!-- 商品摘要 -->
            <div class="item-summary">
                <img src="{{ item.get_main_image_url() }}" class="item-image" alt="{{ item.title }}">
                <div class="item-details">
                    <h5>{{ item.title }}</h5>
                    <p class="text-muted mb-1">卖家:{{ item.seller.username }}</p>
                    <p class="text-muted mb-1">
                        状况:{{ {'brand_new': '全新', 'like_new': '几乎全新', 'slightly_used': '轻微使用痕迹', 'used': '使用过', 'heavily_used': '重度使用'}[item.condition] }}
                    </p>
                    <p class="item-price mb-0">¥{{ "%.2f"|format(item.price) }}</p>
                </div>
            </div>
            
            <!-- 订单表单 -->
            <div class="card shadow">
                <div class="card-header bg-primary text-white">
                    <h4 class="mb-0">订单信息</h4>
                </div>
                <div class="card-body">
                    <form method="post">
                        {{ form.hidden_tag() }}
                        
                        <div class="mb-3">
                            <label class="form-label">交易地点</label>
                            <p class="form-control-plaintext">{{ item.location }}</p>
                        </div>
                        
                        <div class="mb-3">
                            {{ form.message.label(class="form-label") }}
                            {{ form.message(class="form-control", rows=3) }}
                            {% if form.message.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.message.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                            <div class="form-text">可以给卖家留言,如:具体交易时间、地点等</div>
                        </div>
                        
                        <div class="order-total d-flex justify-content-between">
                            <span>订单总价:</span>
                            <span class="item-price">¥{{ "%.2f"|format(item.price) }}</span>
                        </div>
                        
                        <div class="alert alert-info mt-3">
                            <h5 class="alert-heading"><i class="bi bi-info-circle"></i> 交易提示</h5>
                            <ul class="mb-0">
                                <li>请在校园内公共场所进行交易,确保安全</li>
                                <li>交易前请仔细检查商品</li>
                                <li>确认收到商品并满意后再确认完成交易</li>
                                <li>如有问题请及时联系卖家或平台客服</li>
                            </ul>
                        </div>
                        
                        <div class="d-grid gap-2 mt-4">
                            {{ form.submit(class="btn btn-primary btn-lg") }}
                            <a href="{{ url_for('item.detail', item_id=item.id) }}" class="btn btn-outline-secondary">取消</a>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

app\templates\item\category.html

{% extends 'base.html' %}

{% block title %}{{ category.name }} | {{ super() }}{% endblock %}

{% block styles %}
{{ super() }}
<style>
    .category-header {
        background-color: #f8f9fa;
        padding: 30px 0;
        margin-bottom: 30px;
        border-radius: 8px;
    }
    .category-icon {
        font-size: 2.5rem;
        margin-bottom: 15px;
        color: #0d6efd;
    }
    .item-card {
        transition: transform 0.3s, box-shadow 0.3s;
        height: 100%;
    }
    .item-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.1);
    }
    .item-image {
        height: 200px;
        object-fit: cover;
    }
    .item-price {
        font-size: 1.2rem;
        font-weight: bold;
        color: #ff4136;
    }
    .item-original-price {
        text-decoration: line-through;
        color: #adb5bd;
        font-size: 0.9rem;
    }
    .discount-badge {
        position: absolute;
        top: 10px;
        right: 10px;
        background-color: #ff4136;
        color: white;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 0.8rem;
    }
    .new-badge {
        position: absolute;
        top: 10px;
        left: 10px;
        background-color: #28a745;
        color: white;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 0.8rem;
    }
    .pagination {
        justify-content: center;
        margin-top: 2rem;
    }
    .no-results {
        text-align: center;
        padding: 3rem 0;
    }
    .condition-badge {
        font-size: 0.8rem;
        margin-right: 5px;
    }
    .sort-options {
        margin-bottom: 20px;
    }
</style>
{% endblock %}

{% block content %}
<div class="container my-5">
    <!-- 分类头部 -->
    <div class="category-header text-center">
        <div class="category-icon">
            <i class="bi {{ category.icon or 'bi-tag' }}"></i>
        </div>
        <h1 class="mb-2">{{ category.name }}</h1>
        <p class="text-muted">{{ category.description or '浏览该分类下的所有商品' }}</p>
    </div>
    
    <!-- 排序选项 -->
    <div class="d-flex justify-content-between align-items-center sort-options">
        <p class="mb-0">共 <strong>{{ pagination.total }}</strong> 个商品</p>
        <div class="btn-group">
            <a href="{{ url_for('item.category', category_id=category.id, sort='newest') }}" class="btn btn-outline-secondary {{ 'active' if request.args.get('sort') == 'newest' or not request.args.get('sort') }}">最新发布</a>
            <a href="{{ url_for('item.category', category_id=category.id, sort='price_asc') }}" class="btn btn-outline-secondary {{ 'active' if request.args.get('sort') == 'price_asc' }}">价格从低到高</a>
            <a href="{{ url_for('item.category', category_id=category.id, sort='price_desc') }}" class="btn btn-outline-secondary {{ 'active' if request.args.get('sort') == 'price_desc' }}">价格从高到低</a>
            <a href="{{ url_for('item.category', category_id=category.id, sort='popular') }}" class="btn btn-outline-secondary {{ 'active' if request.args.get('sort') == 'popular' }}">最受欢迎</a>
        </div>
    </div>
    
    <!-- 商品列表 -->
    {% if items %}
    <div class="row">
        {% for item in items %}
        <div class="col-md-3 mb-4">
            <div class="card item-card">
                <div class="position-relative">
                    {% if item.discount_percentage > 0 %}
                    <span class="discount-badge">{{ item.discount_percentage }}% OFF</span>
                    {% endif %}
                    
                    {% if item.is_new %}
                    <span class="new-badge">新上架</span>
                    {% endif %}
                    
                    <img src="{{ item.get_main_image_url() }}" class="card-img-top item-image" alt="{{ item.title }}">
                </div>
                
                <div class="card-body">
                    <h5 class="card-title text-truncate">{{ item.title }}</h5>
                    
                    <div class="mb-2">
                        <span class="badge bg-secondary condition-badge">
                            {{ {'brand_new': '全新', 'like_new': '几乎全新', 'slightly_used': '轻微使用痕迹', 'used': '使用过', 'heavily_used': '重度使用'}[item.condition] }}
                        </span>
                        <small class="text-muted">{{ item.location }}</small>
                    </div>
                    
                    <div class="d-flex justify-content-between align-items-center">
                        <div>
                            <span class="item-price">¥{{ "%.2f"|format(item.price) }}</span>
                            {% if item.original_price and item.original_price > item.price %}
                            <span class="item-original-price">¥{{ "%.2f"|format(item.original_price) }}</span>
                            {% endif %}
                        </div>
                        <small class="text-muted">{{ item.created_at.strftime('%m-%d') }}</small>
                    </div>
                </div>
                
                <div class="card-footer bg-white border-top-0">
                    <div class="d-flex justify-content-between align-items-center">
                        <small class="text-muted">
                            <i class="bi bi-eye"></i> {{ item.views }}
                        </small>
                        <small class="text-muted">
                            {{ item.seller.username }}
                        </small>
                    </div>
                </div>
                
                <a href="{{ url_for('item.detail', item_id=item.id) }}" class="stretched-link"></a>
            </div>
        </div>
        {% endfor %}
    </div>
    
    <!-- 分页 -->
    {% if pagination.pages > 1 %}
    <nav aria-label="Page navigation">
        <ul class="pagination">
            {% if pagination.has_prev %}
            <li class="page-item">
                <a class="page-link" href="{{ url_for('item.category', category_id=category.id, page=pagination.prev_num, sort=request.args.get('sort', 'newest')) }}" aria-label="Previous">
                    <span aria-hidden="true">&laquo;</span>
                </a>
            </li>
            {% else %}
            <li class="page-item disabled">
                <a class="page-link" href="#" aria-label="Previous">
                    <span aria-hidden="true">&laquo;</span>
                </a>
            </li>
            {% endif %}
            
            {% for page in pagination.iter_pages(left_edge=2, left_current=2, right_current=3, right_edge=2) %}
                {% if page %}
                    {% if page == pagination.page %}
                    <li class="page-item active">
                        <a class="page-link" href="#">{{ page }}</a>
                    </li>
                    {% else %}
                    <li class="page-item">
                        <a class="page-link" href="{{ url_for('item.category', category_id=category.id, page=page, sort=request.args.get('sort', 'newest')) }}">{{ page }}</a>
                    </li>
                    {% endif %}
                {% else %}
                    <li class="page-item disabled">
                        <a class="page-link" href="#">...</a>
                    </li>
                {% endif %}
            {% endfor %}
            
            {% if pagination.has_next %}
            <li class="page-item">
                <a class="page-link" href="{{ url_for('item.category', category_id=category.id, page=pagination.next_num, sort=request.args.get('sort', 'newest')) }}" aria-label="Next">
                    <span aria-hidden="true">&raquo;</span>
                </a>
            </li>
            {% else %}
            <li class="page-item disabled">
                <a class="page-link" href="#" aria-label="Next">
                    <span aria-hidden="true">&raquo;</span>
                </a>
            </li>
            {% endif %}
        </ul>
    </nav>
    {% endif %}
    
    {% else %}
    <div class="no-results">
        <img src="{{ url_for('static', filename='images/no_results.svg') }}" alt="没有找到商品" style="max-width: 200px; margin-bottom: 20px;">
        <h3>该分类下暂无商品</h3>
        <p class="text-muted">成为第一个在该分类下发布商品的人吧!</p>
        <a href="{{ url_for('item.new_item') }}" class="btn btn-primary mt-3">发布商品</a>
    </div>
    {% endif %}
</div>
{% endblock %}

app\templates\item\detail.html

{% extends 'base.html' %}

{% block title %}{{ item.title }} | {{ super() }}{% endblock %}

{% block styles %}
{{ super() }}
<style>
    .item-image {
        width: 100%;
        height: 400px;
        object-fit: cover;
        border-radius: 8px;
    }
    .thumbnail {
        width: 80px;
        height: 80px;
        object-fit: cover;
        cursor: pointer;
        border: 2px solid transparent;
        border-radius: 4px;
        margin-right: 10px;
    }
    .thumbnail.active {
        border-color: #0d6efd;
    }
    .price-tag {
        font-size: 1.8rem;
        color: #ff4136;
        font-weight: bold;
    }
    .original-price {
        text-decoration: line-through;
        color: #adb5bd;
        font-size: 1.2rem;
    }
    .discount-badge {
        background-color: #ff4136;
        color: white;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 0.9rem;
        margin-left: 10px;
    }
    .seller-info {
        display: flex;
        align-items: center;
        margin-bottom: 20px;
    }
    .seller-avatar {
        width: 50px;
        height: 50px;
        border-radius: 50%;
        object-fit: cover;
        margin-right: 15px;
    }
    .item-stats {
        display: flex;
        gap: 15px;
        color: #6c757d;
        margin-bottom: 20px;
    }
    .similar-item {
        transition: transform 0.3s;
    }
    .similar-item:hover {
        transform: translateY(-5px);
    }
</style>
{% endblock %}

{% block content %}
<div class="container my-5">
    <nav aria-label="breadcrumb">
        <ol class="breadcrumb">
            <li class="breadcrumb-item"><a href="{{ url_for('main.index') }}">首页</a></li>
            <li class="breadcrumb-item"><a href="{{ url_for('item.category', category_id=item.category.id) }}">{{ item.category.name }}</a></li>
            <li class="breadcrumb-item active" aria-current="page">{{ item.title }}</li>
        </ol>
    </nav>

    <div class="row">
        <!-- 商品图片 -->
        <div class="col-md-6 mb-4">
            <div class="position-relative">
                {% if item.is_sold %}
                <div class="position-absolute top-50 start-50 translate-middle bg-dark bg-opacity-50 text-white p-3 rounded" style="z-index: 10; font-size: 2rem;">
                    已售出
                </div>
                {% elif not item.is_active %}
                <div class="position-absolute top-50 start-50 translate-middle bg-dark bg-opacity-50 text-white p-3 rounded" style="z-index: 10; font-size: 2rem;">
                    已下架
                </div>
                {% endif %}
                
                {% if item.image_list %}
                <img id="main-image" src="{{ url_for('static', filename='uploads/items/' + item.image_list[0]) }}" class="item-image" alt="{{ item.title }}">
                {% else %}
                <img src="{{ url_for('static', filename='images/default_item.jpg') }}" class="item-image" alt="{{ item.title }}">
                {% endif %}
            </div>
            
            {% if item.image_list and item.image_list|length > 1 %}
            <div class="d-flex mt-3 overflow-auto">
                {% for image in item.image_list %}
                <img src="{{ url_for('static', filename='uploads/items/' + image) }}" 
                     class="thumbnail {% if loop.first %}active{% endif %}" 
                     alt="缩略图 {{ loop.index }}"
                     onclick="changeMainImage('{{ url_for('static', filename='uploads/items/' + image) }}', this)">
                {% endfor %}
            </div>
            {% endif %}
        </div>
        
        <!-- 商品信息 -->
        <div class="col-md-6">
            <h1 class="mb-3">{{ item.title }}</h1>
            
            <div class="item-stats">
                <span><i class="bi bi-eye"></i> {{ item.views }} 浏览</span>
                <span><i class="bi bi-calendar3"></i> {{ item.created_at.strftime('%Y-%m-%d') }}</span>
                <span><i class="bi bi-geo-alt"></i> {{ item.location }}</span>
            </div>
            
            <div class="mb-4">
                <span class="price-tag">¥{{ "%.2f"|format(item.price) }}</span>
                {% if item.original_price and item.original_price > item.price %}
                <span class="original-price ms-2">¥{{ "%.2f"|format(item.original_price) }}</span>
                <span class="discount-badge">{{ item.discount_percentage }}% OFF</span>
                {% endif %}
            </div>
            
            <div class="mb-4">
                <span class="badge bg-secondary">{{ {'brand_new': '全新', 'like_new': '几乎全新', 'slightly_used': '轻微使用痕迹', 'used': '使用过', 'heavily_used': '重度使用'}[item.condition] }}</span>
                {% if item.is_new %}
                <span class="badge bg-success ms-2">新上架</span>
                {% endif %}
            </div>
            
            <div class="seller-info">
                <img src="{{ url_for('static', filename='uploads/avatars/' + item.seller.avatar) if item.seller.avatar else url_for('static', filename='images/default_avatar.jpg') }}" 
                     alt="{{ item.seller.username }}" 
                     class="seller-avatar">
                <div>
                    <h5 class="mb-0">{{ item.seller.username }}</h5>
                    <small class="text-muted">{{ item.seller.dormitory or '未填写宿舍信息' }}</small>
                </div>
            </div>
            
            <div class="d-grid gap-2 mb-4">
                {% if current_user.is_authenticated and not item.is_sold and item.is_active and current_user.id != item.seller_id %}
                <a href="{{ url_for('item.buy', item_id=item.id) }}" class="btn btn-primary btn-lg">立即购买</a>
                {% endif %}
                
                {% if current_user.is_authenticated %}
                <button id="favorite-btn" class="btn btn-outline-danger" onclick="toggleFavorite()">
                    <i class="bi {% if is_favorite %}bi-heart-fill{% else %}bi-heart{% endif %}"></i>
                    {% if is_favorite %}已收藏{% else %}收藏{% endif %}
                </button>
                {% endif %}
                
                {% if current_user.is_authenticated and current_user.id == item.seller_id %}
                <div class="btn-group">
                    <a href="{{ url_for('item.edit_item', item_id=item.id) }}" class="btn btn-outline-secondary">编辑商品</a>
                    <button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
                        <span class="visually-hidden">Toggle Dropdown</span>
                    </button>
                    <ul class="dropdown-menu">
                        <li>
                            <form action="{{ url_for('item.toggle_status', item_id=item.id) }}" method="post">
                                <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
                                <button type="submit" class="dropdown-item">
                                    {% if item.is_active %}下架商品{% else %}上架商品{% endif %}
                                </button>
                            </form>
                        </li>
                        <li>
                            <button type="button" class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
                                删除商品
                            </button>
                        </li>
                    </ul>
                </div>
                {% endif %}
            </div>
            
            <div class="card mb-4">
                <div class="card-header">
                    <h5 class="mb-0">商品描述</h5>
                </div>
                <div class="card-body">
                    <p class="card-text" style="white-space: pre-line;">{{ item.description }}</p>
                </div>
            </div>
        </div>
    </div>
    
    <!-- 相似商品 -->
    {% if similar_items %}
    <div class="mt-5">
        <h3 class="mb-4">相似商品</h3>
        <div class="row">
            {% for similar_item in similar_items %}
            <div class="col-md-3 mb-4">
                <div class="card h-100 similar-item">
                    <img src="{{ similar_item.get_main_image_url() }}" class="card-img-top" alt="{{ similar_item.title }}" style="height: 200px; object-fit: cover;">
                    <div class="card-body">
                        <h5 class="card-title text-truncate">{{ similar_item.title }}</h5>
                        <p class="card-text text-danger fw-bold">¥{{ "%.2f"|format(similar_item.price) }}</p>
                        <a href="{{ url_for('item.detail', item_id=similar_item.id) }}" class="stretched-link"></a>
                    </div>
                </div>
            </div>
            {% endfor %}
        </div>
    </div>
    {% endif %}
    
    <!-- 卖家其他商品 -->
    {% if seller_other_items %}
    <div class="mt-5">
        <h3 class="mb-4">卖家其他商品</h3>
        <div class="row">
            {% for other_item in seller_other_items %}
            <div class="col-md-3 mb-4">
                <div class="card h-100 similar-item">
                    <img src="{{ other_item.get_main_image_url() }}" class="card-img-top" alt="{{ other_item.title }}" style="height: 200px; object-fit: cover;">
                    <div class="card-body">
                        <h5 class="card-title text-truncate">{{ other_item.title }}</h5>
                        <p class="card-text text-danger fw-bold">¥{{ "%.2f"|format(other_item.price) }}</p>
                        <a href="{{ url_for('item.detail', item_id=other_item.id) }}" class="stretched-link"></a>
                    </div>
                </div>
            </div>
            {% endfor %}
        </div>
    </div>
    {% endif %}
</div>

<!-- 删除确认模态框 -->
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="deleteModalLabel">确认删除</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                您确定要删除这个商品吗?此操作不可撤销。
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                <form action="{{ url_for('item.delete_item', item_id=item.id) }}" method="post">
                    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
                    <button type="submit" class="btn btn-danger">确认删除</button>
                </form>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block scripts %}
{{ super() }}
<script>
    function changeMainImage(src, thumbnail) {
        document.getElementById('main-image').src = src;
        
        // 更新缩略图选中状态
        document.querySelectorAll('.thumbnail').forEach(thumb => {
            thumb.classList.remove('active');
        });
        thumbnail.classList.add('active');
    }
    
    function toggleFavorite() {
        fetch('{{ url_for("item.toggle_favorite", item_id=item.id) }}', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-Requested-With': 'XMLHttpRequest',
                'X-CSRFToken': '{{ csrf_token() }}'
            }
        })
        .then(response => response.json())
        .then(data => {
            const favoriteBtn = document.getElementById('favorite-btn');
            const icon = favoriteBtn.querySelector('i');
            
            if (data.is_favorite) {
                icon.classList.remove('bi-heart');
                icon.classList.add('bi-heart-fill');
                favoriteBtn.innerHTML = '<i class="bi bi-heart-fill"></i> 已收藏';
            } else {
                icon.classList.remove('bi-heart-fill');
                icon.classList.add('bi-heart');
                favoriteBtn.innerHTML = '<i class="bi bi-heart"></i> 收藏';
            }
            
            // 显示提示消息
            const toast = new bootstrap.Toast(document.createElement('div'));
            const toastContainer = document.createElement('div');
            toastContainer.className = 'toast-container position-fixed bottom-0 end-0 p-3';
            toastContainer.innerHTML = `
                <div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
                    <div class="toast-header">
                        <strong class="me-auto">提示</strong>
                        <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
                    </div>
                    <div class="toast-body">
                        ${data.message}
                    </div>
                </div>
            `;
            document.body.appendChild(toastContainer);
            const toastEl = toastContainer.querySelector('.toast');
            const toast = new bootstrap.Toast(toastEl);
            toast.show();
            
            // 自动移除toast
            setTimeout(() => {
                toastContainer.remove();
            }, 3000);
        })
        .catch(error => {
            console.error('Error:', error);
        });
    }
</script>
{% endblock %}

app\templates\item\edit.html

{% extends 'base.html' %}

{% block title %}编辑商品 | {{ super() }}{% endblock %}

{% block styles %}
{{ super() }}
<style>
    .image-preview-container {
        display: flex;
        flex-wrap: wrap;
        gap: 10px;
        margin-top: 10px;
    }
    .image-preview {
        width: 150px;
        height: 150px;
        object-fit: cover;
        border-radius: 4px;
        border: 1px solid #dee2e6;
    }
    .existing-image-container {
        position: relative;
        width: 150px;
        margin-bottom: 10px;
    }
    .existing-image {
        width: 150px;
        height: 150px;
        object-fit: cover;
        border-radius: 4px;
        border: 1px solid #dee2e6;
    }
    .delete-image-btn {
        position: absolute;
        top: 5px;
        right: 5px;
        background-color: rgba(255, 0, 0, 0.7);
        color: white;
        border: none;
        border-radius: 50%;
        width: 25px;
        height: 25px;
        font-size: 12px;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
    }
    .form-label.required::after {
        content: " *";
        color: red;
    }
    .price-input {
        position: relative;
    }
    .price-input::before {
        content: "¥";
        position: absolute;
        left: 10px;
        top: 50%;
        transform: translateY(-50%);
        z-index: 10;
    }
    .price-input input {
        padding-left: 25px;
    }
</style>
{% endblock %}

{% block content %}
<div class="container my-5">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card shadow">
                <div class="card-header bg-primary text-white">
                    <h3 class="mb-0">编辑商品</h3>
                </div>
                <div class="card-body">
                    <form method="post" enctype="multipart/form-data">
                        {{ form.hidden_tag() }}
                        
                        <div class="mb-3">
                            {{ form.title.label(class="form-label required") }}
                            {{ form.title(class="form-control") }}
                            {% if form.title.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.title.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                        </div>
                        
                        <div class="row">
                            <div class="col-md-6 mb-3">
                                {{ form.category.label(class="form-label required") }}
                                {{ form.category(class="form-select") }}
                                {% if form.category.errors %}
                                <div class="invalid-feedback d-block">
                                    {% for error in form.category.errors %}
                                    {{ error }}
                                    {% endfor %}
                                </div>
                                {% endif %}
                            </div>
                            
                            <div class="col-md-6 mb-3">
                                {{ form.condition.label(class="form-label required") }}
                                {{ form.condition(class="form-select") }}
                                {% if form.condition.errors %}
                                <div class="invalid-feedback d-block">
                                    {% for error in form.condition.errors %}
                                    {{ error }}
                                    {% endfor %}
                                </div>
                                {% endif %}
                            </div>
                        </div>
                        
                        <div class="row">
                            <div class="col-md-6 mb-3">
                                {{ form.price.label(class="form-label required") }}
                                <div class="price-input">
                                    {{ form.price(class="form-control") }}
                                </div>
                                {% if form.price.errors %}
                                <div class="invalid-feedback d-block">
                                    {% for error in form.price.errors %}
                                    {{ error }}
                                    {% endfor %}
                                </div>
                                {% endif %}
                            </div>
                            
                            <div class="col-md-6 mb-3">
                                {{ form.original_price.label(class="form-label") }}
                                <div class="price-input">
                                    {{ form.original_price(class="form-control") }}
                                </div>
                                {% if form.original_price.errors %}
                                <div class="invalid-feedback d-block">
                                    {% for error in form.original_price.errors %}
                                    {{ error }}
                                    {% endfor %}
                                </div>
                                {% endif %}
                                <div class="form-text">如果有原价,可以显示折扣信息</div>
                            </div>
                        </div>
                        
                        <div class="mb-3">
                            {{ form.location.label(class="form-label required") }}
                            {{ form.location(class="form-control") }}
                            {% if form.location.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.location.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                            <div class="form-text">填写校内交易地点,如:一食堂门口、图书馆等</div>
                        </div>
                        
                        <div class="mb-3">
                            {{ form.description.label(class="form-label required") }}
                            {{ form.description(class="form-control", rows=5) }}
                            {% if form.description.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.description.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                            <div class="form-text">详细描述商品的情况,如品牌、型号、使用时长、瑕疵等</div>
                        </div>
                        
                        <!-- 现有图片展示 -->
                        {% if item.image_list %}
                        <div class="mb-3">
                            <label class="form-label">现有图片</label>
                            <div class="d-flex flex-wrap gap-3">
                                {% for image in item.image_list %}
                                <div class="existing-image-container" id="image-container-{{ loop.index }}">
                                    <img src="{{ url_for('static', filename='uploads/items/' + image) }}" class="existing-image" alt="商品图片 {{ loop.index }}">
                                    <button type="button" class="delete-image-btn" onclick="deleteImage('{{ image }}', {{ loop.index }})">
                                        <i class="bi bi-x"></i>
                                    </button>
                                </div>
                                {% endfor %}
                            </div>
                        </div>
                        {% endif %}
                        
                        <div class="mb-3">
                            {{ form.images.label(class="form-label") }}
                            {{ form.images(class="form-control", id="imageInput", onchange="previewImages(event)") }}
                            {% if form.images.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.images.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                            <div class="form-text">上传新图片,最多总共5张图片</div>
                            
                            <div id="imagePreviewContainer" class="image-preview-container"></div>
                        </div>
                        
                        <div class="d-grid gap-2 mt-4">
                            {{ form.submit(class="btn btn-primary btn-lg", value="保存修改") }}
                            <a href="{{ url_for('item.detail', item_id=item.id) }}" class="btn btn-outline-secondary">取消</a>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block scripts %}
{{ super() }}
<script>
    function previewImages(event) {
        const container = document.getElementById('imagePreviewContainer');
        container.innerHTML = '';
        
        const files = event.target.files;
        const maxFiles = 5;
        const existingImageCount = {{ item.image_list|length }};
        const remainingSlots = maxFiles - existingImageCount;
        const previewCount = Math.min(files.length, remainingSlots);
        
        for (let i = 0; i < previewCount; i++) {
            const file = files[i];
            
            if (!file.type.match('image.*')) {
                continue;
            }
            
            const reader = new FileReader();
            
            reader.onload = function(e) {
                const img = document.createElement('img');
                img.classList.add('image-preview');
                img.src = e.target.result;
                container.appendChild(img);
            }
            
            reader.readAsDataURL(file);
        }
        
        if (files.length > remainingSlots) {
            const message = document.createElement('div');
            message.classList.add('alert', 'alert-warning', 'mt-2');
            message.textContent = `您选择了 ${files.length} 张图片,但只能上传前 ${remainingSlots} 张(总共最多5张)。`;
            container.appendChild(message);
        }
    }
    
    function deleteImage(filename, index) {
        if (confirm('确定要删除这张图片吗?')) {
            fetch(`{{ url_for('item.api_delete_image', item_id=item.id, filename='') }}${filename}`, {
                method: 'DELETE',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRFToken': '{{ csrf_token() }}'
                }
            })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    // 移除图片容器
                    document.getElementById(`image-container-${index}`).remove();
                    
                    // 显示成功消息
                    const toast = new bootstrap.Toast(document.createElement('div'));
                    const toastContainer = document.createElement('div');
                    toastContainer.className = 'toast-container position-fixed bottom-0 end-0 p-3';
                    toastContainer.innerHTML = `
                        <div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
                            <div class="toast-header">
                                <strong class="me-auto">提示</strong>
                                <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
                            </div>
                            <div class="toast-body">
                                图片已成功删除
                            </div>
                        </div>
                    `;
                    document.body.appendChild(toastContainer);
                    const toastEl = toastContainer.querySelector('.toast');
                    const toast = new bootstrap.Toast(toastEl);
                    toast.show();
                    
                    // 自动移除toast
                    setTimeout(() => {
                        toastContainer.remove();
                    }, 3000);
                } else {
                    alert('删除图片失败:' + data.message);
                }
            })
            .catch(error => {
                console.error('Error:', error);
                alert('删除图片时发生错误');
            });
        }
    }
</script>
{% endblock %}

app\templates\item\new.html

{% extends 'base.html' %}

{% block title %}发布商品 | {{ super() }}{% endblock %}

{% block styles %}
{{ super() }}
<style>
    .image-preview-container {
        display: flex;
        flex-wrap: wrap;
        gap: 10px;
        margin-top: 10px;
    }
    .image-preview {
        width: 150px;
        height: 150px;
        object-fit: cover;
        border-radius: 4px;
        border: 1px solid #dee2e6;
    }
    .form-label.required::after {
        content: " *";
        color: red;
    }
    .price-input {
        position: relative;
    }
    .price-input::before {
        content: "¥";
        position: absolute;
        left: 10px;
        top: 50%;
        transform: translateY(-50%);
        z-index: 10;
    }
    .price-input input {
        padding-left: 25px;
    }
</style>
{% endblock %}

{% block content %}
<div class="container my-5">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card shadow">
                <div class="card-header bg-primary text-white">
                    <h3 class="mb-0">发布商品</h3>
                </div>
                <div class="card-body">
                    <form method="post" enctype="multipart/form-data">
                        {{ form.hidden_tag() }}
                        
                        <div class="mb-3">
                            {{ form.title.label(class="form-label required") }}
                            {{ form.title(class="form-control") }}
                            {% if form.title.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.title.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                        </div>
                        
                        <div class="row">
                            <div class="col-md-6 mb-3">
                                {{ form.category.label(class="form-label required") }}
                                {{ form.category(class="form-select") }}
                                {% if form.category.errors %}
                                <div class="invalid-feedback d-block">
                                    {% for error in form.category.errors %}
                                    {{ error }}
                                    {% endfor %}
                                </div>
                                {% endif %}
                            </div>
                            
                            <div class="col-md-6 mb-3">
                                {{ form.condition.label(class="form-label required") }}
                                {{ form.condition(class="form-select") }}
                                {% if form.condition.errors %}
                                <div class="invalid-feedback d-block">
                                    {% for error in form.condition.errors %}
                                    {{ error }}
                                    {% endfor %}
                                </div>
                                {% endif %}
                            </div>
                        </div>
                        
                        <div class="row">
                            <div class="col-md-6 mb-3">
                                {{ form.price.label(class="form-label required") }}
                                <div class="price-input">
                                    {{ form.price(class="form-control") }}
                                </div>
                                {% if form.price.errors %}
                                <div class="invalid-feedback d-block">
                                    {% for error in form.price.errors %}
                                    {{ error }}
                                    {% endfor %}
                                </div>
                                {% endif %}
                            </div>
                            
                            <div class="col-md-6 mb-3">
                                {{ form.original_price.label(class="form-label") }}
                                <div class="price-input">
                                    {{ form.original_price(class="form-control") }}
                                </div>
                                {% if form.original_price.errors %}
                                <div class="invalid-feedback d-block">
                                    {% for error in form.original_price.errors %}
                                    {{ error }}
                                    {% endfor %}
                                </div>
                                {% endif %}
                                <div class="form-text">如果有原价,可以显示折扣信息</div>
                            </div>
                        </div>
                        
                        <div class="mb-3">
                            {{ form.location.label(class="form-label required") }}
                            {{ form.location(class="form-control") }}
                            {% if form.location.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.location.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                            <div class="form-text">填写校内交易地点,如:一食堂门口、图书馆等</div>
                        </div>
                        
                        <div class="mb-3">
                            {{ form.description.label(class="form-label required") }}
                            {{ form.description(class="form-control", rows=5) }}
                            {% if form.description.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.description.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                            <div class="form-text">详细描述商品的情况,如品牌、型号、使用时长、瑕疵等</div>
                        </div>
                        
                        <div class="mb-3">
                            {{ form.images.label(class="form-label") }}
                            {{ form.images(class="form-control", id="imageInput", onchange="previewImages(event)") }}
                            {% if form.images.errors %}
                            <div class="invalid-feedback d-block">
                                {% for error in form.images.errors %}
                                {{ error }}
                                {% endfor %}
                            </div>
                            {% endif %}
                            <div class="form-text">最多上传5张图片,第一张将作为主图</div>
                            
                            <div id="imagePreviewContainer" class="image-preview-container"></div>
                        </div>
                        
                        <div class="d-grid gap-2 mt-4">
                            {{ form.submit(class="btn btn-primary btn-lg") }}
                            <a href="{{ url_for('main.index') }}" class="btn btn-outline-secondary">取消</a>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block scripts %}
{{ super() }}
<script>
    function previewImages(event) {
        const container = document.getElementById('imagePreviewContainer');
        container.innerHTML = '';
        
        const files = event.target.files;
        const maxFiles = 5;
        const previewCount = Math.min(files.length, maxFiles);
        
        for (let i = 0; i < previewCount; i++) {
            const file = files[i];
            
            if (!file.type.match('image.*')) {
                continue;
            }
            
            const reader = new FileReader();
            
            reader.onload = function(e) {
                const img = document.createElement('img');
                img.classList.add('image-preview');
                img.src = e.target.result;
                container.appendChild(img);
            }
            
            reader.readAsDataURL(file);
        }
        
        if (files.length > maxFiles) {
            const message = document.createElement('div');
            message.classList.add('alert', 'alert-warning', 'mt-2');
            message.textContent = `您选择了 ${files.length} 张图片,但只能上传前 ${maxFiles} 张。`;
            container.appendChild(message);
        }
    }
</script>
{% endblock %}

app\templates\item\search.html

{% extends 'base.html' %}

{% block title %}搜索商品 | {{ super() }}{% endblock %}

{% block styles %}
{{ super() }}
<style>
    .filter-card {
        position: sticky;
        top: 20px;
    }
    .item-card {
        transition: transform 0.3s, box-shadow 0.3s;
        height: 100%;
    }
    .item-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.1);
    }
    .item-image {
        height: 200px;
        object-fit: cover;
    }
    .item-price {
        font-size: 1.2rem;
        font-weight: bold;
        color: #ff4136;
    }
    .item-original-price {
        text-decoration: line-through;
        color: #adb5bd;
        font-size: 0.9rem;
    }
    .discount-badge {
        position: absolute;
        top: 10px;
        right: 10px;
        background-color: #ff4136;
        color: white;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 0.8rem;
    }
    .new-badge {
        position: absolute;
        top: 10px;
        left: 10px;
        background-color: #28a745;
        color: white;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 0.8rem;
    }
    .pagination {
        justify-content: center;
        margin-top: 2rem;
    }
    .no-results {
        text-align: center;
        padding: 3rem 0;
    }
    .condition-badge {
        font-size: 0.8rem;
        margin-right: 5px;
    }
</style>
{% endblock %}

{% block content %}
<div class="container my-5">
    <h1 class="mb-4">搜索商品</h1>
    
    <div class="row">
        <!-- 筛选栏 -->
        <div class="col-md-3 mb-4">
            <div class="card filter-card">
                <div class="card-header bg-primary text-white">
                    <h5 class="mb-0">筛选条件</h5>
                </div>
                <div class="card-body">
                    <form method="get" action="{{ url_for('item.search') }}">
                        <div class="mb-3">
                            {{ form.keyword.label(class="form-label") }}
                            {{ form.keyword(class="form-control") }}
                        </div>
                        
                        <div class="mb-3">
                            {{ form.category.label(class="form-label") }}
                            {{ form.category(class="form-select") }}
                        </div>
                        
                        <div class="mb-3">
                            <label class="form-label">价格范围</label>
                            <div class="row">
                                <div class="col-6">
                                    {{ form.min_price(class="form-control", placeholder="最低价") }}
                                </div>
                                <div class="col-6">
                                    {{ form.max_price(class="form-control", placeholder="最高价") }}
                                </div>
                            </div>
                        </div>
                        
                        <div class="mb-3">
                            {{ form.condition.label(class="form-label") }}
                            {{ form.condition(class="form-select") }}
                        </div>
                        
                        <div class="mb-3">
                            {{ form.sort.label(class="form-label") }}
                            {{ form.sort(class="form-select") }}
                        </div>
                        
                        <div class="d-grid">
                            {{ form.submit(class="btn btn-primary") }}
                        </div>
                    </form>
                </div>
            </div>
        </div>
        
        <!-- 商品列表 -->
        <div class="col-md-9">
            {% if items %}
                <div class="d-flex justify-content-between align-items-center mb-4">
                    <p class="mb-0">共找到 <strong>{{ pagination.total }}</strong> 个商品</p>
                    <div class="btn-group">
                        <button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
                            排序方式
                        </button>
                        <ul class="dropdown-menu dropdown-menu-end">
                            <li><a class="dropdown-item {% if form.sort.data == 'newest' %}active{% endif %}" href="{{ url_for('item.search', **request.args|dict_update(sort='newest')) }}">最新发布</a></li>
                            <li><a class="dropdown-item {% if form.sort.data == 'price_asc' %}active{% endif %}" href="{{ url_for('item.search', **request.args|dict_update(sort='price_asc')) }}">价格从低到高</a></li>
                            <li><a class="dropdown-item {% if form.sort.data == 'price_desc' %}active{% endif %}" href="{{ url_for('item.search', **request.args|dict_update(sort='price_desc')) }}">价格从高到低</a></li>
                            <li><a class="dropdown-item {% if form.sort.data == 'popular' %}active{% endif %}" href="{{ url_for('item.search', **request.args|dict_update(sort='popular')) }}">最受欢迎</a></li>
                        </ul>
                    </div>
                </div>
                
                <div class="row">
                    {% for item in items %}
                    <div class="col-md-4 mb-4">
                        <div class="card item-card">
                            <div class="position-relative">
                                {% if item.discount_percentage > 0 %}
                                <span class="discount-badge">{{ item.discount_percentage }}% OFF</span>
                                {% endif %}
                                
                                {% if item.is_new %}
                                <span class="new-badge">新上架</span>
                                {% endif %}
                                
                                <img src="{{ item.get_main_image_url() }}" class="card-img-top item-image" alt="{{ item.title }}">
                            </div>
                            
                            <div class="card-body">
                                <h5 class="card-title text-truncate">{{ item.title }}</h5>
                                
                                <div class="mb-2">
                                    <span class="badge bg-secondary condition-badge">
                                        {{ {'brand_new': '全新', 'like_new': '几乎全新', 'slightly_used': '轻微使用痕迹', 'used': '使用过', 'heavily_used': '重度使用'}[item.condition] }}
                                    </span>
                                    <small class="text-muted">{{ item.location }}</small>
                                </div>
                                
                                <div class="d-flex justify-content-between align-items-center">
                                    <div>
                                        <span class="item-price">¥{{ "%.2f"|format(item.price) }}</span>
                                        {% if item.original_price and item.original_price > item.price %}
                                        <span class="item-original-price">¥{{ "%.2f"|format(item.original_price) }}</span>
                                        {% endif %}
                                    </div>
                                    <small class="text-muted">{{ item.created_at.strftime('%m-%d') }}</small>
                                </div>
                            </div>
                            
                            <div class="card-footer bg-white border-top-0">
                                <div class="d-flex justify-content-between align-items-center">
                                    <small class="text-muted">
                                        <i class="bi bi-eye"></i> {{ item.views }}
                                    </small>
                                    <small class="text-muted">
                                        {{ item.seller.username }}
                                    </small>
                                </div>
                            </div>
                            
                            <a href="{{ url_for('item.detail', item_id=item.id) }}" class="stretched-link"></a>
                        </div>
                    </div>
                    {% endfor %}
                </div>
                
                <!-- 分页 -->
                {% if pagination.pages > 1 %}
                <nav aria-label="Page navigation">
                    <ul class="pagination">
                        {% if pagination.has_prev %}
                        <li class="page-item">
                            <a class="page-link" href="{{ url_for('item.search', **request.args|dict_update(page=pagination.prev_num)) }}" aria-label="Previous">
                                <span aria-hidden="true">&laquo;</span>
                            </a>
                        </li>
                        {% else %}
                        <li class="page-item disabled">
                            <a class="page-link" href="#" aria-label="Previous">
                                <span aria-hidden="true">&laquo;</span>
                            </a>
                        </li>
                        {% endif %}
                        
                        {% for page in pagination.iter_pages(left_edge=2, left_current=2, right_current=3, right_edge=2) %}
                            {% if page %}
                                {% if page == pagination.page %}
                                <li class="page-item active">
                                    <a class="page-link" href="#">{{ page }}</a>
                                </li>
                                {% else %}
                                <li class="page-item">
                                    <a class="page-link" href="{{ url_for('item.search', **request.args|dict_update(page=page)) }}">{{ page }}</a>
                                </li>
                                {% endif %}
                            {% else %}
                                <li class="page-item disabled">
                                    <a class="page-link" href="#">...</a>
                                </li>
                            {% endif %}
                        {% endfor %}
                        
                        {% if pagination.has_next %}
                        <li class="page-item">
                            <a class="page-link" href="{{ url_for('item.search', **request.args|dict_update(page=pagination.next_num)) }}" aria-label="Next">
                                <span aria-hidden="true">&raquo;</span>
                            </a>
                        </li>
                        {% else %}
                        <li class="page-item disabled">
                            <a class="page-link" href="#" aria-label="Next">
                                <span aria-hidden="true">&raquo;</span>
                            </a>
                        </li>
                        {% endif %}
                    </ul>
                </nav>
                {% endif %}
                
            {% else %}
                <div class="no-results">
                    <img src="{{ url_for('static', filename='images/no_results.svg') }}" alt="没有找到商品" style="max-width: 200px; margin-bottom: 20px;">
                    <h3>没有找到符合条件的商品</h3>
                    <p class="text-muted">尝试修改筛选条件或者搜索其他关键词</p>
                    <a href="{{ url_for('main.index') }}" class="btn btn-primary mt-3">返回首页</a>
                </div>
            {% endif %}
        </div>
    </div>
</div>
{% endblock %}

{% block scripts %}
{{ super() }}
<script>
    // 辅助函数,用于更新URL参数
    if (!window.Jinja2) {
        window.Jinja2 = {};
    }
    
    window.Jinja2.dict_update = function(dict, key, value) {
        dict[key] = value;
        return dict;
    };
</script>
{% endblock %}

app\templates\main\about.html

{% extends "base.html" %}

{% block title %}关于我们 - {{ super() }}{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-10">
        <div class="card shadow mb-4">
            <div class="card-header bg-primary text-white">
                <h4 class="mb-0"><i class="fas fa-info-circle me-2"></i>关于我们</h4>
            </div>
            <div class="card-body">
                <div class="text-center mb-4">
                    <img src="{{ url_for('static', filename='images/logo.png') }}" alt="校园二手物品交易平台" class="img-fluid" style="max-width: 200px;">
                    <h2 class="mt-3">校园二手物品交易平台</h2>
                    <p class="lead text-muted">让闲置物品流动起来,创造更多价值</p>
                </div>
                
                <div class="row mb-4">
                    <div class="col-md-6">
                        <h4><i class="fas fa-bullseye text-primary me-2"></i>我们的使命</h4>
                        <p>校园二手物品交易平台致力于为校园内的学生提供一个安全、便捷、高效的二手物品交易环境。我们希望通过这个平台,让闲置物品得到更好的利用,减少资源浪费,同时也帮助学生节省开支。</p>
                    </div>
                    <div class="col-md-6">
                        <h4><i class="fas fa-eye text-primary me-2"></i>我们的愿景</h4>
                        <p>我们希望成为校园内最受欢迎的二手物品交易平台,打造一个绿色、环保、互助的校园生态系统。通过我们的平台,让每一件物品都能找到它的新主人,让每一位学生都能享受到便捷的二手交易体验。</p>
                    </div>
                </div>
                
                <div class="mb-4">
                    <h4><i class="fas fa-history text-primary me-2"></i>平台历史</h4>
                    <p>校园二手物品交易平台创建于2023年,由一群热爱创新的大学生共同开发。我们注意到校园内二手物品交易需求旺盛,但缺乏一个专门的平台,于是决定自主开发这个平台,为校园内的同学们提供服务。</p>
                    <p>经过不断的改进和完善,我们的平台功能日益丰富,用户体验不断提升。目前,我们已经拥有了数千名注册用户,每天有数百件物品在平台上交易。</p>
                </div>
                
                <div class="mb-4">
                    <h4><i class="fas fa-shield-alt text-primary me-2"></i>平台特色</h4>
                    <div class="row mt-3">
                        <div class="col-md-6 mb-3">
                            <div class="card h-100">
                                <div class="card-body">
                                    <h5><i class="fas fa-user-check text-success me-2"></i>校内实名认证</h5>
                                    <p>所有用户必须通过学生身份认证,确保交易双方都是校内学生,提高交易安全性。</p>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6 mb-3">
                            <div class="card h-100">
                                <div class="card-body">
                                    <h5><i class="fas fa-map-marker-alt text-danger me-2"></i>校内面对面交易</h5>
                                    <p>买卖双方在校内面对面交易,方便快捷,避免了物流环节可能带来的问题。</p>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6 mb-3">
                            <div class="card h-100">
                                <div class="card-body">
                                    <h5><i class="fas fa-star text-warning me-2"></i>信用评价系统</h5>
                                    <p>完善的信用评价系统,让用户可以了解交易对象的信用状况,选择更可靠的交易伙伴。</p>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6 mb-3">
                            <div class="card h-100">
                                <div class="card-body">
                                    <h5><i class="fas fa-comments text-info me-2"></i>即时通讯功能</h5>
                                    <p>内置即时通讯功能,方便买卖双方沟通交流,协商交易细节。</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div class="mb-4">
                    <h4><i class="fas fa-users text-primary me-2"></i>团队成员</h4>
                    <div class="row mt-3">
                        <div class="col-md-4 text-center mb-4">
                            <img src="{{ url_for('static', filename='images/team/member1.jpg') }}" alt="团队成员1" class="rounded-circle img-fluid mb-3" style="width: 150px; height: 150px; object-fit: cover;">
                            <h5>张三</h5>
                            <p class="text-muted">项目负责人</p>
                        </div>
                        <div class="col-md-4 text-center mb-4">
                            <img src="{{ url_for('static', filename='images/team/member2.jpg') }}" alt="团队成员2" class="rounded-circle img-fluid mb-3" style="width: 150px; height: 150px; object-fit: cover;">
                            <h5>李四</h5>
                            <p class="text-muted">前端开发</p>
                        </div>
                        <div class="col-md-4 text-center mb-4">
                            <img src="{{ url_for('static', filename='images/team/member3.jpg') }}" alt="团队成员3" class="rounded-circle img-fluid mb-3" style="width: 150px; height: 150px; object-fit: cover;">
                            <h5>王五</h5>
                            <p class="text-muted">后端开发</p>
                        </div>
                    </div>
                </div>
                
                <div>
                    <h4><i class="fas fa-envelope text-primary me-2"></i>联系我们</h4>
                    <p>如果您有任何问题、建议或合作意向,欢迎通过以下方式联系我们:</p>
                    <ul class="list-unstyled">
                        <li><i class="fas fa-envelope-open me-2"></i>电子邮箱:contact@campus-trading.com</li>
                        <li><i class="fas fa-phone me-2"></i>联系电话:123-4567-8901</li>
                        <li><i class="fas fa-map-marker-alt me-2"></i>办公地址:大学生创新创业中心 B栋305室</li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

app\templates\main\help.html

{% extends "base.html" %}

{% block title %}帮助中心 - {{ super() }}{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-10">
        <div class="card shadow mb-4">
            <div class="card-header bg-primary text-white">
                <h4 class="mb-0"><i class="fas fa-question-circle me-2"></i>帮助中心</h4>
            </div>
            <div class="card-body">
                <div class="accordion" id="helpAccordion">
                    <!-- 常见问题 -->
                    <div class="accordion-item">
                        <h2 class="accordion-header" id="headingOne">
                            <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                                <i class="fas fa-question-circle me-2"></i>常见问题
                            </button>
                        </h2>
                        <div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#helpAccordion">
                            <div class="accordion-body">
                                <div class="mb-4">
                                    <h5>1. 如何注册账号?</h5>
                                    <p>点击网站右上角的"注册"按钮,填写相关信息并提交,然后按照邮箱中的验证链接完成注册。</p>
                                </div>
                                
                                <div class="mb-4">
                                    <h5>2. 如何发布商品?</h5>
                                    <p>登录后,点击"发布商品"按钮,填写商品信息,上传图片,设置价格后提交即可。</p>
                                </div>
                                
                                <div class="mb-4">
                                    <h5>3. 如何联系卖家?</h5>
                                    <p>在商品详情页面,点击"联系卖家"按钮,可以发送私信与卖家沟通。</p>
                                </div>
                                
                                <div class="mb-4">
                                    <h5>4. 如何完成交易?</h5>
                                    <p>买卖双方协商好交易细节后,可以选择线下面对面交易,确认无误后,买家在平台上确认交易完成。</p>
                                </div>
                                
                                <div>
                                    <h5>5. 忘记密码怎么办?</h5>
                                    <p>在登录页面点击"忘记密码",输入注册邮箱,按照邮件中的指引重置密码。</p>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <!-- 用户指南 -->
                    <div class="accordion-item">
                        <h2 class="accordion-header" id="headingTwo">
                            <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
                                <i class="fas fa-book me-2"></i>用户指南
                            </button>
                        </h2>
                        <div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#helpAccordion">
                            <div class="accordion-body">
                                <div class="mb-4">
                                    <h5>新用户注册</h5>
                                    <ol>
                                        <li>点击网站右上角的"注册"按钮</li>
                                        <li>填写用户名、邮箱、学号和密码</li>
                                        <li>阅读并同意用户协议</li>
                                        <li>点击"注册"按钮提交</li>
                                        <li>前往邮箱查收验证邮件</li>
                                        <li>点击邮件中的验证链接完成注册</li>
                                    </ol>
                                </div>
                                
                                <div class="mb-4">
                                    <h5>发布商品</h5>
                                    <ol>
                                        <li>登录账号</li>
                                        <li>点击"发布商品"按钮</li>
                                        <li>选择商品分类</li>
                                        <li>填写商品标题、描述、价格等信息</li>
                                        <li>上传商品图片(最多5张)</li>
                                        <li>设置交易地点和时间偏好</li>
                                        <li>点击"发布"按钮提交</li>
                                    </ol>
                                </div>
                                
                                <div>
                                    <h5>购买商品</h5>
                                    <ol>
                                        <li>浏览或搜索商品</li>
                                        <li>查看商品详情</li>
                                        <li>点击"联系卖家"与卖家沟通</li>
                                        <li>协商交易细节(时间、地点等)</li>
                                        <li>线下面对面交易</li>
                                        <li>确认收货后,在平台上点击"确认交易完成"</li>
                                        <li>对卖家进行评价</li>
                                    </ol>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <!-- 安全交易提示 -->
                    <div class="accordion-item">
                        <h2 class="accordion-header" id="headingThree">
                            <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
                                <i class="fas fa-shield-alt me-2"></i>安全交易提示
                            </button>
                        </h2>
                        <div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#helpAccordion">
                            <div class="accordion-body">
                                <div class="alert alert-warning">
                                    <i class="fas fa-exclamation-triangle me-2"></i>请注意:平台不会要求您提供银行卡密码、验证码等敏感信息,请警惕诈骗!
                                </div>
                                
                                <div class="mb-4">
                                    <h5>交易前</h5>
                                    <ul>
                                        <li>查看卖家信用评价和历史交易记录</li>
                                        <li>仔细核对商品信息,必要时要求卖家提供更多图片或视频</li>
                                        <li>与卖家充分沟通,明确商品状况、价格和交易方式</li>
                                        <li>不要轻信过低的价格,谨防虚假信息</li>
                                    </ul>
                                </div>
                                
                                <div class="mb-4">
                                    <h5>交易中</h5>
                                    <ul>
                                        <li>选择安全的公共场所进行交易,如学校食堂、图书馆等</li>
                                        <li>尽量白天交易,避免夜间或偏僻地点</li>
                                        <li>交易前仔细检查商品,确认无误后再付款</li>
                                        <li>保留交易凭证和聊天记录</li>
                                    </ul>
                                </div>
                                
                                <div>
                                    <h5>交易后</h5>
                                    <ul>
                                        <li>及时在平台上确认交易完成</li>
                                        <li>对卖家进行客观、公正的评价</li>
                                        <li>如遇问题,及时联系平台客服处理</li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                    
                    <!-- 联系客服 -->
                    <div class="accordion-item">
                        <h2 class="accordion-header" id="headingFour">
                            <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFour" aria-expanded="false" aria-controls="collapseFour">
                                <i class="fas fa-headset me-2"></i>联系客服
                            </button>
                        </h2>
                        <div id="collapseFour" class="accordion-collapse collapse" aria-labelledby="headingFour" data-bs-parent="#helpAccordion">
                            <div class="accordion-body">
                                <p>如果您在使用过程中遇到任何问题,或者有任何建议和反馈,欢迎通过以下方式联系我们的客服团队:</p>
                                
                                <div class="row mt-4">
                                    <div class="col-md-6 mb-4">
                                        <div class="card h-100">
                                            <div class="card-body text-center">
                                                <i class="fas fa-envelope fa-3x text-primary mb-3"></i>
                                                <h5>电子邮件</h5>
                                                <p>support@campus-trading.com</p>
                                                <p class="text-muted small">工作日回复时间:24小时内</p>
                                            </div>
                                        </div>
                                    </div>
                                    
                                    <div class="col-md-6 mb-4">
                                        <div class="card h-100">
                                            <div class="card-body text-center">
                                                <i class="fas fa-comment-dots fa-3x text-success mb-3"></i>
                                                <h5>在线客服</h5>
                                                <p>工作时间:9:00-21:00</p>
                                                <a href="#" class="btn btn-primary">立即咨询</a>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                
                                <div class="alert alert-info mt-3">
                                    <i class="fas fa-info-circle me-2"></i>提示:联系客服时,请提供您的用户名和问题详情,以便我们更快地为您解决问题。
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

app\templates\main\index.html

{% extends "base.html" %}

{% block title %}首页 - {{ super() }}{% endblock %}

{% block content %}
<!-- 轮播图 -->
<div id="homeCarousel" class="carousel slide mb-4 shadow rounded" data-bs-ride="carousel">
    <div class="carousel-indicators">
        <button type="button" data-bs-target="#homeCarousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
        <button type="button" data-bs-target="#homeCarousel" data-bs-slide-to="1" aria-label="Slide 2"></button>
        <button type="button" data-bs-target="#homeCarousel" data-bs-slide-to="2" aria-label="Slide 3"></button>
    </div>
    <div class="carousel-inner rounded">
        <div class="carousel-item active">
            <img src="{{ url_for('static', filename='images/banner1.jpg') }}" class="d-block w-100" alt="校园二手物品交易平台">
            <div class="carousel-caption d-none d-md-block">
                <h2>校园二手物品交易平台</h2>
                <p>让闲置物品流动起来,创造更多价值</p>
                <a href="#" class="btn btn-primary">立即浏览</a>
            </div>
        </div>
        <div class="carousel-item">
            <img src="{{ url_for('static', filename='images/banner2.jpg') }}" class="d-block w-100" alt="安全可靠">
            <div class="carousel-caption d-none d-md-block">
                <h2>安全可靠的交易环境</h2>
                <p>校内实名认证,安全有保障</p>
                <a href="#" class="btn btn-primary">了解更多</a>
            </div>
        </div>
        <div class="carousel-item">
            <img src="{{ url_for('static', filename='images/banner3.jpg') }}" class="d-block w-100" alt="便捷交易">
            <div class="carousel-caption d-none d-md-block">
                <h2>便捷的校园交易</h2>
                <p>线上沟通,线下交易,方便快捷</p>
                <a href="#" class="btn btn-primary">立即注册</a>
            </div>
        </div>
    </div>
    <button class="carousel-control-prev" type="button" data-bs-target="#homeCarousel" data-bs-slide="prev">
        <span class="carousel-control-prev-icon" aria-hidden="true"></span>
        <span class="visually-hidden">Previous</span>
    </button>
    <button class="carousel-control-next" type="button" data-bs-target="#homeCarousel" data-bs-slide="next">
        <span class="carousel-control-next-icon" aria-hidden="true"></span>
        <span class="visually-hidden">Next</span>
    </button>
</div>

<!-- 搜索栏 -->
<div class="card shadow mb-4">
    <div class="card-body">
        <form class="row g-3" action="{{ url_for('main.search') }}" method="get">
            <div class="col-md-6">
                <div class="input-group">
                    <span class="input-group-text bg-primary text-white"><i class="fas fa-search"></i></span>
                    <input type="text" class="form-control" name="q" placeholder="搜索商品名称、描述或卖家..." aria-label="搜索商品">
                </div>
            </div>
            <div class="col-md-3">
                <select class="form-select" name="category">
                    <option value="">所有分类</option>
                    <option value="books">教材书籍</option>
                    <option value="electronics">电子产品</option>
                    <option value="clothing">服装鞋帽</option>
                    <option value="daily">日常用品</option>
                    <option value="sports">体育用品</option>
                    <option value="others">其他物品</option>
                </select>
            </div>
            <div class="col-md-3">
                <button type="submit" class="btn btn-primary w-100">搜索</button>
            </div>
        </form>
    </div>
</div>

<!-- 分类导航 -->
<div class="row mb-4">
    <div class="col-12">
        <div class="card shadow">
            <div class="card-header bg-primary text-white">
                <h5 class="mb-0"><i class="fas fa-th-large me-2"></i>商品分类</h5>
            </div>
            <div class="card-body">
                <div class="row text-center">
                    <div class="col-4 col-md-2 mb-3">
                        <a href="#" class="text-decoration-none category-link">
                            <div class="category-icon mb-2">
                                <i class="fas fa-book fa-2x text-primary"></i>
                            </div>
                            <div>教材书籍</div>
                        </a>
                    </div>
                    <div class="col-4 col-md-2 mb-3">
                        <a href="#" class="text-decoration-none category-link">
                            <div class="category-icon mb-2">
                                <i class="fas fa-laptop fa-2x text-success"></i>
                            </div>
                            <div>电子产品</div>
                        </a>
                    </div>
                    <div class="col-4 col-md-2 mb-3">
                        <a href="#" class="text-decoration-none category-link">
                            <div class="category-icon mb-2">
                                <i class="fas fa-tshirt fa-2x text-danger"></i>
                            </div>
                            <div>服装鞋帽</div>
                        </a>
                    </div>
                    <div class="col-4 col-md-2 mb-3">
                        <a href="#" class="text-decoration-none category-link">
                            <div class="category-icon mb-2">
                                <i class="fas fa-home fa-2x text-info"></i>
                            </div>
                            <div>日常用品</div>
                        </a>
                    </div>
                    <div class="col-4 col-md-2 mb-3">
                        <a href="#" class="text-decoration-none category-link">
                            <div class="category-icon mb-2">
                                <i class="fas fa-futbol fa-2x text-warning"></i>
                            </div>
                            <div>体育用品</div>
                        </a>
                    </div>
                    <div class="col-4 col-md-2 mb-3">
                        <a href="#" class="text-decoration-none category-link">
                            <div class="category-icon mb-2">
                                <i class="fas fa-ellipsis-h fa-2x text-secondary"></i>
                            </div>
                            <div>其他物品</div>
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- 最新上架 -->
<div class="row mb-4">
    <div class="col-12">
        <div class="card shadow">
            <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
                <h5 class="mb-0"><i class="fas fa-fire me-2"></i>最新上架</h5>
                <a href="#" class="btn btn-sm btn-light">查看更多</a>
            </div>
            <div class="card-body">
                <div class="row">
                    {% if latest_items %}
                        {% for item in latest_items %}
                        <div class="col-md-6 col-lg-3 mb-4">
                            <div class="card h-100 item-card">
                                <div class="position-relative">
                                    <img src="{{ item.get_main_image_url() }}" class="card-img-top item-thumbnail" alt="{{ item.title }}">
                                    {% if item.is_new %}
                                    <span class="position-absolute top-0 start-0 badge bg-success m-2">新品</span>
                                    {% endif %}
                                    <button class="btn btn-sm btn-outline-danger position-absolute top-0 end-0 m-2 favorite-btn" data-item-id="{{ item.id }}">
                                        <i class="far fa-heart"></i>
                                    </button>
                                </div>
                                <div class="card-body">
                                    <h5 class="card-title text-truncate">{{ item.title }}</h5>
                                    <p class="card-text text-danger fw-bold">¥{{ item.price }}</p>
                                    <p class="card-text small text-muted">
                                        <i class="fas fa-user me-1"></i>{{ item.seller.username }}
                                        <i class="fas fa-eye ms-2 me-1"></i>{{ item.views }}
                                    </p>
                                </div>
                                <div class="card-footer bg-white">
                                    <a href="{{ url_for('item.detail', item_id=item.id) }}" class="btn btn-primary w-100">查看详情</a>
                                </div>
                            </div>
                        </div>
                        {% endfor %}
                    {% else %}
                        <div class="col-12 text-center py-5">
                            <i class="fas fa-box-open fa-4x text-muted mb-3"></i>
                            <h5>暂无商品</h5>
                            <p>目前还没有商品上架,请稍后再来查看</p>
                        </div>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
</div>

<!-- 热门商品 -->
<div class="row mb-4">
    <div class="col-12">
        <div class="card shadow">
            <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
                <h5 class="mb-0"><i class="fas fa-star me-2"></i>热门商品</h5>
                <a href="#" class="btn btn-sm btn-light">查看更多</a>
            </div>
            <div class="card-body">
                <div class="row">
                    {% if popular_items %}
                        {% for item in popular_items %}
                        <div class="col-md-6 col-lg-3 mb-4">
                            <div class="card h-100 item-card">
                                <div class="position-relative">
                                    <img src="{{ item.get_main_image_url() }}" class="card-img-top item-thumbnail" alt="{{ item.title }}">
                                    <span class="position-absolute top-0 start-0 badge bg-danger m-2">热门</span>
                                    <button class="btn btn-sm btn-outline-danger position-absolute top-0 end-0 m-2 favorite-btn" data-item-id="{{ item.id }}">
                                        <i class="far fa-heart"></i>
                                    </button>
                                </div>
                                <div class="card-body">
                                    <h5 class="card-title text-truncate">{{ item.title }}</h5>
                                    <p class="card-text text-danger fw-bold">¥{{ item.price }}</p>
                                    <p class="card-text small text-muted">
                                        <i class="fas fa-user me-1"></i>{{ item.seller.username }}
                                        <i class="fas fa-eye ms-2 me-1"></i>{{ item.views }}
                                    </p>
                                </div>
                                <div class="card-footer bg-white">
                                    <a href="{{ url_for('item.detail', item_id=item.id) }}" class="btn btn-primary w-100">查看详情</a>
                                </div>
                            </div>
                        </div>
                        {% endfor %}
                    {% else %}
                        <div class="col-12 text-center py-5">
                            <i class="fas fa-box-open fa-4x text-muted mb-3"></i>
                            <h5>暂无热门商品</h5>
                            <p>目前还没有热门商品,请稍后再来查看</p>
                        </div>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
</div>

<!-- 平台优势 -->
<div class="row mb-4">
    <div class="col-12">
        <div class="card shadow">
            <div class="card-header bg-primary text-white">
                <h5 class="mb-0"><i class="fas fa-thumbs-up me-2"></i>平台优势</h5>
            </div>
            <div class="card-body">
                <div class="row text-center">
                    <div class="col-md-3 mb-4">
                        <div class="p-3">
                            <i class="fas fa-shield-alt fa-3x text-primary mb-3"></i>
                            <h4>安全可靠</h4>
                            <p class="text-muted">校内实名认证,交易更有保障</p>
                        </div>
                    </div>
                    <div class="col-md-3 mb-4">
                        <div class="p-3">
                            <i class="fas fa-hand-holding-usd fa-3x text-success mb-3"></i>
                            <h4>价格实惠</h4>
                            <p class="text-muted">二手商品,物美价廉</p>
                        </div>
                    </div>
                    <div class="col-md-3 mb-4">
                        <div class="p-3">
                            <i class="fas fa-map-marker-alt fa-3x text-danger mb-3"></i>
                            <h4>就近交易</h4>
                            <p class="text-muted">校内面对面交易,方便快捷</p>
                        </div>
                    </div>
                    <div class="col-md-3 mb-4">
                        <div class="p-3">
                            <i class="fas fa-recycle fa-3x text-info mb-3"></i>
                            <h4>环保节约</h4>
                            <p class="text-muted">物尽其用,减少浪费</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block scripts %}
<script>
    document.addEventListener('DOMContentLoaded', function() {
        // 收藏按钮点击事件
        const favoriteBtns = document.querySelectorAll('.favorite-btn');
        favoriteBtns.forEach(btn => {
            btn.addEventListener('click', function(e) {
                e.preventDefault();
                const itemId = this.getAttribute('data-item-id');
                
                // 检查是否已登录
                {% if current_user.is_authenticated %}
                    // 发送收藏请求
                    fetch(`/api/items/${itemId}/favorite`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRFToken': '{{ csrf_token() }}'
                        }
                    })
                    .then(response => response.json())
                    .then(data => {
                        if (data.success) {
                            // 切换图标
                            const icon = this.querySelector('i');
                            if (data.is_favorite) {
                                icon.classList.remove('far');
                                icon.classList.add('fas');
                                this.classList.add('btn-danger');
                                this.classList.remove('btn-outline-danger');
                            } else {
                                icon.classList.remove('fas');
                                icon.classList.add('far');
                                this.classList.remove('btn-danger');
                                this.classList.add('btn-outline-danger');
                            }
                        }
                    });
                {% else %}
                    // 未登录,跳转到登录页面
                    window.location.href = "{{ url_for('auth.login', next=request.path) }}";
                {% endif %}
            });
        });
    });
</script>
{% endblock %}

app\templates\order\detail.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值