Forráskód Böngészése

增加换货流程

ext.liuqiwen3 3 hete
szülő
commit
7f58c708e7

+ 12 - 0
api/order.js

@@ -323,3 +323,15 @@ export function exchangeCouponApi(data) {
 export function validateApplePaymentResult(data) {
   return request.post("applePay/setIapCertificate", data);
 }
+// 申请换货接口
+export function applyExchange(data) {
+  return request.post("order/exchange", data);
+}
+// 用户补充换货物流信息
+export function exchangeDelivery(data) {
+  return request.post("order/exchangeDelivery", data);
+}
+// 获取订单换货信息
+export function applyExchangeInfo(orderId) {
+  return request.get(`order/apply/exchange/${orderId}`);
+}

+ 15 - 0
pages.json

@@ -268,6 +268,21 @@
             }
           }
         },
+        {
+          "path": "goods_change/index",
+          "style": {
+            "navigationBarTitleText": "申请退货",
+            "navigationBarBackgroundColor": "#ffe079",
+            "navigationBarTextStyle": "black",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
         {
           "path": "goods_logistics/index",
           "style": {

+ 98 - 4
pages/order_details/index.vue

@@ -74,14 +74,30 @@
 					:sbMerchant="orderInfo.sbMerchant"></orderGoods>
 				<view class="wrapper-return" v-if="
 						    orderInfo.paid === true &&
-						    orderInfo.refundStatus === 0 &&
 						    orderInfo.type !== 1 &&
 						    orderInfo.mallType !== 1 &&
-						    type === 'normal' && isGoodsReturn == false
+						    type === 'normal'
 						  ">
+          <view hover-class="none" @click="changeProduct"
+						   class="cancel" style="margin-right: 10rpx;"  v-if="orderInfo.exchangeStatus === 0 && orderInfo.refundStatus === 0 && isGoodsReturn == false">
+            申请换货
+          </view>
+          <navigator hover-class="none" :url="
+						    '/pages/users/goods_change/index?orderId=' + orderInfo.orderId"
+                class="cancel" style="margin-right: 10rpx;"  v-if="orderInfo.exchangeStatus === 2 && orderInfo.refundStatus === 0 && isGoodsReturn == false">
+            退货信息填写
+          </navigator>
+          <view hover-class="none"
+                class="cancel" style="margin-right: 10rpx;"  v-if="orderInfo.exchangeStatus === 4 && orderInfo.refundStatus === 0 && isGoodsReturn == false">
+            换货中
+          </view>
+          <view hover-class="none"
+                class="cancel" style="margin-right: 10rpx;"  v-if="orderInfo.exchangeStatus === 1 && orderInfo.refundStatus === 0 && isGoodsReturn == false">
+            换货申请中
+          </view>
 					<navigator hover-class="none" :url="
 						    '/pages/users/goods_return/index?orderId=' + orderInfo.orderId
-						  " class="cancel">
+						  " class="cancel" v-if="orderInfo.refundStatus === 0 && isGoodsReturn == false && orderInfo.exchangeStatus === 0">
 						申请退款
 					</navigator>
 				</view>
@@ -256,7 +272,19 @@
 
 		<payment :payMode="payMode" :showPopup="showPopup" @payComplete="payComplete" @close="payClose"
 			:order_id="pay_order_id" :totalPrice="totalPrice" :mallType="orderInfo.mallType"></payment>
-	</view>
+
+<!--    申请换货弹窗-->
+    <up-popup :show="changeProductShow" @close="changeProductShow = false" closeable>
+      <view class="changeProductReasonPopup">
+        <view class="title">理由</view>
+        <up-textarea class="text-area" v-model="changeProductReason" placeholder="请输入换货理由" ></up-textarea>
+        <view class="btnView">
+          <button class="sure" @click="changeProductSure">确定</button>
+          <button class="cancel" @click="changeProductShow = false">取消</button>
+        </view>
+      </view>
+    </up-popup>
+  </view>
 </template>
 
 <script setup>
@@ -279,6 +307,7 @@
 		orderDel,
 		orderCancel,
 		qrcodeApi,
+    applyExchange
 	} from "@/api/order.js";
 	import {
 		openOrderRefundSubscribe
@@ -343,6 +372,9 @@
 	const uniId = ref("");
 	const type = ref("normal");
 
+  const changeProductShow = ref(false);
+  const changeProductReason = ref('');
+
 	function payComplete() {
 		showPopup.value = false;
 		pay_order_id.value = "";
@@ -652,6 +684,29 @@
 			},
 		});
 	};
+  // 申请换货
+  const changeProduct = () => {
+    changeProductShow.value = true;
+    changeProductReason.value = '';
+  }
+  // 换货申请确认
+  const changeProductSure = async () => {
+    if(!changeProductReason.value){
+      uni.showToast({title:"请输入换货理由",icon:'none'});
+      return;
+    }
+    let obj = {
+      text:changeProductReason.value,
+      uni:orderInfo.orderId
+    }
+    const res = await applyExchange(obj);
+    if(res.code == 200){
+      changeProductShow.value = false;
+      getOrderInfo();
+      payMode.value[0].number = appStore.$userInfo.nowMoney;
+      payMode.value = [...payMode.value];
+    }
+  }
 </script>
 <style>
 	page {
@@ -1120,4 +1175,43 @@
 			background: #F8C008;
 		}
 	}
