import React, { useEffect, useRef } from "react" import { useSelector } from "react-redux" import { useImmer } from "use-immer" import Taro, { getCurrentInstance } from "@tarojs/taro" import api from "@/api" import doc from "@/doc" import { AtButton, AtInput, AtCurtain, AtCountdown } from 'taro-ui' import { SpPage, SpTabs, SpCell, SpCheckbox, SpImage, SpInputNumber, SpFloatLayout, SpUpload, SpPrice, SpHtml, SpOrderItem } from '@/components' import { View, Text, Picker, Input, ScrollView } from "@tarojs/components" import { AFTER_SALE_TYPE, REFUND_FEE_TYPE, LOGISTICS_CODE } from '@/consts' import { pickBy, showToast, classNames, VERSION_STANDARD, VERSION_PLATFORM, JumpGoodDetail, copyText } from '@/utils' import "./after-sale.scss" const initialState = { info: null, curTabIdx: 1, tabList: AFTER_SALE_TYPE, reasonIndex: '', reasons: [], refundFee: 0, refundPoint: 0, refundType: 'offline', description: '', pic: '', // 用于云店后台交易设置-到店退货关闭时判断 offlineAftersalesIsOpen: false, offlineAftersales: false, refundTypeList: REFUND_FEE_TYPE, refundStore: '', // 退货门店 contact: '', // 联系人 mobile: '', // 联系电话 openRefundType: false, selectRefundValue: 'offline', afterSaleDesc: { intro: '', is_open: false }, afterSaleChecked: {}, afterSaleTotalNum: 0, allClicked: false, afterSaleTotalprice: 0, loading: true, isOpened: false, isAddrOpened: false, aftersales: null, expressList: [], corpIndex: null, logi_no: '' } function TradeAfterSale (props) { const $instance = getCurrentInstance() const { aftersales_bn: afterSaleTid } = $instance.router.params const [state, setState] = useImmer(initialState) const pageRef = useRef() const { info, curTabIdx, tabList, reasonIndex, reasons, refundFee, refundPoint, refundType, refundTypeList, description, pic, openRefundType, selectRefundValue, refundStore, contact, mobile, afterSaleDesc, offlineAftersalesIsOpen, offlineAftersales, afterSaleTotalNum, allClicked, afterSaleTotalprice, loading, isOpened, isAddrOpened, aftersales, expressList, corpIndex, logi_no } = state useEffect(() => { fetch() Taro.eventCenter.on('onEventPickerStore', (item) => { console.log('onEventPickerStore:', item) setState(draft => { draft.refundStore = item }) }) const _expressList = Object.keys(LOGISTICS_CODE).map(key => { return { name: LOGISTICS_CODE[key], code: key } }) setState(draft => { draft.expressList = _expressList }) return () => { Taro.eventCenter.off('onEventPickerStore') } }, []) useEffect(() => { if (openRefundType) { pageRef.current.pageLock() } else { pageRef.current.pageUnLock() } }, [openRefundType]) const onCancel = () => { Taro.navigateBack() } const onSubmitExp = async () => { const { item_id, orderId: order_id, afterSalesBn: aftersales_bn } = aftersales const corp_code = expressList[corpIndex]?.code if (!corp_code) { showToast('请填写物流公司') return } if (!logi_no) { showToast('请填写物流单号') return } await api.aftersales.sendback({ item_id, order_id, aftersales_bn, logi_no, corp_code }) showToast('操作成功') setTimeout(() => { // Taro.navigateBack() fetch() }, 300) } const onChangeExpress = (e) => { const { value } = e.detail setState(draft => { draft.corpIndex = value }) } const getLogisticName = () => { const { name } = expressList[corpIndex] || {} return name } const fetch = async () => { const { id, aftersales_bn } = $instance.router.params if (aftersales_bn) { const resInfo = await api.aftersales.info({ aftersales_bn, // item_id, // order_id }) const _aftersales = pickBy(resInfo, doc.trade.TRADE_AFTER_SALES_ITEM) console.log("🚀 ~ _aftersales:", _aftersales) if (_aftersales.sendbackData) { const { corp_code } = _aftersales.sendbackData _aftersales.sendbackData.name = LOGISTICS_CODE[corp_code] } setState(draft => { draft.aftersales = _aftersales draft.afterSaleTotalNum = _aftersales.items.reduce((sum, { num }) => sum + num, 0) draft.afterSaleTotalprice = _aftersales.items.reduce((sum, { price }) => sum + price, 0) }) } const { orderInfo, offline_aftersales_is_open, distributor } = await api.trade.detail(id) const reasons = await api.aftersales.reasonList() const { intro, is_open } = await api.aftersales.remindDetail() const { offline_aftersales } = distributor const _info = pickBy(orderInfo, doc.trade.TRADE_ITEM) setState(draft => { draft.info = _info draft.reasons = reasons draft.offlineAftersalesIsOpen = offline_aftersales_is_open draft.offlineAftersales = offline_aftersales == 1 draft.afterSaleDesc = { intro, is_open } if ((VERSION_STANDARD && !offline_aftersales_is_open) || (VERSION_PLATFORM && offline_aftersales == 0)) { draft.refundTypeList = REFUND_FEE_TYPE.filter(item => item.value != 'offline') draft.refundType = 'logistics' } draft.loading = false }) } const onChangeItemCheck = (item, index, type) => { // const _info = info // _info.items[index].checked = e setState(draft => { if (type === 'all') { draft.allClicked = !allClicked draft.info.items.map((_item) => { _item.checked = !allClicked }) } else { draft.info.items[index].checked = !item.checked } draft.allClicked = draft.info.items.every((item) => item.checked) draft.afterSaleTotalNum = draft.info.items.filter((_item) => _item.checked).reduce((sum, { num }) => sum + num, 0) draft.afterSaleTotalprice = draft.info.items.filter((_item) => _item.checked).reduce((sum, { price }) => sum + price, 0) }) } const onChangeItemNum = (e, index) => { setState(draft => { draft.info.items[index].refundNum = e }) } const getRealRefundFee = () => { let rFee = 0 if (info) { const { items } = info rFee = items .filter((item) => item.checked) .reduce((sum, { price, num, refundNum }) => sum + price / num * refundNum, 0) } return rFee.toFixed(2) } const getRealRefundPoint = () => { let rPoint = 0 if (info) { const { items } = info rPoint = items .filter((item) => item.checked) .reduce((sum, { point, num, refundNum }) => sum + point / num * refundNum, 0) } return rPoint.toFixed(2) } const onChangeRefundType = ({ value }) => { setState(draft => { draft.selectRefundValue = value }) } const getRefundTypeName = () => { const { title } = refundTypeList.find(item => item.value == refundType) || {} return title } const onSubmit = async () => { const { id } = $instance.router.params const checkedItems = info?.items.filter(item => !!item.checked) if (checkedItems.length == 0) { return showToast('请选择需要售后的商品') } if (!reasons?.[reasonIndex]) { return showToast('请选择退货原因') } const aftersales_type = tabList[curTabIdx].type const reason = reasons?.[reasonIndex] let params = { detail: checkedItems.map(({ id: _id, refundNum, num }) => { return { id: _id, num: num || refundNum } }), order_id: id, aftersales_type, reason, description, evidence_pic: pic } // 退货退款 if (aftersales_type == 'REFUND_GOODS') { params = { ...params, return_type: refundType } // 到店退货 if (refundType == 'offline') { if (!refundStore) { return showToast('请选择退货门店') } if (!contact) { return showToast('请输入联系人姓名') } if (!mobile) { return showToast('请输入联系人电话') } params = { ...params, return_type: refundType, aftersales_address_id: refundStore.address_id, contact, mobile } } } await api.aftersales.apply(params) showToast('提交成功') setTimeout(() => { // Taro.redirectTo({ // url: `/subpage/pages/trade/detail?id=${id}` // }) // fetch() Taro.navigateBack() }, 500) } const handleClickCopy = (val) => { copyText(val) Taro.showToast({ title: '复制成功', icon: 'none' }) } return 提交售后申请 : null } > {!afterSaleTid ? 请选择售后类型: item.title)} onChange={(e) => { setState(draft => { draft.curTabIdx = +e.detail.value }) }} > {tabList[curTabIdx] ? tabList[curTabIdx].title : '请选择售后类型'} -1 ? '#000' : '#a5a5a5' }}> : aftersales?.progress && aftersales.progress != 12 ? 售后单号:{afterSaleTid} {['', '售后审核通过,请您发货并填写物流单号', '等待商家确认收货', '已驳回', '已完成', '退款驳回', '退款完成', '已关闭', '商家确认收货,等待审核退款', '退款处理中'][aftersales?.progress || 0]} {/* 还剩 */} setState(draft => { draft.isOpened = true })} style={{ fontSize: '20rpx', borderBottom: '1px solid #000', padding: '0 0 4rpx' }}>全部流程 : null} {aftersales?.progress >= 1 && aftersales?.progress != 3 && <> 退货单号填写 {aftersales?.hasAftersalesAddress && setState(draft => { draft.isAddrOpened = true })} style={{ fontSize: '20rpx', borderBottom: '1px solid #000', padding: '0 0 4rpx', marginTop: '-10rpx', lineHeight: 0.8 }}>查看退货地址} {!aftersales?.hasSendbackData ? {`${getLogisticName() || '请选择快递公司'}`} : {`${aftersales?.sendbackData?.name || ''}`} } {!aftersales?.hasSendbackData ? { setState(draft => { draft.logi_no = e.detail.value }) }}> : {`${aftersales?.sendbackData?.logi_no || ''}`}} {/* 确认上传 */} handleClickCopy(aftersales?.sendbackData?.logi_no || '')} style={{ fontSize: '20rpx', borderBottom: '1px solid #000', lineHeight: 0.8 }}>复制物流单号 } {/* { setState(draft => { draft.curTabIdx = e }) }} /> */} {!afterSaleTid ? <> 请选择您要退货的商品 : 已选择的退货商品} { (aftersales?.items || info?.items || []).map((item, index) => ( {!afterSaleTid && } {/* { if (info.order_class == 'pointsmall') { Taro.navigateTo({ url: `/subpages/pointshop/espier-detail?id=${item.good_id}` }) } else { JumpGoodDetail(item.good_id, item.distributor_id) } }} /> */} {item.itemName} {item.itemSpecDesc && {`${item.descInfo}`}} {/* x {item.num} */} 数量:{item.num} {/* onChangeItemNum(e, index)} /> */} )) } 退货原因 {!afterSaleTid ? { setState(draft => { draft.reasonIndex = e.detail.value }) }} > {`${reasons?.[reasonIndex] || '请选择退货原因'}`} : {`${aftersales?.reason || reasons?.[reasonIndex] || '请选择退货原因'}`} } 退货数量* {`${afterSaleTotalNum || '请选择退货数量'}`} {/* { setState(draft => { draft.reasonIndex = e.detail.value }) }} > {`${reasons?.[reasonIndex] || '请选择取消原因'}`}}> */} {false && {/* */} } {/* {curTabIdx == 1 && { setState(draft => { draft.openRefundType = true draft.selectRefundValue = refundType }) }}> { refundType == 'offline' && ((offlineAftersalesIsOpen && VERSION_STANDARD) || (VERSION_PLATFORM && offlineAftersales)) && <> {refundStore ? refundStore.name : '请选择退货门店'}} onClick={() => { Taro.navigateTo({ url: `/subpages/trade/store-picker?distributor_id=${info.distributorId}&refund_store=${refundStore?.address_id}` }) }} /> { setState(draft => { draft.contact = e }) }} />}> { setState(draft => { draft.mobile = e }) }} />}> } } */} 退货商品{afterSaleTotalNum}件 退款金额: {!afterSaleTid ? {/* */} {/* { setState(draft => { draft.description = e }) }} /> */} { setState(draft => { draft.description = e.detail.value }) }}> : 备注:{aftersales?.description || description}} {/* { setState((draft) => { draft.pic = val }) }} /> */} { afterSaleDesc.is_open && 售后提醒 } { setState((draft) => { draft.openRefundType = false }) }} renderFooter={ { setState(draft => { draft.refundType = selectRefundValue draft.openRefundType = false }) }}> 确定 } > {refundTypeList.map((item, index) => ( {item.title} {item.desc} ))} { setState((draft) => { draft.isOpened = false }) }} > 退货流程 提交申请 商家处理 {/* 还剩 */} 商家同意后,请按照给出的退货地址退货,并请记录退货运单 如商家拒绝,您可以修改申请后再次发起,商家会重新处理 如商家超时未处理,退货申请将达成,请按系统给出的退货地址退货 寄回商品 商家退款 退款成功 温馨提示 BIRKENSTOCK支持七天(从收到商品之日起开始计算)无理由退换货如需退换货,退回货品需不影响二次销售原装鞋盒务必完好(如鞋盒有遗失需补偿20元)。试穿时需将鞋盒内的包装纸垫于脚下,过程中不刻意踩踏后跟如鞋面或鞋底出现脏污、磨损、破损,鞋跟出现折痕等,都将影响商品的二次销售。我们将无法为您提供七天无理由退换货服务,敬请谅解。如果您还有其他问题或需要更多帮助,可及时联系客服,我们将竭诚为您服务(特别提示:仓库不接受到付、平邮、邮政小包。) setState((draft) => { draft.isOpened = false })}>我知道了 { setState((draft) => { draft.isAddrOpened = false }) }} > 退货地址 收件人 {aftersales?.afterSalesContact} 联系电话 {aftersales?.afterSalesMobile} 收件地址 {aftersales?.afterSalesAddress} 邮编 {aftersales?.afterSalesZip} 复制地址 温馨提示 BIRKENSTOCK支持七天(从收到商品之日起开始计算)无理由退换货如需退换货,退回货品需不影响二次销售原装鞋盒务必完好(如鞋盒有遗失需补偿20元)。试穿时需将鞋盒内的包装纸垫于脚下,过程中不刻意踩踏后跟如鞋面或鞋底出现脏污、磨损、破损,鞋跟出现折痕等,都将影响商品的二次销售。我们将无法为您提供七天无理由退换货服务,敬请谅解。如果您还有其他问题或需要更多帮助,可及时联系客服,我们将竭诚为您服务(特别提示:仓库不接受到付、平邮、邮政小包。) } TradeAfterSale.options = { addGlobalClass: true } export default TradeAfterSale