FastAPI + 原生js 写的一个 前后端 电脑组装报价指南

图:

前端:

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. 视觉引导: 颜色和图标清晰区分不同功能区域

内容概要:本文提出了一种结合在线鲁棒主成分分析(RPCA)模型与长短期记忆(LSTM)循环网络的商品需求预测方法,并提供了完整的Python代码实现。该方法首先利用RPCA模型对原始商品需求时间序列进行分解,分离出低秩的潜在趋势成分与稀疏的异常波动成分,有效实现数据去噪与异常值修正,提升输入数据的鲁棒性;随后将净化后的数据输入LSTM网络,充分挖掘时间序列中的长期依赖关系与时序模式,从而提高对未来需求的预测精度。整个模型设计针对实际商业场景中普遍存在的数据噪声大、波动剧烈、突发性事件干扰等问题,展现出较强的稳定性与预测能力。文中通过实验验证了该混合模型在多个指标上优于传统统计模型及单一LSTM模型,体现了其在复杂环境下的优越性能。; 适合人群:具备一定Python编程能力和机器学习基础知识,从事数据分析、供应链管理、电商运营、零售优化及相关领域研究的研发人员或研究生;特别适合关注时间序列预测、深度学习建模以及鲁棒数据处理技术的技术人员。; 使用场景及目标:①应用于电商平台、零售企业或制造行业中的销量预测,以支持库存优化、生产计划制定与物流调度决策;②为科研工作者提供一种融合鲁棒统计与深度学习的预测建模范例,推动高噪声环境下预测算法的创新与复现研究;③帮助开发者深入理解RPCA与LSTM的集成机制,掌握复杂预测模型的构建、训练与调优流程。; 阅读建议:建议读者结合所提供的Python代码逐步实现模型,重点理解RPCA在数据预处理阶段的作用机制以及LSTM网络的结构设计与超参数配置。学习过程中应在真实或模拟数据集上复现实验结果,对比不同参数设置下的模型表现,以深化对模型内在工作原理的理解。同时可进一步探索其他深度学习模型(如GRU、Transformer)与鲁棒分解方法(如VMD、STL)的融合可能性,拓展应用场景。
内容概要:本文针对传统三电平并网逆变器在谐波抑制、电网不平衡适应性及动态响应方面的不足,提出一种基于有源中点箝位(ANPC)三电平拓扑的高性能并网控制策略。通过融合双极性倍频脉宽调制(DPWMA)、正负序分离锁相技术与电网电压前馈控制,构建一体化控制系统。ANPC拓扑具备开关损耗均衡、中点电位可控、输出谐波低等优势,为系统性能提升提供硬件基础;DPWMA调制有效提升等效开关频率,显著降低输出电压电流的低次谐波含量,优化稳态电能质量;正负序分离锁相技术可精准提取电网正序分量,实现不平衡工况下的精确同步,保障并网电流对称性;电网电压前馈控制则提前补偿电网扰动,大幅缩短动态调节时间,抑制电压骤变引起的电流畸变与功率冲击。文章通过Simulink仿真平台对稳态、电网不平衡及动态切换等多种工况进行全面验证,结果表明该复合控制策略能显著提升系统的电能质量、运行稳定性与工况适应能力,适用于新能源发电、工业变频等大功率高质量并网应用场景。; 适合人群:具备电力电子与电力系统基础知识,从事新能源并网、电能质量治理、大功率变流器控制等方向研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究高电能质量要求下的大功率并网逆变器系统设计方法;②掌握DPWMA调制、正负序分离锁相、电网电压前馈等先进控制技术的原理与协同机制;③提升在电网电压不平衡、动态扰动等复杂工况下的系统稳定控制能力;④为实际工程应用或学术研究提供可复现的仿真模型与技术解决方案。; 阅读建议:此资源以Simulink仿真为核心,结合理论分析与性能验证,建议读者结合文中控制策略的原理讲解,动手搭建仿真模型,重点理解DPWMA调制逻辑、正负序分解算法及前馈控制的实现方式,并通过不同工况下的仿真对比,深入掌握各模块对系统性能的贡献。
源码链接: https://pan.quark.cn/s/7d0192dd9e83 【定制系统更新包 A300】是一款专门为联想A300手机设计的系统升级文件,其核心功能在于改善设备的运行表现并实现个性化调整。在信息技术领域中,刷机这一术语指的是对手机、平板等智能终端的操作系统进行更换或升级,通常目的是为了解锁更多功能、加快处理速度或解决原装系统存在的缺陷。针对此特定的更新包,我们着重分析以下几个关键点: 1. **官方系统固件的定制化版本**:ROM(只读存储器)在移动设备中代表存储系统数据的非易失性存储区,官方ROM是由设备生产商发布的初始系统软件。而定制化版本则表明该更新包在官方版本的基础上进行了调整和改进,可能包含对系统核心、应用程序、用户界面等部分的修改。 2. **用户界面定制功能**:更新包内含的个性化选项允许用户依据个人偏好调整手机的外观和操作环境,如图标样式、桌面背景、启动应用等,从而创造更加独特的操作感受。这些定制可能涉及对系统底层设置的深入修改,例如字型更换、主题设计等。 3. **系统稳定性和响应速度的提升**:这是该更新包的主要优势之一,意味着经过优化的系统能够保证设备在运行过程中的可靠性,减少系统崩溃或运行迟缓的情况,同时增强操作的流畅性,从而提升用户日常操作的满意度。 4. **电源管理脚本的集成**:省电脚本是一种自动监控设备能耗的程序,通过调节硬件参数、关闭非必要进程等方式降低电池消耗。在此次更新包中,该脚本被整合进系统,旨在延长手机的续航能力,对于电池容量有限或经常需要外出的用户尤为适用。 5. **运行效能的强化**:这表明更新包的另一核心目标在于增强设备的处理能力,可能涉及提升中央处理器的运算效率、改进内存使用策略、减...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

PieroPc

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

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

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

打赏作者

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

抵扣说明:

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

余额充值