综述: 新增用户端APP订单管理模块页面
- 新增订单列表页面 (`order-list.html`),包含订单分类标签栏、订单卡片展示等功能 - 新增订单详情页面 (`order-detail.html`),展示订单商品信息、配送信息、订单信息等 - 新增订单退款页面 (`order-refund.html`),支持售后申请和退款流程展示
This commit is contained in:
		
							parent
							
								
									c56b88d0ae
								
							
						
					
					
						commit
						6a08901a82
					
				|  | @ -0,0 +1,748 @@ | |||
| <!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', 'Helvetica Neue', Arial, sans-serif; | ||||
|             background-color: #f7f7f7; | ||||
|             padding-bottom: 80px; | ||||
|         } | ||||
| 
 | ||||
|         .header { | ||||
|             background-color: #013820; | ||||
|             color: white; | ||||
|             padding: 15px 20px; | ||||
|             font-size: 20px; | ||||
|             font-weight: bold; | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: space-between; | ||||
|             position: sticky; | ||||
|             top: 0; | ||||
|             z-index: 100; | ||||
|         } | ||||
| 
 | ||||
|         .back-btn { | ||||
|             width: 24px; | ||||
|             height: 24px; | ||||
|             cursor: pointer; | ||||
|         } | ||||
| 
 | ||||
|         .title-text { | ||||
|             flex: 1; | ||||
|             margin: 0 10px; | ||||
|         } | ||||
| 
 | ||||
|         .contact-icon { | ||||
|             width: 20px; | ||||
|             height: 20px; | ||||
|             cursor: pointer; | ||||
|         } | ||||
| 
 | ||||
