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>
 |