完成H5的积分商品添加
This commit is contained in:
		
							parent
							
								
									34e958f004
								
							
						
					
					
						commit
						1b167e31b2
					
				|  | @ -0,0 +1,950 @@ | |||
| <!DOCTYPE html> | ||||
| <html lang="zh-CN"> | ||||
| <head> | ||||
|     <meta charset="UTF-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|     <title>积分商城 - 商品管理</title> | ||||
|     <style> | ||||
|         * { | ||||
|             margin: 0; | ||||
|             padding: 0; | ||||
|             box-sizing: border-box; | ||||
|         } | ||||
| 
 | ||||
|         body { | ||||
|             font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | ||||
|             background-color: #f5f5f5; | ||||
|             color: #333; | ||||
|             line-height: 1.6; | ||||
|         } | ||||
| 
 | ||||
|         .container { | ||||
|             max-width: 100%; | ||||
|             margin: 0 auto; | ||||
|             padding: 16px; | ||||
|         } | ||||
| 
 | ||||
|         .header { | ||||
|             background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | ||||
|             color: white; | ||||
|             padding: 20px 16px; | ||||
|             margin: -16px -16px 20px -16px; | ||||
|         } | ||||
| 
 | ||||
|         .header h1 { | ||||
|             font-size: 18px; | ||||
|             font-weight: 600; | ||||
|             text-align: center; | ||||
|         } | ||||
| 
 | ||||
|         .search-section { | ||||
|             background: white; | ||||
|             border-radius: 12px; | ||||
|             padding: 20px; | ||||
|             margin-bottom: 20px; | ||||
|             box-shadow: 0 2px 8px rgba(0,0,0,0.1); | ||||
|         } | ||||
| 
 | ||||
|         .search-grid { | ||||
|             display: grid; | ||||
|             gap: 15px; | ||||
|             margin-bottom: 20px; | ||||
|         } | ||||
| 
 | ||||
|         .input-group { | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|             gap: 8px; | ||||
|         } | ||||
| 
 | ||||
|         .input-group label { | ||||
|             font-size: 14px; | ||||
|             font-weight: 500; | ||||
|             color: #666; | ||||
|         } | ||||
| 
 | ||||
|         .input-group input { | ||||
|             padding: 12px 16px; | ||||
|             border: 1px solid #ddd; | ||||
|             border-radius: 8px; | ||||
|             font-size: 16px; | ||||
|             transition: all 0.3s ease; | ||||
|         } | ||||
| 
 | ||||
|         .input-group input:focus { | ||||
|             outline: none; | ||||
|             border-color: #667eea; | ||||
|             box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); | ||||
|         } | ||||
| 
 | ||||
|         .search-btn { | ||||
|             background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | ||||
|             color: white; | ||||
|             border: none; | ||||
|             padding: 12px 24px; | ||||
|             border-radius: 8px; | ||||
|             font-size: 16px; | ||||
|             font-weight: 500; | ||||
|             cursor: pointer; | ||||
|             transition: all 0.3s ease; | ||||
|             width: 100%; | ||||
|         } | ||||
| 
 | ||||
|         .search-btn:hover { | ||||
|             transform: translateY(-2px); | ||||
|             box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); | ||||
|         } | ||||
| 
 | ||||
|         .search-btn:active { | ||||
|             transform: translateY(0); | ||||
|         } | ||||
| 
 | ||||
|         .products-section { | ||||
|             background: white; | ||||
|             border-radius: 12px; | ||||
|             overflow: hidden; | ||||
|             box-shadow: 0 2px 8px rgba(0,0,0,0.1); | ||||
|             margin-bottom: 20px; | ||||
|         } | ||||
| 
 | ||||
|         .products-header { | ||||
|             background: #f8f9fa; | ||||
|             padding: 16px; | ||||
|             border-bottom: 1px solid #eee; | ||||
|         } | ||||
| 
 | ||||
|         .products-header h2 { | ||||
|             font-size: 16px; | ||||
|             font-weight: 600; | ||||
|             color: #333; | ||||
|         } | ||||
| 
 | ||||
|         .product-list { | ||||
|             padding: 0; | ||||
|         } | ||||
| 
 | ||||
|         .product-card { | ||||
|             padding: 16px; | ||||
|             border-bottom: 1px solid #f0f0f0; | ||||
|             transition: background-color 0.2s ease; | ||||
|         } | ||||
| 
 | ||||