|         .content { | ||||
|             padding: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .card { | ||||
|             background-color: white; | ||||
|             border-radius: 8px; | ||||
|             padding: 10px; | ||||
|             margin-bottom: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .shop-header { | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             align-items: center; | ||||
|             margin-bottom: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .shop-info { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             cursor: pointer; | ||||
|         } | ||||
| 
 | ||||
|         .shop-icon { | ||||
|             width: 11px; | ||||
|             height: 10px; | ||||
|             margin-right: 7px; | ||||
|         } | ||||
| 
 | ||||
|         .shop-name { | ||||
|             font-size: 13px; | ||||
|             font-weight: bold; | ||||
|             color: #1f1f1f; | ||||
|             margin-right: 7px; | ||||
|         } | ||||
| 
 | ||||
|         .market-name { | ||||
|             font-size: 11px; | ||||
|             color: #575859; | ||||
|         } | ||||
| 
 | ||||
|         .arrow-right { | ||||
|             width: 4px; | ||||
|             height: 7px; | ||||
|         } | ||||
| 
 | ||||
|         .product-list { | ||||
|             margin-top: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .product-item { | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             margin-bottom: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .product-left { | ||||
|             display: flex; | ||||
|         } | ||||
| 
 | ||||
|         .product-img { | ||||
|             width: 46px; | ||||
|             height: 46px; | ||||
|             border-radius: 8px; | ||||
|             margin-right: 10px; | ||||
|             cursor: pointer; | ||||
|             background: linear-gradient(135deg, #e0e0e0 0%, #f5f5f5 100%); | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             font-size: 24px; | ||||
|             border: 1px solid #ddd; | ||||
|             flex-shrink: 0; | ||||
|         } | ||||
| 
 | ||||
|         .product-info { | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|             gap: 2px; | ||||
|             color: #808080; | ||||
|         } | ||||
| 
 | ||||
|         .product-name { | ||||
|             font-size: 13px; | ||||
|             color: #1f1f1f; | ||||
|         } | ||||
| 
 | ||||
|         .product-spec { | ||||
|             font-size: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .product-right { | ||||
|             display: flex; | ||||
|             align-items: flex-start; | ||||
|             color: #ff6300; | ||||
|         } | ||||
| 
 | ||||
|         .product-right .label { | ||||
|             font-size: 13px; | ||||
|         } | ||||
| 
 | ||||
|         .product-right .price { | ||||
|             font-size: 14px; | ||||
|             font-weight: bold; | ||||
|         } | ||||
| 
 | ||||
|         .divider { | ||||
|             height: 1px; | ||||
|             background-color: #ededed; | ||||
|             margin: 15px 0; | ||||
|         } | ||||
| 
 | ||||
|         .price-row { | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             align-items: center; | ||||
|             margin-bottom: 8px; | ||||
|         } | ||||
| 
 | ||||
|         .price-label { | ||||
|             font-size: 13px; | ||||
|             color: #1f1f1f; | ||||
|         } | ||||
| 
 | ||||
|         .price-value { | ||||
|             font-size: 14px; | ||||
|             font-weight: bold; | ||||
|         } | ||||
| 
 | ||||
|         .price-value.discount { | ||||
|             color: #ff6300; | ||||
|         } | ||||
| 
 | ||||
|         .total-price { | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             align-items: center; | ||||
|             font-weight: bold; | ||||
|         } | ||||
| 
 | ||||
|         .total-price .label { | ||||
|             font-size: 13px; | ||||
|             color: #1f1f1f; | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             cursor: pointer; | ||||
|         } | ||||
| 
 | ||||
|         .toggle-icon { | ||||
|             width: 4px; | ||||
|             height: 7px; | ||||
|             margin-left: 8px; | ||||
|             transform: rotate(90deg); | ||||
|         } | ||||
| 
 | ||||
|         .toggle-icon.up { | ||||
|             transform: rotate(-90deg); | ||||
|         } | ||||
| 
 | ||||
|         .total-price .value { | ||||
|             font-size: 19px; | ||||
|             color: #ff6300; | ||||
|         } | ||||
| 
 | ||||
|         .section-title { | ||||
|             font-size: 13px; | ||||
|             font-weight: bold; | ||||
|             color: #1f1f1f; | ||||
|             margin-bottom: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .info-row { | ||||
|             display: flex; | ||||
|             margin: 10px 0; | ||||
|         } | ||||
| 
 | ||||
|         .info-label { | ||||
|             width: 85px; | ||||
|             font-size: 13px; | ||||
|             color: #808080; | ||||
|         } | ||||
| 
 | ||||
|         .info-value { | ||||
|             width: calc(100% - 85px); | ||||
|             font-size: 13px; | ||||
|             color: #1f1f1f; | ||||
|         } | ||||
| 
 | ||||
|         .copy-btn { | ||||
|             color: #808080; | ||||
|             margin-left: 8px; | ||||
|             cursor: pointer; | ||||
|         } | ||||
| 
 | ||||
|         .copy-btn:hover { | ||||
|             color: #013820; | ||||
|         } | ||||
| 
 | ||||
|         .footer { | ||||
|             position: fixed; | ||||
|             bottom: 0; | ||||
|             left: 0; | ||||
|             right: 0; | ||||
|             background-color: white; | ||||
|             padding: 15px 25px; | ||||
|             display: flex; | ||||
|             justify-content: flex-end; | ||||
|             gap: 15px; | ||||
|             box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); | ||||
|         } | ||||
| 
 | ||||
|         .btn { | ||||
|             padding: 10px 25px; | ||||
|             border-radius: 4px; | ||||
|             border: 1px solid; | ||||
|             font-size: 14px; | ||||
|             cursor: pointer; | ||||
|             transition: all 0.3s; | ||||
|             min-width: 85px; | ||||
|             text-align: center; | ||||
|         } | ||||
| 
 | ||||
|         .btn-primary { | ||||
|             background-color: #013820; | ||||
|             color: white; | ||||
|             border-color: #013820; | ||||
|         } | ||||
| 
 | ||||
|         .btn-primary:hover { | ||||
|             background-color: #025530; | ||||
|         } | ||||
| 
 | ||||
|         .btn-info { | ||||
|             background-color: white; | ||||
|             color: #013820; | ||||
|             border-color: #dcdcdc; | ||||
|         } | ||||
| 
 | ||||
|         .btn-info:hover { | ||||
|             background-color: #f5f5f5; | ||||
|         } | ||||
| 
 | ||||
|         .hidden { | ||||
|             display: none; | ||||
|         } | ||||
| 
 | ||||
|         .view-all { | ||||
|             display: flex; | ||||
|             justify-content: center; | ||||
|             align-items: center; | ||||
|             margin: 10px 0; | ||||
|             cursor: pointer; | ||||
|         } | ||||
| 
 | ||||
|         .view-all-text { | ||||
|             font-size: 11px; | ||||
|             color: #808080; | ||||
|         } | ||||
| 
 | ||||
|         .view-all .arrow { | ||||
|             width: 4px; | ||||
|             height: 7px; | ||||
|             margin-left: 5px; | ||||
|         } | ||||
| 
 | ||||
|         .arrow.down { | ||||
|             transform: rotate(90deg); | ||||
|         } | ||||
| 
 | ||||
|         .arrow.up { | ||||
|             transform: rotate(-90deg); | ||||
|         } | ||||
|     </style> | ||||
| </head> | ||||
| <body> | ||||
|     <div class="header"> | ||||
|         <span class="back-btn" onclick="goBack()">◀</span> | ||||
|         <span class="title-text" id="pageTitle">订单详情</span> | ||||
|         <span class="contact-icon" onclick="contactMerchant()">💬</span> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="content"> | ||||
|         <!-- 店铺和商品信息 --> | ||||
|         <div class="card"> | ||||
|             <div id="shopOrdersContainer"> | ||||
|                 <!-- 动态生成店铺订单 --> | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="divider"></div> | ||||
| 
 | ||||
|             <!-- 价格明细 --> | ||||
|             <div id="priceDetail" class="hidden"> | ||||
|                 <!-- 动态生成价格明细 --> | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="total-price"> | ||||
|                 <div class="label" onclick="togglePriceDetail()"> | ||||
|                     实付款 | ||||
|                     <span class="toggle-icon" id="toggleIcon">›</span> | ||||
|                 </div> | ||||
|                 <div class="value"> | ||||
|                     ¥<span id="totalMoney">0.00</span> | ||||
|                 </div> | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="footer" style="position: relative; padding: 15px 0; margin-top: 15px;"> | ||||
|                 <button class="btn btn-info" id="refundBtn" onclick="applyRefund()">申请售后</button> | ||||
|                 <button class="btn btn-primary" onclick="contactMerchant()">联系商家</button> | ||||
|                 <button class="btn btn-primary" id="callBtn" onclick="callMerchant()">致电商家</button> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- 配送信息 --> | ||||
|         <div class="card"> | ||||
|             <div class="section-title">配送信息</div> | ||||
|             <div class="info-row"> | ||||
|                 <div class="info-label">配送方式</div> | ||||
|                 <div class="info-value" id="deliveryType">同城配送</div> | ||||
|             </div> | ||||
|             <div class="info-row" id="pickAddressRow" class="hidden"> | ||||
|                 <div class="info-label">自提点地址</div> | ||||
|                 <div class="info-value" id="pickAddress"></div> | ||||
|             </div> | ||||
|             <div class="info-row" id="expressCompanyRow" class="hidden"> | ||||
|                 <div class="info-label">快递公司</div> | ||||
|                 <div class="info-value" id="expressCompany"></div> | ||||
|             </div> | ||||
|             <div class="info-row" id="expressNoRow" class="hidden"> | ||||
|                 <div class="info-label">快递单号</div> | ||||
|                 <div class="info-value"> | ||||
|                     <span id="expressNo"></span> | ||||
|                     <span class="copy-btn" onclick="copyText('expressNo')">复制</span> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div class="info-row"> | ||||
|                 <div class="info-label">收货地址</div> | ||||
|                 <div class="info-value" id="receiverInfo"> | ||||
|                     <div id="receiverAddress"></div> | ||||
|                     <div id="receiverContact"></div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <!-- 订单信息 --> | ||||
|         <div class="card"> | ||||
|             <div class="section-title">订单信息</div> | ||||
|             <div class="info-row"> | ||||
|                 <div class="info-label">订单备注</div> | ||||
|                 <div class="info-value" id="orderRemark">无</div> | ||||
|             </div> | ||||
|             <div class="info-row" style="cursor: pointer;" onclick="copyText('unitOrderNo')"> | ||||
|                 <div class="info-label">订单编号</div> | ||||
|                 <div class="info-value" id="unitOrderNo"></div> | ||||
|             </div> | ||||
|             <div class="info-row"> | ||||
|                 <div class="info-label">下单时间</div> | ||||
|                 <div class="info-value" id="createTime"></div> | ||||
|             </div> | ||||
|             <div class="info-row" id="preSaleStageRow" class="hidden"> | ||||
|                 <div class="info-label">预售状态</div> | ||||
|                 <div class="info-value" id="preSaleStage"></div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <script> | ||||
|         // 从URL获取订单编号 | ||||
|         function getQueryParam(name) { | ||||
|             const urlParams = new URLSearchParams(window.location.search); | ||||
|             return urlParams.get(name); | ||||
|         } | ||||
| 
 | ||||
|         const unitOrderNo = getQueryParam('unitOrderNo'); | ||||
| 
 | ||||
|         // 模拟订单详情数据 | ||||
|         const mockOrderDetail = { | ||||
|             unitOrderNo: unitOrderNo || 'ORDER20250116001', | ||||
|             unitType: 2, | ||||
|             status: 1, | ||||
|             refundStatus: 0, | ||||
|             orderCategory: 1, | ||||
|             marketName: '大妈集市', | ||||
|             marketId: '1001', | ||||
|             shopId: '2001', | ||||
|             totalMoney: 88.50, | ||||
|             productMoney: 80.00, | ||||
|             packageMoney: 2.00, | ||||
|             deliveryMoney: 8.00, | ||||
|             couponMoney: 1.50, | ||||
|             dispatchMoney: 0, | ||||
|             dispatchMode: 0, | ||||
|             deliveryType: 1, // 0:自提 1:同城配送 2:全国快递 | ||||
|             pickAddress: '', | ||||
|             expressCompany: '', | ||||
|             expressNo: '', | ||||
|             receiver: { | ||||
|                 poi: '北京市朝阳区某某小区', | ||||
|                 detail: '1号楼2单元302', | ||||
|                 receiverName: '张三', | ||||
|                 receiverPhone: '13800138000' | ||||
|             }, | ||||
|             remark: '请尽快配送', | ||||
|             createTime: '2025-01-16 10:30:00', | ||||
|             contactPhone: '400-123-4567', | ||||
|             shopOrders: [ | ||||
|                 { | ||||
|                     shopName: '新鲜蔬菜店', | ||||
|                     shopId: '2001', | ||||
|                     products: [ | ||||
|                         { | ||||
|                             productId: '3001', | ||||
|                             productName: '新鲜白菜', | ||||
|                             productImg: '🥬', | ||||
|                             productSpecName: '500g/份', | ||||
|                             originPrice: 5.00, | ||||
|                             finalPrice: 4.50, | ||||
|                             productCount: 2 | ||||
|                         }, | ||||
|                         { | ||||
|                             productId: '3002', | ||||
|                             productName: '有机西红柿', | ||||
|                             productImg: '🍅', | ||||
|                             productSpecName: '1kg/份', | ||||
|                             originPrice: 12.00, | ||||
|                             finalPrice: 11.50, | ||||
|                             productCount: 3 | ||||
|                         }, | ||||
|                         { | ||||
|                             productId: '3003', | ||||
|                             productName: '新鲜土豆', | ||||
|                             productImg: '🥔', | ||||
|                             productSpecName: '500g/份', | ||||
|                             originPrice: 6.00, | ||||
|                             finalPrice: 5.50, | ||||
|                             productCount: 1 | ||||
|                         }, | ||||
|                         { | ||||
|                             productId: '3004', | ||||
|                             productName: '农家黄瓜', | ||||
|                             productImg: '🥒', | ||||
|                             productSpecName: '500g/份', | ||||
|                             originPrice: 8.00, | ||||
|                             finalPrice: 7.50, | ||||
|                             productCount: 2 | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             ] | ||||
|         }; | ||||
| 
 | ||||
|         let showAllProducts = false; | ||||
|         let showPriceDetail = false; | ||||
| 
 | ||||
|         // 初始化页面 | ||||
|         function init() { | ||||
|             renderOrderDetail(mockOrderDetail); | ||||
|         } | ||||
| 
 | ||||
|         // 渲染订单详情 | ||||
|         function renderOrderDetail(order) { | ||||
|             // 设置标题 | ||||
|             const title = getOrderTitle(order); | ||||
|             document.getElementById('pageTitle').textContent = title; | ||||
| 
 | ||||
|             // 设置总价 | ||||
|             document.getElementById('totalMoney').textContent = order.totalMoney.toFixed(2); | ||||
| 
 | ||||
|             // 渲染店铺订单 | ||||
|             const shopOrdersContainer = document.getElementById('shopOrdersContainer'); | ||||
|             shopOrdersContainer.innerHTML = order.shopOrders.map((shopOrder, shopIndex) => { | ||||
|                 const productCount = shopOrder.products.length; | ||||
|                 const displayProducts = showAllProducts ? shopOrder.products : shopOrder.products.slice(0, 3); | ||||
|                 const remainingProducts = showAllProducts ? [] : shopOrder.products.slice(3); | ||||
| 
 | ||||
|                 return ` | ||||
|                     <div class="shop-order"> | ||||
|                         <div class="shop-header"> | ||||
|                             <div class="shop-info"> | ||||
|                                 <span class="shop-icon">🏪</span> | ||||
|                                 <span class="shop-name">${shopOrder.shopName}</span> | ||||
|                                 <span class="market-name">(${order.marketName})</span> | ||||
|                             </div> | ||||
|                             <span class="arrow-right">›</span> | ||||
|                         </div> | ||||
|                         <div class="product-list"> | ||||
|                             ${displayProducts.map(product => ` | ||||
|                                 <div class="product-item"> | ||||
|                                     <div class="product-left"> | ||||
|                                         <div class="product-img" onclick="toProduct('${product.productId}')">${product.productImg}</div> | ||||
|                                         <div class="product-info"> | ||||
|                                             <div class="product-name">${product.productName}</div> | ||||
|                                             <div class="product-spec">规格:${product.productSpecName}</div> | ||||
|                                             <div class="product-spec">单价:¥${product.originPrice.toFixed(2)}</div> | ||||
|                                             <div class="product-spec">数量:${product.productCount}</div> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                     <div class="product-right"> | ||||
|                                         <span class="label">实付</span> | ||||
|                                         <span class="price">¥${product.finalPrice.toFixed(2)}</span> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             `).join('')} | ||||
|                             ${productCount > 3 && !showAllProducts ? ` | ||||
|                                 <div class="view-all" onclick="toggleProducts()"> | ||||
|                                     <span class="view-all-text">查看全部</span> | ||||
|                                     <span class="arrow down">›</span> | ||||
|                                 </div> | ||||
|                             ` : ''} | ||||
|                             ${remainingProducts.length > 0 && showAllProducts ? ` | ||||
|                                 ${remainingProducts.map(product => ` | ||||
|                                     <div class="product-item"> | ||||
|                                         <div class="product-left"> | ||||
|                                             <div class="product-img" onclick="toProduct('${product.productId}')">${product.productImg}</div> | ||||
|                                             <div class="product-info"> | ||||
|                                                 <div class="product-name">${product.productName}</div> | ||||
|                                                 <div class="product-spec">规格:${product.productSpecName}</div> | ||||
|                                                 <div class="product-spec">单价:¥${product.originPrice.toFixed(2)}</div> | ||||
|                                                 <div class="product-spec">数量:${product.productCount}</div> | ||||
|                                             </div> | ||||
|                                         </div> | ||||
|                                         <div class="product-right"> | ||||
|                                             <span class="label">实付</span> | ||||
|                                             <span class="price">¥${product.finalPrice.toFixed(2)}</span> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 `).join('')} | ||||
|                             ` : ''} | ||||
|                             ${showAllProducts && productCount > 3 ? ` | ||||
|                                 <div class="view-all" onclick="toggleProducts()"> | ||||
|                                     <span class="view-all-text">收起全部</span> | ||||
|                                     <span class="arrow up">›</span> | ||||
|                                 </div> | ||||
|                             ` : ''} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 `; | ||||
|             }).join(''); | ||||
| 
 | ||||
|             // 渲染价格明细 | ||||
|             const priceDetailHtml = ` | ||||
|                 ${order.orderCategory === 1 ? ` | ||||
|                     <div class="price-row"> | ||||
|                         <div class="price-label">商品金额</div> | ||||
|                         <div class="price-value">¥${order.productMoney.toFixed(2)}</div> | ||||
|                     </div> | ||||
|                 ` : ''} | ||||
|                 <div class="price-row"> | ||||
|                     <div class="price-label">包装费</div> | ||||
|                     <div class="price-value">¥${order.packageMoney.toFixed(2)}</div> | ||||
|                 </div> | ||||
|                 ${order.dispatchMode === 1 ? ` | ||||
|                     <div class="price-row"> | ||||
|                         <div class="price-label">调度费(多店铺)</div> | ||||
|                         <div class="price-value">¥${order.dispatchMoney.toFixed(2)}</div> | ||||
|                     </div> | ||||
|                 ` : ''} | ||||
|                 <div class="price-row"> | ||||
|                     <div class="price-label">配送费</div> | ||||
|                     <div class="price-value">¥${order.deliveryMoney.toFixed(2)}</div> | ||||
|                 </div> | ||||
|                 <div class="price-row"> | ||||
|                     <div class="price-label">优惠券</div> | ||||
|                     <div class="price-value discount">-¥${order.couponMoney.toFixed(2)}</div> | ||||
|                 </div> | ||||
|             `; | ||||
|             document.getElementById('priceDetail').innerHTML = priceDetailHtml; | ||||
| 
 | ||||
|             // 配送信息 | ||||
|             const deliveryTypeText = order.deliveryType === 0 ? '自提' : | ||||
|                                     order.deliveryType === 1 ? '同城配送' : '全国快递'; | ||||
|             document.getElementById('deliveryType').textContent = deliveryTypeText; | ||||
| 
 | ||||
|             if (order.deliveryType === 0 && order.pickAddress) { | ||||
|                 document.getElementById('pickAddressRow').classList.remove('hidden'); | ||||
|                 document.getElementById('pickAddress').textContent = order.pickAddress; | ||||
|             } | ||||
| 
 | ||||
|             if (order.deliveryType === 2) { | ||||
|                 if (order.expressCompany) { | ||||
|                     document.getElementById('expressCompanyRow').classList.remove('hidden'); | ||||
|                     document.getElementById('expressCompany').textContent = order.expressCompany; | ||||
|                 } | ||||
|                 if (order.expressNo) { | ||||
|                     document.getElementById('expressNoRow').classList.remove('hidden'); | ||||
|                     document.getElementById('expressNo').textContent = order.expressNo; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             document.getElementById('receiverAddress').textContent = | ||||
|                 order.receiver.poi + order.receiver.detail; | ||||
|             document.getElementById('receiverContact').textContent = | ||||
|                 order.receiver.receiverName + ' ' + order.receiver.receiverPhone; | ||||
| 
 | ||||
|             // 订单信息 | ||||
|             document.getElementById('orderRemark').textContent = order.remark || '无'; | ||||
|             document.getElementById('unitOrderNo').textContent = order.unitOrderNo; | ||||
|             document.getElementById('createTime').textContent = order.createTime; | ||||
| 
 | ||||
|             // 显示/隐藏申请售后按钮 | ||||
|             if (order.refundStatus === 0 && order.status < 5) { | ||||
|                 document.getElementById('refundBtn').classList.remove('hidden'); | ||||
|             } else { | ||||
|                 document.getElementById('refundBtn').classList.add('hidden'); | ||||
|             } | ||||
| 
 | ||||
|             // 显示/隐藏致电商家按钮 | ||||
|             if (!order.contactPhone) { | ||||
|                 document.getElementById('callBtn').classList.add('hidden'); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 获取订单标题 | ||||
|         function getOrderTitle(order) { | ||||
|             const { status, refundStatus } = order; | ||||
| 
 | ||||
|             if (refundStatus === -2) { | ||||
|                 return '申请退款中'; | ||||
|             } | ||||
| 
 | ||||
|             switch (status) { | ||||
|                 case 0: return '待付款'; | ||||
|                 case 1: return '待发货'; | ||||
|                 case 2: return '已取货'; | ||||
|                 case 3: return '待收货'; | ||||
|                 case 5: return '已完成'; | ||||
|                 case 6: return '已取消'; | ||||
|                 case 7: return '退款中'; | ||||
|                 case 8: return '已退款'; | ||||
|                 default: return '订单详情'; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 切换商品显示 | ||||
|         function toggleProducts() { | ||||
|             showAllProducts = !showAllProducts; | ||||
|             renderOrderDetail(mockOrderDetail); | ||||
|         } | ||||
| 
 | ||||
|         // 切换价格明细 | ||||
|         function togglePriceDetail() { | ||||
|             showPriceDetail = !showPriceDetail; | ||||
|             const priceDetail = document.getElementById('priceDetail'); | ||||
|             const toggleIcon = document.getElementById('toggleIcon'); | ||||
| 
 | ||||
|             if (showPriceDetail) { | ||||
|                 priceDetail.classList.remove('hidden'); | ||||
|                 toggleIcon.classList.add('up'); | ||||
|             } else { | ||||
|                 priceDetail.classList.add('hidden'); | ||||
|                 toggleIcon.classList.remove('up'); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 返回上一页 | ||||
|         function goBack() { | ||||
|             window.history.back(); | ||||
|         } | ||||
| 
 | ||||
|         // 跳转到商品详情 | ||||
|         function toProduct(productId) { | ||||
|             console.log('跳转到商品详情:', productId); | ||||
|         } | ||||
| 
 | ||||
|         // 联系商家 | ||||
|         function contactMerchant() { | ||||
|             console.log('联系商家'); | ||||
|             alert('打开聊天窗口'); | ||||
|         } | ||||
| 
 | ||||
|         // 致电商家 | ||||
|         function callMerchant() { | ||||
|             if (mockOrderDetail.contactPhone) { | ||||
|                 window.location.href = `tel:${mockOrderDetail.contactPhone}`; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 申请售后 | ||||
|         function applyRefund() { | ||||
|             console.log('申请售后'); | ||||
|             window.location.href = `refund-standalone.html?unitOrderNo=${mockOrderDetail.unitOrderNo}`; | ||||
|         } | ||||
| 
 | ||||
|         // 复制文本 | ||||
|         function copyText(elementId) { | ||||
|             const text = document.getElementById(elementId).textContent; | ||||
|             navigator.clipboard.writeText(text).then(() => { | ||||
|                 alert('复制成功'); | ||||
|             }).catch(() => { | ||||
|                 alert('复制失败'); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // 页面加载完成后初始化 | ||||
|         document.addEventListener('DOMContentLoaded', init); | ||||
|     </script> | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,531 @@ | |||
| <!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', 'Helvetica Neue', Arial, sans-serif; | ||||
|             background-color: #f7f7f7; | ||||
|         } | ||||
| 
 | ||||
|         .header { | ||||
|             background-color: #013820; | ||||
|             color: white; | ||||
|             padding: 15px 20px; | ||||
|             font-size: 18px; | ||||
|             font-weight: bold; | ||||
|             text-align: center; | ||||
|             position: sticky; | ||||
|             top: 0; | ||||
|             z-index: 100; | ||||
|         } | ||||
| 
 | ||||
|         .tabs { | ||||
|             background-color: white; | ||||
|             display: flex; | ||||
|             justify-content: space-around; | ||||
|             padding: 12px 0; | ||||
|             position: sticky; | ||||
|             top: 48px; | ||||
|             z-index: 99; | ||||
|             box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||||
|         } | ||||
| 
 | ||||
|         .tab-item { | ||||
|             font-size: 15px; | ||||
|             color: #1f1f1f; | ||||
|             cursor: pointer; | ||||
|             padding: 8px 16px; | ||||
|             position: relative; | ||||
|             transition: all 0.3s; | ||||
|         } | ||||
| 
 | ||||
|         .tab-item.active { | ||||
|             font-size: 18px; | ||||
|             font-weight: bold; | ||||
|             color: #1f1f1f; | ||||
|         } | ||||
| 
 | ||||
|         .tab-item.active::after { | ||||
|             content: ''; | ||||
|             position: absolute; | ||||
|             bottom: -6px; | ||||
|             left: 50%; | ||||
|             transform: translateX(-50%); | ||||
|             width: 100%; | ||||
|             height: 7px; | ||||
|             background: linear-gradient(150deg, #FFC534 0%, #FF8421 100%); | ||||
|             border-radius: 4px; | ||||
|         } | ||||
| 
 | ||||
|         .order-list { | ||||
|             padding: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .order-card { | ||||
|             background-color: white; | ||||
|             border-radius: 8px; | ||||
|             padding: 10px; | ||||
|             margin-bottom: 10px; | ||||
|             cursor: pointer; | ||||
|         } | ||||
| 
 | ||||
|         .order-header { | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             align-items: center; | ||||
|             margin-bottom: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .shop-info { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|         } | ||||
| 
 | ||||
|         .shop-icon { | ||||
|             width: 13px; | ||||
|             height: 12px; | ||||
|             margin-right: 7px; | ||||
|         } | ||||
| 
 | ||||
|         .shop-name { | ||||
|             font-size: 15px; | ||||
|             font-weight: bold; | ||||
|             color: #1f1f1f; | ||||
|             margin-right: 7px; | ||||
|         } | ||||
| 
 | ||||
|         .market-name { | ||||
|             font-size: 15px; | ||||
|             color: #575859; | ||||
|         } | ||||
| 
 | ||||
|         .order-status { | ||||
|             font-size: 15px; | ||||
|         } | ||||
| 
 | ||||
|         .status-normal { | ||||
|             color: #808080; | ||||
|         } | ||||
| 
 | ||||
|         .status-important { | ||||
|             color: #FF6300; | ||||
|         } | ||||
| 
 | ||||
|         .order-content { | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             align-items: center; | ||||
|             padding: 10px 0; | ||||
|         } | ||||
| 
 | ||||
|         .product-images { | ||||
|             display: flex; | ||||
|             gap: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .product-img { | ||||
|             width: 68px; | ||||
|             height: 68px; | ||||
|             border-radius: 8px; | ||||
|             background: linear-gradient(135deg, #e0e0e0 0%, #f5f5f5 100%); | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             font-size: 32px; | ||||
|             border: 1px solid #ddd; | ||||
|         } | ||||
| 
 | ||||
|         .order-price { | ||||
|             text-align: right; | ||||
|         } | ||||
| 
 | ||||
|         .price-value { | ||||
|             font-size: 21px; | ||||
|             color: #1f1f1f; | ||||
|         } | ||||
| 
 | ||||
|         .price-symbol { | ||||
|             font-size: 15px; | ||||
|             position: relative; | ||||
|             bottom: 2px; | ||||
|         } | ||||
| 
 | ||||
|         .product-count { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: flex-end; | ||||
|             margin-top: 5px; | ||||
|             color: #808080; | ||||
|             font-size: 13px; | ||||
|         } | ||||
| 
 | ||||
|         .arrow-icon { | ||||
|             width: 4px; | ||||
|             height: 7px; | ||||
|             margin-left: 4px; | ||||
|         } | ||||
| 
 | ||||
|         .order-actions { | ||||
|             display: flex; | ||||
|             justify-content: flex-end; | ||||
|             gap: 10px; | ||||
|             margin-top: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .btn { | ||||
|             padding: 8px 20px; | ||||
|             border-radius: 4px; | ||||
|             border: 1px solid; | ||||
|             font-size: 14px; | ||||
|             cursor: pointer; | ||||
|             transition: all 0.3s; | ||||
|         } | ||||
| 
 | ||||
|         .btn-primary { | ||||
|             background-color: #013820; | ||||
|             color: white; | ||||
|             border-color: #013820; | ||||
|         } | ||||
| 
 | ||||
|         .btn-primary:hover { | ||||
|             background-color: #025530; | ||||
|         } | ||||
| 
 | ||||
|         .btn-info { | ||||
|             background-color: white; | ||||
|             color: #013820; | ||||
|             border-color: #013820; | ||||
|         } | ||||
| 
 | ||||
|         .btn-info:hover { | ||||
|             background-color: #f5f5f5; | ||||
|         } | ||||
| 
 | ||||
|         .empty-view { | ||||
|             text-align: center; | ||||
|             padding: 50px 20px; | ||||
|             color: #999; | ||||
|             font-size: 14px; | ||||
|         } | ||||
| 
 | ||||
|         .hidden { | ||||
|             display: none; | ||||
|         } | ||||
|     </style> | ||||
| </head> | ||||
| <body> | ||||
|     <div class="header">我的订单</div> | ||||
| 
 | ||||
|     <div class="tabs"> | ||||
|         <div class="tab-item active" data-tab="0">全部订单</div> | ||||
|         <div class="tab-item" data-tab="1">待发货</div> | ||||
|         <div class="tab-item" data-tab="2">待收货</div> | ||||
|         <div class="tab-item" data-tab="3">待评价</div> | ||||
|         <div class="tab-item" data-tab="4">退款/售后</div> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="order-list" id="orderList"> | ||||
|         <!-- 订单卡片动态生成 --> | ||||
|     </div> | ||||
| 
 | ||||
|     <script> | ||||
|         // 模拟订单数据 | ||||
|         const mockOrders = [ | ||||
|             { | ||||
|                 unitOrderNo: 'ORDER20250116001', | ||||
|                 unitType: 2, | ||||
|                 shopName: '新鲜蔬菜店', | ||||
|                 marketName: '大妈集市', | ||||
|                 status: 1, // 待发货 | ||||
|                 refundStatus: 0, | ||||
|                 productImgs: '🥬,🥕,🥔', | ||||
|                 totalMoney: 88.50, | ||||
|                 productCount: 5, | ||||
|                 orderCategory: 1, | ||||
|             }, | ||||
|             { | ||||
|                 unitOrderNo: 'ORDER20250116002', | ||||
|                 unitType: 2, | ||||
|                 shopName: '水果超市', | ||||
|                 marketName: '大妈集市', | ||||
|                 status: 3, // 待收货 | ||||
|                 refundStatus: 0, | ||||
|                 productImgs: '🍎,🍌', | ||||
|                 totalMoney: 128.00, | ||||
|                 productCount: 3, | ||||
|                 orderCategory: 1, | ||||
|             }, | ||||
|             { | ||||
|                 unitOrderNo: 'ORDER20250116003', | ||||
|                 unitType: 2, | ||||
|                 shopName: '肉类专营店', | ||||
|                 marketName: '大妈集市', | ||||
|                 status: 5, // 已完成 | ||||
|                 refundStatus: 0, | ||||
|                 productImgs: '🥩', | ||||
|                 totalMoney: 256.80, | ||||
|                 productCount: 2, | ||||
|                 orderCategory: 1, | ||||
|                 evaluated: false, | ||||
|             }, | ||||
|             { | ||||
|                 unitOrderNo: 'ORDER20250116004', | ||||
|                 unitType: 1, | ||||
|                 marketName: '大妈集市', | ||||
|                 status: 0, // 待付款 | ||||
|                 refundStatus: 0, | ||||
|                 productImgs: '🍞,🥐', | ||||
|                 totalMoney: 99.90, | ||||
|                 productCount: 4, | ||||
|                 orderCategory: 1, | ||||
|             }, | ||||
|         ]; | ||||
| 
 | ||||
|         // 订单状态枚举 | ||||
|         const OrderStatus = { | ||||
|             WAIT_PAY: 0, | ||||
|             WAIT_PREPARE: 1, | ||||
|             WAIT_RECEIVE: 2, | ||||
|             WAIT_CONFIRM: 3, | ||||
|             COMPLETE: 5, | ||||
|             CANCEL: 6, | ||||
|             REFUNDING: 7, | ||||
|             REFUND: 8, | ||||
|         }; | ||||
| 
 | ||||
|         let currentTab = 0; | ||||
| 
 | ||||
|         // 初始化页面 | ||||
|         function init() { | ||||
|             // 绑定tab点击事件 | ||||
|             document.querySelectorAll('.tab-item').forEach(tab => { | ||||
|                 tab.addEventListener('click', function() { | ||||
|                     // 移除所有active状态 | ||||
|                     document.querySelectorAll('.tab-item').forEach(t => t.classList.remove('active')); | ||||
|                     // 添加当前active状态 | ||||
|                     this.classList.add('active'); | ||||
|                     // 获取tab索引 | ||||
|                     currentTab = parseInt(this.dataset.tab); | ||||
|                     // 渲染订单列表 | ||||
|                     renderOrders(); | ||||
|                 }); | ||||
|             }); | ||||
| 
 | ||||
|             // 初始渲染 | ||||
|             renderOrders(); | ||||
|         } | ||||
| 
 | ||||
|         // 根据tab过滤订单 | ||||
|         function filterOrders(orders, tabIndex) { | ||||
|             switch (tabIndex) { | ||||
|                 case 0: // 全部订单 | ||||
|                     return orders; | ||||
|                 case 1: // 待发货 | ||||
|                     return orders.filter(o => o.status === OrderStatus.WAIT_PREPARE); | ||||
|                 case 2: // 待收货 | ||||
|                     return orders.filter(o => o.status === OrderStatus.WAIT_CONFIRM); | ||||
|                 case 3: // 待评价 | ||||
|                     return orders.filter(o => o.status === OrderStatus.COMPLETE && !o.evaluated); | ||||
|                 case 4: // 退款/售后 | ||||
|                     return orders.filter(o => o.refundStatus !== 0 || o.status === OrderStatus.REFUNDING || o.status === OrderStatus.REFUND); | ||||
|                 default: | ||||
|                     return orders; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 获取订单状态文本和样式 | ||||
|         function getOrderStatus(order) { | ||||
|             const { status, refundStatus } = order; | ||||
| 
 | ||||
|             if (refundStatus === -2) { | ||||
|                 return { text: '申请退款中', isImportant: true }; | ||||
|             } | ||||
| 
 | ||||
|             let text = ''; | ||||
|             let isImportant = false; | ||||
| 
 | ||||
|             switch (status) { | ||||
|                 case OrderStatus.WAIT_PAY: | ||||
|                     text = '待付款'; | ||||
|                     isImportant = true; | ||||
|                     break; | ||||
|                 case OrderStatus.WAIT_PREPARE: | ||||
|                     text = '待发货'; | ||||
|                     isImportant = false; | ||||
|                     break; | ||||
|                 case OrderStatus.WAIT_CONFIRM: | ||||
|                     text = '待收货'; | ||||
|                     isImportant = true; | ||||
|                     break; | ||||
|                 case OrderStatus.COMPLETE: | ||||
|                     text = '已完成'; | ||||
|                     isImportant = false; | ||||
|                     break; | ||||
|                 case OrderStatus.CANCEL: | ||||
|                     text = '已取消'; | ||||
|                     isImportant = false; | ||||
|                     break; | ||||
|                 case OrderStatus.REFUNDING: | ||||
|                     text = '退款中'; | ||||
|                     isImportant = false; | ||||
|                     break; | ||||
|                 case OrderStatus.REFUND: | ||||
|                     text = '已退款'; | ||||
|                     isImportant = false; | ||||
|                     break; | ||||
|                 default: | ||||
|                     text = '未知状态'; | ||||
|                     isImportant = false; | ||||
|             } | ||||
| 
 | ||||
|             return { text, isImportant }; | ||||
|         } | ||||
| 
 | ||||
|         // 渲染订单列表 | ||||
|         function renderOrders() { | ||||
|             const orderListEl = document.getElementById('orderList'); | ||||
|             const filteredOrders = filterOrders(mockOrders, currentTab); | ||||
| 
 | ||||
|             if (filteredOrders.length === 0) { | ||||
|                 orderListEl.innerHTML = '<div class="empty-view">暂无订单数据哦</div>'; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             orderListEl.innerHTML = filteredOrders.map(order => { | ||||
|                 const statusInfo = getOrderStatus(order); | ||||
|                 const productImages = order.productImgs.split(',').slice(0, 3); | ||||
| 
 | ||||
|                 return ` | ||||
|                     <div class="order-card" onclick="toOrderDetail('${order.unitOrderNo}')"> | ||||
|                         <div class="order-header"> | ||||
|                             <div class="shop-info"> | ||||
|                                 <span class="shop-icon">🏪</span> | ||||
|                                 ${order.unitType === 2 ? ` | ||||
|                                     <span class="shop-name">${order.shopName}</span> | ||||
|                                     <span class="market-name">(${order.marketName})</span> | ||||
|                                 ` : ` | ||||
|                                     <span class="market-name">${order.marketName}</span> | ||||
|                                 `} | ||||
|                             </div> | ||||
|                             <div class="order-status ${statusInfo.isImportant ? 'status-important' : 'status-normal'}"> | ||||
|                                 ${statusInfo.text} | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <div class="order-content"> | ||||
|                             <div class="product-images"> | ||||
|                                 ${productImages.map(emoji => `<div class="product-img">${emoji}</div>`).join('')} | ||||
|                             </div> | ||||
|                             <div class="order-price"> | ||||
|                                 <div class="price-value"> | ||||
|                                     <span class="price-symbol">¥</span>${order.totalMoney.toFixed(2)} | ||||
|                                 </div> | ||||
|                                 <div class="product-count"> | ||||
|                                     共${order.productCount}件 | ||||
|                                     <span class="arrow-icon">›</span> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         ${renderOrderActions(order)} | ||||
|                     </div> | ||||
|                 `; | ||||
|             }).join(''); | ||||
|         } | ||||
| 
 | ||||
|         // 渲染订单操作按钮 | ||||
|         function renderOrderActions(order) { | ||||
|             const { status, orderCategory } = order; | ||||
|             let buttons = ''; | ||||
| 
 | ||||
|             // 待付款 | ||||
|             if (status === OrderStatus.WAIT_PAY && orderCategory === 1) { | ||||
|                 buttons = ` | ||||
|                     <div class="order-actions"> | ||||
|                         <button class="btn btn-info" onclick="event.stopPropagation(); cancelOrder('${order.unitOrderNo}')">取消订单</button> | ||||
|                         <button class="btn btn-primary" onclick="event.stopPropagation(); payOrder('${order.unitOrderNo}')">去结算</button> | ||||
|                     </div> | ||||
|                 `; | ||||
|             } | ||||
|             // 待收货 | ||||
|             else if (status === OrderStatus.WAIT_CONFIRM) { | ||||
|                 buttons = ` | ||||
|                     <div class="order-actions"> | ||||
|                         <button class="btn btn-primary" onclick="event.stopPropagation(); confirmReceive('${order.unitOrderNo}')">确认收货</button> | ||||
|                     </div> | ||||
|                 `; | ||||
|             } | ||||
|             // 已完成 | ||||
|             else if (status === OrderStatus.COMPLETE && orderCategory === 1) { | ||||
|                 buttons = ` | ||||
|                     <div class="order-actions"> | ||||
|                         <button class="btn btn-info" onclick="event.stopPropagation(); addToCart('${order.unitOrderNo}')">加入购物车</button> | ||||
|                         <button class="btn btn-primary" onclick="event.stopPropagation(); orderAgain('${order.unitOrderNo}')">再来一单</button> | ||||
|                         ${!order.evaluated ? `<button class="btn btn-primary" onclick="event.stopPropagation(); goReview('${order.unitOrderNo}')">去评价</button>` : ''} | ||||
|                     </div> | ||||
|                 `; | ||||
|             } | ||||
| 
 | ||||
|             return buttons; | ||||
|         } | ||||
| 
 | ||||
|         // 跳转到订单详情 | ||||
|         function toOrderDetail(unitOrderNo) { | ||||
|             console.log('跳转到订单详情:', unitOrderNo); | ||||
|             window.location.href = `order-detail.html?unitOrderNo=${unitOrderNo}`; | ||||
|         } | ||||
| 
 | ||||
|         // 取消订单 | ||||
|         function cancelOrder(unitOrderNo) { | ||||
|             if (confirm('是否确认取消订单?')) { | ||||
|                 console.log('取消订单:', unitOrderNo); | ||||
|                 alert('取消订单成功'); | ||||
|                 renderOrders(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 支付订单 | ||||
|         function payOrder(unitOrderNo) { | ||||
|             console.log('去支付:', unitOrderNo); | ||||
|             alert('跳转到支付页面'); | ||||
|         } | ||||
| 
 | ||||
|         // 确认收货 | ||||
|         function confirmReceive(unitOrderNo) { | ||||
|             if (confirm('是否确认收货?')) { | ||||
|                 console.log('确认收货:', unitOrderNo); | ||||
|                 alert('确认收货成功'); | ||||
|                 renderOrders(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 再来一单 | ||||
|         function orderAgain(unitOrderNo) { | ||||
|             console.log('再来一单:', unitOrderNo); | ||||
|             alert('跳转到结算页面'); | ||||
|         } | ||||
| 
 | ||||
|         // 加入购物车 | ||||
|         function addToCart(unitOrderNo) { | ||||
|             console.log('加入购物车:', unitOrderNo); | ||||
|             alert('加入购物车成功'); | ||||
|         } | ||||
| 
 | ||||
|         // 去评价 | ||||
|         function goReview(unitOrderNo) { | ||||
|             console.log('去评价:', unitOrderNo); | ||||
|             alert('跳转到评价页面'); | ||||
|         } | ||||
| 
 | ||||
|         // 页面加载完成后初始化 | ||||
|         document.addEventListener('DOMContentLoaded', init); | ||||
|     </script> | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,559 @@ | |||
| <!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', 'Helvetica Neue', Arial, sans-serif; | ||||
|             background-color: #f5f5f5; | ||||
|             padding-bottom: 80px; | ||||
|         } | ||||
| 
 | ||||
|         .header { | ||||
|             background-color: #013820; | ||||
|             color: white; | ||||
|             padding: 15px 20px; | ||||
|             font-size: 18px; | ||||
|             font-weight: bold; | ||||
|             text-align: center; | ||||
|         } | ||||
| 
 | ||||
|         .feed-all { | ||||
|             min-height: 100vh; | ||||
|         } | ||||
| 
 | ||||
|         .group { | ||||
|             background-color: white; | ||||
|             margin: 10px; | ||||
|             border-radius: 8px; | ||||
|             overflow: hidden; | ||||
|             border: 1px solid #e5e5e5; | ||||
|         } | ||||
| 
 | ||||
|         .form-item { | ||||
|             padding: 15px; | ||||
|             border-bottom: 1px solid #f0f0f0; | ||||
|         } | ||||
| 
 | ||||
|         .form-item:last-child { | ||||
|             border-bottom: none; | ||||
|         } | ||||
| 
 | ||||
|         .form-label { | ||||
|             display: block; | ||||
|             color: #333; | ||||
|             font-size: 15px; | ||||
|             margin-bottom: 10px; | ||||
|             font-weight: 500; | ||||
|         } | ||||
| 
 | ||||
|         .form-label.required::before { | ||||
|             content: '*'; | ||||
|             color: #ff0000; | ||||
|             margin-right: 4px; | ||||
|         } | ||||
| 
 | ||||
|         .textarea-wrapper { | ||||
|             position: relative; | ||||
|         } | ||||
| 
 | ||||
|         .textarea-field { | ||||
|             width: 100%; | ||||
|             min-height: 120px; | ||||
|             padding: 10px; | ||||
|             border: 1px solid #dcdcdc; | ||||
|             border-radius: 4px; | ||||
|             font-size: 14px; | ||||
|             resize: vertical; | ||||
|             font-family: inherit; | ||||
|             line-height: 1.5; | ||||
|         } | ||||
| 
 | ||||
|         .textarea-field:focus { | ||||
|             outline: none; | ||||
|             border-color: #013820; | ||||
|         } | ||||
| 
 | ||||
|         .textarea-field::placeholder { | ||||
|             color: #999; | ||||
|         } | ||||
| 
 | ||||
|         .word-limit { | ||||
|             text-align: right; | ||||
|             color: #999; | ||||
|             font-size: 12px; | ||||
|             margin-top: 5px; | ||||
|         } | ||||
| 
 | ||||
|         .upload-section { | ||||
|             margin-top: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .upload-wrapper { | ||||
|             display: flex; | ||||
|             flex-wrap: wrap; | ||||
|             gap: 10px; | ||||
|             margin-top: 10px; | ||||
|         } | ||||
| 
 | ||||
|         .upload-item { | ||||
|             position: relative; | ||||
|             width: 80px; | ||||
|             height: 80px; | ||||
|             border: 1px dashed #dcdcdc; | ||||
|             border-radius: 4px; | ||||
|             overflow: hidden; | ||||
|         } | ||||
| 
 | ||||
|         .upload-item img { | ||||
|             width: 100%; | ||||
|             height: 100%; | ||||
|             object-fit: cover; | ||||
|             background: linear-gradient(135deg, #e0e0e0 0%, #f5f5f5 100%); | ||||
|         } | ||||
| 
 | ||||
|         .upload-preview { | ||||
|             width: 100%; | ||||
|             height: 100%; | ||||
|             background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%); | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             font-size: 36px; | ||||
|         } | ||||
| 
 | ||||
|         .upload-item .remove-btn { | ||||
|             position: absolute; | ||||
|             top: -8px; | ||||
|             right: -8px; | ||||
|             width: 20px; | ||||
|             height: 20px; | ||||
|             background-color: #ff0000; | ||||
|             color: white; | ||||
|             border: none; | ||||
|             border-radius: 50%; | ||||
|             cursor: pointer; | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             font-size: 14px; | ||||
|             line-height: 1; | ||||
|         } | ||||
| 
 | ||||
|         .upload-btn { | ||||
|             width: 80px; | ||||
|             height: 80px; | ||||
|             border: 1px dashed #dcdcdc; | ||||
|             border-radius: 4px; | ||||
|             background-color: #fafafa; | ||||
|             cursor: pointer; | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             color: #999; | ||||
|             font-size: 12px; | ||||
|             transition: all 0.3s; | ||||
|         } | ||||
| 
 | ||||
|         .upload-btn:hover { | ||||
|             border-color: #013820; | ||||
|             color: #013820; | ||||
|         } | ||||
| 
 | ||||
|         .upload-btn .icon { | ||||
|             font-size: 24px; | ||||
|             margin-bottom: 5px; | ||||
|         } | ||||
| 
 | ||||
|         .upload-input { | ||||
|             display: none; | ||||
|         } | ||||
| 
 | ||||
|         .footer { | ||||
|             position: fixed; | ||||
|             bottom: 0; | ||||
|             left: 0; | ||||
|             right: 0; | ||||
|             padding: 15px 25px; | ||||
|             background-color: white; | ||||
|             box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); | ||||
|         } | ||||
| 
 | ||||
|         .submit-btn { | ||||
|             width: 100%; | ||||
|             padding: 15px; | ||||
|             background-color: #013820; | ||||
|             color: white; | ||||
|             border: none; | ||||
|             border-radius: 4px; | ||||
|             font-size: 16px; | ||||
|             font-weight: bold; | ||||
|             cursor: pointer; | ||||
|             transition: all 0.3s; | ||||
|         } | ||||
| 
 | ||||
|         .submit-btn:hover { | ||||
|             background-color: #025530; | ||||
|         } | ||||
| 
 | ||||
|         .submit-btn:active { | ||||
|             transform: scale(0.98); | ||||
|         } | ||||
| 
 | ||||
|         .error-message { | ||||
|             color: #ff0000; | ||||
|             font-size: 12px; | ||||
|             margin-top: 5px; | ||||
|         } | ||||
| 
 | ||||
|         .toast { | ||||
|             position: fixed; | ||||
|             top: 50%; | ||||
|             left: 50%; | ||||
|             transform: translate(-50%, -50%); | ||||
|             background-color: rgba(0, 0, 0, 0.7); | ||||
|             color: white; | ||||
|             padding: 15px 25px; | ||||
|             border-radius: 4px; | ||||
|             z-index: 1000; | ||||
|             display: none; | ||||
|         } | ||||
| 
 | ||||
|         .toast.show { | ||||
|             display: block; | ||||
|             animation: fadeIn 0.3s; | ||||
|         } | ||||
| 
 | ||||
|         @keyframes fadeIn { | ||||
|             from { opacity: 0; } | ||||
|             to { opacity: 1; } | ||||
|         } | ||||
| 
 | ||||
|         .loading { | ||||
|             position: fixed; | ||||
|             top: 0; | ||||
|             left: 0; | ||||
|             right: 0; | ||||
|             bottom: 0; | ||||
|             background-color: rgba(0, 0, 0, 0.5); | ||||
|             display: none; | ||||
|             align-items: center; | ||||
|             justify-content: center; | ||||
|             z-index: 1000; | ||||
|         } | ||||
| 
 | ||||
|         .loading.show { | ||||
|             display: flex; | ||||
|         } | ||||
| 
 | ||||
|         .loading-content { | ||||
|             background-color: rgba(0, 0, 0, 0.7); | ||||
|             color: white; | ||||
|             padding: 20px 30px; | ||||
|             border-radius: 8px; | ||||
|             text-align: center; | ||||
|         } | ||||
| 
 | ||||
|         .spinner { | ||||
|             border: 3px solid rgba(255, 255, 255, 0.3); | ||||
|             border-top: 3px solid white; | ||||
|             border-radius: 50%; | ||||
|             width: 40px; | ||||
|             height: 40px; | ||||
|             animation: spin 1s linear infinite; | ||||
|             margin: 0 auto 10px; | ||||
|         } | ||||
| 
 | ||||
|         @keyframes spin { | ||||
|             0% { transform: rotate(0deg); } | ||||
|             100% { transform: rotate(360deg); } | ||||
|         } | ||||
|     </style> | ||||
| </head> | ||||
| <body> | ||||
|     <div class="header">退款申请</div> | ||||
| 
 | ||||
|     <div class="feed-all"> | ||||
|         <form id="refundForm"> | ||||
|             <div class="group"> | ||||
|                 <div class="form-item"> | ||||
|                     <label class="form-label required">申请理由</label> | ||||
|                     <div class="textarea-wrapper"> | ||||
|                         <textarea | ||||
|                             id="reason" | ||||
|                             class="textarea-field" | ||||
|                             placeholder="请输入申请理由" | ||||
|                             maxlength="300" | ||||
|                         ></textarea> | ||||
|                         <div class="word-limit"> | ||||
|                             <span id="wordCount">0</span>/300 | ||||
|                         </div> | ||||
|                     </div> | ||||
|                     <div id="reasonError" class="error-message" style="display: none;">请输入申请理由</div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="form-item"> | ||||
|                     <label class="form-label required">上传凭证</label> | ||||
|                     <div class="upload-section"> | ||||
|                         <div class="upload-wrapper" id="uploadWrapper"> | ||||
|                             <div class="upload-btn" id="uploadBtn"> | ||||
|                                 <div class="icon">+</div> | ||||
|                                 <div>上传图片</div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <input | ||||
|                             type="file" | ||||
|                             id="fileInput" | ||||
|                             class="upload-input" | ||||
|                             accept="image/*" | ||||
|                             multiple | ||||
|                         > | ||||
|                     </div> | ||||
|                     <div id="uploadError" class="error-message" style="display: none;">请上传凭证</div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </form> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="footer"> | ||||
|         <button class="submit-btn" id="submitBtn">提交</button> | ||||
|     </div> | ||||
| 
 | ||||
|     <div id="toast" class="toast"></div> | ||||
|     <div id="loading" class="loading"> | ||||
|         <div class="loading-content"> | ||||
|             <div class="spinner"></div> | ||||
|             <div>申请中...</div> | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <script> | ||||
|         // 获取URL参数 | ||||
|         function getQueryParam(name) { | ||||
|             const urlParams = new URLSearchParams(window.location.search); | ||||
|             return urlParams.get(name); | ||||
|         } | ||||
| 
 | ||||
|         // 订单编号(从URL参数获取) | ||||
|         const unitOrderNo = getQueryParam('unitOrderNo') || ''; | ||||
| 
 | ||||
|         // 文件列表 | ||||
|         let fileList = []; | ||||
|         const MAX_FILES = 5; | ||||
| 
 | ||||
|         // DOM元素 | ||||
|         const reasonTextarea = document.getElementById('reason'); | ||||
|         const wordCountSpan = document.getElementById('wordCount'); | ||||
|         const uploadBtn = document.getElementById('uploadBtn'); | ||||
|         const fileInput = document.getElementById('fileInput'); | ||||
|         const uploadWrapper = document.getElementById('uploadWrapper'); | ||||
|         const submitBtn = document.getElementById('submitBtn'); | ||||
|         const reasonError = document.getElementById('reasonError'); | ||||
|         const uploadError = document.getElementById('uploadError'); | ||||
|         const toast = document.getElementById('toast'); | ||||
|         const loading = document.getElementById('loading'); | ||||
| 
 | ||||
|         // 字数统计 | ||||
|         reasonTextarea.addEventListener('input', function() { | ||||
|             const length = this.value.length; | ||||
|             wordCountSpan.textContent = length; | ||||
|             if (length > 0) { | ||||
|                 reasonError.style.display = 'none'; | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         // 点击上传按钮 | ||||
|         uploadBtn.addEventListener('click', function() { | ||||
|             if (fileList.length < MAX_FILES) { | ||||
|                 fileInput.click(); | ||||
|             } else { | ||||
|                 showToast('最多只能上传5张图片'); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         // 文件选择 | ||||
|         fileInput.addEventListener('change', function(e) { | ||||
|             const files = Array.from(e.target.files); | ||||
| 
 | ||||
|             if (fileList.length + files.length > MAX_FILES) { | ||||
|                 showToast(`最多只能上传${MAX_FILES}张图片`); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             files.forEach(file => { | ||||
|                 if (file.type.startsWith('image/')) { | ||||
|                     const reader = new FileReader(); | ||||
|                     reader.onload = function(event) { | ||||
|                         fileList.push({ | ||||
|                             file: file, | ||||
|                             url: event.target.result | ||||
|                         }); | ||||
|                         renderFiles(); | ||||
|                         uploadError.style.display = 'none'; | ||||
|                     }; | ||||
|                     reader.readAsDataURL(file); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             // 清空input,以便可以重复选择同一文件 | ||||
|             fileInput.value = ''; | ||||
|         }); | ||||
| 
 | ||||
|         // 渲染文件列表 | ||||
|         function renderFiles() { | ||||
|             // 清空现有内容 | ||||
|             uploadWrapper.innerHTML = ''; | ||||
| 
 | ||||
|             // 渲染已上传的图片 | ||||
|             fileList.forEach((item, index) => { | ||||
|                 const div = document.createElement('div'); | ||||
|                 div.className = 'upload-item'; | ||||
|                 // 使用表情符号作为占位符 | ||||
|                 const emojis = ['📷', '🖼️', '🎨', '📸', '🌅']; | ||||
|                 const emoji = emojis[index % emojis.length]; | ||||
|                 div.innerHTML = ` | ||||
|                     <div class="upload-preview">${emoji}</div> | ||||
|                     <button class="remove-btn" onclick="removeFile(${index})">×</button> | ||||
|                 `; | ||||
|                 uploadWrapper.appendChild(div); | ||||
|             }); | ||||
| 
 | ||||
|             // 如果未达到上限,显示上传按钮 | ||||
|             if (fileList.length < MAX_FILES) { | ||||
|                 const uploadBtnClone = document.createElement('div'); | ||||
|                 uploadBtnClone.className = 'upload-btn'; | ||||
|                 uploadBtnClone.id = 'uploadBtn'; | ||||
|                 uploadBtnClone.innerHTML = ` | ||||
|                     <div class="icon">+</div> | ||||
|                     <div>上传图片</div> | ||||
|                 `; | ||||
|                 uploadBtnClone.addEventListener('click', function() { | ||||
|                     fileInput.click(); | ||||
|                 }); | ||||
|                 uploadWrapper.appendChild(uploadBtnClone); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // 删除文件 | ||||
|         window.removeFile = function(index) { | ||||
|             fileList.splice(index, 1); | ||||
|             renderFiles(); | ||||
|         }; | ||||
| 
 | ||||
|         // 显示提示 | ||||
|         function showToast(message, duration = 2000) { | ||||
|             toast.textContent = message; | ||||
|             toast.classList.add('show'); | ||||
|             setTimeout(() => { | ||||
|                 toast.classList.remove('show'); | ||||
|             }, duration); | ||||
|         } | ||||
| 
 | ||||
|         // 显示加载中 | ||||
|         function showLoading() { | ||||
|             loading.classList.add('show'); | ||||
|         } | ||||
| 
 | ||||
|         // 隐藏加载中 | ||||
|         function hideLoading() { | ||||
|             loading.classList.remove('show'); | ||||
|         } | ||||
| 
 | ||||
|         // 表单验证 | ||||
|         function validateForm() { | ||||
|             let isValid = true; | ||||
| 
 | ||||
|             // 验证申请理由 | ||||
|             if (!reasonTextarea.value.trim()) { | ||||
|                 reasonError.style.display = 'block'; | ||||
|                 isValid = false; | ||||
|             } else { | ||||
|                 reasonError.style.display = 'none'; | ||||
|             } | ||||
| 
 | ||||
|             // 验证上传凭证 | ||||
|             if (fileList.length === 0) { | ||||
|                 uploadError.style.display = 'block'; | ||||
|                 showToast('请上传凭证'); | ||||
|                 isValid = false; | ||||
|             } else { | ||||
|                 uploadError.style.display = 'none'; | ||||
|             } | ||||
| 
 | ||||
|             return isValid; | ||||
|         } | ||||
| 
 | ||||
|         // 模拟文件上传到服务器 | ||||
|         async function uploadFilesToServer(files) { | ||||
|             // 这里应该是实际的上传逻辑,返回文件URL列表 | ||||
|             // 现在使用模拟数据 | ||||
|             const urls = files.map((item, index) => { | ||||
|                 return `https://example.com/uploads/refund_${Date.now()}_${index}.jpg`; | ||||
|             }); | ||||
|             return urls; | ||||
|         } | ||||
| 
 | ||||
|         // 提交表单 | ||||
|         submitBtn.addEventListener('click', async function() { | ||||
|             if (!validateForm()) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             showLoading(); | ||||
| 
 | ||||
|             try { | ||||
|                 // 模拟上传文件并获取URL | ||||
|                 const imageUrls = await uploadFilesToServer(fileList); | ||||
| 
 | ||||
|                 // 准备提交数据 | ||||
|                 const submitData = { | ||||
|                     unitOrderNo: unitOrderNo, | ||||
|                     reason: reasonTextarea.value.trim(), | ||||
|                     img: imageUrls.join(',') | ||||
|                 }; | ||||
| 
 | ||||
|                 console.log('提交数据:', submitData); | ||||
| 
 | ||||
|                 // 模拟API请求 | ||||
|                 // 实际项目中应该调用真实的API接口 | ||||
|                 await new Promise((resolve, reject) => { | ||||
|                     setTimeout(() => { | ||||
|                         // 模拟成功 | ||||
|                         resolve(); | ||||
|                         // 模拟失败,取消下面的注释 | ||||
|                         // reject(new Error('提交失败')); | ||||
|                     }, 1500); | ||||
|                 }); | ||||
| 
 | ||||
|                 hideLoading(); | ||||
|                 showToast('申请成功,等待审核中'); | ||||
| 
 | ||||
|                 // 延迟后返回上一页 | ||||
|                 setTimeout(() => { | ||||
|                     window.history.back(); | ||||
|                     console.log('返回上一页并刷新订单列表'); | ||||
|                 }, 1500); | ||||
| 
 | ||||
|             } catch (error) { | ||||
|                 hideLoading(); | ||||
|                 showToast('申请失败,请联系商家'); | ||||
|                 console.error('提交失败:', error); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         // 页面加载完成 | ||||
|         document.addEventListener('DOMContentLoaded', function() { | ||||
|             console.log('页面加载完成,订单编号:', unitOrderNo); | ||||
|         }); | ||||
|     </script> | ||||
| </body> | ||||
| </html> | ||||
		Loading…
	
		Reference in New Issue