图:

前端:

frontend/index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>电脑组装报价指南</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        /* 保持原有样式不变 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            font-size: 13px;
        }
        
        body {
            background-color: #f0f2f5;
            color: #333;
            line-height: 1.4;
            padding: 8px;
        }
        
        .container {
            max-width: 1400px;
            margin: 0 auto;
        }
        
        header {
            padding: 12px 15px;
            background: linear-gradient(135deg, #1e3c72, #2a5298);
            color: white;
            border-radius: 8px;
            margin-bottom: 12px;
            box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
        }
        
        header h1 {
            font-size: 1.5rem;
            margin-bottom: 6px;
            letter-spacing: 0.5px;
        }
        
        header p {
            font-size: 0.85rem;
            opacity: 0.9;
            max-width: 800px;
            margin: 0 auto;
        }
        
        .budget-selector {
            display: flex;
            justify-content: center;
            gap: 8px;
            margin: 12px 0 5px;
            flex-wrap: wrap;
        }
        
        .budget-btn {
            padding: 6px 12px;
            background-color: rgba(255, 255, 255, 0.15);
            border: 1px solid rgba(255, 255, 255, 0.3);
            border-radius: 15px;
            font-weight: 600;
            font-size: 0.8rem;
            color: white;
            cursor: pointer;
            transition: all 0.2s ease;
        }
        
        .budget-btn:hover {
            background-color: rgba(255, 255, 255, 0.25);
        }
        
        .budget-btn.active {
            background-color: #ff7e30;
            border-color: #ff7e30;
        }
        
        .main-content {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-bottom: 15px;
        }
        
        .components-section {
            flex: 1;
            min-width: 350px;
            background-color: white;
            border-radius: 8px;
            padding: 15px;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
        }
        
        /* 左侧组件管理侧边栏 */
        .left-sidebar-toggle {
            position: fixed;
            left: 20px;
            top: 50%;
            transform: translateY(-50%);
            background: linear-gradient(135deg, #28a745, #20c997);
            color: white;
            border: none;
            border-radius: 50%;
            width: 50px;
            height: 50px;
            font-size: 1.2rem;
            cursor: pointer;
            box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
            z-index: 100;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
        }
        
        .left-sidebar-toggle:hover {
            transform: translateY(-50%) scale(1.1);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        }
        
        .left-sidebar {
            position: fixed;
            top: 0;
            left: -450px;
            width: 420px;
            height: 100vh;
            background-color: white;
            box-shadow: 3px 0 15px rgba(0, 0, 0, 0.1);
            transition: left 0.3s ease;
            z-index: 1000;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
        }
        
        .left-sidebar.open {
            left: 0;
        }
        
        .left-sidebar-header {
            background: linear-gradient(135deg, #28a745, #20c997);
            color: white;
            padding: 15px 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .left-sidebar-title {
            font-size: 1.3rem;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .left-sidebar-close {
            background: none;
            border: none;
            color: white;
            font-size: 1.5rem;
            cursor: pointer;
            padding: 5px;
            border-radius: 50%;
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.2s ease;
        }
        
        .left-sidebar-close:hover {
            background-color: rgba(255, 255, 255, 0.2);
        }
        
        .left-sidebar-content {
            flex: 1;
            padding: 20px;
            display: flex;
            flex-direction: column;
            gap: 20px;
        }
        
        .left-sidebar-section {
            background-color: #f9fafc;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
        }
        
        /* 右侧配置侧边栏 */
        .right-sidebar-toggle {
            position: fixed;
            right: 20px;
            top: 50%;
            transform: translateY(-50%);
            background: linear-gradient(135deg, #2a5298, #1e3c72);
            color: white;
            border: none;
            border-radius: 50%;
            width: 50px;
            height: 50px;
            font-size: 1.2rem;
            cursor: pointer;
            box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
            z-index: 100;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
        }
        
        .right-sidebar-toggle:hover {
            transform: translateY(-50%) scale(1.1);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
        }
        
        .right-sidebar {
            position: fixed;
            top: 0;
            right: -450px;
            width: 420px;
            height: 100vh;
            background-color: white;
            box-shadow: -3px 0 15px rgba(0, 0, 0, 0.1);
            transition: right 0.3s ease;
            z-index: 1000;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
        }
        
        .right-sidebar.open {
            right: 0;
        }
        
        .right-sidebar-header {
            background: linear-gradient(135deg, #2a5298, #1e3c72);
            color: white;
            padding: 15px 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .right-sidebar-title {
            font-size: 1.3rem;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .right-sidebar-close {
            background: none;
            border: none;
            color: white;
            font-size: 1.5rem;
            cursor: pointer;
            padding: 5px;
            border-radius: 50%;
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.2s ease;
        }
        
        .right-sidebar-close:hover {
            background-color: rgba(255, 255, 255, 0.2);
        }
        
        .right-sidebar-content {
            flex: 1;
            padding: 20px;
            display: flex;
            flex-direction: column;
            gap: 20px;
        }
        
        .right-sidebar-section {
            background-color: #f9fafc;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
        }
        
        /* 通用侧边栏样式 */
        .sidebar-section {
            background-color: #f9fafc;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
        }
        
        .section-title {
            font-size: 1.1rem;
            color: #2a5298;
            margin-bottom: 15px;
            padding-bottom: 8px;
            border-bottom: 1px solid #eaeaea;
            display: flex;
            align-items: center;
        }
        
        .section-title i {
            margin-right: 8px;
            color: #ff7e30;
            font-size: 0.9rem;
        }
        
        .category {
            margin-bottom: 15px;
        }
        
        .category-title {
            font-size: 0.95rem;
            font-weight: 600;
            color: #444;
            margin-bottom: 8px;
            padding-left: 6px;
            border-left: 3px solid #2a5298;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .component-options {
            display: flex;
            flex-direction: column;
            gap: 6px;
        }
        
        .option {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 8px 10px;
            background-color: white;
            border-radius: 5px;
            border: 1px solid #eaeaea;
            transition: all 0.2s ease;
            cursor: pointer;
        }
        
        .option:hover {
            background-color: #edf2ff;
        }
        
        .option.selected {
            background-color: #e6eeff;
            border-color: #2a5298;
            border-left-width: 3px;
        }
        
        .option-name {
            font-weight: 500;
            color: #333;
            font-size: 0.9rem;
        }
        
        .option-price {
            font-weight: 700;
            color: #ff7e30;
            font-size: 0.9rem;
        }
        
        /* 配置清单样式 */
        .config-list {
            list-style-type: none;
            max-height: 350px;
            overflow-y: auto;
            margin-bottom: 10px;
        }
        
        .config-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 12px;
            margin-bottom: 8px;
            background-color: white;
            border-radius: 5px;
            border: 1px solid #eaeaea;
            border-left: 3px solid #2a5298;
            font-size: 0.9rem;
        }
        
        .config-item-name {
            font-weight: 500;
            flex: 1;
        }
        
        .config-item-price {
            font-weight: 700;
            color: #ff7e30;
            margin-left: 10px;
        }
        
        /* 价格总计样式 */
        .total-price {
            background: linear-gradient(135deg, #2a5298, #1e3c72);
            color: white;
            padding: 20px;
            border-radius: 8px;
            text-align: center;
        }
        
        .total-label {
            font-size: 0.9rem;
            opacity: 0.9;
            margin-bottom: 5px;
        }
        
        .total-amount {
            font-size: 2.5rem;
            font-weight: 800;
            margin: 10px 0;
        }
        
        .price-indicator {
            display: flex;
            justify-content: space-between;
            margin-top: 15px;
            font-size: 0.85rem;
            opacity: 0.9;
        }
        
        .current-budget {
            font-weight: 600;
            color: #ff7e30;
        }
        
        #budget-status {
            font-weight: 500;
        }
        
        /* 建议样式 */
        .recommendations {
            margin-top: 10px;
        }
        
        .recommendation {
            background-color: white;
            padding: 12px 15px;
            border-radius: 5px;
            margin-bottom: 10px;
            border-left: 3px solid #ff7e30;
            font-size: 0.85rem;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
        }
        
        .recommendation h4 {
            color: #2a5298;
            margin-bottom: 5px;
            font-size: 0.9rem;
        }
        
        /* 按钮样式 */
        .buttons {
            display: flex;
            gap: 10px;
            margin-top: 15px;
        }
        
        .btn {
            flex: 1;
            padding: 10px 15px;
            border: none;
            border-radius: 5px;
            font-weight: 600;
            font-size: 0.9rem;
            cursor: pointer;
            transition: all 0.2s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
        }
        
        .btn-primary {
            background-color: #2a5298;
            color: white;
        }
        
        .btn-primary:hover {
            background-color: #1e3c72;
        }
        
        .btn-secondary {
            background-color: #f0f7ff;
            color: #2a5298;
            border: 1px solid #2a5298;
        }
        
        .btn-secondary:hover {
            background-color: #e6eeff;
        }
        
        .btn-success {
            background-color: #28a745;
            color: white;
        }
        
        .btn-success:hover {
            background-color: #218838;
        }
        
        .btn-warning {
            background-color: #ffc107;
            color: #212529;
        }
        
        .btn-warning:hover {
            background-color: #e0a800;
        }
        
        .btn-danger {
            background-color: #dc3545;
            color: white;
        }
        
        .btn-danger:hover {
            background-color: #c82333;
        }
        
        footer {
            text-align: center;
            padding: 12px;
            color: #666;
            font-size: 0.8rem;
            border-top: 1px solid #eee;
            margin-top: 15px;
        }
        
        .empty-config {
            text-align: center;
            color: #888;
            padding: 30px 10px;
            font-size: 0.9rem;
        }
        
        .empty-config i {
            font-size: 2.5rem;
            margin-bottom: 10px;
            color: #d1deff;
        }
        
        /* 组件标签样式 */
        .component-tag {
            display: inline-block;
            background-color: #e6eeff;
            color: #2a5298;
            padding: 2px 8px;
            border-radius: 3px;
            font-size: 0.75rem;
            margin-top: 3px;
            font-weight: 500;
        }
        
        /* 紧凑布局调整 */
        @media (max-width: 1100px) {
            .main-content {
                flex-direction: column;
            }
        }
        
        @media (max-width: 768px) {
            .left-sidebar,
            .right-sidebar {
                width: 100%;
            }
            
            .left-sidebar {
                left: -100%;
            }
            
            .right-sidebar {
                right: -100%;
            }
            
            .left-sidebar.open {
                left: 0;
            }
            
            .right-sidebar.open {
                right: 0;
            }
            
            .left-sidebar-toggle {
                left: 10px;
                width: 40px;
                height: 40px;
                font-size: 1rem;
            }
            
            .right-sidebar-toggle {
                right: 10px;
                width: 40px;
                height: 40px;
                font-size: 1rem;
            }
            
            header h1 {
                font-size: 1.3rem;
            }
            
            .option {
                flex-direction: column;
                align-items: flex-start;
                gap: 3px;
            }
            
            .buttons {
                flex-direction: column;
            }
            
            .budget-selector {
                flex-direction: column;
                align-items: center;
            }
            
            .budget-btn {
                width: 100%;
                max-width: 200px;
            }
        }
        
        /* 滚动条样式 */
        .config-list::-webkit-scrollbar,
        .components-list::-webkit-scrollbar {
            width: 5px;
        }
        
        .config-list::-webkit-scrollbar-track,
        .components-list::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 5px;
        }
        
        .config-list::-webkit-scrollbar-thumb,
        .components-list::-webkit-scrollbar-thumb {
            background: #c1c1c1;
            border-radius: 5px;
        }
        
        .config-list::-webkit-scrollbar-thumb:hover,
        .components-list::-webkit-scrollbar-thumb:hover {
            background: #a8a8a8;
        }
        
        /* 新增:消息提示样式 */
        .message {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 12px 20px;
            border-radius: 5px;
            box-shadow: 0 3px 10px rgba(0,0,0,0.2);
            z-index: 100;
            display: flex;
            align-items: center;
            gap: 10px;
            opacity: 0;
            transform: translateX(100px);
            transition: all 0.3s ease;
        }
        
        .message.show {
            opacity: 1;
            transform: translateX(0);
        }
        
        .message.success {
            background-color: #4CAF50;
            color: white;
        }
        
        .message.error {
            background-color: #f44336;
            color: white;
        }
        
        .message.info {
            background-color: #2196F3;
            color: white;
        }
        
        .message.warning {
            background-color: #ff9800;
            color: white;
        }
        
        /* 组件管理样式 */
        .components-list {
            max-height: 300px;
            overflow-y: auto;
            margin-bottom: 10px;
        }
        
        .component-item-manage {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 12px;
            margin-bottom: 8px;
            background-color: white;
            border-radius: 5px;
            border: 1px solid #eaeaea;
            border-left: 3px solid #28a745;
            font-size: 0.9rem;
        }
        
        .component-item-info {
            flex: 1;
        }
        
        .component-item-title {
            font-weight: 500;
            color: #333;
        }
        
        .component-item-meta {
            font-size: 0.8rem;
            color: #666;
            margin-top: 2px;
        }
        
        .component-item-actions {
            display: flex;
            gap: 5px;
        }
        
        .action-btn {
            padding: 5px 8px;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            font-size: 0.8rem;
            display: flex;
            align-items: center;
            gap: 3px;
            transition: all 0.2s ease;
        }
        
        .action-btn.load {
            background-color: #e6eeff;
            color: #2a5298;
        }
        
        .action-btn.load:hover {
            background-color: #d1deff;
        }
        
        .action-btn.edit {
            background-color: #fff3cd;
            color: #856404;
        }
        
        .action-btn.edit:hover {
            background-color: #ffeaa7;
        }
        
        .action-btn.delete {
            background-color: #f8d7da;
            color: #721c24;
        }
        
        .action-btn.delete:hover {
            background-color: #f1b0b7;
        }
        
        /* 表单样式 */
        .form-group {
            margin-bottom: 15px;
        }
        
        .form-label {
            display: block;
            margin-bottom: 5px;
            font-weight: 500;
            color: #444;
        }
        
        .form-control {
            width: 100%;
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 0.9rem;
            transition: border-color 0.2s ease;
        }
        
        .form-control:focus {
            outline: none;
            border-color: #2a5298;
            box-shadow: 0 0 0 2px rgba(42, 82, 152, 0.1);
        }
        
        .form-row {
            display: flex;
            gap: 10px;
        }
        
        .form-row .form-group {
            flex: 1;
        }
        
        /* 管理按钮样式 */
        .manage-components-btn {
            background-color: #f0f7ff;
            color: #2a5298;
            border: 1px solid #2a5298;
            padding: 6px 12px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 0.8rem;
            font-weight: 500;
            display: flex;
            align-items: center;
            gap: 5px;
            transition: all 0.2s ease;
        }
        
        .manage-components-btn:hover {
            background-color: #e6eeff;
            transform: translateY(-1px);
        }
        
        /* 搜索和筛选样式 */
        .search-box {
            margin-bottom: 15px;
            position: relative;
        }
        
        .search-input {
            width: 100%;
            padding: 8px 12px 8px 35px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 0.9rem;
        }
        
        .search-icon {
            position: absolute;
            left: 10px;
            top: 50%;
            transform: translateY(-50%);
            color: #999;
        }
        
        .filters {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
            flex-wrap: wrap;
        }
        
        .filter-group {
            flex: 1;
            min-width: 150px;
        }
        
        /* 表格样式 */
        .table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 15px;
        }
        
        .table th,
        .table td {
            padding: 8px;
            text-align: left;
            border-bottom: 1px solid #eee;
        }
        
        .table th {
            background-color: #f8f9fa;
            font-weight: 600;
            color: #333;
        }
        
        .table tr:hover {
            background-color: #f5f5f5;
        }
        
        /* 徽章样式 */
        .cart-count {
            position: absolute;
            top: -5px;
            right: -5px;
            background-color: #ff7e30;
            color: white;
            border-radius: 50%;
            width: 20px;
            height: 20px;
            font-size: 0.7rem;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
        }
        
        .components-count {
            position: absolute;
            top: -5px;
            right: -5px;
            background-color: #28a745;
            color: white;
            border-radius: 50%;
            width: 20px;
            height: 20px;
            font-size: 0.7rem;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1><i class="fas fa-desktop"></i> 电脑组装报价指南</h1>
            <p>选择组件自动计算总价,提供配置建议,适合不同预算需求</p>
            
            <div class="budget-selector">
                <div class="budget-btn" data-budget="4000">入门级 (¥4000)</div>
                <div class="budget-btn active" data-budget="6000">主流级 (¥6000)</div>
                <div class="budget-btn" data-budget="8000">高性能 (¥8000)</div>
                <div class="budget-btn" data-budget="12000">发烧级 (¥12000)</div>
            </div>
        </header>
        
        <div class="main-content">
            <section class="components-section">
                <h2 class="section-title">
                    <i class="fas fa-microchip"></i> 组件选择
                </h2>
                
                <div class="category">
                    <h3 class="category-title">CPU 处理器</h3>
                    <div class="component-options" id="cpu-options">
                        <!-- 选项将通过JS动态生成 -->
                    </div>
                </div>
                
                <div class="category">
                    <h3 class="category-title">GPU 显卡</h3>
                    <div class="component-options" id="gpu-options">
                        <!-- 选项将通过JS动态生成 -->
                    </div>
                </div>
                
                <div class="category">
                    <h3 class="category-title">主板</h3>
                    <div class="component-options" id="motherboard-options">
                        <!-- 选项将通过JS动态生成 -->
                    </div>
                </div>
                
                <div class="category">
                    <h3 class="category-title">内存</h3>
                    <div class="component-options" id="ram-options">
                        <!-- 选项将通过JS动态生成 -->
                    </div>
                </div>
                
                <div class="category">
                    <h3 class="category-title">存储</h3>
                    <div class="component-options" id="storage-options">
                        <!-- 选项将通过JS动态生成 -->
                    </div>
                </div>
                
                <div class="category">
                    <h3 class="category-title">电源</h3>
                    <div class="component-options" id="psu-options">
                        <!-- 选项将通过JS动态生成 -->
                    </div>
                </div>
                
                <div class="category">
                    <h3 class="category-title">机箱</h3>
                    <div class="component-options" id="case-options">
                        <!-- 选项将通过JS动态生成 -->
                    </div>
                </div>
            </section>
        </div>
        
        <footer>
            <p>电脑组装报价指南 &copy; 2026 | 价格仅供参考,实际价格可能因市场波动而变化</p>
            <p>左侧按钮:组件管理 | 右侧按钮:配置详情</p>
        </footer>
    </div>

    <!-- 左侧组件管理侧边栏 -->
    <button class="left-sidebar-toggle" id="left-sidebar-toggle">
        <i class="fas fa-cogs"></i>
        <span class="components-count" id="components-count">0</span>
    </button>
    
    <div class="left-sidebar" id="left-sidebar">
        <div class="left-sidebar-header">
            <h2 class="left-sidebar-title">
                <i class="fas fa-cogs"></i> 组件管理
            </h2>
            <button class="left-sidebar-close" id="left-sidebar-close">
                <i class="fas fa-times"></i>
            </button>
        </div>
        
        <div class="left-sidebar-content">
            <!-- 搜索和筛选区域 -->
            <div class="sidebar-section">
                <h3 class="section-title">
                    <i class="fas fa-search"></i> 搜索和筛选
                </h3>
                
                <div class="search-box">
                    <i class="fas fa-search search-icon"></i>
                    <input type="text" class="search-input" id="component-search" placeholder="搜索组件名称...">
                </div>
                
                <div class="filters">
                    <div class="filter-group">
                        <label class="form-label">类别筛选</label>
                        <select class="form-control" id="category-filter">
                            <option value="">所有类别</option>
                            <option value="cpu">CPU</option>
                            <option value="gpu">显卡</option>
                            <option value="motherboard">主板</option>
                            <option value="ram">内存</option>
                            <option value="storage">存储</option>
                            <option value="psu">电源</option>
                            <option value="case">机箱</option>
                        </select>
                    </div>
                    <div class="filter-group">
                        <label class="form-label">价格范围</label>
                        <select class="form-control" id="price-filter">
                            <option value="">所有价格</option>
                            <option value="0-999">¥0-999</option>
                            <option value="1000-1999">¥1000-1999</option>
                            <option value="2000-2999">¥2000-2999</option>
                            <option value="3000+">¥3000+</option>
                        </select>
                    </div>
                </div>
            </div>
            
            <!-- 组件列表区域 -->
            <div class="sidebar-section">
                <h3 class="section-title">
                    <i class="fas fa-list"></i> 所有组件
                    <span style="font-size: 0.8rem; color: #666; margin-left: auto;" id="components-total">共0个</span>
                </h3>
                
                <div class="components-list" id="components-list">
                    <!-- 组件列表将通过JS动态生成 -->
                </div>
            </div>
            
            <!-- 添加组件区域 -->
            <div class="sidebar-section">
                <h3 class="section-title">
                    <i class="fas fa-plus-circle"></i> 添加新组件
                </h3>
                
                <form id="component-form">
                    <div class="form-row">
                        <div class="form-group">
                            <label class="form-label" for="new-component-name">组件名称 *</label>
                            <input type="text" class="form-control" id="new-component-name" required>
                        </div>
                        
                        <div class="form-group">
                            <label class="form-label" for="new-component-category">类别 *</label>
                            <select class="form-control" id="new-component-category" required>
                                <option value="">选择类别</option>
                                <option value="cpu">CPU</option>
                                <option value="gpu">显卡</option>
                                <option value="motherboard">主板</option>
                                <option value="ram">内存</option>
                                <option value="storage">存储</option>
                                <option value="psu">电源</option>
                                <option value="case">机箱</option>
                            </select>
                        </div>
                    </div>
                    
                    <div class="form-row">
                        <div class="form-group">
                            <label class="form-label" for="new-component-price">价格 (¥) *</label>
                            <input type="number" class="form-control" id="new-component-price" min="0" required>
                        </div>
                        
                        <div class="form-group">
                            <label class="form-label" for="new-component-tag">标签</label>
                            <input type="text" class="form-control" id="new-component-tag" placeholder="如:入门、主流、高端">
                        </div>
                    </div>
                    
                    <div class="buttons">
                        <button type="button" class="btn btn-secondary" id="clear-form-btn">
                            <i class="fas fa-eraser"></i> 清空
                        </button>
                        <button type="button" class="btn btn-success" id="add-component-btn">
                            <i class="fas fa-plus"></i> 添加组件
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <!-- 右侧配置侧边栏 -->
    <button class="right-sidebar-toggle" id="right-sidebar-toggle">
        <i class="fas fa-shopping-cart"></i>
        <span class="cart-count" id="cart-count">0</span>
    </button>
    
    <div class="right-sidebar" id="right-sidebar">
        <div class="right-sidebar-header">
            <h2 class="right-sidebar-title">
                <i class="fas fa-desktop"></i> 配置详情
            </h2>
            <button class="right-sidebar-close" id="right-sidebar-close">
                <i class="fas fa-times"></i>
            </button>
        </div>
        
        <div class="right-sidebar-content">
            <!-- 当前配置区域 -->
            <div class="right-sidebar-section">
                <h3 class="section-title">
                    <i class="fas fa-list-alt"></i> 当前配置
                </h3>
                
                <ul class="config-list" id="config-list">
                    <!-- 配置清单将通过JS动态生成 -->
                </ul>
                
                <div class="empty-config" id="empty-config">
                    <i class="fas fa-shopping-cart"></i>
                    <h3>配置清单为空</h3>
                    <p>请从主页面选择组件开始配置</p>
                </div>
                
                <div class="buttons">
                    <button class="btn btn-secondary" id="reset-btn">
                        <i class="fas fa-redo"></i> 重置配置
                    </button>
                    <button class="btn btn-primary" id="save-btn">
                        <i class="fas fa-download"></i> 保存配置
                    </button>
                </div>
            </div>
            
            <!-- 价格总计区域 -->
            <div class="right-sidebar-section">
                <h3 class="section-title">
                    <i class="fas fa-calculator"></i> 价格总计
                </h3>
                
                <div class="total-price">
                    <div class="total-label">总计价格</div>
                    <div class="total-amount" id="total-amount">¥0</div>
                    <div class="price-indicator">
                        <span>预算: <span class="current-budget" id="current-budget">¥6000</span></span>
                        <span id="budget-status">预算范围内</span>
                    </div>
                </div>
                
                <div class="buttons">
                    <button class="btn btn-success" id="share-btn">
                        <i class="fas fa-share-alt"></i> 分享配置
                    </button>
                </div>
            </div>
            
            <!-- 配置建议区域 -->
            <div class="right-sidebar-section">
                <h3 class="section-title">
                    <i class="fas fa-lightbulb"></i> 配置建议
                </h3>
                
                <div class="recommendations">
                    <div class="recommendation" id="cpu-gpu-match">
                        <h4>CPU与显卡匹配</h4>
                        <p>根据CPU和显卡选择,系统将提供优化建议。</p>
                    </div>
                    
                    <div class="recommendation" id="psu-recommendation">
                        <h4>电源建议</h4>
                        <p>请根据配置选择合适的电源功率。</p>
                    </div>
                    
                    <div class="recommendation" id="budget-recommendation">
                        <h4>预算建议</h4>
                        <p>您当前的配置在所选预算范围内。</p>
                    </div>
                </div>
            </div>
            
            <!-- 配置管理区域 -->
            <div class="right-sidebar-section">
                <h3 class="section-title">
                    <i class="fas fa-database"></i> 已保存配置
                </h3>
                
                <div class="configs-list" id="configs-list">
                    <!-- 配置列表将通过JS动态生成 -->
                </div>
                
                <div class="buttons">
                    <button class="btn btn-secondary" id="load-configs-btn">
                        <i class="fas fa-sync"></i> 刷新列表
                    </button>
                </div>
            </div>
        </div>
    </div>

    <!-- 消息提示容器 -->
    <div id="message-container"></div>

    <script>
        // API基础URL
        const API_BASE_URL = 'http://localhost:8000';
        
        // 当前选中的组件
        let selectedComponents = {
            cpu: null,
            gpu: null,
            motherboard: null,
            ram: null,
            storage: null,
            psu: null,
            case: null
        };

        // 当前预算
        let currentBudget = 6000;
        
        // 配置ID(用于分享)
        let currentConfigId = null;
        
        // 所有组件数据
        let allComponents = {};
        
        // 所有已保存配置
        let savedConfigs = [];

        // 初始化页面
        document.addEventListener('DOMContentLoaded', function() {
            // 加载组件数据
            loadComponents();
            
            // 加载已保存配置
            loadSavedConfigs();
            
            // 设置预算选择器
            setupBudgetSelector();
            
            // 设置侧边栏事件
            setupSidebars();
            
            // 设置按钮事件
            setupButtons();
            
            // 设置筛选和搜索事件
            setupFilters();
            
            // 默认加载主流级配置
            loadBudgetPreset(6000);
            
            // 检查URL中是否有分享的配置ID
            checkUrlForSharedConfig();
            
            // 更新徽章数量
            updateBadges();
        });

        // 设置侧边栏
        function setupSidebars() {
            // 左侧侧边栏
            const leftSidebarToggle = document.getElementById('left-sidebar-toggle');
            const leftSidebarClose = document.getElementById('left-sidebar-close');
            const leftSidebar = document.getElementById('left-sidebar');
            
            leftSidebarToggle.addEventListener('click', () => {
                leftSidebar.classList.add('open');
                leftSidebarToggle.style.display = 'none';
            });
            
            leftSidebarClose.addEventListener('click', () => {
                leftSidebar.classList.remove('open');
                leftSidebarToggle.style.display = 'flex';
            });
            
            // 右侧侧边栏
            const rightSidebarToggle = document.getElementById('right-sidebar-toggle');
            const rightSidebarClose = document.getElementById('right-sidebar-close');
            const rightSidebar = document.getElementById('right-sidebar');
            
            rightSidebarToggle.addEventListener('click', () => {
                rightSidebar.classList.add('open');
                rightSidebarToggle.style.display = 'none';
            });
            
            rightSidebarClose.addEventListener('click', () => {
                rightSidebar.classList.remove('open');
                rightSidebarToggle.style.display = 'flex';
            });
            
            // 点击侧边栏外部关闭
            leftSidebar.addEventListener('click', (e) => {
                if (e.target === leftSidebar) {
                    leftSidebar.classList.remove('open');
                    leftSidebarToggle.style.display = 'flex';
                }
            });
            
            rightSidebar.addEventListener('click', (e) => {
                if (e.target === rightSidebar) {
                    rightSidebar.classList.remove('open');
                    rightSidebarToggle.style.display = 'flex';
                }
            });
            
            // ESC键关闭侧边栏
            document.addEventListener('keydown', (e) => {
                if (e.key === 'Escape') {
                    leftSidebar.classList.remove('open');
                    rightSidebar.classList.remove('open');
                    leftSidebarToggle.style.display = 'flex';
                    rightSidebarToggle.style.display = 'flex';
                }
            });
        }

        // 设置按钮事件
        function setupButtons() {
            document.getElementById('reset-btn').addEventListener('click', resetConfiguration);
            document.getElementById('save-btn').addEventListener('click', saveConfiguration);
            document.getElementById('share-btn').addEventListener('click', shareConfiguration);
            document.getElementById('load-configs-btn').addEventListener('click', loadSavedConfigs);
            document.getElementById('clear-form-btn').addEventListener('click', clearComponentForm);
            document.getElementById('add-component-btn').addEventListener('click', addNewComponent);
        }

        // 设置筛选和搜索事件
        function setupFilters() {
            document.getElementById('category-filter').addEventListener('change', filterComponents);
            document.getElementById('price-filter').addEventListener('change', filterComponents);
            document.getElementById('component-search').addEventListener('input', filterComponents);
        }

        // 加载组件数据
        async function loadComponents() {
            try {
                const response = await fetch(`${API_BASE_URL}/api/components`);
                allComponents = await response.json();
                
                // 生成组件选项
                generateComponentOptions(allComponents);
                
                // 更新组件列表
                updateComponentsList();
                
                // 显示成功消息
                showMessage('组件数据加载成功', 'success');
            } catch (error) {
                console.error('加载组件数据失败:', error);
                showMessage('加载组件数据失败,使用本地数据', 'warning');
                
                // 使用本地数据作为后备
                allComponents = getLocalComponents();
                generateComponentOptions(allComponents);
                updateComponentsList();
            }
        }

        // 生成组件选项
        function generateComponentOptions(components) {
            // 清空现有选项
            const containers = document.querySelectorAll('.component-options');
            containers.forEach(container => {
                container.innerHTML = '';
            });
            
            for (const category in components) {
                const container = document.getElementById(`${category}-options`);
                if (!container) continue;
                
                components[category].forEach(component => {
                    const option = document.createElement('div');
                    option.className = 'option';
                    option.dataset.id = component.id;
                    option.dataset.category = component.category;
                    option.innerHTML = `
                        <div>
                            <div class="option-name">${component.name}</div>
                            ${component.tag ? `<div class="component-tag">${component.tag}</div>` : ''}
                        </div>
                        <div class="option-price">¥${component.price}</div>
                    `;
                    option.addEventListener('click', () => selectComponent(component));
                    container.appendChild(option);
                });
            }
        }

        // 选择组件
        function selectComponent(component) {
            const category = component.category;
            selectedComponents[category] = component;
            
            // 更新UI
            updateSelectedUI(category, component.id);
            updateConfigurationList();
            updateTotalPrice();
            updateBadges();
            updateRecommendations();
            
            // 自动打开右侧配置侧边栏
            openRightSidebar();
            
            // 显示选择消息
            showMessage(`已选择 ${component.name}`, 'info');
        }

        // 打开右侧侧边栏
        function openRightSidebar() {
            const rightSidebar = document.getElementById('right-sidebar');
            const rightSidebarToggle = document.getElementById('right-sidebar-toggle');
            
            if (!rightSidebar.classList.contains('open')) {
                rightSidebar.classList.add('open');
                rightSidebarToggle.style.display = 'none';
            }
        }

        // 更新徽章数量
        function updateBadges() {
            // 更新购物车徽章
            const cartCount = document.getElementById('cart-count');
            const selectedCount = Object.values(selectedComponents).filter(comp => comp !== null).length;
            cartCount.textContent = selectedCount;
            cartCount.style.display = selectedCount > 0 ? 'flex' : 'none';
            
            // 更新组件总数徽章
            const componentsCount = document.getElementById('components-count');
            let totalComponents = 0;
            for (const category in allComponents) {
                totalComponents += allComponents[category].length;
            }
            componentsCount.textContent = totalComponents;
            componentsCount.style.display = 'flex';
        }

        // 更新选中UI
        function updateSelectedUI(category, componentId) {
            // 移除该类别所有选项的选中状态
            const options = document.querySelectorAll(`#${category}-options .option`);
            options.forEach(option => {
                option.classList.remove('selected');
            });
            
            // 为选中的选项添加选中状态
            const selectedOption = document.querySelector(`#${category}-options .option[data-id="${componentId}"]`);
            if (selectedOption) {
                selectedOption.classList.add('selected');
            }
        }

        // 更新配置清单
        function updateConfigurationList() {
            const configList = document.getElementById('config-list');
            const emptyConfig = document.getElementById('empty-config');
            
            // 检查是否有选中的组件
            const hasSelectedComponents = Object.values(selectedComponents).some(component => component !== null);
            
            if (!hasSelectedComponents) {
                configList.innerHTML = '';
                emptyConfig.style.display = 'block';
                return;
            }
            
            emptyConfig.style.display = 'none';
            
            // 生成配置清单
            let listHTML = '';
            
            for (const category in selectedComponents) {
                const component = selectedComponents[category];
                if (component) {
                    listHTML += `
                        <li class="config-item">
                            <div class="config-item-name">${getCategoryName(category)}: ${component.name}</div>
                            <div class="config-item-price">¥${component.price}</div>
                        </li>
                    `;
                }
            }
            
            configList.innerHTML = listHTML;
        }

        // 更新总价
        function updateTotalPrice() {
            let totalPrice = 0;
            
            for (const category in selectedComponents) {
                const component = selectedComponents[category];
                if (component) {
                    totalPrice += component.price;
                }
            }
            
            document.getElementById('total-amount').textContent = `¥${totalPrice}`;
            
            // 更新预算状态
            const budgetStatus = document.getElementById('budget-status');
            const diff = totalPrice - currentBudget;
            
            if (diff > 500) {
                budgetStatus.textContent = `超预算 ¥${diff}`;
                budgetStatus.style.color = '#ff6b6b';
            } else if (diff > 0) {
                budgetStatus.textContent = `略超 ¥${diff}`;
                budgetStatus.style.color = '#ffa726';
            } else if (diff > -500) {
                budgetStatus.textContent = `预算范围内`;
                budgetStatus.style.color = '#4caf50';
            } else {
                budgetStatus.textContent = `低于预算 ¥${-diff}`;
                budgetStatus.style.color = '#42a5f5';
            }
        }

        // 更新组件列表
        function updateComponentsList(filtered = false) {
            const componentsList = document.getElementById('components-list');
            const componentsTotal = document.getElementById('components-total');
            
            let listHTML = '';
            let totalCount = 0;
            
            // 如果没有组件数据
            if (Object.keys(allComponents).length === 0) {
                componentsList.innerHTML = `
                    <div class="empty-config">
                        <i class="fas fa-box-open"></i>
                        <h3>暂无组件数据</h3>
                        <p>请添加第一个组件</p>
                    </div>
                `;
                componentsTotal.textContent = '共0个';
                return;
            }
            
            for (const category in allComponents) {
                allComponents[category].forEach(component => {
                    totalCount++;
                    listHTML += `
                        <div class="component-item-manage">
                            <div class="component-item-info">
                                <div class="component-item-title">${component.name}</div>
                                <div class="component-item-meta">
                                    ${getCategoryName(category)} | ¥${component.price} ${component.tag ? `| ${component.tag}` : ''}
                                </div>
                            </div>
                            <div class="component-item-actions">
                                <button class="action-btn edit" onclick="editComponent(${component.id}, '${category}')" title="编辑组件">
                                    <i class="fas fa-edit"></i>
                                </button>
                                <button class="action-btn delete" onclick="deleteComponent(${component.id}, '${category}')" title="删除组件">
                                    <i class="fas fa-trash"></i>
                                </button>
                            </div>
                        </div>
                    `;
                });
            }
            
            componentsList.innerHTML = listHTML;
            componentsTotal.textContent = `共${totalCount}个`;
            
            // 更新徽章
            if (!filtered) {
                updateBadges();
            }
        }

        // 筛选组件
        function filterComponents() {
            const categoryFilter = document.getElementById('category-filter').value;
            const priceFilter = document.getElementById('price-filter').value;
            const searchTerm = document.getElementById('component-search').value.toLowerCase();
            
            const componentsList = document.getElementById('components-list');
            let listHTML = '';
            let totalCount = 0;
            
            for (const category in allComponents) {
                if (categoryFilter && category !== categoryFilter) {
                    continue;
                }
                
                allComponents[category].forEach(component => {
                    // 搜索过滤
                    if (searchTerm && !component.name.toLowerCase().includes(searchTerm)) {
                        return;
                    }
                    
                    // 价格过滤
                    if (priceFilter) {
                        const [min, max] = priceFilter.split('-').map(Number);
                        if (max) {
                            if (component.price < min || component.price > max) return;
                        } else {
                            if (component.price < min) return;
                        }
                    }
                    
                    totalCount++;
                    listHTML += `
                        <div class="component-item-manage">
                            <div class="component-item-info">
                                <div class="component-item-title">${component.name}</div>
                                <div class="component-item-meta">
                                    ${getCategoryName(category)} | ¥${component.price} ${component.tag ? `| ${component.tag}` : ''}
                                </div>
                            </div>
                            <div class="component-item-actions">
                                <button class="action-btn edit" onclick="editComponent(${component.id}, '${category}')" title="编辑组件">
                                    <i class="fas fa-edit"></i>
                                </button>
                                <button class="action-btn delete" onclick="deleteComponent(${component.id}, '${category}')" title="删除组件">
                                    <i class="fas fa-trash"></i>
                                </button>
                            </div>
                        </div>
                    `;
                });
            }
            
            if (totalCount === 0) {
                listHTML = `
                    <div class="empty-config">
                        <i class="fas fa-search"></i>
                        <h3>未找到匹配的组件</h3>
                        <p>请调整搜索条件或添加新组件</p>
                    </div>
                `;
            }
            
            componentsList.innerHTML = listHTML;
            document.getElementById('components-total').textContent = `共${totalCount}个`;
        }

        // 清空组件表单
        function clearComponentForm() {
            document.getElementById('component-form').reset();
            showMessage('表单已清空', 'info');
        }

        // 添加新组件
        async function addNewComponent() {
            const name = document.getElementById('new-component-name').value.trim();
            const category = document.getElementById('new-component-category').value;
            const price = document.getElementById('new-component-price').value;
            const tag = document.getElementById('new-component-tag').value.trim();
            
            if (!name || !category || !price) {
                showMessage('请填写所有必填字段', 'warning');
                return;
            }
            
            // 生成新ID
            let newId = 1;
            for (const cat in allComponents) {
                allComponents[cat].forEach(comp => {
                    if (comp.id >= newId) newId = comp.id + 1;
                });
            }
            
            const newComponent = {
                id: newId,
                name,
                price: parseInt(price),
                category,
                tag: tag || null
            };
            
            try {
                // 注意:这里需要后端API支持添加组件
                // 暂时只在前端添加
                if (!allComponents[category]) {
                    allComponents[category] = [];
                }
                
                allComponents[category].push(newComponent);
                
                // 更新UI
                generateComponentOptions(allComponents);
                updateComponentsList();
                filterComponents();
                clearComponentForm();
                
                showMessage(`组件 "${name}" 添加成功`, 'success');
            } catch (error) {
                console.error('添加组件失败:', error);
                showMessage('添加组件失败', 'error');
            }
        }

        // 编辑组件
        async function editComponent(componentId, category) {
            const component = allComponents[category].find(comp => comp.id === componentId);
            if (!component) return;
            
            // 填充表单
            document.getElementById('new-component-name').value = component.name;
            document.getElementById('new-component-category').value = component.category;
            document.getElementById('new-component-price').value = component.price;
            document.getElementById('new-component-tag').value = component.tag || '';
            
            // 更改添加按钮为更新按钮
            const addBtn = document.getElementById('add-component-btn');
            addBtn.innerHTML = '<i class="fas fa-save"></i> 更新组件';
            addBtn.onclick = function() { updateComponent(componentId, category); };
            
            // 自动打开左侧侧边栏
            const leftSidebar = document.getElementById('left-sidebar');
            const leftSidebarToggle = document.getElementById('left-sidebar-toggle');
            leftSidebar.classList.add('open');
            leftSidebarToggle.style.display = 'none';
            
            showMessage(`正在编辑组件: ${component.name}`, 'info');
        }

        // 更新组件
        async function updateComponent(componentId, oldCategory) {
            const name = document.getElementById('new-component-name').value.trim();
            const category = document.getElementById('new-component-category').value;
            const price = document.getElementById('new-component-price').value;
            const tag = document.getElementById('new-component-tag').value.trim();
            
            if (!name || !category || !price) {
                showMessage('请填写所有必填字段', 'warning');
                return;
            }
            
            try {
                // 从原位置移除
                allComponents[oldCategory] = allComponents[oldCategory].filter(comp => comp.id !== componentId);
                
                // 添加到新位置
                const updatedComponent = {
                    id: componentId,
                    name,
                    price: parseInt(price),
                    category,
                    tag: tag || null
                };
                
                if (!allComponents[category]) {
                    allComponents[category] = [];
                }
                
                allComponents[category].push(updatedComponent);
                
                // 如果组件正在被选中,更新选中状态
                for (const cat in selectedComponents) {
                    if (selectedComponents[cat] && selectedComponents[cat].id === componentId) {
                        selectedComponents[cat] = updatedComponent;
                        updateSelectedUI(cat, componentId);
                    }
                }
                
                // 更新UI
                generateComponentOptions(allComponents);
                updateConfigurationList();
                updateTotalPrice();
                updateComponentsList();
                filterComponents();
                clearComponentForm();
                
                // 恢复添加按钮
                const addBtn = document.getElementById('add-component-btn');
                addBtn.innerHTML = '<i class="fas fa-plus"></i> 添加组件';
                addBtn.onclick = addNewComponent;
                
                showMessage(`组件 "${name}" 更新成功`, 'success');
            } catch (error) {
                console.error('更新组件失败:', error);
                showMessage('更新组件失败', 'error');
            }
        }

        // 删除组件
        async function deleteComponent(componentId, category) {
            const component = allComponents[category].find(comp => comp.id === componentId);
            if (!component) return;
            
            if (!confirm(`确定要删除组件 "${component.name}" 吗?`)) {
                return;
            }
            
            try {
                // 检查组件是否正在被使用
                let isInUse = false;
                for (const cat in selectedComponents) {
                    if (selectedComponents[cat] && selectedComponents[cat].id === componentId) {
                        isInUse = true;
                        break;
                    }
                }
                
                if (isInUse) {
                    showMessage('该组件正在当前配置中使用,请先从配置中移除', 'warning');
                    return;
                }
                
                // 从组件列表中移除
                allComponents[category] = allComponents[category].filter(comp => comp.id !== componentId);
                
                // 更新UI
                generateComponentOptions(allComponents);
                updateComponentsList();
                filterComponents();
                
                showMessage(`组件 "${component.name}" 已删除`, 'success');
            } catch (error) {
                console.error('删除组件失败:', error);
                showMessage('删除组件失败', 'error');
            }
        }

        // 更新建议
        async function updateRecommendations() {
            const cpu = selectedComponents.cpu;
            const gpu = selectedComponents.gpu;
            const psu = selectedComponents.psu;
            
            // CPU与显卡匹配建议
            const cpuGpuMatch = document.getElementById('cpu-gpu-match');
            if (cpu && gpu) {
                try {
                    const response = await fetch(`${API_BASE_URL}/api/recommendations/cpu-gpu-match`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify({
                            cpu: cpu.name,
                            gpu: gpu.name
                        })
                    });
                    const data = await response.json();
                    cpuGpuMatch.innerHTML = `<h4>CPU与显卡匹配</h4><p>${data.recommendation}</p>`;
                } catch (error) {
                    // 使用本地逻辑作为后备
                    const cpuPrice = cpu.price;
                    const gpuPrice = gpu.price;
                    
                    if (gpuPrice > cpuPrice * 2) {
                        cpuGpuMatch.innerHTML = `<h4>CPU与显卡匹配</h4><p>显卡价格远高于CPU,可能存在CPU瓶颈。</p>`;
                    } else if (cpuPrice > gpuPrice * 1.5) {
                        cpuGpuMatch.innerHTML = `<h4>CPU与显卡匹配</h4><p>CPU价格远高于显卡,可能存在显卡瓶颈。</p>`;
                    } else {
                        cpuGpuMatch.innerHTML = `<h4>CPU与显卡匹配</h4><p>CPU和显卡搭配合理,性能平衡。</p>`;
                    }
                }
            } else {
                cpuGpuMatch.innerHTML = `<h4>CPU与显卡匹配</h4><p>根据CPU和显卡选择,系统将提供优化建议。</p>`;
            }
            
            // 电源建议
            const psuRecommendation = document.getElementById('psu-recommendation');
            if (psu && gpu) {
                try {
                    const response = await fetch(`${API_BASE_URL}/api/recommendations/psu`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify({
                            psu: psu.name,
                            gpu: gpu.name
                        })
                    });
                    const data = await response.json();
                    psuRecommendation.innerHTML = `<h4>电源建议</h4><p>${data.recommendation}</p>`;
                } catch (error) {
                    // 使用本地逻辑作为后备
                    const psuWattage = parseInt(psu.name.match(/\d+/)?.[0]) || 550;
                    let recommendedWattage = 550;
                    
                    if (gpu.name.includes('4070') || gpu.name.includes('7700')) {
                        recommendedWattage = 650;
                    } else if (gpu.name.includes('4060') || gpu.name.includes('6600')) {
                        recommendedWattage = 550;
                    } else if (gpu.name.includes('3060')) {
                        recommendedWattage = 550;
                    } else if (gpu.name.includes('7900') || gpu.name.includes('4090')) {
                        recommendedWattage = 850;
                    }
                    
                    if (psuWattage >= recommendedWattage) {
                        psuRecommendation.innerHTML = `<h4>电源建议</h4><p>${psuWattage}W电源足够为当前配置供电。</p>`;
                    } else {
                        psuRecommendation.innerHTML = `<h4>电源建议</h4><p>${psuWattage}W电源可能不足,建议${recommendedWattage}W+电源。</p>`;
                    }
                }
            } else {
                psuRecommendation.innerHTML = `<h4>电源建议</h4><p>请根据配置选择合适的电源功率。</p>`;
            }
            
            // 预算建议
            const budgetRecommendation = document.getElementById('budget-recommendation');
            let totalPrice = 0;
            for (const category in selectedComponents) {
                const component = selectedComponents[category];
                if (component) {
                    totalPrice += component.price;
                }
            }
            
            let budgetLevel = "未知";
            if (totalPrice < 5000) budgetLevel = "入门级";
            else if (totalPrice < 8000) budgetLevel = "主流级";
            else if (totalPrice < 12000) budgetLevel = "高性能";
            else budgetLevel = "发烧级";
            
            budgetRecommendation.innerHTML = `<h4>预算建议</h4><p>当前配置总价¥${totalPrice},属于${budgetLevel}配置。</p>`;
        }

        // 设置预算选择器
        function setupBudgetSelector() {
            const budgetButtons = document.querySelectorAll('.budget-btn');
            budgetButtons.forEach(button => {
                button.addEventListener('click', function() {
                    // 移除所有按钮的active类
                    budgetButtons.forEach(btn => btn.classList.remove('active'));
                    // 为当前按钮添加active类
                    this.classList.add('active');
                    // 更新当前预算
                    currentBudget = parseInt(this.dataset.budget);
                    document.getElementById('current-budget').textContent = `¥${currentBudget}`;
                    // 加载预算预设
                    loadBudgetPreset(currentBudget);
                });
            });
        }

        // 加载预算预设
        async function loadBudgetPreset(budget) {
            try {
                const response = await fetch(`${API_BASE_URL}/api/budget-presets/${budget}`);
                const preset = await response.json();
                
                // 重置选中组件
                selectedComponents = {
                    cpu: null,
                    gpu: null,
                    motherboard: null,
                    ram: null,
                    storage: null,
                    psu: null,
                    case: null
                };
                
                // 选择预设组件
                preset.components.forEach(id => {
                    selectComponentById(id);
                });
                
                showMessage(`已加载${budget}元预算配置`, 'success');
            } catch (error) {
                console.error('加载预算预设失败:', error);
                // 使用本地预设作为后备
                const localPresets = {
                    4000: [1, 8, 15, 21, 26, 32, 37],
                    6000: [2, 9, 15, 22, 27, 33, 38],
                    8000: [3, 10, 16, 23, 28, 34, 39],
                    12000: [6, 13, 19, 23, 29, 34, 40]
                };
                
                const componentIds = localPresets[budget];
                if (componentIds) {
                    selectedComponents = {
                        cpu: null,
                        gpu: null,
                        motherboard: null,
                        ram: null,
                        storage: null,
                        psu: null,
                        case: null
                    };
                    
                    componentIds.forEach(selectComponentById);
                }
                
                showMessage(`已加载本地${budget}元预算配置`, 'info');
            }
        }

        // 根据ID选择组件
        function selectComponentById(id) {
            // 在所有组件中查找
            for (const category in allComponents) {
                const component = allComponents[category].find(comp => comp.id === id);
                if (component) {
                    selectComponent(component);
                    break;
                }
            }
        }

        // 重置配置
        function resetConfiguration() {
            // 重置选中组件
            selectedComponents = {
                cpu: null,
                gpu: null,
                motherboard: null,
                ram: null,
                storage: null,
                psu: null,
                case: null
            };
            
            // 重置UI
            const options = document.querySelectorAll('.option');
            options.forEach(option => {
                option.classList.remove('selected');
            });
            
            updateConfigurationList();
            updateTotalPrice();
            updateBadges();
            updateRecommendations();
            
            showMessage('配置已重置', 'info');
        }

        // 保存配置
        async function saveConfiguration() {
            let totalPrice = 0;
            const config = {};
            
            for (const category in selectedComponents) {
                const component = selectedComponents[category];
                if (component) {
                    config[category] = {
                        id: component.id,
                        name: component.name,
                        price: component.price
                    };
                    totalPrice += component.price;
                }
            }
            
            if (Object.keys(config).length === 0) {
                showMessage('请先选择组件', 'warning');
                return;
            }
            
            try {
                const response = await fetch(`${API_BASE_URL}/api/configurations`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                        components: config,
                        total_price: totalPrice,
                        budget: currentBudget
                    })
                });
                
                const data = await response.json();
                currentConfigId = data.id;
                
                // 重新加载配置列表
                loadSavedConfigs();
                
                // 创建下载链接
                let configText = "电脑组装配置清单\n";
                configText += "====================\n\n";
                
                for (const category in config) {
                    const component = config[category];
                    configText += `${getCategoryName(category)}: ${component.name} - ¥${component.price}\n`;
                }
                
                configText += `\n总计价格: ¥${totalPrice}\n`;
                configText += `预算: ¥${currentBudget}\n`;
                configText += `配置ID: ${data.id}\n`;
                configText += `分享链接: ${window.location.origin}${window.location.pathname}?config=${data.id}\n`;
                configText += `生成时间: ${new Date().toLocaleString()}\n`;
                
                const blob = new Blob([configText], { type: 'text/plain' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `电脑配置_${data.id}.txt`;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
                
                showMessage('配置已保存并分享链接已生成', 'success');
            } catch (error) {
                console.error('保存配置失败:', error);
                // 使用本地保存作为后备
                saveConfigurationLocally(config, totalPrice);
                showMessage('配置已本地保存', 'info');
            }
        }

        // 本地保存配置
        function saveConfigurationLocally(config, totalPrice) {
            let configText = "电脑组装配置清单\n";
            configText += "====================\n\n";
            
            for (const category in config) {
                const component = config[category];
                configText += `${getCategoryName(category)}: ${component.name} - ¥${component.price}\n`;
            }
            
            configText += `\n总计价格: ¥${totalPrice}\n`;
            configText += `预算: ¥${currentBudget}\n`;
            configText += `生成时间: ${new Date().toLocaleString()}\n`;
            
            const blob = new Blob([configText], { type: 'text/plain' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `电脑配置_${new Date().getTime()}.txt`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }

        // 分享配置
        async function shareConfiguration() {
            let totalPrice = 0;
            const config = {};
            
            for (const category in selectedComponents) {
                const component = selectedComponents[category];
                if (component) {
                    config[category] = {
                        id: component.id,
                        name: component.name,
                        price: component.price
                    };
                    totalPrice += component.price;
                }
            }
            
            if (Object.keys(config).length === 0) {
                showMessage('请先选择组件', 'warning');
                return;
            }
            
            try {
                const response = await fetch(`${API_BASE_URL}/api/configurations`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                        components: config,
                        total_price: totalPrice,
                        budget: currentBudget
                    })
                });
                
                const data = await response.json();
                currentConfigId = data.id;
                
                // 创建分享链接
                const shareUrl = `${window.location.origin}${window.location.pathname}?config=${data.id}`;
                
                // 复制到剪贴板
                await navigator.clipboard.writeText(shareUrl);
                
                showMessage('分享链接已复制到剪贴板', 'success');
            } catch (error) {
                console.error('分享配置失败:', error);
                showMessage('分享失败,请先保存配置', 'error');
            }
        }

        // 加载已保存配置
        async function loadSavedConfigs() {
            try {
                const response = await fetch(`${API_BASE_URL}/api/configurations`);
                savedConfigs = await response.json();
                
                updateSavedConfigsList();
                showMessage('配置列表已刷新', 'success');
            } catch (error) {
                console.error('加载配置列表失败:', error);
                savedConfigs = [];
                updateSavedConfigsList();
                showMessage('加载配置列表失败', 'error');
            }
        }

        // 更新已保存配置列表
        function updateSavedConfigsList() {
            const configsList = document.getElementById('configs-list');
            
            if (savedConfigs.length === 0) {
                configsList.innerHTML = `
                    <div class="empty-config">
                        <i class="fas fa-database"></i>
                        <h3>暂无保存的配置</h3>
                        <p>点击"保存配置"按钮创建第一个配置</p>
                    </div>
                `;
                return;
            }
            
            let listHTML = '';
            
            savedConfigs.forEach(config => {
                const date = new Date(config.created_at).toLocaleString();
                const componentsCount = Object.keys(config.components || {}).length;
                
                listHTML += `
                    <div class="component-item-manage">
                        <div class="component-item-info">
                            <div class="component-item-title">配置 ${config.id}</div>
                            <div class="component-item-meta">
                                ¥${config.total_price} | ${componentsCount}个组件 | ${date}
                            </div>
                        </div>
                        <div class="component-item-actions">
                            <button class="action-btn load" onclick="loadConfig('${config.id}')" title="加载配置">
                                <i class="fas fa-folder-open"></i>
                            </button>
                            <button class="action-btn delete" onclick="deleteConfig('${config.id}')" title="删除配置">
                                <i class="fas fa-trash"></i>
                            </button>
                        </div>
                    </div>
                `;
            });
            
            configsList.innerHTML = listHTML;
        }

        // 加载配置
        async function loadConfig(configId) {
            try {
                const response = await fetch(`${API_BASE_URL}/api/configurations/${configId}`);
                const configData = await response.json();
                
                // 重置当前配置
                resetConfiguration();
                
                // 加载配置中的组件
                if (configData.components) {
                    for (const category in configData.components) {
                        const component = configData.components[category];
                        selectComponentById(component.id);
                    }
                }
                
                // 更新预算
                if (configData.budget) {
                    currentBudget = configData.budget;
                    document.getElementById('current-budget').textContent = `¥${currentBudget}`;
                    
                    // 更新预算按钮状态
                    const budgetButtons = document.querySelectorAll('.budget-btn');
                    budgetButtons.forEach(btn => {
                        btn.classList.remove('active');
                        if (parseInt(btn.dataset.budget) === currentBudget) {
                            btn.classList.add('active');
                        }
                    });
                }
                
                currentConfigId = configId;
                showMessage('配置已加载', 'success');
            } catch (error) {
                console.error('加载配置失败:', error);
                showMessage('加载配置失败', 'error');
            }
        }

        // 删除配置
        async function deleteConfig(configId) {
            if (!confirm('确定要删除这个配置吗?')) {
                return;
            }
            
            try {
                const response = await fetch(`${API_BASE_URL}/api/configurations/${configId}`, {
                    method: 'DELETE'
                });
                
                if (response.ok) {
                    // 重新加载配置列表
                    loadSavedConfigs();
                    showMessage('配置已删除', 'success');
                } else {
                    throw new Error('删除失败');
                }
            } catch (error) {
                console.error('删除配置失败:', error);
                showMessage('删除配置失败', 'error');
            }
        }

        // 检查URL中是否有分享的配置ID
        async function checkUrlForSharedConfig() {
            const urlParams = new URLSearchParams(window.location.search);
            const configId = urlParams.get('config');
            
            if (configId) {
                try {
                    const response = await fetch(`${API_BASE_URL}/api/configurations/${configId}`);
                    const configData = await response.json();
                    
                    // 加载分享的配置
                    loadConfig(configId);
                    showMessage('已加载分享的配置', 'success');
                } catch (error) {
                    console.error('加载分享配置失败:', error);
                    showMessage('加载分享配置失败', 'error');
                }
            }
        }

        // 显示消息提示
        function showMessage(text, type = 'info') {
            const container = document.getElementById('message-container');
            const message = document.createElement('div');
            message.className = `message ${type}`;
            message.innerHTML = `
                <i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : type === 'warning' ? 'exclamation-triangle' : 'info-circle'}"></i>
                <span>${text}</span>
            `;
            
            container.appendChild(message);
            
            // 显示消息
            setTimeout(() => {
                message.classList.add('show');
            }, 10);
            
            // 3秒后隐藏并移除消息
            setTimeout(() => {
                message.classList.remove('show');
                setTimeout(() => {
                    container.removeChild(message);
                }, 300);
            }, 3000);
        }

        // 获取本地组件数据(后备方案)
        function getLocalComponents() {
            return {
                cpu: [
                    { id: 1, name: "i3-12100F", price: 799, category: "cpu", tag: "入门" },
                    { id: 2, name: "i5-12400F", price: 1199, category: "cpu", tag: "主流" },
                    { id: 3, name: "i5-13400F", price: 1599, category: "cpu", tag: "中端" },
                    { id: 4, name: "i7-13700K", price: 2899, category: "cpu", tag: "高端" },
                    { id: 5, name: "R5 5600X", price: 1299, category: "cpu", tag: "主流" },
                    { id: 6, name: "R7 7700X", price: 2599, category: "cpu", tag: "高端" },
                    { id: 7, name: "R9 7950X", price: 4499, category: "cpu", tag: "旗舰" }
                ],
                gpu: [
                    { id: 8, name: "GTX 1660S", price: 1599, category: "gpu", tag: "入门" },
                    { id: 9, name: "RTX 3060", price: 2399, category: "gpu", tag: "主流" },
                    { id: 10, name: "RTX 4060Ti", price: 3299, category: "gpu", tag: "中端" },
                    { id: 11, name: "RTX 4070", price: 4799, category: "gpu", tag: "高端" },
                    { id: 12, name: "RX 6600XT", price: 1999, category: "gpu", tag: "主流" },
                    { id: 13, name: "RX 7700XT", price: 3699, category: "gpu", tag: "高端" },
                    { id: 14, name: "RX 7900XTX", price: 7999, category: "gpu", tag: "旗舰" }
                ],
                motherboard: [
                    { id: 15, name: "微星 B660M", price: 899, category: "motherboard", tag: "主流" },
                    { id: 16, name: "华硕 B760", price: 1299, category: "motherboard", tag: "中端" },
                    { id: 17, name: "技嘉 Z790", price: 2299, category: "motherboard", tag: "高端" },
                    { id: 18, name: "微星 B550M", price: 849, category: "motherboard", tag: "主流" },
                    { id: 19, name: "华硕 B650", price: 1899, category: "motherboard", tag: "高端" },
                    { id: 20, name: "技嘉 X670E", price: 3499, category: "motherboard", tag: "旗舰" }
                ],
                ram: [
                    { id: 21, name: "16GB DDR4", price: 299, category: "ram", tag: "基础" },
                    { id: 22, name: "32GB DDR4", price: 599, category: "ram", tag: "足够" },
                    { id: 23, name: "32GB DDR5", price: 899, category: "ram", tag: "中端" },
                    { id: 24, name: "64GB DDR5", price: 1599, category: "ram", tag: "高端" },
                    { id: 25, name: "32GB DDR5 海盗船", price: 799, category: "ram", tag: "中端" }
                ],
                storage: [
                    { id: 26, name: "500GB NVMe", price: 299, category: "storage", tag: "基础" },
                    { id: 27, name: "1TB NVMe", price: 499, category: "storage", tag: "足够" },
                    { id: 28, name: "1TB WD SN770", price: 459, category: "storage", tag: "性价比" },
                    { id: 29, name: "2TB 三星 990 PRO", price: 1299, category: "storage", tag: "高端" },
                    { id: 30, name: "2TB HDD", price: 399, category: "storage", tag: "仓库" },
                    { id: 31, name: "4TB HDD", price: 699, category: "storage", tag: "大容量" }
                ],
                psu: [
                    { id: 32, name: "550W 铜牌", price: 349, category: "psu", tag: "基础" },
                    { id: 33, name: "750W 金牌", price: 799, category: "psu", tag: "足够" },
                    { id: 34, name: "850W 金牌", price: 899, category: "psu", tag: "中端" },
                    { id: 35, name: "1000W 白金", price: 1299, category: "psu", tag: "高端" },
                    { id: 36, name: "850W 金牌 安钛克", price: 699, category: "psu", tag: "性价比" }
                ],
                case: [
                    { id: 37, name: "先马 平头哥", price: 199, category: "case", tag: "入门" },
                    { id: 38, name: "酷冷 MB520", price: 399, category: "case", tag: "主流" },
                    { id: 39, name: "恩杰 H510", price: 599, category: "case", tag: "中端" },
                    { id: 40, name: "联力 包豪斯", price: 899, category: "case", tag: "高端" },
                    { id: 41, name: "分形工艺 Meshify", price: 799, category: "case", tag: "中端" }
                ]
            };
        }

        // 获取类别中文名称
        function getCategoryName(category) {
            const names = {
                cpu: "CPU",
                gpu: "显卡",
                motherboard: "主板",
                ram: "内存",
                storage: "存储",
                psu: "电源",
                case: "机箱"
            };
            return names[category] || category;
        }
        
        // 将函数暴露给全局作用域,供HTML中的onclick调用
        window.loadConfig = loadConfig;
        window.deleteConfig = deleteConfig;
        window.editComponent = editComponent;
        window.deleteComponent = deleteComponent;
    </script>
</body>
</html>

后端:

backend/main.py

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Dict, List, Optional
import json
import uuid
from datetime import datetime
from pathlib import Path

app = FastAPI(title="电脑组装报价指南 API", description="电脑配置报价和推荐系统")

# 允许跨域请求
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 数据存储目录
DATA_DIR = Path("data")
DATA_DIR.mkdir(exist_ok=True)

# 数据模型
class Component(BaseModel):
    id: int
    name: str
    price: int
    category: str
    tag: Optional[str] = None

class Configuration(BaseModel):
    id: Optional[str] = None
    components: Dict[str, Dict]
    total_price: float
    budget: int
    created_at: Optional[str] = None

class RecommendationRequest(BaseModel):
    cpu: Optional[str] = None
    gpu: Optional[str] = None
    psu: Optional[str] = None

# 加载组件数据
def load_components() -> Dict[str, List[Component]]:
    components_path = DATA_DIR / "components.json"
    
    if components_path.exists():
        with open(components_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
            return data
    
    # 默认组件数据
    default_components = {
        "cpu": [
            {"id": 1, "name": "i3-12100F", "price": 799, "category": "cpu", "tag": "入门"},
            {"id": 2, "name": "i5-12400F", "price": 1199, "category": "cpu", "tag": "主流"},
            {"id": 3, "name": "i5-13400F", "price": 1599, "category": "cpu", "tag": "中端"},
            {"id": 4, "name": "i7-13700K", "price": 2899, "category": "cpu", "tag": "高端"},
            {"id": 5, "name": "R5 5600X", "price": 1299, "category": "cpu", "tag": "主流"},
            {"id": 6, "name": "R7 7700X", "price": 2599, "category": "cpu", "tag": "高端"},
            {"id": 7, "name": "R9 7950X", "price": 4499, "category": "cpu", "tag": "旗舰"}
        ],
        "gpu": [
            {"id": 8, "name": "GTX 1660S", "price": 1599, "category": "gpu", "tag": "入门"},
            {"id": 9, "name": "RTX 3060", "price": 2399, "category": "gpu", "tag": "主流"},
            {"id": 10, "name": "RTX 4060Ti", "price": 3299, "category": "gpu", "tag": "中端"},
            {"id": 11, "name": "RTX 4070", "price": 4799, "category": "gpu", "tag": "高端"},
            {"id": 12, "name": "RX 6600XT", "price": 1999, "category": "gpu", "tag": "主流"},
            {"id": 13, "name": "RX 7700XT", "price": 3699, "category": "gpu", "tag": "高端"},
            {"id": 14, "name": "RX 7900XTX", "price": 7999, "category": "gpu", "tag": "旗舰"}
        ],
        "motherboard": [
            {"id": 15, "name": "微星 B660M", "price": 899, "category": "motherboard", "tag": "主流"},
            {"id": 16, "name": "华硕 B760", "price": 1299, "category": "motherboard", "tag": "中端"},
            {"id": 17, "name": "技嘉 Z790", "price": 2299, "category": "motherboard", "tag": "高端"},
            {"id": 18, "name": "微星 B550M", "price": 849, "category": "motherboard", "tag": "主流"},
            {"id": 19, "name": "华硕 B650", "price": 1899, "category": "motherboard", "tag": "高端"},
            {"id": 20, "name": "技嘉 X670E", "price": 3499, "category": "motherboard", "tag": "旗舰"}
        ],
        "ram": [
            {"id": 21, "name": "16GB DDR4", "price": 299, "category": "ram", "tag": "基础"},
            {"id": 22, "name": "32GB DDR4", "price": 599, "category": "ram", "tag": "足够"},
            {"id": 23, "name": "32GB DDR5", "price": 899, "category": "ram", "tag": "中端"},
            {"id": 24, "name": "64GB DDR5", "price": 1599, "category": "ram", "tag": "高端"},
            {"id": 25, "name": "32GB DDR5 海盗船", "price": 799, "category": "ram", "tag": "中端"}
        ],
        "storage": [
            {"id": 26, "name": "500GB NVMe", "price": 299, "category": "storage", "tag": "基础"},
            {"id": 27, "name": "1TB NVMe", "price": 499, "category": "storage", "tag": "足够"},
            {"id": 28, "name": "1TB WD SN770", "price": 459, "category": "storage", "tag": "性价比"},
            {"id": 29, "name": "2TB 三星 990 PRO", "price": 1299, "category": "storage", "tag": "高端"},
            {"id": 30, "name": "2TB HDD", "price": 399, "category": "storage", "tag": "仓库"},
            {"id": 31, "name": "4TB HDD", "price": 699, "category": "storage", "tag": "大容量"}
        ],
        "psu": [
            {"id": 32, "name": "550W 铜牌", "price": 349, "category": "psu", "tag": "基础"},
            {"id": 33, "name": "750W 金牌", "price": 799, "category": "psu", "tag": "足够"},
            {"id": 34, "name": "850W 金牌", "price": 899, "category": "psu", "tag": "中端"},
            {"id": 35, "name": "1000W 白金", "price": 1299, "category": "psu", "tag": "高端"},
            {"id": 36, "name": "850W 金牌 安钛克", "price": 699, "category": "psu", "tag": "性价比"}
        ],
        "case": [
            {"id": 37, "name": "先马 平头哥", "price": 199, "category": "case", "tag": "入门"},
            {"id": 38, "name": "酷冷 MB520", "price": 399, "category": "case", "tag": "主流"},
            {"id": 39, "name": "恩杰 H510", "price": 599, "category": "case", "tag": "中端"},
            {"id": 40, "name": "联力 包豪斯", "price": 899, "category": "case", "tag": "高端"},
            {"id": 41, "name": "分形工艺 Meshify", "price": 799, "category": "case", "tag": "中端"}
        ]
    }
    
    # 保存默认数据
    with open(components_path, 'w', encoding='utf-8') as f:
        json.dump(default_components, f, ensure_ascii=False, indent=2)
    
    return default_components

# 加载配置数据
def load_configurations() -> Dict[str, Configuration]:
    configs_path = DATA_DIR / "configurations.json"
    
    if configs_path.exists():
        with open(configs_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
            return {k: Configuration(**v) for k, v in data.items()}
    
    return {}

# 保存配置数据
def save_configurations(configs: Dict[str, Configuration]):
    configs_path = DATA_DIR / "configurations.json"
    
    with open(configs_path, 'w', encoding='utf-8') as f:
        json.dump(
            {k: v.dict() for k, v in configs.items()},
            f,
            ensure_ascii=False,
            indent=2
        )

# 预算预设
BUDGET_PRESETS = {
    4000: {"budget": 4000, "name": "入门级", "components": [1, 8, 15, 21, 26, 32, 37]},
    6000: {"budget": 6000, "name": "主流级", "components": [2, 9, 15, 22, 27, 33, 38]},
    8000: {"budget": 8000, "name": "高性能", "components": [3, 10, 16, 23, 28, 34, 39]},
    12000: {"budget": 12000, "name": "发烧级", "components": [6, 13, 19, 23, 29, 34, 40]}
}

# API 端点
@app.get("/")
async def root():
    return {"message": "电脑组装报价指南 API", "version": "1.0.0"}

@app.get("/api/components")
async def get_components():
    """获取所有组件"""
    return load_components()

@app.get("/api/components/{category}")
async def get_components_by_category(category: str):
    """按类别获取组件"""
    components = load_components()
    if category in components:
        return components[category]
    raise HTTPException(status_code=404, detail="Category not found")

@app.get("/api/budget-presets")
async def get_budget_presets():
    """获取所有预算预设"""
    return BUDGET_PRESETS

@app.get("/api/budget-presets/{budget}")
async def get_budget_preset(budget: int):
    """获取特定预算预设"""
    if budget in BUDGET_PRESETS:
        return BUDGET_PRESETS[budget]
    raise HTTPException(status_code=404, detail="Budget preset not found")

@app.post("/api/recommendations/cpu-gpu-match")
async def get_cpu_gpu_recommendation(request: RecommendationRequest):
    """获取CPU和显卡匹配建议"""
    if not request.cpu or not request.gpu:
        raise HTTPException(status_code=400, detail="CPU and GPU are required")
    
    # 简单的匹配逻辑
    cpu_lower = request.cpu.lower()
    gpu_lower = request.gpu.lower()
    
    # 检查是否为高端配置
    high_end_cpu = any(x in cpu_lower for x in ['i7', 'i9', 'r7', 'r9', '7950', '13900'])
    high_end_gpu = any(x in gpu_lower for x in ['4070', '4080', '4090', '7900', '7700', 'rtx 40'])
    
    if high_end_cpu and not high_end_gpu:
        recommendation = f"{request.cpu}性能较强,建议搭配更高端的显卡以发挥其性能。"
    elif not high_end_cpu and high_end_gpu:
        recommendation = f"{request.gpu}性能较强,建议搭配更高端的CPU以避免瓶颈。"
    else:
        recommendation = f"{request.cpu}和{request.gpu}搭配合理,性能平衡。"
    
    return {"recommendation": recommendation}

@app.post("/api/recommendations/psu")
async def get_psu_recommendation(request: RecommendationRequest):
    """获取电源建议"""
    if not request.psu or not request.gpu:
        raise HTTPException(status_code=400, detail="PSU and GPU are required")
    
    # 提取电源功率
    import re
    psu_match = re.search(r'(\d+)W', request.psu)
    psu_wattage = int(psu_match.group(1)) if psu_match else 550
    
    # 根据GPU推荐功率
    gpu_lower = request.gpu.lower()
    recommended_wattage = 550
    
    if any(x in gpu_lower for x in ['4070', '4080', '4090', '7900']):
        recommended_wattage = 850
    elif any(x in gpu_lower for x in ['4060', '7700', '3070', '3080']):
        recommended_wattage = 650
    elif any(x in gpu_lower for x in ['3060', '6600', '6700']):
        recommended_wattage = 550
    elif any(x in gpu_lower for x in ['1660', '2060', '6500']):
        recommended_wattage = 450
    
    if psu_wattage >= recommended_wattage:
        recommendation = f"{psu_wattage}W电源足够为{request.gpu}供电。"
    else:
        recommendation = f"{psu_wattage}W电源可能不足,建议升级到{recommended_wattage}W+电源。"
    
    return {"recommendation": recommendation}

@app.get("/api/configurations")
async def get_all_configurations():
    """获取所有保存的配置"""
    configs = load_configurations()
    return list(configs.values())

@app.get("/api/configurations/{config_id}")
async def get_configuration(config_id: str):
    """获取特定配置"""
    configs = load_configurations()
    if config_id in configs:
        return configs[config_id]
    raise HTTPException(status_code=404, detail="Configuration not found")

@app.post("/api/configurations")
async def create_configuration(config: Configuration):
    """创建新配置"""
    configs = load_configurations()
    
    # 生成唯一ID
    config_id = str(uuid.uuid4())[:8]
    config.id = config_id
    config.created_at = datetime.now().isoformat()
    
    # 保存配置
    configs[config_id] = config
    save_configurations(configs)
    
    return {"id": config_id, "message": "Configuration saved successfully"}

@app.put("/api/configurations/{config_id}")
async def update_configuration(config_id: str, config: Configuration):
    """更新配置"""
    configs = load_configurations()
    
    if config_id not in configs:
        raise HTTPException(status_code=404, detail="Configuration not found")
    
    config.id = config_id
    config.created_at = datetime.now().isoformat()
    configs[config_id] = config
    save_configurations(configs)
    
    return {"message": "Configuration updated successfully"}

@app.delete("/api/configurations/{config_id}")
async def delete_configuration(config_id: str):
    """删除配置"""
    configs = load_configurations()
    
    if config_id not in configs:
        raise HTTPException(status_code=404, detail="Configuration not found")
    
    del configs[config_id]
    save_configurations(configs)
    
    return {"message": "Configuration deleted successfully"}

@app.get("/api/health")
async def health_check():
    """健康检查"""
    return {"status": "healthy", "timestamp": datetime.now().isoformat()}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

start.bat

python main.py

1. 双侧边栏设计

  • 左侧侧边栏(绿色): 组件管理功能

  • 右侧侧边栏(蓝色): 配置详情功能

  • 两个侧边栏独立控制,可以同时打开或关闭

2. 左侧组件管理侧边栏功能

搜索和筛选区域
  • 搜索框: 按组件名称搜索

  • 类别筛选: 按组件类别筛选

  • 价格范围筛选: 按价格区间筛选

组件列表区域
  • 显示所有组件,包括类别、价格和标签

  • 支持编辑和删除操作

  • 显示组件总数

添加新组件区域
  • 完整的表单支持添加新组件

  • 支持更新现有组件

  • 清空表单功能

3. 右侧配置侧边栏功能

当前配置区域
  • 显示已选组件列表

  • 重置和保存配置按钮

价格总计区域
  • 显示总价格和预算状态

  • 分享配置按钮

配置建议区域
  • CPU与显卡匹配建议

  • 电源建议

  • 预算建议

已保存配置区域
  • 显示所有已保存的配置

  • 支持加载和删除配置

4. 改进的用户体验

双浮动按钮
  • 左侧绿色按钮:组件管理(齿轮图标+组件总数徽章)

  • 右侧蓝色按钮:配置详情(购物车图标+已选数量徽章)

智能交互
  • 选择组件时自动打开右侧配置侧边栏

  • 编辑组件时自动打开左侧组件侧边栏

  • ESC键可关闭所有侧边栏

  • 点击外部可关闭侧边栏

实时更新
  • 所有更改都实时同步更新

  • 筛选和搜索实时生效

  • 徽章数量实时更新

5. 视觉区分

  • 左侧侧边栏: 绿色主题,代表组件管理

  • 右侧侧边栏: 蓝色主题,代表配置管理

  • 主页面: 白色主题,专注组件选择

  • 徽章: 购物车徽章显示已选数量,组件徽章显示总数

6. 完整的CRUD操作

组件管理(左侧)
  • Create: 添加新组件

  • Read: 查看所有组件,支持筛选搜索

  • Update: 编辑现有组件

  • Delete: 删除组件(检查是否正在使用)

配置管理(右侧)
  • Create: 保存新配置

  • Read: 查看已保存配置

  • Update: 加载后修改再保存

  • Delete: 删除已保存配置

这样设计的优势:

  1. 功能分离: 组件管理和配置管理完全分离,职责清晰

  2. 工作流优化: 从左到右的自然工作流:选择组件 → 管理组件 → 查看配置

  3. 空间利用: 主页面专注选择,侧边栏专注管理

  4. 操作便捷: 常用功能一键可达,复杂功能组织有序

  5. 视觉引导: 颜色和图标清晰区分不同功能区域

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