1058 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			HTML
		
	
	
	
		
		
			
		
	
	
			1058 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			HTML
		
	
	
	
|  | <!DOCTYPE html> | |||
|  | <html lang="zh-CN"> | |||
|  | <head> | |||
|  |     <meta charset="UTF-8"> | |||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
|  |     <title>退款申请</title> | |||
|  |     <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; | |||
|  |             overflow-y: auto; | |||
|  |         } | |||
|  | 
 | |||
|  |         .header { | |||
|  |             background-color: #013820; | |||
|  |             color: white; | |||
|  |             padding: 15px 20px; | |||
|  |             font-size: 18px; | |||
|  |             font-weight: bold; | |||
|  |             text-align: center; | |||
|  |             position: relative; | |||
|  |             z-index: 100; | |||
|  |         } | |||
|  | 
 | |||
|  |         .feed-all { | |||
|  |             min-height: auto; | |||
|  |         } | |||
|  | 
 | |||
|  |         .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; | |||
|  |         } | |||
|  | 
 | |||
|  |         .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 { | |||
|  |             padding: 15px 25px; | |||
|  |             background-color: white; | |||
|  |             margin: 10px; | |||
|  |             border-radius: 8px; | |||
|  |         } | |||
|  | 
 | |||
|  |         .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); } | |||
|  |         } | |||
|  | 
 | |||
|  |         /* 订单信息样式 */ | |||
|  |         .order-info { | |||
|  |             background-color: #f9f9f9; | |||
|  |             padding: 15px; | |||
|  |             border-radius: 4px; | |||
|  |         } | |||
|  | 
 | |||
|  |         .order-info-row { | |||
|  |             display: flex; | |||
|  |             justify-content: space-between; | |||
|  |             padding: 8px 0; | |||
|  |             font-size: 14px; | |||
|  |         } | |||
|  | 
 | |||
|  |         .order-info-row .label { | |||
|  |             color: #666; | |||
|  |         } | |||
|  | 
 | |||
|  |         .order-info-row .value { | |||
|  |             color: #333; | |||
|  |             font-weight: 500; | |||
|  |         } | |||
|  | 
 | |||
|  |         .order-info-row .price { | |||
|  |             color: #013820; | |||
|  |             font-weight: bold; | |||
|  |         } | |||
|  | 
 | |||
|  |         /* 选择框样式 */ | |||
|  |         .select-header { | |||
|  |             display: flex; | |||
|  |             align-items: center; | |||
|  |             padding: 5px 0; | |||
|  |         } | |||
|  | 
 | |||
|  |         .checkbox-wrapper { | |||
|  |             display: flex; | |||
|  |             align-items: center; | |||
|  |             cursor: pointer; | |||
|  |         } | |||
|  | 
 | |||
|  |         .checkbox { | |||
|  |             width: 18px; | |||
|  |             height: 18px; | |||
|  |             margin-right: 8px; | |||
|  |             cursor: pointer; | |||
|  |         } | |||
|  | 
 | |||
|  |         .checkbox-label { | |||
|  |             font-size: 15px; | |||
|  |             color: #333; | |||
|  |             font-weight: 500; | |||
|  |         } | |||
|  | 
 | |||
|  |         /* 商品列表样式 */ | |||
|  |         .goods-list { | |||
|  |             border-top: 1px solid #f0f0f0; | |||
|  |         } | |||
|  | 
 | |||
|  |         .shop-group { | |||
|  |             border-bottom: 1px solid #f0f0f0; | |||
|  |         } | |||
|  | 
 | |||
|  |         .shop-group:last-child { | |||
|  |             border-bottom: none; | |||
|  |         } | |||
|  | 
 | |||
|  |         .shop-header { | |||
|  |             display: flex; | |||
|  |             align-items: center; | |||
|  |             padding: 12px 15px; | |||
|  |             background-color: #fafafa; | |||
|  |             border-bottom: 1px solid #f0f0f0; | |||
|  |         } | |||
|  | 
 | |||
