Initial commit
This commit is contained in:
392
miniprogram/pages/refund/refund-apply/index.js
Normal file
392
miniprogram/pages/refund/refund-apply/index.js
Normal file
@@ -0,0 +1,392 @@
|
||||
// pages/refund/refund-apply/index.js
|
||||
import Toast from 'tdesign-miniprogram/toast/index';
|
||||
import { config } from '../../../config/index';
|
||||
|
||||
Page({
|
||||
// 检查登录状态并导航到登录页
|
||||
checkLoginAndNavigate() {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '请先登录后再进行操作',
|
||||
showCancel: true,
|
||||
cancelText: '取消',
|
||||
confirmText: '去登录',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/login/index'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
data: {
|
||||
orderDetail: null,
|
||||
refundAmount: '',
|
||||
maxRefundAmount: '0.00',
|
||||
selectedReason: '',
|
||||
customReason: '',
|
||||
description: '',
|
||||
reasonOptions: [
|
||||
{ value: 'quality', label: '商品质量问题' },
|
||||
{ value: 'description', label: '商品与描述不符' },
|
||||
{ value: 'logistics', label: '物流问题' },
|
||||
{ value: 'service', label: '服务问题' },
|
||||
{ value: 'personal', label: '个人原因' },
|
||||
{ value: 'other', label: '其他原因' }
|
||||
],
|
||||
isReapply: false,
|
||||
originalRefundId: null,
|
||||
submitting: false,
|
||||
loading: true,
|
||||
error: null
|
||||
},
|
||||
|
||||
computed: {
|
||||
canSubmit() {
|
||||
const { refundAmount, selectedReason, customReason } = this.data;
|
||||
const hasValidAmount = refundAmount && parseFloat(refundAmount) > 0;
|
||||
const hasValidReason = selectedReason && (selectedReason !== 'other' || customReason.trim());
|
||||
return hasValidAmount && hasValidReason;
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
console.log('[退款申请] 页面加载', options);
|
||||
|
||||
this.orderNo = options.orderNo;
|
||||
this.setData({
|
||||
isReapply: options.reapply === '1',
|
||||
originalRefundId: options.refundId || null
|
||||
});
|
||||
|
||||
if (!this.orderNo) {
|
||||
this.setData({
|
||||
error: '订单号不能为空',
|
||||
loading: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadOrderDetail();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 重新计算canSubmit
|
||||
this.updateCanSubmit();
|
||||
},
|
||||
|
||||
// 加载订单详情
|
||||
loadOrderDetail() {
|
||||
this.setData({
|
||||
loading: true,
|
||||
error: null
|
||||
});
|
||||
|
||||
if (!this.checkLoginAndNavigate()) {
|
||||
this.setData({
|
||||
loading: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const token = wx.getStorageSync('token');
|
||||
|
||||
console.log('[退款申请] 请求订单详情', { orderNo: this.orderNo });
|
||||
|
||||
wx.request({
|
||||
url: `${config.apiBase}/orders/${this.orderNo}`,
|
||||
method: 'GET',
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('[退款申请] 订单详情API响应', res);
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
const orderDetail = this.processOrderDetail(res.data.data);
|
||||
this.setData({
|
||||
orderDetail: orderDetail,
|
||||
maxRefundAmount: orderDetail.totalAmount,
|
||||
refundAmount: orderDetail.totalAmount, // 默认全额退款
|
||||
loading: false
|
||||
});
|
||||
|
||||
this.updateCanSubmit();
|
||||
} else {
|
||||
console.error('[退款申请] 订单详情API错误', res.data);
|
||||
this.setData({
|
||||
error: res.data.message || '获取订单详情失败',
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('[退款申请] 网络错误', error);
|
||||
this.setData({
|
||||
error: '网络错误',
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 处理订单详情数据
|
||||
processOrderDetail(data) {
|
||||
// 订单状态映射
|
||||
const statusMap = {
|
||||
1: '待付款',
|
||||
2: '待发货',
|
||||
3: '待发货',
|
||||
4: '已发货',
|
||||
5: '待收货',
|
||||
6: '已完成',
|
||||
7: '已取消',
|
||||
8: '退货中',
|
||||
9: '已退款'
|
||||
};
|
||||
|
||||
// 使用正确的字段名(根据后端JSON标签)
|
||||
const rawAmount = data.totalAmount || 0;
|
||||
|
||||
// 格式化金额(后端返回的是以分为单位的整数,需要转换为元)
|
||||
const totalAmount = (rawAmount / 100).toFixed(2);
|
||||
|
||||
return {
|
||||
orderId: data.orderId, // 保存订单ID用于提交退款申请
|
||||
orderNo: data.orderNo,
|
||||
statusText: statusMap[data.orderStatus] || '未知状态',
|
||||
totalAmount: totalAmount
|
||||
};
|
||||
},
|
||||
|
||||
// 更新提交按钮状态
|
||||
updateCanSubmit() {
|
||||
const { refundAmount, selectedReason, customReason } = this.data;
|
||||
const hasValidAmount = refundAmount && parseFloat(refundAmount) > 0;
|
||||
const hasValidReason = selectedReason && (selectedReason !== 'other' || customReason.trim());
|
||||
const canSubmit = hasValidAmount && hasValidReason;
|
||||
|
||||
this.setData({ canSubmit });
|
||||
},
|
||||
|
||||
// 金额输入
|
||||
onAmountInput(e) {
|
||||
let value = e.detail.value;
|
||||
|
||||
// 只允许数字和小数点
|
||||
value = value.replace(/[^\d.]/g, '');
|
||||
|
||||
// 只允许一个小数点
|
||||
const dotIndex = value.indexOf('.');
|
||||
if (dotIndex !== -1) {
|
||||
value = value.substring(0, dotIndex + 1) + value.substring(dotIndex + 1).replace(/\./g, '');
|
||||
// 限制小数点后两位
|
||||
if (value.length > dotIndex + 3) {
|
||||
value = value.substring(0, dotIndex + 3);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否超过最大退款金额
|
||||
const maxAmount = parseFloat(this.data.maxRefundAmount);
|
||||
const inputAmount = parseFloat(value);
|
||||
if (inputAmount > maxAmount) {
|
||||
value = this.data.maxRefundAmount;
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: '退款金额不能超过订单金额',
|
||||
theme: 'warning',
|
||||
});
|
||||
}
|
||||
|
||||
this.setData({ refundAmount: value });
|
||||
this.updateCanSubmit();
|
||||
},
|
||||
|
||||
// 快速填充全额
|
||||
onQuickFillAmount() {
|
||||
this.setData({ refundAmount: this.data.maxRefundAmount });
|
||||
this.updateCanSubmit();
|
||||
},
|
||||
|
||||
// 选择退款原因
|
||||
onReasonSelect(e) {
|
||||
const value = e.currentTarget.dataset.value;
|
||||
this.setData({
|
||||
selectedReason: value,
|
||||
customReason: value === 'other' ? this.data.customReason : ''
|
||||
});
|
||||
this.updateCanSubmit();
|
||||
},
|
||||
|
||||
// 自定义原因输入
|
||||
onCustomReasonInput(e) {
|
||||
this.setData({ customReason: e.detail.value });
|
||||
this.updateCanSubmit();
|
||||
},
|
||||
|
||||
// 退款说明输入
|
||||
onDescriptionInput(e) {
|
||||
this.setData({ description: e.detail.value });
|
||||
},
|
||||
|
||||
// 订单点击
|
||||
onOrderTap() {
|
||||
const { orderDetail } = this.data;
|
||||
if (orderDetail && orderDetail.orderNo) {
|
||||
wx.navigateTo({
|
||||
url: `/pages/order/order-detail/index?orderNo=${orderDetail.orderNo}`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 提交申请
|
||||
onSubmit() {
|
||||
if (!this.data.canSubmit || this.data.submitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证数据
|
||||
const { refundAmount, selectedReason, customReason, description } = this.data;
|
||||
|
||||
if (!refundAmount || parseFloat(refundAmount) <= 0) {
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: '请输入有效的退款金额',
|
||||
theme: 'warning',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedReason) {
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: '请选择退款原因',
|
||||
theme: 'warning',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedReason === 'other' && !customReason.trim()) {
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: '请填写具体的退款原因',
|
||||
theme: 'warning',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 确认提交
|
||||
const confirmText = this.data.isReapply ? '确定要重新提交退款申请吗?' : '确定要提交退款申请吗?';
|
||||
wx.showModal({
|
||||
title: '确认提交',
|
||||
content: confirmText,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.performSubmit();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 执行提交
|
||||
performSubmit() {
|
||||
this.setData({ submitting: true });
|
||||
|
||||
const token = wx.getStorageSync('token');
|
||||
const { refundAmount, selectedReason, customReason, description, isReapply, originalRefundId } = this.data;
|
||||
|
||||
// 构建退款原因
|
||||
let reason = '';
|
||||
if (selectedReason === 'other') {
|
||||
reason = customReason.trim();
|
||||
} else {
|
||||
const reasonOption = this.data.reasonOptions.find(option => option.value === selectedReason);
|
||||
reason = reasonOption ? reasonOption.label : '';
|
||||
}
|
||||
|
||||
// 构建请求数据(UserID由后端从JWT token中获取,不需要前端传递)
|
||||
const requestData = {
|
||||
order_id: parseInt(this.data.orderDetail.orderId), // 转换为数字类型
|
||||
refund_amount: parseFloat(refundAmount), // 后端期望的是元为单位的浮点数
|
||||
refund_reason: reason, // 使用正确的字段名
|
||||
refund_type: 1 // 1:仅退款 2:退货退款,默认为仅退款
|
||||
};
|
||||
|
||||
console.log('[退款申请] 提交数据', requestData);
|
||||
|
||||
// 选择API端点
|
||||
let url = `${config.apiBase}/refunds`;
|
||||
let method = 'POST';
|
||||
|
||||
if (isReapply && originalRefundId) {
|
||||
url = `${config.apiBase}/refunds/${originalRefundId}/reapply`;
|
||||
method = 'PUT';
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: url,
|
||||
method: method,
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: requestData,
|
||||
success: (res) => {
|
||||
console.log('[退款申请] 提交响应', res);
|
||||
|
||||
this.setData({ submitting: false });
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: isReapply ? '重新申请成功' : '申请提交成功',
|
||||
theme: 'success',
|
||||
});
|
||||
|
||||
// 延迟跳转
|
||||
setTimeout(() => {
|
||||
wx.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
}, 1500);
|
||||
} else {
|
||||
console.error('[退款申请] 提交失败', res.data);
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: res.data.message || '提交失败',
|
||||
theme: 'error',
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('[退款申请] 网络错误', error);
|
||||
this.setData({ submitting: false });
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: '网络错误',
|
||||
theme: 'error',
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 重试
|
||||
onRetry() {
|
||||
this.loadOrderDetail();
|
||||
}
|
||||
});
|
||||
7
miniprogram/pages/refund/refund-apply/index.json
Normal file
7
miniprogram/pages/refund/refund-apply/index.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"navigationBarTitleText": "申请退款",
|
||||
"enablePullDownRefresh": false,
|
||||
"usingComponents": {
|
||||
"t-toast": "tdesign-miniprogram/toast/toast"
|
||||
}
|
||||
}
|
||||
129
miniprogram/pages/refund/refund-apply/index.wxml
Normal file
129
miniprogram/pages/refund/refund-apply/index.wxml
Normal file
@@ -0,0 +1,129 @@
|
||||
<!--pages/refund/refund-apply/index.wxml-->
|
||||
<view class="refund-apply-page">
|
||||
<!-- 页面标题 -->
|
||||
<view class="page-header">
|
||||
<text class="page-title">{{isReapply ? '重新申请退款' : '申请退款'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 订单信息 -->
|
||||
<view class="order-section" wx:if="{{orderDetail}}">
|
||||
<view class="section-title">订单信息</view>
|
||||
<view class="order-card" bindtap="onOrderTap">
|
||||
<view class="order-header">
|
||||
<text class="order-no">订单号:{{orderDetail.orderNo}}</text>
|
||||
<text class="order-status">{{orderDetail.statusText}}</text>
|
||||
</view>
|
||||
<view class="order-amount">
|
||||
<text class="amount-label">订单金额:</text>
|
||||
<text class="amount-value">¥{{orderDetail.totalAmount}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退款金额 -->
|
||||
<view class="amount-section">
|
||||
<view class="section-title">退款金额</view>
|
||||
<view class="amount-input-wrapper">
|
||||
<text class="currency-symbol">¥</text>
|
||||
<input
|
||||
class="amount-input"
|
||||
type="digit"
|
||||
placeholder="请输入退款金额"
|
||||
value="{{refundAmount}}"
|
||||
bindinput="onAmountInput"
|
||||
maxlength="10"
|
||||
/>
|
||||
</view>
|
||||
<view class="amount-tips">
|
||||
<text class="tips-text">最多可退款:¥{{maxRefundAmount}}</text>
|
||||
<text class="quick-fill" bindtap="onQuickFillAmount">全额退款</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退款原因 -->
|
||||
<view class="reason-section">
|
||||
<view class="section-title">退款原因</view>
|
||||
<view class="reason-options">
|
||||
<view
|
||||
class="reason-option {{selectedReason === item.value ? 'selected' : ''}}"
|
||||
wx:for="{{reasonOptions}}"
|
||||
wx:key="value"
|
||||
bindtap="onReasonSelect"
|
||||
data-value="{{item.value}}"
|
||||
>
|
||||
<text class="reason-text">{{item.label}}</text>
|
||||
<view class="reason-check {{selectedReason === item.value ? 'checked' : ''}}">
|
||||
<text class="check-icon" wx:if="{{selectedReason === item.value}}">✓</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 自定义原因输入 -->
|
||||
<view class="custom-reason" wx:if="{{selectedReason === 'other'}}">
|
||||
<textarea
|
||||
class="reason-textarea"
|
||||
placeholder="请详细说明退款原因"
|
||||
value="{{customReason}}"
|
||||
bindinput="onCustomReasonInput"
|
||||
maxlength="200"
|
||||
show-confirm-bar="{{false}}"
|
||||
/>
|
||||
<view class="char-count">{{customReason.length}}/200</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退款说明 -->
|
||||
<view class="description-section">
|
||||
<view class="section-title">退款说明(选填)</view>
|
||||
<textarea
|
||||
class="description-textarea"
|
||||
placeholder="请详细描述退款原因,有助于快速处理"
|
||||
value="{{description}}"
|
||||
bindinput="onDescriptionInput"
|
||||
maxlength="500"
|
||||
show-confirm-bar="{{false}}"
|
||||
/>
|
||||
<view class="char-count">{{description.length}}/500</view>
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view class="submit-section">
|
||||
<button
|
||||
class="submit-btn {{canSubmit ? 'enabled' : 'disabled'}}"
|
||||
bindtap="onSubmit"
|
||||
disabled="{{!canSubmit || submitting}}"
|
||||
>
|
||||
{{submitting ? '提交中...' : (isReapply ? '重新提交' : '提交申请')}}
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 温馨提示 -->
|
||||
<view class="tips-section">
|
||||
<view class="tips-title">温馨提示</view>
|
||||
<view class="tips-content">
|
||||
<text class="tip-item">• 退款申请提交后,我们将在1-3个工作日内处理</text>
|
||||
<text class="tip-item">• 退款金额将原路返回到您的支付账户</text>
|
||||
<text class="tip-item">• 如有疑问,请联系客服:400-123-4567</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view class="loading-wrapper" wx:if="{{loading}}">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<view class="error-wrapper" wx:if="{{error}}">
|
||||
<view class="error-content">
|
||||
<text class="error-icon">⚠️</text>
|
||||
<text class="error-text">{{error}}</text>
|
||||
<button class="retry-btn" bindtap="onRetry">重试</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Toast组件 -->
|
||||
<t-toast id="t-toast" />
|
||||
</view>
|
||||
351
miniprogram/pages/refund/refund-apply/index.wxss
Normal file
351
miniprogram/pages/refund/refund-apply/index.wxss
Normal file
@@ -0,0 +1,351 @@
|
||||
/* pages/refund/refund-apply/index.wxss */
|
||||
.refund-apply-page {
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
/* 页面标题 */
|
||||
.page-header {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 通用区块样式 */
|
||||
.order-section,
|
||||
.amount-section,
|
||||
.reason-section,
|
||||
.description-section {
|
||||
background: #fff;
|
||||
margin-top: 20rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
/* 订单信息 */
|
||||
.order-card {
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
border: 1rpx solid #e9ecef;
|
||||
}
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.order-no {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.order-status {
|
||||
font-size: 24rpx;
|
||||
color: #007aff;
|
||||
background: #e3f2fd;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.order-amount {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.amount-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.amount-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #ff4757;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
/* 退款金额 */
|
||||
.amount-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
border: 1rpx solid #e9ecef;
|
||||
}
|
||||
|
||||
.currency-symbol {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.amount-input {
|
||||
flex: 1;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.amount-tips {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.tips-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.quick-fill {
|
||||
font-size: 24rpx;
|
||||
color: #007aff;
|
||||
padding: 8rpx 16rpx;
|
||||
background: #e3f2fd;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
/* 退款原因 */
|
||||
.reason-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.reason-option {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
border: 1rpx solid #e9ecef;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.reason-option.selected {
|
||||
background: #e3f2fd;
|
||||
border-color: #007aff;
|
||||
}
|
||||
|
||||
.reason-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.reason-check {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #ddd;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.reason-check.checked {
|
||||
background: #007aff;
|
||||
border-color: #007aff;
|
||||
}
|
||||
|
||||
.check-icon {
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 自定义原因 */
|
||||
.custom-reason {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.reason-textarea {
|
||||
width: 100%;
|
||||
min-height: 120rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
border: 1rpx solid #e9ecef;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 退款说明 */
|
||||
.description-textarea {
|
||||
width: 100%;
|
||||
min-height: 160rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
border: 1rpx solid #e9ecef;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
/* 提交按钮 */
|
||||
.submit-section {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.submit-btn.enabled {
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.submit-btn.disabled {
|
||||
background: #f5f5f5;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* 温馨提示 */
|
||||
.tips-section {
|
||||
background: #fff;
|
||||
margin-top: 20rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.tips-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tips-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.tip-item {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.loading-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #f3f3f3;
|
||||
border-top: 4rpx solid #007aff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 错误状态 */
|
||||
.error-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.error-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 40rpx;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
font-size: 80rpx;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.retry-btn {
|
||||
background: #007aff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
padding: 16rpx 32rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
Reference in New Issue
Block a user