feat: 新增订单详情退款弹窗
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<view class="login-wrapper">
|
||||
<image class="bg" src="./images/bg.png"></image>
|
||||
<view class="login-wrapper" :style="{ backgroundImage: `url(${loginBg})` }">
|
||||
<!-- 头部内容 -->
|
||||
<view class="login-header">
|
||||
<!-- 卡通形象 -->
|
||||
@@ -66,6 +65,7 @@ import CheckBox from "@/components/CheckBox/index.vue";
|
||||
import AgreePopup from "./components/AgreePopup/index.vue";
|
||||
import { loginAuth, bindPhone, checkPhone } from "@/manager/LoginManager";
|
||||
import { goHome } from "@/hooks/useGoHome";
|
||||
import loginBg from "./images/bg.png";
|
||||
|
||||
const isAgree = ref(false);
|
||||
const visible = ref(false);
|
||||
|
||||
@@ -1,70 +1,62 @@
|
||||
.login-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
font-family: PingFang SC, PingFang SC;
|
||||
height: 100vh;
|
||||
padding-top: 168px;
|
||||
position: relative;
|
||||
|
||||
.bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.login-header {
|
||||
text-align: center;
|
||||
|
||||
.login-avatar {
|
||||
width: 150px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
width: 137px;
|
||||
margin: 6px auto;
|
||||
}
|
||||
|
||||
.login-desc {
|
||||
font-size: 12px;
|
||||
color: #1E4C69;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-btn-area {
|
||||
margin-top: 46px;
|
||||
width: 297px;
|
||||
|
||||
.login-btn {
|
||||
background: linear-gradient( 246deg, #22A7FF 0%, #2567FF 100%);
|
||||
width: 100%;
|
||||
border-radius: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-agreement {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
font-family: PingFang SC, PingFang SC;
|
||||
height: 100vh;
|
||||
padding-top: 168px;
|
||||
position: relative;
|
||||
background-position: 0 0;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
.login-agreement-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
.login-header {
|
||||
text-align: center;
|
||||
max-height: 223px;
|
||||
|
||||
.login-avatar {
|
||||
width: 150px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
width: 137px;
|
||||
margin: 6px auto;
|
||||
}
|
||||
|
||||
.login-desc {
|
||||
font-size: 12px;
|
||||
color: #1e4c69;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-agreement-link {
|
||||
font-size: 14px;
|
||||
color: #007aff;
|
||||
margin: 0 5px;
|
||||
.login-btn-area {
|
||||
margin-top: 46px;
|
||||
width: 297px;
|
||||
|
||||
.login-btn {
|
||||
background: linear-gradient(246deg, #22a7ff 0%, #2567ff 100%);
|
||||
width: 100%;
|
||||
border-radius: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-agreement {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.login-agreement-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.login-agreement-link {
|
||||
font-size: 14px;
|
||||
color: #007aff;
|
||||
margin: 0 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, computed, ref } from "vue";
|
||||
import { defineProps, computed, ref, defineEmits } from "vue";
|
||||
import {
|
||||
preOrder,
|
||||
orderPayNow,
|
||||
@@ -56,6 +56,9 @@ const PAY_WAY_MAP = {
|
||||
// 加载状态
|
||||
const isLoading = ref(false);
|
||||
|
||||
// 定义事件发射器
|
||||
const emit = defineEmits(['show-refund-popup']);
|
||||
|
||||
const props = defineProps({
|
||||
orderData: {
|
||||
type: Object,
|
||||
@@ -111,39 +114,35 @@ const handleButtonClick = async () => {
|
||||
// 支付渠道
|
||||
const paySource = "1";
|
||||
|
||||
if (status === "2") {
|
||||
// 情况2:待使用状态,显示退款弹窗
|
||||
emit('show-refund-popup');
|
||||
return; // 直接返回,不执行后续代码
|
||||
}
|
||||
|
||||
try {
|
||||
isLoading.value = true;
|
||||
|
||||
if (status === "2") {
|
||||
// 情况2:待使用状态,直接申请退款
|
||||
await orderRefund({ orderId });
|
||||
// 情况1:待支付状态或其他状态,先预下单再支付
|
||||
// 第一步:预下单
|
||||
const res = await orderPayNow({ orderId, payWay, paySource });
|
||||
console.log(res);
|
||||
|
||||
uni.showToast({
|
||||
title: "退款申请已提交",
|
||||
icon: "success",
|
||||
});
|
||||
} else {
|
||||
// 情况1:待支付状态或其他状态,先预下单再支付
|
||||
// 第一步:预下单
|
||||
const res = await orderPayNow({ orderId, payWay, paySource });
|
||||
console.log(res);
|
||||
|
||||
// 仅作为示例,非真实参数信息。
|
||||
uni.requestPayment({
|
||||
provider: "wxpay",
|
||||
timeStamp: String(Date.now()),
|
||||
nonceStr: "A1B2C3D4E5",
|
||||
package: "prepay_id=wx20180101abcdefg",
|
||||
signType: "MD5",
|
||||
paySign: "",
|
||||
success: (res) => {
|
||||
console.log("success:" + JSON.stringify(res));
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log("fail:" + JSON.stringify(err));
|
||||
},
|
||||
});
|
||||
}
|
||||
// 仅作为示例,非真实参数信息。
|
||||
uni.requestPayment({
|
||||
provider: "wxpay",
|
||||
timeStamp: String(Date.now()),
|
||||
nonceStr: "A1B2C3D4E5",
|
||||
package: "prepay_id=wx20180101abcdefg",
|
||||
signType: "MD5",
|
||||
paySign: "",
|
||||
success: (res) => {
|
||||
console.log("success:" + JSON.stringify(res));
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log("fail:" + JSON.stringify(err));
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("操作失败:", error);
|
||||
uni.showToast({
|
||||
|
||||
158
pages/order/components/RefundPopup/README.md
Normal file
158
pages/order/components/RefundPopup/README.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# RefundPopup 退款弹窗组件
|
||||
|
||||
## 组件概述
|
||||
`RefundPopup` 是一个用于处理订单退款相关操作的弹窗组件,支持多种退款场景和状态展示。
|
||||
|
||||
## 功能需求分析
|
||||
|
||||
### 界面设计规范
|
||||
1. **弹窗容器**
|
||||
- 使用圆角矩形容器,背景色为白色
|
||||
- 弹窗宽度适中,居中显示
|
||||
- 支持遮罩层,点击遮罩可关闭弹窗
|
||||
|
||||
2. **头部区域**
|
||||
- 显示可爱的花朵卡通形象作为视觉元素
|
||||
- 卡通形象位于弹窗顶部中央位置
|
||||
|
||||
3. **内容区域**
|
||||
- 主标题:根据不同场景显示相应提示文字
|
||||
- 副标题:显示详细的退款规则和说明
|
||||
- 金额显示:突出显示可退金额(橙色字体)
|
||||
- 退款政策:详细列出各种退款条件和规则
|
||||
|
||||
4. **按钮区域**
|
||||
- 双按钮布局:左侧为次要操作,右侧为主要操作
|
||||
- 按钮样式:圆角矩形,左侧蓝色,右侧橙色
|
||||
- 按钮文字:根据场景显示不同的操作文字
|
||||
|
||||
### 交互功能
|
||||
1. **弹窗显示/隐藏**
|
||||
- 支持通过方法调用显示弹窗
|
||||
- 支持点击遮罩层关闭弹窗
|
||||
- 支持点击按钮后关闭弹窗
|
||||
|
||||
2. **退款场景处理**
|
||||
- **不予退款场景**:显示"不予退款:12小时以内取消或未入住,不予退款"
|
||||
- **免费取消场景**:显示"免费取消:提前48小时以上,全额退还房费"
|
||||
- **部分退款场景**:显示退款政策详情和可退金额
|
||||
- **商品限制场景**:显示"该商品未使用随时可退"
|
||||
|
||||
3. **按钮交互**
|
||||
- 左侧按钮:"退订政策"或"退订政策"(查看详情)
|
||||
- 右侧按钮:"我知道了"或"点击退款"(确认操作)
|
||||
- 支持按钮点击事件回调
|
||||
|
||||
4. **数据展示**
|
||||
- 动态显示可退金额
|
||||
- 展示详细的退款规则列表
|
||||
- 支持不同退款类型的文案切换
|
||||
|
||||
### 技术要求
|
||||
1. **组件架构**
|
||||
- 使用 Vue 3 Composition API
|
||||
- 支持 TypeScript(可选)
|
||||
- 使用 uni-popup 作为弹窗基础组件
|
||||
|
||||
2. **样式处理**
|
||||
- 使用 SASS 预处理器
|
||||
- 支持响应式设计
|
||||
- 遵循设计规范的颜色和字体
|
||||
|
||||
3. **性能优化**
|
||||
- 懒加载弹窗内容
|
||||
- 合理使用计算属性
|
||||
- 避免不必要的重渲染
|
||||
|
||||
4. **代码规范**
|
||||
- 清晰的组件结构
|
||||
- 详细的注释说明
|
||||
- 统一的命名规范
|
||||
|
||||
### 样式规范
|
||||
1. **颜色规范**
|
||||
- 主色调:蓝色 #007AFF(左侧按钮)
|
||||
- 强调色:橙色 #FF9500(右侧按钮、金额)
|
||||
- 文字色:黑色 #000000(主要文字)
|
||||
- 辅助色:灰色 #666666(辅助文字)
|
||||
- 背景色:白色 #FFFFFF
|
||||
|
||||
2. **字体规范**
|
||||
- 主标题:16px,加粗
|
||||
- 副标题:14px,常规
|
||||
- 金额:18px,加粗,橙色
|
||||
- 按钮文字:16px,加粗
|
||||
- 说明文字:12px,常规
|
||||
|
||||
3. **间距规范**
|
||||
- 弹窗内边距:20px
|
||||
- 元素间距:12px
|
||||
- 按钮间距:12px
|
||||
- 按钮高度:44px
|
||||
|
||||
### 组件接口
|
||||
|
||||
#### Props
|
||||
```typescript
|
||||
interface RefundPopupProps {
|
||||
// 弹窗显示状态
|
||||
visible: boolean
|
||||
// 退款类型:'no_refund' | 'free_cancel' | 'partial_refund' | 'anytime_refund'
|
||||
refundType: string
|
||||
// 可退金额
|
||||
refundAmount?: number
|
||||
// 退款规则列表
|
||||
refundRules?: string[]
|
||||
// 自定义标题
|
||||
title?: string
|
||||
// 自定义描述
|
||||
description?: string
|
||||
}
|
||||
```
|
||||
|
||||
#### Events
|
||||
```typescript
|
||||
interface RefundPopupEvents {
|
||||
// 弹窗关闭事件
|
||||
'update:visible': (visible: boolean) => void
|
||||
// 查看政策按钮点击
|
||||
'policy-click': () => void
|
||||
// 确认按钮点击
|
||||
'confirm-click': () => void
|
||||
// 弹窗关闭事件
|
||||
'close': () => void
|
||||
}
|
||||
```
|
||||
|
||||
#### Methods
|
||||
```typescript
|
||||
interface RefundPopupMethods {
|
||||
// 显示弹窗
|
||||
show(): void
|
||||
// 隐藏弹窗
|
||||
hide(): void
|
||||
}
|
||||
```
|
||||
|
||||
### 使用场景
|
||||
1. **订单详情页面**:用户查看退款政策
|
||||
2. **退款申请流程**:确认退款操作
|
||||
3. **客服咨询场景**:展示退款规则
|
||||
4. **订单管理后台**:处理退款申请
|
||||
|
||||
### 文件结构
|
||||
```
|
||||
RefundPopup/
|
||||
├── index.vue # 主组件文件
|
||||
├── styles/
|
||||
│ └── index.scss # 样式文件
|
||||
├── demo.vue # 演示页面
|
||||
└── README.md # 组件文档
|
||||
```
|
||||
|
||||
### 开发注意事项
|
||||
1. 确保弹窗在不同屏幕尺寸下的适配
|
||||
2. 处理长文本的换行和显示
|
||||
3. 考虑无障碍访问支持
|
||||
4. 添加适当的动画效果
|
||||
5. 确保组件的可复用性和可扩展性
|
||||
389
pages/order/components/RefundPopup/demo.vue
Normal file
389
pages/order/components/RefundPopup/demo.vue
Normal file
@@ -0,0 +1,389 @@
|
||||
<template>
|
||||
<view class="demo-container">
|
||||
<view class="demo-header">
|
||||
<text class="demo-title">RefundPopup 退款弹窗组件演示</text>
|
||||
</view>
|
||||
|
||||
<view class="demo-content">
|
||||
<!-- 场景选择 -->
|
||||
<view class="demo-section">
|
||||
<text class="section-title">退款场景</text>
|
||||
<view class="scenario-buttons">
|
||||
<button
|
||||
class="scenario-btn"
|
||||
:class="{ active: currentScenario === 'no_refund' }"
|
||||
@click="setScenario('no_refund')"
|
||||
>
|
||||
不予退款
|
||||
</button>
|
||||
<button
|
||||
class="scenario-btn"
|
||||
:class="{ active: currentScenario === 'free_cancel' }"
|
||||
@click="setScenario('free_cancel')"
|
||||
>
|
||||
免费取消
|
||||
</button>
|
||||
<button
|
||||
class="scenario-btn"
|
||||
:class="{ active: currentScenario === 'partial_refund' }"
|
||||
@click="setScenario('partial_refund')"
|
||||
>
|
||||
部分退款
|
||||
</button>
|
||||
<button
|
||||
class="scenario-btn"
|
||||
:class="{ active: currentScenario === 'anytime_refund' }"
|
||||
@click="setScenario('anytime_refund')"
|
||||
>
|
||||
随时可退
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 金额设置 -->
|
||||
<view class="demo-section">
|
||||
<text class="section-title">退款金额</text>
|
||||
<view class="amount-input">
|
||||
<input
|
||||
class="amount-field"
|
||||
type="number"
|
||||
v-model="refundAmount"
|
||||
placeholder="请输入退款金额"
|
||||
/>
|
||||
<text class="amount-unit">元</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="demo-section">
|
||||
<button class="demo-btn primary" @click="showPopup">
|
||||
显示退款弹窗
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 事件日志 -->
|
||||
<view class="demo-section">
|
||||
<text class="section-title">事件日志</text>
|
||||
<view class="event-log">
|
||||
<view
|
||||
class="log-item"
|
||||
v-for="(log, index) in eventLogs"
|
||||
:key="index"
|
||||
>
|
||||
<text class="log-time">{{ log.time }}</text>
|
||||
<text class="log-event">{{ log.event }}</text>
|
||||
</view>
|
||||
<view class="log-empty" v-if="eventLogs.length === 0">
|
||||
暂无事件日志
|
||||
</view>
|
||||
</view>
|
||||
<button class="demo-btn secondary" @click="clearLogs">
|
||||
清空日志
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- RefundPopup 组件 -->
|
||||
<RefundPopup
|
||||
v-model="popupVisible"
|
||||
:refund-type="currentScenario"
|
||||
:refund-amount="refundAmount"
|
||||
:refund-rules="customRules"
|
||||
@policy-click="handlePolicyClick"
|
||||
@confirm-click="handleConfirmClick"
|
||||
@close="handleClose"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import RefundPopup from './index.vue'
|
||||
|
||||
// 响应式数据
|
||||
const popupVisible = ref(false)
|
||||
const currentScenario = ref('no_refund')
|
||||
const refundAmount = ref(399)
|
||||
const eventLogs = ref([])
|
||||
|
||||
// 自定义退款规则(可选)
|
||||
const customRules = ref([])
|
||||
|
||||
// 方法定义
|
||||
const setScenario = (scenario) => {
|
||||
currentScenario.value = scenario
|
||||
addLog(`切换到场景: ${getScenarioName(scenario)}`)
|
||||
|
||||
// 根据场景设置默认金额
|
||||
switch (scenario) {
|
||||
case 'no_refund':
|
||||
refundAmount.value = 0
|
||||
break
|
||||
case 'free_cancel':
|
||||
refundAmount.value = 399
|
||||
break
|
||||
case 'partial_refund':
|
||||
refundAmount.value = 199
|
||||
break
|
||||
case 'anytime_refund':
|
||||
refundAmount.value = 399
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const getScenarioName = (scenario) => {
|
||||
const names = {
|
||||
'no_refund': '不予退款',
|
||||
'free_cancel': '免费取消',
|
||||
'partial_refund': '部分退款',
|
||||
'anytime_refund': '随时可退'
|
||||
}
|
||||
return names[scenario] || scenario
|
||||
}
|
||||
|
||||
const showPopup = () => {
|
||||
popupVisible.value = true
|
||||
addLog('显示退款弹窗')
|
||||
}
|
||||
|
||||
const handlePolicyClick = () => {
|
||||
addLog('点击了退订政策按钮')
|
||||
// 这里可以跳转到政策详情页面
|
||||
uni.showToast({
|
||||
title: '查看退订政策',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
const handleConfirmClick = () => {
|
||||
addLog(`确认操作 - 场景: ${getScenarioName(currentScenario.value)}, 金额: ¥${refundAmount.value}`)
|
||||
|
||||
// 根据不同场景执行不同操作
|
||||
if (currentScenario.value === 'no_refund') {
|
||||
uni.showToast({
|
||||
title: '已知晓退款政策',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '退款申请已提交',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
addLog('关闭退款弹窗')
|
||||
}
|
||||
|
||||
const addLog = (event) => {
|
||||
const now = new Date()
|
||||
const time = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`
|
||||
|
||||
eventLogs.value.unshift({
|
||||
time,
|
||||
event
|
||||
})
|
||||
|
||||
// 限制日志数量
|
||||
if (eventLogs.value.length > 10) {
|
||||
eventLogs.value = eventLogs.value.slice(0, 10)
|
||||
}
|
||||
}
|
||||
|
||||
const clearLogs = () => {
|
||||
eventLogs.value = []
|
||||
addLog('清空事件日志')
|
||||
}
|
||||
|
||||
// 初始化
|
||||
addLog('演示页面已加载')
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.demo-container {
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.demo-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
.demo-section {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
margin-bottom: 16px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scenario-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
|
||||
.scenario-btn {
|
||||
flex: 1;
|
||||
min-width: 80px;
|
||||
height: 40px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 20px;
|
||||
background: #ffffff;
|
||||
color: #666666;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.active {
|
||||
border-color: #007aff;
|
||||
background: #007aff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.amount-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.amount-field {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 0 16px;
|
||||
font-size: 16px;
|
||||
background: #ffffff;
|
||||
|
||||
&:focus {
|
||||
border-color: #007aff;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.amount-unit {
|
||||
font-size: 16px;
|
||||
color: #666666;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-btn {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
border: none;
|
||||
border-radius: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.primary {
|
||||
background: #007aff;
|
||||
color: #ffffff;
|
||||
|
||||
&:active {
|
||||
background: #0056cc;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
background: #f0f0f0;
|
||||
color: #666666;
|
||||
margin-top: 12px;
|
||||
|
||||
&:active {
|
||||
background: #e0e0e0;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.event-log {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
background: #f9f9f9;
|
||||
|
||||
.log-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 4px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.log-time {
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
font-family: monospace;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.log-event {
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.log-empty {
|
||||
text-align: center;
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式适配
|
||||
@media screen and (max-width: 375px) {
|
||||
.demo-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
.demo-section {
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.scenario-buttons {
|
||||
.scenario-btn {
|
||||
min-width: 70px;
|
||||
height: 36px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
274
pages/order/components/RefundPopup/example.vue
Normal file
274
pages/order/components/RefundPopup/example.vue
Normal file
@@ -0,0 +1,274 @@
|
||||
<template>
|
||||
<view class="example-page">
|
||||
<view class="page-header">
|
||||
<text class="page-title">订单详情</text>
|
||||
</view>
|
||||
|
||||
<view class="order-info">
|
||||
<view class="order-item">
|
||||
<text class="item-name">鲜牛肉红烧牛肉面二两+例汤1份</text>
|
||||
<text class="item-price">¥128</text>
|
||||
</view>
|
||||
<view class="order-item">
|
||||
<text class="item-name">红油干拌鲜肉云吞+例汤1份</text>
|
||||
<text class="item-price">¥50</text>
|
||||
</view>
|
||||
<view class="order-total">
|
||||
<text class="total-label">总计:</text>
|
||||
<text class="total-price">¥178</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="order-actions">
|
||||
<button class="action-button refund-btn" @click="showRefundPopup">
|
||||
申请退款
|
||||
</button>
|
||||
<button class="action-button contact-btn" @click="contactService">
|
||||
联系客服
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 退款弹窗组件 -->
|
||||
<RefundPopup
|
||||
v-model="refundVisible"
|
||||
:refund-type="refundType"
|
||||
:refund-amount="refundAmount"
|
||||
@policy-click="viewRefundPolicy"
|
||||
@confirm-click="handleRefundConfirm"
|
||||
@close="handleRefundClose"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import RefundPopup from './index.vue'
|
||||
|
||||
// 响应式数据
|
||||
const refundVisible = ref(false)
|
||||
const refundType = ref('partial_refund')
|
||||
const refundAmount = ref(89) // 50% 退款
|
||||
|
||||
// 方法定义
|
||||
const showRefundPopup = () => {
|
||||
// 根据订单状态和时间判断退款类型
|
||||
const orderTime = new Date('2024-01-15 10:00:00')
|
||||
const currentTime = new Date()
|
||||
const hoursDiff = (currentTime - orderTime) / (1000 * 60 * 60)
|
||||
|
||||
if (hoursDiff < 12) {
|
||||
refundType.value = 'no_refund'
|
||||
refundAmount.value = 0
|
||||
} else if (hoursDiff < 24) {
|
||||
refundType.value = 'partial_refund'
|
||||
refundAmount.value = 89 // 50% 退款
|
||||
} else if (hoursDiff < 48) {
|
||||
refundType.value = 'free_cancel'
|
||||
refundAmount.value = 178 // 全额退款
|
||||
} else {
|
||||
refundType.value = 'anytime_refund'
|
||||
refundAmount.value = 178
|
||||
}
|
||||
|
||||
refundVisible.value = true
|
||||
}
|
||||
|
||||
const viewRefundPolicy = () => {
|
||||
// 跳转到退款政策页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/policy/refund'
|
||||
})
|
||||
}
|
||||
|
||||
const handleRefundConfirm = () => {
|
||||
if (refundType.value === 'no_refund') {
|
||||
uni.showToast({
|
||||
title: '已了解退款政策',
|
||||
icon: 'success'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 提交退款申请
|
||||
uni.showLoading({
|
||||
title: '提交中...'
|
||||
})
|
||||
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '退款申请已提交',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 可以跳转到退款状态页面
|
||||
// uni.navigateTo({
|
||||
// url: '/pages/refund/status'
|
||||
// })
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
const handleRefundClose = () => {
|
||||
console.log('退款弹窗已关闭')
|
||||
}
|
||||
|
||||
const contactService = () => {
|
||||
uni.showActionSheet({
|
||||
itemList: ['在线客服', '电话客服', '意见反馈'],
|
||||
success: (res) => {
|
||||
switch (res.tapIndex) {
|
||||
case 0:
|
||||
// 打开在线客服
|
||||
uni.navigateTo({
|
||||
url: '/pages/service/chat'
|
||||
})
|
||||
break
|
||||
case 1:
|
||||
// 拨打客服电话
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: '400-123-4567'
|
||||
})
|
||||
break
|
||||
case 2:
|
||||
// 打开意见反馈
|
||||
uni.navigateTo({
|
||||
url: '/pages/feedback/index'
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.example-page {
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.page-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
|
||||
.order-info {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.order-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
font-size: 16px;
|
||||
color: #ff6b35;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.order-total {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding-top: 12px;
|
||||
margin-top: 12px;
|
||||
border-top: 2px solid #f0f0f0;
|
||||
|
||||
.total-label {
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.total-price {
|
||||
font-size: 20px;
|
||||
color: #ff6b35;
|
||||
font-weight: 700;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.order-actions {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
||||
.action-button {
|
||||
flex: 1;
|
||||
height: 48px;
|
||||
border: none;
|
||||
border-radius: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.refund-btn {
|
||||
background: #ff6b35;
|
||||
color: #ffffff;
|
||||
|
||||
&:active {
|
||||
background: #e55a2b;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
&.contact-btn {
|
||||
background: #007aff;
|
||||
color: #ffffff;
|
||||
|
||||
&:active {
|
||||
background: #0056cc;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式适配
|
||||
@media screen and (max-width: 375px) {
|
||||
.example-page {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.order-actions {
|
||||
gap: 12px;
|
||||
|
||||
.action-button {
|
||||
height: 44px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
217
pages/order/components/RefundPopup/index.vue
Normal file
217
pages/order/components/RefundPopup/index.vue
Normal file
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<uni-popup ref="popupRef" type="center" @maskClick="handleClose">
|
||||
<view class="refund-popup">
|
||||
<!-- 头部卡通形象 -->
|
||||
<image
|
||||
src="@/static/dh.png"
|
||||
class="refund-popup__avatar"
|
||||
mode="widthFix"
|
||||
/>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<view class="refund-popup__content">
|
||||
<!-- 主标题 -->
|
||||
<view class="refund-popup__title">{{ currentTitle }}</view>
|
||||
|
||||
<!-- 金额显示 -->
|
||||
<view class="refund-popup__amount" v-if="showAmount">
|
||||
<text class="amount-symbol">¥</text>
|
||||
<text class="amount-value">{{ refundAmount }}</text>
|
||||
<text class="amount-unit">元</text>
|
||||
</view>
|
||||
<view class="refund-popup__amount-label" v-if="showAmount"
|
||||
>可退金额</view
|
||||
>
|
||||
|
||||
<!-- 描述信息 -->
|
||||
<view class="refund-popup__description" v-if="currentDescription">
|
||||
{{ currentDescription }}
|
||||
</view>
|
||||
|
||||
<!-- 退款政策详情 -->
|
||||
<view class="refund-popup__policy" v-if="showPolicy">
|
||||
<view class="policy-title">退订政策:</view>
|
||||
<view class="policy-list">
|
||||
<view
|
||||
class="policy-item"
|
||||
v-for="(rule, index) in currentRules"
|
||||
:key="index"
|
||||
>
|
||||
{{ rule }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 按钮区域 -->
|
||||
<view class="refund-popup__actions">
|
||||
<view class="action-btn secondary-btn" @click="handlePolicyClick">
|
||||
{{ leftButtonText }}
|
||||
</view>
|
||||
<view class="action-btn primary-btn" @click="handleConfirmClick">
|
||||
{{ rightButtonText }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, shallowRef } from "vue";
|
||||
|
||||
// Props定义
|
||||
const props = defineProps({
|
||||
// 弹窗显示状态
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 退款类型
|
||||
refundType: {
|
||||
type: String,
|
||||
default: "no_refund",
|
||||
validator: (value) =>
|
||||
["no_refund", "all_refund", "anytime_refund"].includes(value),
|
||||
},
|
||||
// 可退金额
|
||||
refundAmount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 退款规则列表
|
||||
refundRules: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 自定义标题
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
// 自定义描述
|
||||
description: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
// Events定义
|
||||
const emit = defineEmits([
|
||||
"update:modelValue",
|
||||
"policy-click",
|
||||
"confirm-click",
|
||||
"close",
|
||||
]);
|
||||
|
||||
// 弹窗引用
|
||||
const popupRef = ref(null);
|
||||
|
||||
// 退款场景配置(使用shallowRef优化性能)
|
||||
const refundScenarios = shallowRef({
|
||||
no_refund: {
|
||||
title: "您在入住日期12小时以内申请退款,不可退款,如有疑问请咨询客服",
|
||||
description: "",
|
||||
showAmount: false,
|
||||
showPolicy: false,
|
||||
leftButton: "退订政策",
|
||||
rightButton: "我知道了",
|
||||
rules: [],
|
||||
},
|
||||
all_refund: {
|
||||
title: "您在入住日期24小时内申请退款,可退还100%金额",
|
||||
description: "",
|
||||
showAmount: true,
|
||||
showPolicy: true,
|
||||
leftButton: "退订政策",
|
||||
rightButton: "点击退款",
|
||||
rules: [],
|
||||
},
|
||||
anytime_refund: {
|
||||
title: "该商品未使用随时可退",
|
||||
description: "",
|
||||
showAmount: true,
|
||||
showPolicy: false,
|
||||
leftButton: "退订政策",
|
||||
rightButton: "点击退款",
|
||||
rules: [],
|
||||
},
|
||||
});
|
||||
|
||||
// 计算属性
|
||||
const currentScenario = computed(
|
||||
() =>
|
||||
refundScenarios.value[props.refundType] || refundScenarios.value.no_refund
|
||||
);
|
||||
|
||||
const currentTitle = computed(() => props.title || currentScenario.value.title);
|
||||
|
||||
const currentDescription = computed(
|
||||
() => props.description || currentScenario.value.description
|
||||
);
|
||||
|
||||
const currentRules = computed(() => {
|
||||
if (props.refundRules.length) {
|
||||
return props.refundRules;
|
||||
}
|
||||
return currentScenario.value.rules;
|
||||
});
|
||||
|
||||
const showAmount = computed(
|
||||
() => currentScenario.value.showAmount && props.refundAmount > 0
|
||||
);
|
||||
|
||||
const showPolicy = computed(
|
||||
() => currentScenario.value.showPolicy && currentRules.value.length > 0
|
||||
);
|
||||
|
||||
const leftButtonText = computed(() => currentScenario.value.leftButton);
|
||||
|
||||
const rightButtonText = computed(() => currentScenario.value.rightButton);
|
||||
|
||||
// 方法定义
|
||||
const show = () => popupRef.value.open();
|
||||
|
||||
const hide = () => popupRef.value.close();
|
||||
|
||||
// 监听modelValue变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
show();
|
||||
} else {
|
||||
hide();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 监听退款金额变化,进行数据验证
|
||||
watch(
|
||||
() => props.refundAmount,
|
||||
(newVal) => {
|
||||
if (newVal < 0) {
|
||||
console.warn("RefundPopup: 退款金额不能为负数");
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const handleClose = () => {
|
||||
emit("update:modelValue", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
const handlePolicyClick = () => {
|
||||
emit("policy-click");
|
||||
};
|
||||
|
||||
const handleConfirmClick = () => {
|
||||
emit("confirm-click");
|
||||
handleClose();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
168
pages/order/components/RefundPopup/styles/index.scss
Normal file
168
pages/order/components/RefundPopup/styles/index.scss
Normal file
@@ -0,0 +1,168 @@
|
||||
// RefundPopup 退款弹窗样式
|
||||
.refund-popup {
|
||||
width: 320px;
|
||||
background: linear-gradient(173deg, #cbf6ff 3%, #ffffff 32%);
|
||||
border-radius: 12px;
|
||||
box-sizing: border-box;
|
||||
padding-top: 64px;
|
||||
position: relative;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
|
||||
// 头部区域
|
||||
&__avatar {
|
||||
width: 132px;
|
||||
height: 132px;
|
||||
position: absolute;
|
||||
top: -45px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
// 内容区域
|
||||
&__content {
|
||||
padding: 12px 20px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
line-height: 22px;
|
||||
margin-bottom: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__amount {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
margin-bottom: 4px;
|
||||
|
||||
.amount-symbol {
|
||||
font-size: 12px;
|
||||
color: #ff6a00;
|
||||
}
|
||||
|
||||
.amount-value {
|
||||
font-size: 24px;
|
||||
color: #ff6a00;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.amount-unit {
|
||||
font-size: 12px;
|
||||
color: #ff6a00;
|
||||
}
|
||||
}
|
||||
|
||||
&__amount-label {
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
&__description {
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__policy {
|
||||
text-align: left;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.policy-title {
|
||||
font-size: 14px;
|
||||
color: #007aff;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.policy-list {
|
||||
.policy-item {
|
||||
font-size: 12px;
|
||||
color: #333333;
|
||||
line-height: 22px;
|
||||
text-align: justify;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮区域
|
||||
&__actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 0 20px 20px;
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
border-radius: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
transition: all 0.3s ease;
|
||||
outline: none;
|
||||
|
||||
&.secondary-btn {
|
||||
background: #007aff;
|
||||
color: #ffffff;
|
||||
|
||||
&:active {
|
||||
background: #0056cc;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
&.primary-btn {
|
||||
background: #ff9500;
|
||||
color: #ffffff;
|
||||
|
||||
&:active {
|
||||
background: #e6850e;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 动画效果
|
||||
@keyframes popupFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes flowerBounce {
|
||||
0%,
|
||||
20%,
|
||||
50%,
|
||||
80%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
40% {
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
60% {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
.refund-popup {
|
||||
animation: popupFadeIn 0.3s ease-out;
|
||||
}
|
||||
@@ -12,26 +12,41 @@
|
||||
<GoodsInfo :orderData="orderData" />
|
||||
<UserInfo :orderData="orderData" />
|
||||
<NoticeInfo :orderData="orderData" />
|
||||
<OrderInfo :orderData="orderData" />
|
||||
<OrderInfo :orderData="orderData" @show-refund-popup="showRefundPopup" />
|
||||
|
||||
<!-- 退款状态显示 -->
|
||||
<RefundPopup
|
||||
v-model="refundVisible"
|
||||
:refund-type="refundType"
|
||||
:refund-amount="refundAmount"
|
||||
@policy-click="viewRefundPolicy"
|
||||
@confirm-click="handleRefundConfirm"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { userOrderDetail } from "@/request/api/OrderApi";
|
||||
import { userOrderDetail, orderRefund } from "@/request/api/OrderApi";
|
||||
import OrderQrcode from "./components/OrderQrcode/index.vue";
|
||||
import OrderStatusInfo from "./components/OrderStatusInfo/index.vue";
|
||||
import GoodsInfo from "./components/GoodsInfo/index.vue";
|
||||
import UserInfo from "./components/UserInfo/index.vue";
|
||||
import NoticeInfo from "./components/NoticeInfo/index.vue";
|
||||
import OrderInfo from "./components/OrderInfo/index.vue";
|
||||
import RefundPopup from "./components/RefundPopup/index.vue";
|
||||
|
||||
const refundVisible = ref(false);
|
||||
const refundType = ref("free_cancel"); // 默认退款类型
|
||||
const refundAmount = ref(0); // 退款金额
|
||||
const orderData = ref({});
|
||||
onLoad(async ({ orderId }) => {
|
||||
const res = await userOrderDetail({ orderId });
|
||||
|
||||
orderData.value = res.data;
|
||||
// 设置退款金额为订单支付金额
|
||||
refundAmount.value = parseFloat(res.data.payAmt || 0);
|
||||
console.log(res);
|
||||
});
|
||||
|
||||
@@ -41,6 +56,42 @@ const goBack = () => {
|
||||
delta: 1,
|
||||
});
|
||||
};
|
||||
|
||||
// 显示退款弹窗
|
||||
const showRefundPopup = () => {
|
||||
refundVisible.value = true;
|
||||
};
|
||||
|
||||
// 查看退款政策
|
||||
const viewRefundPolicy = () => {
|
||||
console.log("查看退款政策");
|
||||
// 这里可以跳转到退款政策页面或显示详细政策
|
||||
};
|
||||
|
||||
// 确认退款
|
||||
const handleRefundConfirm = async () => {
|
||||
try {
|
||||
// 调用退款API
|
||||
await orderRefund({ orderId: orderData.value.orderId });
|
||||
|
||||
uni.showToast({
|
||||
title: "退款申请已提交",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
// 刷新订单状态
|
||||
const res = await userOrderDetail({ orderId: orderData.value.orderId });
|
||||
orderData.value = res.data;
|
||||
// 更新退款金额
|
||||
refundAmount.value = parseFloat(res.data.payAmt || 0);
|
||||
} catch (error) {
|
||||
console.error("退款失败:", error);
|
||||
uni.showToast({
|
||||
title: "退款申请失败,请重试",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
BIN
static/dh.png
Normal file
BIN
static/dh.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Reference in New Issue
Block a user