|
|
@@ -0,0 +1,317 @@
|
|
|
+<template>
|
|
|
+ <view class="container">
|
|
|
+ <scroll-view scroll-y class="form-scroll">
|
|
|
+ <view class="section">
|
|
|
+ <text class="section-title">售后类型</text>
|
|
|
+ <view class="type-options">
|
|
|
+ <view
|
|
|
+ :class="['type-card', form.type === 'refund' ? 'active' : '']"
|
|
|
+ @click="form.type = 'refund'"
|
|
|
+ >
|
|
|
+ <text class="type-icon">💰</text>
|
|
|
+ <text class="type-name">仅退款</text>
|
|
|
+ <text class="type-desc">未收到货或与描述不符</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ :class="['type-card', form.type === 'return' ? 'active' : '']"
|
|
|
+ @click="form.type = 'return'"
|
|
|
+ >
|
|
|
+ <text class="type-icon">📦</text>
|
|
|
+ <text class="type-name">退货退款</text>
|
|
|
+ <text class="type-desc">需要将商品寄回后退款</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section">
|
|
|
+ <text class="section-title">退款原因</text>
|
|
|
+ <picker :range="reasons" @change="onReasonChange">
|
|
|
+ <view class="picker-value">
|
|
|
+ <text :class="['reason-text', form.reason ? '' : 'placeholder']">{{ form.reason || '请选择退款原因' }}</text>
|
|
|
+ <text class="arrow">›</text>
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section" v-if="showDescription">
|
|
|
+ <text class="section-title">问题描述(可选)</text>
|
|
|
+ <textarea
|
|
|
+ v-model="form.description"
|
|
|
+ class="desc-textarea"
|
|
|
+ placeholder="请详细描述遇到的问题,以便商家快速处理"
|
|
|
+ maxlength="500"
|
|
|
+ />
|
|
|
+ <text class="char-count">{{ (form.description || '').length }}/500</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="section">
|
|
|
+ <text class="section-title">订单信息</text>
|
|
|
+ <view class="info-row">
|
|
|
+ <text class="info-label">订单编号</text>
|
|
|
+ <text class="info-value">{{ order.orderNo || '-' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="info-row">
|
|
|
+ <text class="info-label">商品名称</text>
|
|
|
+ <text class="info-value">{{ order.productName || '-' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="info-row">
|
|
|
+ <text class="info-label">退款金额</text>
|
|
|
+ <text class="info-value price">{{ formatPrice(refundAmount) }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="submit-wrap">
|
|
|
+ <button class="submit-btn" :disabled="submitting" @click="onSubmit">{{ submitting ? '提交中...' : '提交申请' }}</button>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import config from '@/config.js'
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ orderId: null,
|
|
|
+ orderNo: '',
|
|
|
+ order: {},
|
|
|
+ form: {
|
|
|
+ type: 'refund',
|
|
|
+ reason: '',
|
|
|
+ description: ''
|
|
|
+ },
|
|
|
+ reasons: [
|
|
|
+ '商品质量问题',
|
|
|
+ '与描述不符',
|
|
|
+ '发错货',
|
|
|
+ '缺件/少发',
|
|
|
+ '不想要了',
|
|
|
+ '商家发错地址',
|
|
|
+ '其他原因'
|
|
|
+ ],
|
|
|
+ submitting: false,
|
|
|
+ refundAmount: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ showDescription() {
|
|
|
+ return this.form.reason && this.form.reason !== ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad(options) {
|
|
|
+ if (options.orderId) {
|
|
|
+ this.orderId = parseInt(options.orderId)
|
|
|
+ }
|
|
|
+ if (options.orderNo) {
|
|
|
+ this.orderNo = options.orderNo
|
|
|
+ }
|
|
|
+ this.loadOrder()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ loadOrder() {
|
|
|
+ if (!this.orderNo) return
|
|
|
+ var that = this
|
|
|
+ uni.request({
|
|
|
+ url: config.api('/api/product/order/detail'),
|
|
|
+ method: 'POST',
|
|
|
+ data: { orderNo: this.orderNo },
|
|
|
+ header: {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ 'Authorization': 'Bearer ' + uni.getStorageSync('token')
|
|
|
+ },
|
|
|
+ success: function(res) {
|
|
|
+ if (res.data && res.data.code === 200) {
|
|
|
+ that.order = res.data.data || {}
|
|
|
+ that.refundAmount = that.order.totalAmount || 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onReasonChange(e) {
|
|
|
+ this.form.reason = this.reasons[e.detail.value]
|
|
|
+ },
|
|
|
+ onSubmit() {
|
|
|
+ if (!this.form.type) {
|
|
|
+ uni.showToast({ title: '请选择售后类型', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.form.reason) {
|
|
|
+ uni.showToast({ title: '请选择退款原因', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.orderId) {
|
|
|
+ uni.showToast({ title: '订单信息缺失', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.submitting = true
|
|
|
+ var that = this
|
|
|
+ uni.request({
|
|
|
+ url: config.api('/api/shop/after-sales/create'),
|
|
|
+ method: 'POST',
|
|
|
+ data: {
|
|
|
+ orderId: this.orderId,
|
|
|
+ type: this.form.type,
|
|
|
+ reason: this.form.reason,
|
|
|
+ description: this.form.description
|
|
|
+ },
|
|
|
+ header: {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ 'Authorization': 'Bearer ' + uni.getStorageSync('token')
|
|
|
+ },
|
|
|
+ success: function(res) {
|
|
|
+ that.submitting = false
|
|
|
+ if (res.data && res.data.code === 200) {
|
|
|
+ uni.showToast({ title: '申请已提交', icon: 'success' })
|
|
|
+ setTimeout(function() {
|
|
|
+ uni.navigateTo({ url: '/pages/shop/after-sales/after-sales' })
|
|
|
+ }, 1000)
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: res.data.message || '提交失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: function() {
|
|
|
+ that.submitting = false
|
|
|
+ uni.showToast({ title: '网络请求失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ formatPrice(amount) {
|
|
|
+ if (amount === null || amount === undefined) return '¥0.00'
|
|
|
+ return '¥' + (Number(amount) / 100).toFixed(2)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.container {
|
|
|
+ min-height: 100vh;
|
|
|
+ background: #f5f5f5;
|
|
|
+}
|
|
|
+.form-scroll {
|
|
|
+ padding-bottom: 40rpx;
|
|
|
+}
|
|
|
+.section {
|
|
|
+ background: #fff;
|
|
|
+ margin: 20rpx;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+}
|
|
|
+.section-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+.type-options {
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+}
|
|
|
+.type-card {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ padding: 30rpx 20rpx;
|
|
|
+ border: 2rpx solid #eee;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.type-card.active {
|
|
|
+ border-color: #F97316;
|
|
|
+ background: #fff7e6;
|
|
|
+}
|
|
|
+.type-icon {
|
|
|
+ font-size: 48rpx;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+}
|
|
|
+.type-name {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 8rpx;
|
|
|
+}
|
|
|
+.type-desc {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+.picker-value {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 20rpx;
|
|
|
+ background: #f8f8f8;
|
|
|
+ border-radius: 8rpx;
|
|
|
+}
|
|
|
+.reason-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+.reason-text.placeholder {
|
|
|
+ color: #ccc;
|
|
|
+}
|
|
|
+.arrow {
|
|
|
+ font-size: 36rpx;
|
|
|
+ color: #ccc;
|
|
|
+}
|
|
|
+.desc-textarea {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 160rpx;
|
|
|
+ padding: 20rpx;
|
|
|
+ background: #f8f8f8;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.char-count {
|
|
|
+ display: block;
|
|
|
+ text-align: right;
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #ccc;
|
|
|
+ margin-top: 8rpx;
|
|
|
+}
|
|
|
+.info-row {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 12rpx 0;
|
|
|
+ border-bottom: 1rpx solid #f5f5f5;
|
|
|
+}
|
|
|
+.info-row:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+.info-label {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+.info-value {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+.price {
|
|
|
+ color: #F97316;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 30rpx;
|
|
|
+}
|
|
|
+.submit-wrap {
|
|
|
+ padding: 30rpx;
|
|
|
+}
|
|
|
+.submit-btn {
|
|
|
+ background: linear-gradient(135deg, #F97316, #FB923C);
|
|
|
+ color: #fff;
|
|
|
+ font-size: 30rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ height: 88rpx;
|
|
|
+ line-height: 88rpx;
|
|
|
+ border-radius: 44rpx;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+.submit-btn::after {
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+.submit-btn[disabled] {
|
|
|
+ opacity: 0.6;
|
|
|
+}
|
|
|
+</style>
|