|         .product-card:last-child { | ||||
|             border-bottom: none; | ||||
|         } | ||||
| 
 | ||||
|         .product-card:hover { | ||||
|             background-color: #f8f9fa; | ||||
|         } | ||||
| 
 | ||||
|         .product-info { | ||||
|             margin-bottom: 12px; | ||||
|         } | ||||
| 
 | ||||
|         .product-name { | ||||
|             font-size: 16px; | ||||
|             font-weight: 600; | ||||
|             color: #333; | ||||
|             margin-bottom: 8px; | ||||
|         } | ||||
| 
 | ||||
|         .product-details { | ||||
|             display: grid; | ||||
|             grid-template-columns: 1fr 1fr; | ||||
|             gap: 8px; | ||||
|             margin-bottom: 12px; | ||||
|         } | ||||
| 
 | ||||
|         .product-detail { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             gap: 4px; | ||||
|         } | ||||
| 
 | ||||
|         .detail-label { | ||||
|             font-size: 12px; | ||||
|             color: #666; | ||||
|             min-width: 40px; | ||||
|         } | ||||
| 
 | ||||
|         .detail-value { | ||||
|             font-size: 14px; | ||||
|             color: #333; | ||||
|             font-weight: 500; | ||||
|         } | ||||
| 
 | ||||
|         .product-price { | ||||
|             font-size: 18px; | ||||
|             font-weight: 700; | ||||
|             color: #e74c3c; | ||||
|             margin-bottom: 12px; | ||||
|         } | ||||
| 
 | ||||