+  .changeProductReasonPopup{
+    padding: 20rpx;
+    box-sizing: border-box;
+    .title{
+      font-size: 28rpx;
+      color: #333;
+      text-align: center;
+      padding: 10rpx 20rpx;
+    }
+    .text-area{
+      border: 2rpx solid #dedede;
+      border-radius: 20rpx;
+      padding: 20rpx;
+      margin-top: 20rpx;
+    }
+    .btnView{
+      display: flex;
+      width: 100%;
+      gap: 20rpx;
+      align-items: center;
+      justify-content: center;
+      margin-top: 40rpx;
+      .sure{
+        background: #F8C008;
+        color: #fff;
+        width: 200rpx;
+        height: 60rpx;
+        line-height: 60rpx;
+      }
+      .cancel{
+        background-color: #F1F3F8;
+        color: #333333;
+        width: 200rpx;
+        height: 60rpx;
+        line-height: 60rpx;
+      }
+    }
+
+  }
 </style>

+ 480 - 0
pages/users/goods_change/index.vue

@@ -0,0 +1,480 @@
+<template>
+	<view>
+
+		<view class="apply-return">
+			<view class="apply-return-top">
+				<view class="apply-return-list">
+					<view class="apply-return-card" v-for="(item, idx) in orderInfo.orderInfoList" :key="idx">
+						<image :src="item.image" mode="aspectFill"></image>
+						<view class="con">
+							<view class="name">
+								<view class="">{{ item.storeName }}</view>
+								<view class="">¥{{ item.price }}</view>
+							</view>
+							<view class="num">
+								<view class="">{{ item.sku }}</view>
+								<view class="">X{{ item.cartNum }}</view>
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="apply-return-b">
+					<view class="item">
+						<view>退货件数</view>
+						<view class="num">{{ orderInfo.totalNum }}</view>
+					</view>
+					<view class="item">
+						<view>订单金额</view>
+						<view class="red">¥{{ orderInfo.payPrice }}</view>
+					</view>
+				</view>
+			</view>
+
+			<view class="list">
+
+				<view class="item acea-row row-between-wrapper" @tap="toggleTab('region')">
+					<view>退货原因</view>
+					<picker class="num" @change="bindPickerChange" :value="index" :range="RefundArray">
+						<view class="picker acea-row row-between-wrapper">
+							<view class="reason">{{ RefundArray[index] }}</view>
+							<image class="iconfont" src="/static/images/shop/go@2x.png" mode=""></image>
+						</view>
+					</picker>
+				</view>
+				<view class="item">
+					<view>快递单号</view>
+					<input v-model="form.returnDeliveryId" placeholder-class="express-num" placeholder="请输入快递单号" />
+				</view>
+        <view class="textarea">
+          <view>退货物流截图</view>
+          <up-upload @afterRead="async (e) => {
+                  await afterRead(e);
+                  getImage();
+                }" @delete="onImageDelete" name="product" multiple :maxCount="1" :fileList="previewImages">
+            <view class="upload-btn">
+              <up-icon name="plus" size="20" color="#ccc"></up-icon>
+              <text class="upload-tip">点击上传</text>
+            </view>
+          </up-upload>
+          <text class="format-tip">支持上传PNG、JPG格式的图片,每张不超过5MB。</text>
+        </view>
+				<view class="textarea">
+					<view>备注说明</view>
+					<textarea v-model="form.refund_reason_wap_explain" count placeholder="填写备注信息,100字以内" class="num"></textarea>
+				</view>
+
+			</view>
+		</view>
+		<view class="kong"></view>
+		<view class="footer">
+			<button @click="subRefund" class="returnBnt" form-type="submit">
+				申请退货
+			</button>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		reactive,
+		watch,
+	} from "vue";
+	import {
+		useAppStore
+	} from "@/stores/app";
+	import {
+		onLoad
+	} from "@dcloudio/uni-app";
+	import {
+		ordeRefundReason,
+		applyRefund,
+    exchangeDelivery
+	} from "@/api/order.js";
+	import {
+		toLogin
+	} from "@/libs/login.js";
+  import {
+    useImageUpload
+  } from "@/hooks/useImageUpload";
+
+	const appStore = useAppStore();
+	import {
+		useToast
+	} from "@/hooks/useToast";
+  import {applyExchangeInfo} from "../../../api/order";
+
+	const refund_reason_wap_imgPath = ref([]);
+	const orderInfo = reactive({});
+	const RefundArray = ref([]);
+	const index = ref(0);
+	const orderId = ref(0);
+
+	const {
+		Toast
+	} = useToast();
+
+	const form = ref({
+		text:'',
+    returnDeliveryId: '',
+		refund_reason_wap_explain: '',
+		uni: '',
+		refund_reason_wap_img: ''
+	})
+  const previewImages = ref([]);
+
+  const {
+    imageList,
+    afterRead,
+    deletePic,
+    uploadLoading
+  } = useImageUpload({
+    pid: 1,
+    model: "product",
+  });
+
+	watch(() => appStore.isLogin, (newV) => {
+		if (newV) {
+			getOrderInfo();
+			getRefundReason();
+		}
+	});
+
+	onLoad((options) => {
+		if (!options.orderId)
+			return Toast({
+				title: "缺少订单id,无法退款"
+			}, {
+				tab: 3,
+				url: 1
+			});
+		form.value.uni = options.orderId
+		orderId.value = options.orderId;
+		if (appStore.isLogin) {
+			getOrderInfo();
+			getRefundReason();
+		} else {
+			toLogin();
+		}
+	});
+
+	function onLoadFun() {
+		getOrderInfo();
+		getRefundReason();
+	}
+
+	/**
+	 * 获取订单详情
+	 */
+	function getOrderInfo() {
+    applyExchangeInfo(orderId.value).then((res) => {
+			Object.assign(orderInfo, res.data);
+		});
+	}
+
+	/**
+	 * 获取退款理由
+	 */
+	function getRefundReason() {
+		ordeRefundReason().then((res) => {
+			RefundArray.value = res.data;
+			if (res.data.length) {
+				form.value.text = res.data[index.value]
+			}
+		});
+	}
+
+	/**
+	 * 申请退货
+	 */
+	function subRefund(e) {
+    form.value.id = orderInfo.id;
+    form.value.returnDeliveryImgUrl = previewImages.value[0]?.info?.url || previewImages.value[0]?.url;
+    console.log(form.value)
+    exchangeDelivery(form.value)
+			.then((res) => {
+				return Toast({
+					title: "申请成功",
+					icon: "success"
+				}, {
+					tab: 5,
+					url: "/pages/users/user_return_list/index?isT=1"
+				});
+			})
+			.catch((err) => {
+				return Toast({
+					title: err
+				});
+			});
+	}
+
+	function bindPickerChange(e) {
+		index.value = e.detail.value;
+		form.value.text = RefundArray.value[e.detail.value]
+	}
+
+	function toggleTab() {
+		// 保留原逻辑
+	}
+  async function getImage() {
+    if (imageList.value.length > 0) {
+      if (imageList.value[0].status == "success") {
+        previewImages.value = imageList.value;
+      } else {
+        Toast({
+          title: "上传失败"
+        });
+      }
+    }
+    imageList.value = [];
+  }
+  const onImageDelete = (e) => {
+    previewImages.value.splice(e.index, 1);
+  };
+</script>
+<style>
+	page {
+		background: #F9F7F0;
+	}
+</style>
+<style scoped lang="scss">
+	.apply-return {
+		padding: 16rpx;
+
+		.apply-return-top {
+			padding: 16rpx;
+			border-radius: 16rpx;
+			background: #FFFFFF;
+
+			.apply-return-card {
+				display: flex;
+				margin-bottom: 16rpx;
+
+				image {
+					width: 160rpx;
+					height: 160rpx;
+					margin-right: 16rpx;
+					border-radius: 16rpx;
+				}
+
+				.con {
+					flex: 1;
+
+					.name {
+						font-size: 28rpx;
+						display: flex;
+						font-weight: bold;
+						align-items: center;
+						justify-content: space-between;
+					}
+
+					.num {
+						margin-top: 8rpx;
+						color: #666666;
+						font-size: 24rpx;
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+					}
+				}
+			}
+
+		}
+
+		.apply-return-top {
+			.item {
+				margin-bottom: 16rpx;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+
+				&:last-child {
+					margin-bottom: 0;
+				}
+
+				color: #333333;
+				font-size: 28rpx;
+
+				.red {
+					color: #FD5F3C;
+					font-weight: bold;
+				}
+			}
+		}
+
+		.list {
+
+
+
+			.item {
+				padding: 0 16rpx;
+				height: 100rpx;
+				margin-top: 16rpx;
+				border-radius: 16rpx;
+				background-color: #fff;
+
+				font-size: 28rpx;
+				color: #333333;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+
+				input {
+					font-size: 28rpx;
+					text-align: right;
+				}
+
+				.num {
+					color: #282828;
+					width: 427rpx;
+					text-align: right;
+
+					.picker {
+						.reason {
+							width: 385rpx;
+						}
+
+
+					}
+				}
+
+				.iconfont {
+					width: 32rpx;
+					height: 32rpx;
+					margin-left: 8rpx;
+				}
+
+				::v-deep .express-num {
+					text-align: right;
+				}
+
+
+
+				.placeholder {
+					color: #bbb;
+				}
+
+				.title {
+					height: 95rpx;
+					width: 100%;
+
+					.tip {
+						font-size: 30rpx;
+						color: #bbb;
+					}
+				}
+
+				.upload {
+					padding-bottom: 36rpx;
+
+					.pictrue {
+						border-radius: 14rpx;
+						margin: 22rpx 23rpx 0 0;
+						width: 156rpx;
+						height: 156rpx;
+						position: relative;
+						font-size: 24rpx;
+						color: #bbb;
+
+						&:nth-of-type(4n) {
+							margin-right: 0;
+						}
+
+						image {
+							width: 100%;
+							height: 100%;
+							border-radius: 14rpx;
+						}
+
+						.icon-guanbi1 {
+							position: absolute;
+							font-size: 45rpx;
+							top: -10rpx;
+							right: -10rpx;
+						}
+
+						.icon-icon25201 {
+							color: #bfbfbf;
+							font-size: 50rpx;
+						}
+
+						&:nth-last-child(1) {
+							border: 1rpx solid #ddd;
+							box-sizing: border-box;
+						}
+					}
+				}
+			}
+
+
+		}
+
+		.textarea {
+			padding: 16rpx;
+			border-radius: 16rpx;
+			margin-top: 16rpx;
+			background: #FFFFFF;
+
+			view {
+				margin-bottom: 16rpx;
+			}
+
+			textarea {
+				width: 100%;
+				padding: 16rpx;
+				font-size: 28rpx;
+				height: 264rpx;
+				background: #F9F7F0;
+				border-radius: 16rpx;
+			}
+		}
+	}
+
+	.kong {
+		height: calc(132rpx + constant(safe-area-inset-bottom));
+		height: calc(132rpx + env(safe-area-inset-bottom));
+		background: #F9F7F0;
+	}
+
+	.footer {
+		padding: 22rpx 32rpx calc(22rpx + constant(safe-area-inset-bottom));
+		padding: 22rpx 32rpx calc(22rpx + env(safe-area-inset-bottom));
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		background-color: #fff;
+		z-index: 277;
+		box-shadow: inset 0rpx 1rpx 0rpx 0rpx #F1F3F8;
+	}
+
+	.returnBnt {
+		text-align: center;
+		color: #333333;
+		font-size: 32rpx;
+		line-height: 88rpx;
+		border-radius: 16rpx;
+		background: #F8C008;
+		font-weight: bold;
+		&::after {
+			width: 0;
+			border: none;
+		}
+	}
+  .upload-btn {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    width: 150rpx;
+    height: 150rpx;
+    border: 1rpx dashed #DCDFE6;
+    border-radius: 8rpx;
+    background: #fff;
+  }
+
+  .upload-tip {
+    font-size: 20rpx;
+    color: #666;
+    margin-top: 6rpx;
+  }
+</style>

BIN
static/images/shop/go@2x.png