|  |         .shop-name { | |||
|  |             margin-left: 8px; | |||
|  |             font-size: 14px; | |||
|  |             color: #333; | |||
|  |             font-weight: 500; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-item { | |||
|  |             display: flex; | |||
|  |             padding: 12px 15px; | |||
|  |             border-bottom: 1px solid #f5f5f5; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-item:last-child { | |||
|  |             border-bottom: none; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-checkbox { | |||
|  |             display: flex; | |||
|  |             align-items: center; | |||
|  |             margin-right: 10px; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-content { | |||
|  |             flex: 1; | |||
|  |             display: flex; | |||
|  |             gap: 10px; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-image { | |||
|  |             width: 60px; | |||
|  |             height: 60px; | |||
|  |             border-radius: 4px; | |||
|  |             overflow: hidden; | |||
|  |             flex-shrink: 0; | |||
|  |             background-color: #f0f0f0; | |||
|  |             display: flex; | |||
|  |             align-items: center; | |||
|  |             justify-content: center; | |||
|  |             color: #999; | |||
|  |             font-size: 12px; | |||
|  |             text-align: center; | |||
|  |             border: 1px solid #e5e5e5; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-image img { | |||
|  |             width: 100%; | |||
|  |             height: 100%; | |||
|  |             object-fit: cover; | |||
|  |             display: none; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-image .placeholder { | |||
|  |             font-size: 24px; | |||
|  |             color: #ccc; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-info { | |||
|  |             flex: 1; | |||
|  |             display: flex; | |||
|  |             flex-direction: column; | |||
|  |             justify-content: space-between; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-name { | |||
|  |             font-size: 14px; | |||
|  |             color: #333; | |||
|  |             line-height: 1.4; | |||
|  |             display: -webkit-box; | |||
|  |             -webkit-line-clamp: 2; | |||
|  |             -webkit-box-orient: vertical; | |||
|  |             overflow: hidden; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-spec { | |||
|  |             font-size: 12px; | |||
|  |             color: #999; | |||
|  |             margin-top: 4px; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-bottom { | |||
|  |             display: flex; | |||
|  |             justify-content: space-between; | |||
|  |             align-items: center; | |||
|  |             margin-top: 8px; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-price { | |||
|  |             font-size: 15px; | |||
|  |             color: #013820; | |||
|  |             font-weight: bold; | |||
|  |         } | |||
|  | 
 | |||
|  |         .goods-quantity { | |||
|  |             font-size: 13px; | |||
|  |             color: #666; | |||
|  |         } | |||
|  | 
 | |||
|  |         /* 退款金额样式 */ | |||
|  |         .refund-amount { | |||
|  |             display: flex; | |||
|  |             justify-content: space-between; | |||
|  |             align-items: center; | |||
|  |             padding: 10px 15px; | |||
|  |             background-color: #f9f9f9; | |||
|  |             border-radius: 4px; | |||
|  |         } | |||
|  | 
 | |||
|  |         .refund-amount .label { | |||
|  |             font-size: 15px; | |||
|  |             color: #333; | |||
|  |             font-weight: 500; | |||
|  |         } | |||
|  | 
 | |||
|  |         .refund-amount .amount { | |||
|  |             font-size: 18px; | |||
|  |             color: #ff0000; | |||
|  |             font-weight: bold; | |||
|  |         } | |||
|  |     </style> | |||
|  | </head> | |||
|  | <body> | |||
|  |     <div class="header">退款申请</div> | |||
|  | 
 | |||
|  |     <div class="feed-all"> | |||
|  |         <form id="refundForm"> | |||
|  |             <!-- 订单基础信息 --> | |||
|  |             <div class="group"> | |||
|  |                 <div class="form-item"> | |||
|  |                     <div class="order-info"> | |||
|  |                         <div class="order-info-row"> | |||
|  |                             <span class="label">订单编号:</span> | |||
|  |                             <span class="value" id="orderNo">-</span> | |||
|  |                         </div> | |||
|  |                         <div class="order-info-row"> | |||
|  |                             <span class="label">下单时间:</span> | |||
|  |                             <span class="value" id="orderTime">-</span> | |||
|  |                         </div> | |||
|  |                         <div class="order-info-row"> | |||
|  |                             <span class="label">商品总金额:</span> | |||
|  |                             <span class="value price" id="goodsAmount">¥0.00</span> | |||
|  |                         </div> | |||
|  |                         <div class="order-info-row"> | |||
|  |                             <span class="label">配送费:</span> | |||
|  |                             <span class="value price" id="deliveryFee">¥0.00</span> | |||
|  |                         </div> | |||
|  |                         <div class="order-info-row"> | |||
|  |                             <span class="label">包装费:</span> | |||
|  |                             <span class="value price" id="packingFee">¥0.00</span> | |||
|  |                         </div> | |||
|  |                         <div class="order-info-row"> | |||
|  |                             <span class="label">调度费:</span> | |||
|  |                             <span class="value price" id="dispatchFee">¥0.00</span> | |||
|  |                         </div> | |||
|  |                     </div> | |||
|  |                 </div> | |||
|  |             </div> | |||
|  | 
 | |||
|  |             <!-- 商品明细列表 --> | |||
|  |             <div class="group"> | |||
|  |                 <div class="form-item"> | |||
|  |                     <div class="select-header"> | |||
|  |                         <label class="checkbox-wrapper"> | |||
|  |                             <input type="checkbox" id="selectAll" class="checkbox"> | |||
|  |                             <span class="checkbox-label">全选</span> | |||
|  |                         </label> | |||
|  |                     </div> | |||
|  |                 </div> | |||
|  |                 <div id="goodsList" class="goods-list"> | |||
|  |                     <!-- 商品列表将通过JS动态生成 --> | |||
|  |                 </div> | |||
|  |             </div> | |||
|  | 
 | |||
|  |             <!-- 退款金额 --> | |||
|  |             <div class="group"> | |||
|  |                 <div class="form-item"> | |||
|  |                     <div class="refund-amount"> | |||
|  |                         <span class="label">当前退款金额:</span> | |||
|  |                         <span class="amount" id="refundAmount">¥0.00</span> | |||
|  |                     </div> | |||
|  |                 </div> | |||
|  |             </div> | |||
|  | 
 | |||
|  |             <!-- 申请理由 --> | |||
|  |             <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') || 'ORD202501160001'; | |||
|  | 
 | |||
|  |         // 文件列表 | |||
|  |         let fileList = []; | |||
|  |         const MAX_FILES = 5; | |||
|  | 
 | |||
|  |         // 模拟订单数据 | |||
|  |         const orderData = { | |||
|  |             orderNo: unitOrderNo, | |||
|  |             orderTime: '2025-01-16 09:23:15', | |||
|  |             goodsAmount: 68.50, | |||
|  |             deliveryFee: 6.00, | |||
|  |             packingFee: 2.00, | |||
|  |             dispatchFee: 1.50, | |||
|  |             shops: [ | |||
|  |                 { | |||
|  |                     shopId: '1', | |||
|  |                     shopName: '张记蔬菜店', | |||
|  |                     goods: [ | |||
|  |                         { | |||
|  |                             goodsId: '101', | |||
|  |                             goodsName: '新鲜上海青', | |||
|  |                             goodsSpec: '500g/份', | |||
|  |                             goodsImage: '', | |||
|  |                             placeholder: '🥬', | |||
|  |                             price: 6.50, | |||
|  |                             quantity: 2 | |||
|  |                         }, | |||
|  |                         { | |||
|  |                             goodsId: '102', | |||
|  |                             goodsName: '有机西红柿', | |||
|  |                             goodsSpec: '1斤/份', | |||
|  |                             goodsImage: '', | |||
|  |                             placeholder: '🍅', | |||
|  |                             price: 8.00, | |||
|  |                             quantity: 1 | |||
|  |                         }, | |||
|  |                         { | |||
|  |                             goodsId: '103', | |||
|  |                             goodsName: '土豆', | |||
|  |                             goodsSpec: '1kg/份', | |||
|  |                             goodsImage: '', | |||
|  |                             placeholder: '🥔', | |||
|  |                             price: 5.50, | |||
|  |                             quantity: 1 | |||
|  |                         } | |||
|  |                     ] | |||
|  |                 }, | |||
|  |                 { | |||
|  |                     shopId: '2', | |||
|  |                     shopName: '王家鲜肉铺', | |||
|  |                     goods: [ | |||
|  |                         { | |||
|  |                             goodsId: '201', | |||
|  |                             goodsName: '五花肉', | |||
|  |                             goodsSpec: '1斤/份', | |||
|  |                             goodsImage: '', | |||
|  |                             placeholder: '🥓', | |||
|  |                             price: 18.00, | |||
|  |                             quantity: 2 | |||
|  |                         }, | |||
|  |                         { | |||
|  |                             goodsId: '202', | |||
|  |                             goodsName: '鸡腿', | |||
|  |                             goodsSpec: '500g/份', | |||
|  |                             goodsImage: '', | |||
|  |                             placeholder: '🍗', | |||
|  |                             price: 12.00, | |||
|  |                             quantity: 1 | |||
|  |                         } | |||
|  |                     ] | |||
|  |                 }, | |||
|  |                 { | |||
|  |                     shopId: '3', | |||
|  |                     shopName: '李大妈水产', | |||
|  |                     goods: [ | |||
|  |                         { | |||
|  |                             goodsId: '301', | |||
|  |                             goodsName: '草鱼', | |||
|  |                             goodsSpec: '2斤/条', | |||
|  |                             goodsImage: '', | |||
|  |                             placeholder: '🐟', | |||
|  |                             price: 16.00, | |||
|  |                             quantity: 1 | |||
|  |                         } | |||
|  |                     ] | |||
|  |                 } | |||
|  |             ] | |||
|  |         }; | |||
|  | 
 | |||
|  |         // 已选商品列表 | |||
|  |         let selectedGoods = []; | |||
|  | 
 | |||
|  |         // 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'; | |||
|  |                 div.innerHTML = ` | |||
|  |                     <img src="${item.url}" alt="图片${index + 1}"> | |||
|  |                     <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 (selectedGoods.length === 0) { | |||
|  |                 showToast('请至少选择一个商品'); | |||
|  |                 isValid = false; | |||
|  |                 return isValid; | |||
|  |             } | |||
|  | 
 | |||
|  |             // 验证申请理由 | |||
|  |             if (!reasonTextarea.value.trim()) { | |||
|  |                 reasonError.style.display = 'block'; | |||
|  |                 showToast('请输入申请理由'); | |||
|  |                 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(','), | |||
|  |                     selectedGoods: selectedGoods, | |||
|  |                     refundAmount: document.getElementById('refundAmount').textContent.replace('¥', '') | |||
|  |                 }; | |||
|  | 
 | |||
|  |                 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); | |||
|  |             } | |||
|  |         }); | |||
|  | 
 | |||
|  |         // 初始化订单信息 | |||
|  |         function initOrderInfo() { | |||
|  |             document.getElementById('orderNo').textContent = orderData.orderNo; | |||
|  |             document.getElementById('orderTime').textContent = orderData.orderTime; | |||
|  |             document.getElementById('goodsAmount').textContent = `¥${orderData.goodsAmount.toFixed(2)}`; | |||
|  |             document.getElementById('deliveryFee').textContent = `¥${orderData.deliveryFee.toFixed(2)}`; | |||
|  |             document.getElementById('packingFee').textContent = `¥${orderData.packingFee.toFixed(2)}`; | |||
|  |             document.getElementById('dispatchFee').textContent = `¥${orderData.dispatchFee.toFixed(2)}`; | |||
|  |         } | |||
|  | 
 | |||
|  |         // 渲染商品列表 | |||
|  |         function renderGoodsList() { | |||
|  |             const goodsList = document.getElementById('goodsList'); | |||
|  |             goodsList.innerHTML = ''; | |||
|  | 
 | |||
|  |             orderData.shops.forEach(shop => { | |||
|  |                 const shopGroup = document.createElement('div'); | |||
|  |                 shopGroup.className = 'shop-group'; | |||
|  |                 shopGroup.dataset.shopId = shop.shopId; | |||
|  | 
 | |||
|  |                 // 店铺头部 | |||
|  |                 const shopHeader = document.createElement('div'); | |||
|  |                 shopHeader.className = 'shop-header'; | |||
|  |                 shopHeader.innerHTML = ` | |||
|  |                     <label class="checkbox-wrapper"> | |||
|  |                         <input type="checkbox" class="checkbox shop-checkbox" data-shop-id="${shop.shopId}"> | |||
|  |                         <span class="shop-name">${shop.shopName}</span> | |||
|  |                     </label> | |||
|  |                 `; | |||
|  |                 shopGroup.appendChild(shopHeader); | |||
|  | 
 | |||
|  |                 // 商品列表 | |||
|  |                 shop.goods.forEach(goods => { | |||
|  |                     const goodsItem = document.createElement('div'); | |||
|  |                     goodsItem.className = 'goods-item'; | |||
|  |                     goodsItem.dataset.goodsId = goods.goodsId; | |||
|  |                     goodsItem.dataset.shopId = shop.shopId; | |||
|  |                     goodsItem.innerHTML = ` | |||
|  |                         <div class="goods-checkbox"> | |||
|  |                             <input type="checkbox" class="checkbox goods-checkbox-input" | |||
|  |                                 data-goods-id="${goods.goodsId}" | |||
|  |                                 data-shop-id="${shop.shopId}" | |||
|  |                                 data-price="${goods.price}" | |||
|  |                                 data-quantity="${goods.quantity}"> | |||
|  |                         </div> | |||
|  |                         <div class="goods-content"> | |||
|  |                             <div class="goods-image"> | |||
|  |                                 <div class="placeholder">${goods.placeholder || '📦'}</div> | |||
|  |                             </div> | |||
|  |                             <div class="goods-info"> | |||
|  |                                 <div class="goods-name">${goods.goodsName}</div> | |||
|  |                                 <div class="goods-spec">${goods.goodsSpec}</div> | |||
|  |                                 <div class="goods-bottom"> | |||
|  |                                     <span class="goods-price">¥${goods.price.toFixed(2)}</span> | |||
|  |                                     <span class="goods-quantity">x${goods.quantity}</span> | |||
|  |                                 </div> | |||
|  |                             </div> | |||
|  |                         </div> | |||
|  |                     `; | |||
|  |                     shopGroup.appendChild(goodsItem); | |||
|  |                 }); | |||
|  | 
 | |||
|  |                 goodsList.appendChild(shopGroup); | |||
|  |             }); | |||
|  | 
 | |||
|  |             // 绑定事件 | |||
|  |             bindCheckboxEvents(); | |||
|  |         } | |||
|  | 
 | |||
|  |         // 绑定复选框事件 | |||
|  |         function bindCheckboxEvents() { | |||
|  |             // 全选按钮 | |||
|  |             const selectAll = document.getElementById('selectAll'); | |||
|  |             selectAll.addEventListener('change', function() { | |||
|  |                 const checkboxes = document.querySelectorAll('.goods-checkbox-input'); | |||
|  |                 checkboxes.forEach(checkbox => { | |||
|  |                     checkbox.checked = this.checked; | |||
|  |                 }); | |||
|  |                 const shopCheckboxes = document.querySelectorAll('.shop-checkbox'); | |||
|  |                 shopCheckboxes.forEach(checkbox => { | |||
|  |                     checkbox.checked = this.checked; | |||
|  |                 }); | |||
|  |                 updateSelectedGoods(); | |||
|  |             }); | |||
|  | 
 | |||
|  |             // 店铺复选框 | |||
|  |             const shopCheckboxes = document.querySelectorAll('.shop-checkbox'); | |||
|  |             shopCheckboxes.forEach(shopCheckbox => { | |||
|  |                 shopCheckbox.addEventListener('change', function() { | |||
|  |                     const shopId = this.dataset.shopId; | |||
|  |                     const goodsCheckboxes = document.querySelectorAll(`.goods-checkbox-input[data-shop-id="${shopId}"]`); | |||
|  |                     goodsCheckboxes.forEach(checkbox => { | |||
|  |                         checkbox.checked = this.checked; | |||
|  |                     }); | |||
|  |                     updateSelectAllStatus(); | |||
|  |                     updateSelectedGoods(); | |||
|  |                 }); | |||
|  |             }); | |||
|  | 
 | |||
|  |             // 商品复选框 | |||
|  |             const goodsCheckboxes = document.querySelectorAll('.goods-checkbox-input'); | |||
|  |             goodsCheckboxes.forEach(goodsCheckbox => { | |||
|  |                 goodsCheckbox.addEventListener('change', function() { | |||
|  |                     const shopId = this.dataset.shopId; | |||
|  |                     updateShopCheckboxStatus(shopId); | |||
|  |                     updateSelectAllStatus(); | |||
|  |                     updateSelectedGoods(); | |||
|  |                 }); | |||
|  |             }); | |||
|  |         } | |||
|  | 
 | |||
|  |         // 更新店铺复选框状态 | |||
|  |         function updateShopCheckboxStatus(shopId) { | |||
|  |             const goodsCheckboxes = document.querySelectorAll(`.goods-checkbox-input[data-shop-id="${shopId}"]`); | |||
|  |             const shopCheckbox = document.querySelector(`.shop-checkbox[data-shop-id="${shopId}"]`); | |||
|  | 
 | |||
|  |             const allChecked = Array.from(goodsCheckboxes).every(checkbox => checkbox.checked); | |||
|  |             shopCheckbox.checked = allChecked; | |||
|  |         } | |||
|  | 
 | |||
|  |         // 更新全选按钮状态 | |||
|  |         function updateSelectAllStatus() { | |||
|  |             const selectAll = document.getElementById('selectAll'); | |||
|  |             const allGoodsCheckboxes = document.querySelectorAll('.goods-checkbox-input'); | |||
|  |             const allChecked = Array.from(allGoodsCheckboxes).every(checkbox => checkbox.checked); | |||
|  |             selectAll.checked = allChecked; | |||
|  |         } | |||
|  | 
 | |||
|  |         // 更新已选商品和退款金额 | |||
|  |         function updateSelectedGoods() { | |||
|  |             selectedGoods = []; | |||
|  |             let totalAmount = 0; | |||
|  | 
 | |||
|  |             const checkedBoxes = document.querySelectorAll('.goods-checkbox-input:checked'); | |||
|  |             checkedBoxes.forEach(checkbox => { | |||
|  |                 const goodsId = checkbox.dataset.goodsId; | |||
|  |                 const price = parseFloat(checkbox.dataset.price); | |||
|  |                 const quantity = parseInt(checkbox.dataset.quantity); | |||
|  | 
 | |||
|  |                 selectedGoods.push({ | |||
|  |                     goodsId: goodsId, | |||
|  |                     price: price, | |||
|  |                     quantity: quantity | |||
|  |                 }); | |||
|  | 
 | |||
|  |                 totalAmount += price * quantity; | |||
|  |             }); | |||
|  | 
 | |||
|  |             // 如果全部商品都选中,加上配送费、包装费、调度费 | |||
|  |             const allGoodsCheckboxes = document.querySelectorAll('.goods-checkbox-input'); | |||
|  |             const allChecked = Array.from(allGoodsCheckboxes).every(checkbox => checkbox.checked); | |||
|  | 
 | |||
|  |             if (allChecked && selectedGoods.length > 0) { | |||
|  |                 totalAmount += orderData.deliveryFee + orderData.packingFee + orderData.dispatchFee; | |||
|  |             } | |||
|  | 
 | |||
|  |             // 更新显示 | |||
|  |             document.getElementById('refundAmount').textContent = `¥${totalAmount.toFixed(2)}`; | |||
|  |         } | |||
|  | 
 | |||
|  |         // 页面加载完成 | |||
|  |         document.addEventListener('DOMContentLoaded', function() { | |||
|  |             console.log('页面加载完成,订单编号:', unitOrderNo); | |||
|  |             initOrderInfo(); | |||
|  |             renderGoodsList(); | |||
|  |         }); | |||
|  |     </script> | |||
|  | </body> | |||
|  | </html> |