|         .add-btn { | ||||
|             background: linear-gradient(135deg, #27ae60 0%, #2ecc71 100%); | ||||
|             color: white; | ||||
|             border: none; | ||||
|             padding: 10px 16px; | ||||
|             border-radius: 6px; | ||||
|             font-size: 14px; | ||||
|             font-weight: 500; | ||||
|             cursor: pointer; | ||||
|             transition: all 0.3s ease; | ||||
|             width: 100%; | ||||
|         } | ||||
| 
 | ||||
|         .add-btn:hover { | ||||
|             transform: translateY(-1px); | ||||
|             box-shadow: 0 3px 8px rgba(46, 204, 113, 0.3); | ||||
|         } | ||||
| 
 | ||||
|         .add-btn:active { | ||||
|             transform: translateY(0); | ||||
|         } | ||||
| 
 | ||||
|         .add-btn:disabled { | ||||
|             background: #95a5a6; | ||||
|             cursor: not-allowed; | ||||
|             transform: none; | ||||
|         } | ||||
| 
 | ||||
|         .add-btn:disabled:hover { | ||||
|             transform: none; | ||||
|             box-shadow: none; | ||||
|         } | ||||
| 
 | ||||
|         .pagination { | ||||
|             display: flex; | ||||
|             justify-content: center; | ||||
|             align-items: center; | ||||
|             gap: 8px; | ||||
|             background: white; | ||||
|             padding: 20px; | ||||
|             border-radius: 12px; | ||||
|             box-shadow: 0 2px 8px rgba(0,0,0,0.1); | ||||
|         } | ||||
| 
 | ||||
|         .pagination button { | ||||
|             padding: 8px 12px; | ||||
|             border: 1px solid #ddd; | ||||
|             background: white; | ||||
|             border-radius: 6px; | ||||
|             cursor: pointer; | ||||
|             font-size: 14px; | ||||
|             color: #666; | ||||
|             transition: all 0.2s ease; | ||||
|             min-width: 40px; | ||||
|         } | ||||
| 
 | ||||
|         .pagination button:hover { | ||||
|             background: #f8f9fa; | ||||
|             border-color: #667eea; | ||||
|         } | ||||
| 
 | ||||
|         .pagination button.active { | ||||
|             background: #667eea; | ||||
|             color: white; | ||||
|             border-color: #667eea; | ||||
|         } | ||||
| 
 | ||||
|         .pagination button:disabled { | ||||
|             opacity: 0.5; | ||||
|             cursor: not-allowed; | ||||
|         } | ||||
| 
 | ||||
|         .empty-state { | ||||
|             text-align: center; | ||||
|             padding: 40px 20px; | ||||
|             color: #999; | ||||
|         } | ||||
| 
 | ||||
|         .empty-state i { | ||||
|             font-size: 48px; | ||||
|             margin-bottom: 16px; | ||||
|             display: block; | ||||
|         } | ||||
| 
 | ||||
|         @media (min-width: 768px) { | ||||
|             .container { | ||||
|                 max-width: 768px; | ||||
|                 padding: 20px; | ||||
|             } | ||||
| 
 | ||||
|             .search-grid { | ||||
|                 grid-template-columns: 1fr 1fr; | ||||
|             } | ||||
| 
 | ||||
|             .product-details { | ||||
|                 grid-template-columns: 1fr 1fr 1fr; | ||||
|             } | ||||
| 
 | ||||
|             .add-btn { | ||||
|                 width: auto; | ||||
|                 min-width: 120px; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         .loading { | ||||
|             text-align: center; | ||||
|             padding: 20px; | ||||
|             color: #666; | ||||
|         } | ||||
| 
 | ||||
|         .toast { | ||||
|             position: fixed; | ||||
|             top: 20px; | ||||
|             left: 50%; | ||||
|             transform: translateX(-50%); | ||||
|             background: #333; | ||||
|             color: white; | ||||
|             padding: 12px 20px; | ||||
|             border-radius: 8px; | ||||
|             font-size: 14px; | ||||
|             z-index: 1000; | ||||
|             opacity: 0; | ||||
|             transition: opacity 0.3s ease; | ||||
|         } | ||||
| 
 | ||||
|         .toast.show { | ||||
|             opacity: 1; | ||||
|         } | ||||
| 
 | ||||
|         .toast.success { | ||||
|             background: #27ae60; | ||||
|         } | ||||
| 
 | ||||
|         .toast.error { | ||||
|             background: #e74c3c; | ||||
|         } | ||||
| 
 | ||||
|         .points-status { | ||||
|             display: inline-block; | ||||
|             padding: 4px 8px; | ||||
|             border-radius: 12px; | ||||
|             font-size: 12px; | ||||
|             font-weight: 500; | ||||
|             margin-left: 8px; | ||||
|         } | ||||
| 
 | ||||
|         .points-status.active { | ||||
|             background: #e8f5e8; | ||||
|             color: #27ae60; | ||||
|             border: 1px solid #27ae60; | ||||
|         } | ||||
| 
 | ||||
|         .points-status.inactive { | ||||
|             background: #f8f8f8; | ||||
|             color: #666; | ||||
|             border: 1px solid #ddd; | ||||
|         } | ||||
| 
 | ||||
|         .modal-overlay { | ||||
|             position: fixed; | ||||
|             top: 0; | ||||
|             left: 0; | ||||
|             right: 0; | ||||
|             bottom: 0; | ||||
|             background: rgba(0, 0, 0, 0.5); | ||||
|             z-index: 1000; | ||||
|             display: none; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             backdrop-filter: blur(4px); | ||||
|         } | ||||
| 
 | ||||
|         .modal-overlay.show { | ||||
|             display: flex; | ||||
|         } | ||||
| 
 | ||||
|         .modal-content { | ||||
|             background: white; | ||||
|             border-radius: 16px; | ||||
|             max-width: 400px; | ||||
|             width: 90%; | ||||
|             max-height: 80vh; | ||||
|             overflow-y: auto; | ||||
|             box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); | ||||
|             animation: modalSlideIn 0.3s ease-out; | ||||
|         } | ||||
| 
 | ||||
|         @keyframes modalSlideIn { | ||||
|             from { | ||||
|                 transform: scale(0.8) translateY(-20px); | ||||
|                 opacity: 0; | ||||
|             } | ||||
|             to { | ||||
|                 transform: scale(1) translateY(0); | ||||
|                 opacity: 1; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         .modal-header { | ||||
|             padding: 20px 24px; | ||||
|             border-bottom: 1px solid #eee; | ||||
|             position: relative; | ||||
|         } | ||||
| 
 | ||||
|         .modal-title { | ||||
|             font-size: 18px; | ||||
|             font-weight: 600; | ||||
|             color: #333; | ||||
|             margin: 0; | ||||
|         } | ||||
| 
 | ||||
|         .modal-close { | ||||
|             position: absolute; | ||||
|             top: 20px; | ||||
|             right: 24px; | ||||
|             background: none; | ||||
|             border: none; | ||||
|             font-size: 24px; | ||||
|             color: #999; | ||||
|             cursor: pointer; | ||||
|             line-height: 1; | ||||
|             transition: color 0.2s ease; | ||||
|         } | ||||
| 
 | ||||
|         .modal-close:hover { | ||||
|             color: #666; | ||||
|         } | ||||
| 
 | ||||
|         .modal-body { | ||||
|             padding: 24px; | ||||
|         } | ||||
| 
 | ||||
|         .exchange-info { | ||||
|             margin-bottom: 24px; | ||||
|         } | ||||
| 
 | ||||
|         .info-item { | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             align-items: center; | ||||
|             padding: 12px 0; | ||||
|             border-bottom: 1px solid #f5f5f5; | ||||
|         } | ||||
| 
 | ||||
|         .info-item:last-child { | ||||
|             border-bottom: none; | ||||
|         } | ||||
| 
 | ||||
|         .info-label { | ||||
|             font-size: 14px; | ||||
|             color: #666; | ||||
|             font-weight: 500; | ||||
|         } | ||||
| 
 | ||||
|         .info-value { | ||||
|             font-size: 16px; | ||||
|             color: #333; | ||||
|             font-weight: 600; | ||||
|         } | ||||
| 
 | ||||
|         .info-value.highlight { | ||||
|             color: #e74c3c; | ||||
|         } | ||||
| 
 | ||||
|         .modal-footer { | ||||
|             padding: 16px 24px; | ||||
|             border-top: 1px solid #eee; | ||||
|             display: flex; | ||||
|             gap: 12px; | ||||
|         } | ||||
| 
 | ||||
|         .modal-btn { | ||||
|             flex: 1; | ||||
|             padding: 12px 16px; | ||||
|             border: none; | ||||
|             border-radius: 8px; | ||||
|             font-size: 16px; | ||||
|             font-weight: 500; | ||||
|             cursor: pointer; | ||||
|             transition: all 0.3s ease; | ||||
|         } | ||||
| 
 | ||||
|         .modal-btn.cancel { | ||||
|             background: #f8f9fa; | ||||
|             color: #666; | ||||
|             border: 1px solid #ddd; | ||||
|         } | ||||
| 
 | ||||
|         .modal-btn.cancel:hover { | ||||
|             background: #e9ecef; | ||||
|             border-color: #adb5bd; | ||||
|         } | ||||
| 
 | ||||
|         .modal-btn.confirm { | ||||
|             background: linear-gradient(135deg, #27ae60 0%, #2ecc71 100%); | ||||
|             color: white; | ||||
|         } | ||||
| 
 | ||||
|         .modal-btn.confirm:hover { | ||||
|             transform: translateY(-1px); | ||||
|             box-shadow: 0 4px 12px rgba(39, 174, 96, 0.3); | ||||
|         } | ||||
| 
 | ||||
|         .info-input { | ||||
|             flex: 1; | ||||
|             padding: 8px 12px; | ||||
|             border: 1px solid #ddd; | ||||
|             border-radius: 6px; | ||||
|             font-size: 14px; | ||||
|             font-weight: 600; | ||||
|             color: #333; | ||||
|             transition: all 0.3s ease; | ||||
|             min-width: 120px; | ||||
|             text-align: right; | ||||
|         } | ||||
| 
 | ||||
|         .info-input:focus { | ||||
|             outline: none; | ||||
|             border-color: #667eea; | ||||
|             box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1); | ||||
|         } | ||||
| 
 | ||||
|         .info-input.highlight { | ||||
|             color: #e74c3c; | ||||
|             border-color: #e74c3c; | ||||
|         } | ||||
| 
 | ||||
|         .info-input.highlight:focus { | ||||
|             border-color: #e74c3c; | ||||
|             box-shadow: 0 0 0 2px rgba(231, 76, 60, 0.1); | ||||
|         } | ||||
| 
 | ||||
|         .info-input::placeholder { | ||||
|             color: #999; | ||||
|             font-weight: normal; | ||||
|         } | ||||
| 
 | ||||
|         .info-input.error { | ||||
|             border-color: #e74c3c; | ||||
|             background-color: #ffeaea; | ||||
|         } | ||||
| 
 | ||||
|         .input-error-message { | ||||
|             color: #e74c3c; | ||||
|             font-size: 12px; | ||||
|             margin-top: 4px; | ||||
|             display: none; | ||||
|         } | ||||
|     </style> | ||||
| </head> | ||||
| <body> | ||||
|     <div class="container"> | ||||
|         <div class="header"> | ||||
|             <h1>积分商城 - 商品管理</h1> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="search-section"> | ||||
|             <div class="search-grid"> | ||||
|                 <div class="input-group"> | ||||
|                     <label for="shopName">店铺</label> | ||||
|                     <input type="text" id="shopName" placeholder="请输入店铺名称"> | ||||
|                 </div> | ||||
|                 <div class="input-group"> | ||||
|                     <label for="productName">商品名称</label> | ||||
|                     <input type="text" id="productName" placeholder="请输入商品名称"> | ||||
|                 </div> | ||||
|                 <div class="input-group"> | ||||
|                     <label for="productId">商品ID</label> | ||||
|                     <input type="text" id="productId" placeholder="请输入商品ID"> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <button class="search-btn" onclick="searchProducts()">查询</button> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="products-section"> | ||||
|             <div class="products-header"> | ||||
|                 <h2>商品列表</h2> | ||||
|             </div> | ||||
|             <div class="product-list" id="productList"> | ||||
|                 <div class="product-card"> | ||||
|                     <div class="product-info"> | ||||
|                         <div class="product-name">猪肉<span class="points-status inactive">普通商品</span></div> | ||||
|                         <div class="product-details"> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">店铺:</span> | ||||
|                                 <span class="detail-value">猪肉铺</span> | ||||
|                             </div> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">ID:</span> | ||||
|                                 <span class="detail-value">1212</span> | ||||
|                             </div> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">库存:</span> | ||||
|                                 <span class="detail-value">150件</span> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="product-price">¥2</div> | ||||
|                     </div> | ||||
|                     <button class="add-btn" onclick="addToPointsMall('1212', '猪肉')">添加为积分商品</button> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="product-card"> | ||||
|                     <div class="product-info"> | ||||
|                         <div class="product-name">牛肉<span class="points-status active">积分商品</span></div> | ||||
|                         <div class="product-details"> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">店铺:</span> | ||||
|                                 <span class="detail-value">牛肉铺</span> | ||||
|                             </div> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">ID:</span> | ||||
|                                 <span class="detail-value">1213</span> | ||||
|                             </div> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">库存:</span> | ||||
|                                 <span class="detail-value">80件</span> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="product-price">¥5</div> | ||||
|                     </div> | ||||
|                     <button class="add-btn" onclick="addToPointsMall('1213', '牛肉')" disabled>已是积分商品</button> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="product-card"> | ||||
|                     <div class="product-info"> | ||||
|                         <div class="product-name">鸡肉<span class="points-status inactive">普通商品</span></div> | ||||
|                         <div class="product-details"> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">店铺:</span> | ||||
|                                 <span class="detail-value">鸡肉铺</span> | ||||
|                             </div> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">ID:</span> | ||||
|                                 <span class="detail-value">1214</span> | ||||
|                             </div> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">库存:</span> | ||||
|                                 <span class="detail-value">200件</span> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="product-price">¥3</div> | ||||
|                     </div> | ||||
|                     <button class="add-btn" onclick="addToPointsMall('1214', '鸡肉')">添加为积分商品</button> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="pagination"> | ||||
|             <button onclick="changePage('prev')" id="prevBtn">Previous</button> | ||||
|             <button class="active" onclick="changePage(1)">1</button> | ||||
|             <button onclick="changePage(2)">2</button> | ||||
|             <button onclick="changePage(3)">3</button> | ||||
|             <button onclick="changePage('next')" id="nextBtn">Next</button> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="toast" id="toast"></div> | ||||
| 
 | ||||
|     <!-- 积分兑换确认弹窗 --> | ||||
|     <div class="modal-overlay" id="exchangeModal"> | ||||
|         <div class="modal-content"> | ||||
|             <div class="modal-header"> | ||||
|                 <h3 class="modal-title">添加积分商品确认</h3> | ||||
|                 <button class="modal-close" onclick="closeExchangeModal()">×</button> | ||||
|             </div> | ||||
|             <div class="modal-body"> | ||||
|                 <div class="exchange-info"> | ||||
|                     <div class="info-item"> | ||||
|                         <span class="info-label">商品名称</span> | ||||
|                         <span class="info-value" id="modalProductName">-</span> | ||||
|                     </div> | ||||
|                     <div class="info-item"> | ||||
|                         <span class="info-label">当前库存</span> | ||||
|                         <span class="info-value" id="modalProductStock">-</span> | ||||
|                     </div> | ||||
|                     <div class="info-item"> | ||||
|                         <span class="info-label">兑换所需积分</span> | ||||
|                         <input type="number" class="info-input highlight" id="modalPointsRequired" min="1" placeholder="请输入积分"> | ||||
|                     </div> | ||||
|                     <div class="info-item"> | ||||
|                         <span class="info-label">最大可兑换数量</span> | ||||
|                         <input type="number" class="info-input" id="modalMaxExchange" min="1" placeholder="请输入数量"> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div class="modal-footer"> | ||||
|                 <button class="modal-btn cancel" onclick="closeExchangeModal()">取消</button> | ||||
|                 <button class="modal-btn confirm" onclick="confirmAddToPointsMall()" id="confirmBtn">确认添加</button> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <script> | ||||
|         let currentPage = 1; | ||||
|         const totalPages = 3; | ||||
| 
 | ||||
|         // 模拟商品数据 | ||||
|         const allProducts = [ | ||||
|             {id: '1212', name: '猪肉', shop: '猪肉铺', price: 2, stock: 150, isPointsProduct: false, pointsRequired: 200, maxExchangeCount: 50}, | ||||
|             {id: '1213', name: '牛肉', shop: '牛肉铺', price: 5, stock: 80, isPointsProduct: true, pointsRequired: 500, maxExchangeCount: 30}, | ||||
|             {id: '1214', name: '鸡肉', shop: '鸡肉铺', price: 3, stock: 200, isPointsProduct: false, pointsRequired: 300, maxExchangeCount: 80}, | ||||
|             {id: '1215', name: '鱼肉', shop: '鱼肉铺', price: 8, stock: 60, isPointsProduct: true, pointsRequired: 800, maxExchangeCount: 25}, | ||||
|             {id: '1216', name: '虾', shop: '海鲜铺', price: 12, stock: 45, isPointsProduct: false, pointsRequired: 1200, maxExchangeCount: 20}, | ||||
|             {id: '1217', name: '蟹', shop: '海鲜铺', price: 25, stock: 30, isPointsProduct: false, pointsRequired: 2500, maxExchangeCount: 15}, | ||||
|         ]; | ||||
| 
 | ||||
|         let filteredProducts = [...allProducts]; | ||||
|         let currentEditingProduct = null; | ||||
| 
 | ||||
|         function showToast(message, type = 'success') { | ||||
|             const toast = document.getElementById('toast'); | ||||
|             toast.textContent = message; | ||||
|             toast.className = `toast ${type} show`; | ||||
|              | ||||
|             setTimeout(() => { | ||||
|                 toast.classList.remove('show'); | ||||
|             }, 3000); | ||||
|         } | ||||
| 
 | ||||
|         function searchProducts() { | ||||
|             const shopName = document.getElementById('shopName').value.trim().toLowerCase(); | ||||
|             const productName = document.getElementById('productName').value.trim().toLowerCase(); | ||||
|             const productId = document.getElementById('productId').value.trim(); | ||||
| 
 | ||||
|             filteredProducts = allProducts.filter(product => { | ||||
|                 const matchShop = !shopName || product.shop.toLowerCase().includes(shopName); | ||||
|                 const matchName = !productName || product.name.toLowerCase().includes(productName); | ||||
|                 const matchId = !productId || product.id.includes(productId); | ||||
|                  | ||||
|                 return matchShop && matchName && matchId; | ||||
|             }); | ||||
| 
 | ||||
|             currentPage = 1; | ||||
|             renderProducts(); | ||||
|             updatePagination(); | ||||
| 
 | ||||
|             if (filteredProducts.length === 0) { | ||||
|                 showToast('未找到匹配的商品', 'error'); | ||||
|             } else { | ||||
|                 showToast(`找到 ${filteredProducts.length} 个商品`); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         function renderProducts() { | ||||
|             const productList = document.getElementById('productList'); | ||||
|             const startIndex = (currentPage - 1) * 3; | ||||
|             const endIndex = startIndex + 3; | ||||
|             const pageProducts = filteredProducts.slice(startIndex, endIndex); | ||||
| 
 | ||||
|             if (pageProducts.length === 0) { | ||||
|                 productList.innerHTML = ` | ||||
|                     <div class="empty-state"> | ||||
|                         <i>📦</i> | ||||
|                         <div>暂无商品数据</div> | ||||
|                     </div> | ||||
|                 `; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             productList.innerHTML = pageProducts.map(product => { | ||||
|                 const statusClass = product.isPointsProduct ? 'active' : 'inactive'; | ||||
|                 const statusText = product.isPointsProduct ? '积分商品' : '普通商品'; | ||||
|                 const buttonText = product.isPointsProduct ? '已是积分商品' : '添加为积分商品'; | ||||
|                 const buttonDisabled = product.isPointsProduct ? 'disabled' : ''; | ||||
|                  | ||||
|                 return ` | ||||
|                 <div class="product-card"> | ||||
|                     <div class="product-info"> | ||||
|                         <div class="product-name">${product.name}<span class="points-status ${statusClass}">${statusText}</span></div> | ||||
|                         <div class="product-details"> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">店铺:</span> | ||||
|                                 <span class="detail-value">${product.shop}</span> | ||||
|                             </div> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">ID:</span> | ||||
|                                 <span class="detail-value">${product.id}</span> | ||||
|                             </div> | ||||
|                             <div class="product-detail"> | ||||
|                                 <span class="detail-label">库存:</span> | ||||
|                                 <span class="detail-value">${product.stock}件</span> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="product-price">¥${product.price}</div> | ||||
|                     </div> | ||||
|                     <button class="add-btn" onclick="addToPointsMall('${product.id}', '${product.name}')" ${buttonDisabled}>${buttonText}</button> | ||||
|                 </div>`; | ||||
|             }).join(''); | ||||
|         } | ||||
| 
 | ||||
|         function addToPointsMall(productId, productName) { | ||||
|             // 检查是否已经是积分商品 | ||||
|             const product = allProducts.find(p => p.id === productId); | ||||
|             if (product && product.isPointsProduct) { | ||||
|                 showToast(`${productName} 已经是积分商品了!`, 'error'); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (product) { | ||||
|                 currentEditingProduct = product; | ||||
|                 showExchangeModal(product); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         function showExchangeModal(product) { | ||||
|             document.getElementById('modalProductName').textContent = product.name; | ||||
|             document.getElementById('modalProductStock').textContent = `${product.stock}件`; | ||||
|             document.getElementById('modalPointsRequired').value = product.pointsRequired; | ||||
|             document.getElementById('modalMaxExchange').value = product.maxExchangeCount; | ||||
|              | ||||
|             // 清除之前的错误状态 | ||||
|             clearInputErrors(); | ||||
|              | ||||
|             document.getElementById('exchangeModal').classList.add('show'); | ||||
|             document.body.style.overflow = 'hidden'; // 防止背景滚动 | ||||
|         } | ||||
| 
 | ||||
|         function closeExchangeModal() { | ||||
|             document.getElementById('exchangeModal').classList.remove('show'); | ||||
|             document.body.style.overflow = 'auto'; | ||||
|             currentEditingProduct = null; | ||||
|         } | ||||
| 
 | ||||
|         function validateInputs() { | ||||
|             const pointsInput = document.getElementById('modalPointsRequired'); | ||||
|             const maxExchangeInput = document.getElementById('modalMaxExchange'); | ||||
|              | ||||
|             let isValid = true; | ||||
|              | ||||
|             // 验证积分输入 | ||||
|             const pointsValue = parseInt(pointsInput.value); | ||||
|             if (!pointsValue || pointsValue < 1) { | ||||
|                 pointsInput.classList.add('error'); | ||||
|                 showToast('兑换所需积分必须大于0', 'error'); | ||||
|                 isValid = false; | ||||
|             } else { | ||||
|                 pointsInput.classList.remove('error'); | ||||
|             } | ||||
|              | ||||
|             // 验证数量输入 | ||||
|             const maxExchangeValue = parseInt(maxExchangeInput.value); | ||||
|             if (!maxExchangeValue || maxExchangeValue < 1) { | ||||
|                 maxExchangeInput.classList.add('error'); | ||||
|                 showToast('最大可兑换数量必须大于0', 'error'); | ||||
|                 isValid = false; | ||||
|             } else if (maxExchangeValue > currentEditingProduct.stock) { | ||||
|                 maxExchangeInput.classList.add('error'); | ||||
|                 showToast('最大可兑换数量不能超过库存数量', 'error'); | ||||
|                 isValid = false; | ||||
|             } else { | ||||
|                 maxExchangeInput.classList.remove('error'); | ||||
|             } | ||||
|              | ||||
|             return isValid; | ||||
|         } | ||||
|          | ||||
|         function clearInputErrors() { | ||||
|             document.getElementById('modalPointsRequired').classList.remove('error'); | ||||
|             document.getElementById('modalMaxExchange').classList.remove('error'); | ||||
|         } | ||||
| 
 | ||||
|         function confirmAddToPointsMall() { | ||||
|             if (!currentEditingProduct) return; | ||||
|              | ||||
|             // 验证输入 | ||||
|             if (!validateInputs()) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             const confirmBtn = document.getElementById('confirmBtn'); | ||||
|             const pointsRequired = parseInt(document.getElementById('modalPointsRequired').value); | ||||
|             const maxExchangeCount = parseInt(document.getElementById('modalMaxExchange').value); | ||||
|              | ||||
|             confirmBtn.disabled = true; | ||||
|             confirmBtn.textContent = '添加中...'; | ||||
| 
 | ||||
|             setTimeout(() => { | ||||
|                 // 更新数据状态,使用用户输入的值 | ||||
|                 currentEditingProduct.isPointsProduct = true; | ||||
|                 currentEditingProduct.pointsRequired = pointsRequired; | ||||
|                 currentEditingProduct.maxExchangeCount = maxExchangeCount; | ||||
|                  | ||||
|                 // 重新渲染当前页面 | ||||
|                 renderProducts(); | ||||
|                  | ||||
|                 // 关闭弹窗 | ||||
|                 closeExchangeModal(); | ||||
|                  | ||||
|                 // 恢复按钮状态 | ||||
|                 confirmBtn.disabled = false; | ||||
|                 confirmBtn.textContent = '确认添加'; | ||||
|                  | ||||
|                 showToast(`${currentEditingProduct.name} 已成功添加到积分商城!需要${pointsRequired}积分,最多可兑换${maxExchangeCount}件`); | ||||
|             }, 1000); | ||||
|         } | ||||
| 
 | ||||
|         function changePage(page) { | ||||
|             if (page === 'prev' && currentPage > 1) { | ||||
|                 currentPage--; | ||||
|             } else if (page === 'next' && currentPage < Math.ceil(filteredProducts.length / 3)) { | ||||
|                 currentPage++; | ||||
|             } else if (typeof page === 'number') { | ||||
|                 currentPage = page; | ||||
|             } | ||||
| 
 | ||||
|             renderProducts(); | ||||
|             updatePagination(); | ||||
|         } | ||||
| 
 | ||||
|         function updatePagination() { | ||||
|             const maxPages = Math.ceil(filteredProducts.length / 3); | ||||
|             const prevBtn = document.getElementById('prevBtn'); | ||||
|             const nextBtn = document.getElementById('nextBtn'); | ||||
| 
 | ||||
|             prevBtn.disabled = currentPage === 1; | ||||
|             nextBtn.disabled = currentPage === maxPages || maxPages === 0; | ||||
| 
 | ||||
|             // 更新页码按钮 | ||||
|             const pageButtons = document.querySelectorAll('.pagination button:not(#prevBtn):not(#nextBtn)'); | ||||
|             pageButtons.forEach((btn, index) => { | ||||
|                 const pageNum = index + 1; | ||||
|                 btn.style.display = pageNum <= maxPages ? 'block' : 'none'; | ||||
|                 btn.classList.toggle('active', pageNum === currentPage); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // 初始化页面 | ||||
|         document.addEventListener('DOMContentLoaded', function() { | ||||
|             renderProducts(); | ||||
|             updatePagination(); | ||||
| 
 | ||||
|             // 添加输入框回车搜索功能 | ||||
|             document.addEventListener('keypress', function(e) { | ||||
|                 if (e.key === 'Enter') { | ||||
|                     searchProducts(); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             // 点击弹窗背景关闭弹窗 | ||||
|             document.getElementById('exchangeModal').addEventListener('click', function(e) { | ||||
|                 if (e.target === this) { | ||||
|                     closeExchangeModal(); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             // ESC键关闭弹窗 | ||||
|             document.addEventListener('keydown', function(e) { | ||||
|                 if (e.key === 'Escape') { | ||||
|                     closeExchangeModal(); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             // 输入框实时验证 | ||||
|             document.getElementById('modalPointsRequired').addEventListener('input', function() { | ||||
|                 if (this.classList.contains('error')) { | ||||
|                     this.classList.remove('error'); | ||||
|                 } | ||||
|             }); | ||||
|              | ||||
|             document.getElementById('modalMaxExchange').addEventListener('input', function() { | ||||
|                 if (this.classList.contains('error')) { | ||||
|                     this.classList.remove('error'); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|     </script> | ||||
| </body> | ||||
| </html> | ||||
		Loading…
	
		Reference in New Issue