dm-design/用户端APP/我的订单/order-refund.html

560 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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