shish 23 цаг өмнө
parent
commit
8c34a55ab6

+ 683 - 541
hdApp/src/pagesPurchase/refund.vue

@@ -1,195 +1,232 @@
+<!--
+  花店采购单申请售后页
+  用途:选退款方式、填退货数量/金额、上传照片后提交供货商审核
+  入口:采购详情「申请售后」→ /pagesPurchase/refund
+-->
 <template>
-<view class="refund-page">
-	<block v-if="orderInfo.afterSaleRule.afterSale == 1">
-		<!-- 红色提示信息 - 售后说明 -->
-		<view class="info-tip">
-			<view class="info-content">
-				<text class="info-text" style="color:#3385ff;font-weight:bold;margin-bottom:10upx;">没拿货或拿货退还了,<text style="font-weight:bold;">选退货并退款</text></text>
-				<block v-if="orderInfo.ghsShopId && (orderInfo.ghsShopId == 26094 || orderInfo.ghsShopId == 25159)">
-					<text class="info-text" style="font-weight:bold;margin-bottom:10upx;">货拿了质量有问题,损耗超10%,<text style="font-weight:bold;">选只退款</text></text>
-					<text class="info-warning">售后范围:10%以内损耗属正常运输损耗,不售后。超过10%的,可以售后。请在收货后12小时内申请售后。</text>
-				</block>
-				<block v-else>
-					<text class="info-text" style="font-weight:bold;margin-bottom:10upx;">货拿了质量有问题,损耗超20%,<text style="font-weight:bold;">选只退款</text></text>
-					<text class="info-warning">售后范围:20%以内损耗属正常运输损耗,不售后。超过20%的,可以售后。请在收货后12小时内申请售后。</text>
-				</block>
+	<view class="refund-page">
+		<block v-if="orderInfo.afterSaleRule.afterSale == 1">
+			<!-- 售后引导说明 -->
+			<view class="guide-card">
+				<view class="guide-hd">
+					<view class="guide-badge">说明</view>
+					<text class="guide-title">怎么选退款方式</text>
+				</view>
+				<view class="guide-item">
+					<view class="guide-dot guide-dot--blue"></view>
+					<text class="guide-text">
+						没拿货或拿货退还了,选
+						<text class="guide-em guide-em--blue">退货并退款</text>
+					</text>
+				</view>
+				<view class="guide-item">
+					<view class="guide-dot guide-dot--green"></view>
+					<text class="guide-text" v-if="orderInfo.ghsShopId && (orderInfo.ghsShopId == 26094 || orderInfo.ghsShopId == 25159)">
+						货拿了质量有问题、损耗超 10%,选
+						<text class="guide-em guide-em--green">只退款</text>
+					</text>
+					<text class="guide-text" v-else>
+						货拿了质量有问题、损耗超 20%,选
+						<text class="guide-em guide-em--green">只退款</text>
+					</text>
+				</view>
+				<view class="guide-warn">
+					<text v-if="orderInfo.ghsShopId && (orderInfo.ghsShopId == 26094 || orderInfo.ghsShopId == 25159)">
+						售后范围:10% 以内属正常运输损耗,不售后;超过 10% 可售后。请在收货后 12 小时内申请。
+					</text>
+					<text v-else>
+						售后范围:20% 以内属正常运输损耗,不售后;超过 20% 可售后。请在收货后 12 小时内申请。
+					</text>
+				</view>
 			</view>
-		</view>
 
-		<!-- 退款方式卡片 -->
-		<view class="card-section">
-			<view class="section-title">
-				<text class="title-text">退款方式</text>
-			</view>
-			<view class="refund-type-buttons">
-				<button 
-					class="type-button" 
-					:class="refundType==1?'active':''" 
-					@tap="refundType=1">
-					退货并退款
-				</button>
-				<button v-if="orderInfo.afterSaleRule.refundOnlyPrice == 1"
-					class="type-button" 
-					:class="refundType==2?'active':''" 
-					@tap="refundType=2">
-					只退款
-				</button>
+			<!-- 退款方式 -->
+			<view class="card">
+				<view class="card-hd">
+					<view class="card-bar"></view>
+					<text class="card-title">退款方式</text>
+				</view>
+				<view class="type-row">
+					<view
+						class="type-chip"
+						:class="{ 'type-chip--on': refundType == 1 }"
+						@tap="refundType = 1"
+					>
+						<text class="type-chip__name">退货并退款</text>
+						<text class="type-chip__desc">退回花材并退钱</text>
+					</view>
+					<view
+						v-if="orderInfo.afterSaleRule.refundOnlyPrice == 1"
+						class="type-chip type-chip--second"
+						:class="{ 'type-chip--on': refundType == 2 }"
+						@tap="refundType = 2"
+					>
+						<text class="type-chip__name">只退款</text>
+						<text class="type-chip__desc">不退货仅退钱</text>
+					</view>
+				</view>
 			</view>
-		</view>
 
-		<!-- 商品选择卡片 -->
-		<view class="card-section" v-if="refundType==1">
-			<view class="section-title">
-				<text class="title-text">选择商品</text>
-			</view>
-			<view class="product-list">
-				<view class="product-row" v-for="(res,i) in product" :key="i">
-					<view class="product-basic-info">
-						<text class="product-name">{{res.name}}</text>
-						<view class="product-meta">
-							<text class="stock-info">{{parseFloat(res.xhNum)}}{{res.xhUnitName}} X ¥{{parseFloat(res.xhUnitPrice)}}</text>
-							<text class="available-info">可退 {{Number(res.xhNum)-Number(res.refundNum)}}{{res.xhUnitName}}</text>
+			<!-- 选择商品 -->
+			<view class="card" v-if="refundType == 1">
+				<view class="card-hd">
+					<view class="card-bar"></view>
+					<text class="card-title">选择商品</text>
+					<text class="card-sub">填写要退的数量</text>
+				</view>
+				<view class="goods-list">
+					<view class="goods-item" v-for="(res, i) in product" :key="i">
+						<image
+							class="goods-cover"
+							:src="res.cover || res.smallCover || ''"
+							mode="aspectFill"
+						/>
+						<view class="goods-main">
+							<text class="goods-name">{{ res.name }}</text>
+							<view class="goods-meta">
+								<text class="meta-tag">{{ parseFloat(res.xhNum) }}{{ res.xhUnitName }} × ¥{{ parseFloat(res.xhUnitPrice) }}</text>
+							</view>
+							<text class="goods-avail">可退 {{ Number(res.xhNum) - Number(res.refundNum) }}{{ res.xhUnitName }}</text>
 						</view>
-					</view>
-					<view class="refund-control">
-						<view class="input-item">
-							<input 
-								class="refund-input" 
-								type="number" 
-								placeholder="0" 
-								v-model="res.refundCount" 
-								placeholder-style="color:#ccc" />
-							<text class="unit-label">{{res.xhUnitName}}</text>
+						<view class="goods-qty">
+							<input
+								class="qty-input"
+								type="number"
+								placeholder="0"
+								v-model="res.refundCount"
+								placeholder-style="color:#c8c8c8"
+							/>
+							<text class="qty-unit">{{ res.xhUnitName }}</text>
 						</view>
 					</view>
 				</view>
 			</view>
-		</view>
 
-		<!-- 金额信息卡片 -->
-		<view class="card-section">
-			<view class="section-title">
-				<text class="title-text">金额信息</text>
-			</view>
-			<view class="amount-info">
-				<view class="amount-row">
-					<text class="amount-label">订单金额</text>
-					<view class="amount-value">
-						<text class="price-text">¥{{parseFloat(orderInfo.orderPrice)||0}}</text>
-					</view>
+			<!-- 金额信息 -->
+			<view class="card">
+				<view class="card-hd">
+					<view class="card-bar"></view>
+					<text class="card-title">金额信息</text>
 				</view>
-				<view class="amount-row" v-if="Number(orderInfo.tkPrice)>0">
-					<text class="amount-label">已退金额</text>
-					<view class="amount-value">
-						<text class="refunded-text">¥{{orderInfo.tkPrice ? parseFloat(orderInfo.tkPrice) : 0}}</text>
+				<view class="amount-list">
+					<view class="amount-row">
+						<text class="amount-label">订单金额</text>
+						<text class="amount-val">¥{{ parseFloat(orderInfo.orderPrice) || 0 }}</text>
+					</view>
+					<view class="amount-row" v-if="Number(orderInfo.tkPrice) > 0">
+						<text class="amount-label">已退金额</text>
+						<text class="amount-val amount-val--muted">¥{{ orderInfo.tkPrice ? parseFloat(orderInfo.tkPrice) : 0 }}</text>
+					</view>
+					<view class="amount-row">
+						<text class="amount-label">可退金额</text>
+						<text class="amount-val amount-val--green">¥{{ couldRefundPrice }}</text>
+					</view>
+					<view class="amount-row">
+						<text class="amount-label">预计退款</text>
+						<text class="amount-val amount-val--green">¥{{ refundPrice }}</text>
 					</view>
 				</view>
-				<view class="amount-row">
-					<text class="amount-label">可退金额</text>
-					<text class="amount-value available-amount">¥{{couldRefundPrice}}</text>
-				</view>
-				<view class="amount-row">
-					<text class="amount-label">预计退款</text>
-					<text class="amount-value estimate-amount">¥{{refundPrice}}</text>
-				</view>
-				<view class="amount-row input-row">
-					<text class="amount-label required">实际退款</text>
-					<view class="amount-input-wrapper">
-						<text class="currency-symbol">¥</text>
-						<input 
-							class="amount-input" 
-							type="digit" 
-							v-model="refundMoney" 
+				<view class="actual-box">
+					<view class="actual-left">
+						<text class="actual-label">实际退款</text>
+						<text class="actual-star">*</text>
+					</view>
+					<view class="actual-input-wrap">
+						<text class="actual-yen">¥</text>
+						<input
+							class="actual-input"
+							type="digit"
+							v-model="refundMoney"
 							placeholder="请输入"
-							placeholder-style="color:#999"
-							@focus="refundMoney=''" />
+							placeholder-style="color:#bdbdbd"
+							@focus="refundMoney = ''"
+						/>
 					</view>
 				</view>
 			</view>
-		</view>
 
-		<!-- 备注卡片 -->
-		<view class="card-section">
-			<view class="section-title">
-				<text class="title-text">备注说明</text>
+			<!-- 备注 -->
+			<view class="card">
+				<view class="card-hd">
+					<view class="card-bar"></view>
+					<text class="card-title">备注说明</text>
+					<text class="card-sub">选填</text>
+				</view>
+				<textarea
+					class="remark-area"
+					v-model="remark"
+					placeholder="补充说明售后原因,便于供货商更快处理"
+					placeholder-style="color:#bdbdbd"
+				/>
 			</view>
-			<view class="remark-container">
-				<textarea 
-					class="remark-textarea" 
-					v-model="remark" 
-					placeholder="选填"
-					placeholder-style="color:#999" />
+
+			<!-- 照片 -->
+			<view class="card">
+				<view class="card-hd">
+					<view class="card-bar"></view>
+					<text class="card-title">售后花材照片</text>
+				</view>
+				<view class="upload-body">
+					<htz-image-upload
+						:max="9"
+						:compress="true"
+						v-model="refundImgData"
+						:headers="headers"
+						@uploadSuccess="imgUploadSuccess"
+						:quality="60"
+						@imgDelete="imgDeleteFn"
+						:action="getLoginInfo.imgUploadApi"
+					/>
+					<view class="upload-tip">
+						<text class="upload-tip__warn">必须按规范提供照片,否则申请将直接驳回。</text>
+						<text class="upload-tip__link" @click="getRule()">点击查看拍照规范</text>
+					</view>
+				</view>
 			</view>
-		</view>
 
-		<!-- 售后图片卡片 -->
-		<view class="card-section">
-			<view class="section-title">
-				<text class="title-text">售后花材照片</text>
+			<!-- 退款到账提示 -->
+			<view class="pay-tip" :class="payTipClass">
+				<text v-if="orderInfo.onlinePay == 2" class="pay-tip__text">此单线上付款,审核通过后钱会原路自动退回</text>
+				<text v-else-if="orderInfo.payWay == 2" class="pay-tip__text">此单余额付款,审核通过后钱会原路退回余额</text>
+				<text v-else-if="Number(orderInfo.debt) == 1" class="pay-tip__text">此单为挂账单,审核通过后挂账金额会自动减少</text>
+				<text v-else class="pay-tip__text">此单线下付款,审核通过后不会原路退回,请线下与供货商协商</text>
 			</view>
-			<view class="image-upload-section">
-				<htz-image-upload 
-					:max="9" 
-					:compress="true" 
-					v-model="refundImgData" 
-					:headers="headers"
-					@uploadSuccess="imgUploadSuccess" 
-					:quality="60" 
-					@imgDelete="imgDeleteFn" 
-					:action="getLoginInfo.imgUploadApi">
-				</htz-image-upload>
-				<view class="upload-warning">
-					必须按规范提供照片,否则申请将直接驳回。
-					<view style="color:#049E2C;font-weight:bold;text-decoration:underline;font-size:34upx;" @click="getRule()">点击查看拍照规范</view>
-				</view>
+
+			<!-- 底部操作 -->
+			<view class="footer safe-bottom">
+				<button class="foot-btn foot-btn--ghost" @tap="cancelRefund()">取消</button>
+				<button class="foot-btn foot-btn--primary" formType="submit" @tap="confirmRefund">提交申请</button>
 			</view>
-		</view>
-
-		<!-- 退款方式提示:余额/线上/挂账/线下 -->
-		<view class="tip-section">
-			<text v-if="orderInfo.onlinePay == 2" class="tip-text online-tip">此单线上付款,审核通过后,钱会原路自动退回</text>
-			<text v-else-if="orderInfo.payWay == 2" class="tip-text online-tip">此单余额付款,审核通过后,钱会原路自动退回到余额</text>
-			<block v-else>
-				<text v-if="Number(orderInfo.debt) == 1" class="tip-text debt-tip">此单为挂账单,审核通过后,挂账金额会自动减少</text>
-				<text v-else class="tip-text offline-tip">此单线下付款,审核通过后钱不会原路退回,请线下与供货商协商</text>
-			</block>
-		</view>
-
-		<!-- 底部操作按钮 -->
-		<view class="bottom-actions">
-			<button class="action-btn cancel-btn" @tap="cancelRefund()">取消</button>
-			<button class="action-btn confirm-btn" formType="submit" @tap="confirmRefund">提交申请</button>
-		</view>
-
-	</block>
-	<block v-else>
-		<view class="info-tip">
-			<view class="info-content">
-				<text class="info-text" style="font-size:42upx;">暂不支持线上申请售后</text>
+		</block>
+
+		<block v-else>
+			<view class="empty-card">
+				<text class="empty-title">暂不支持线上申请售后</text>
+				<text class="empty-desc">请联系供货商线下处理</text>
 			</view>
-		</view>
-	</block>
-</view>
+		</block>
+	</view>
 </template>
 <script>
-import { mapGetters } from "vuex"
-import TuiListCell from "@/components/plugin/list-cell";
-import { getFullInfo } from "@/api/purchase";
-import { createRefund } from "@/api/cg-refund";
-//图片上传插件来源:https://ext.dcloud.net.cn/plugin?id=2922 已改造,不能再升级 shish 20211228
+import { mapGetters } from 'vuex'
+import TuiListCell from '@/components/plugin/list-cell'
+import { getFullInfo } from '@/api/purchase'
+import { createRefund } from '@/api/cg-refund'
+// 图片上传插件来源:https://ext.dcloud.net.cn/plugin?id=2922 已改造,不能再升级 shish 20211228
 import htzImageUpload from '@/components/htz-image-upload/htz-image-upload.vue'
+
 export default {
-	name: "refund",
+	name: 'refund',
 	components: {
 		TuiListCell,
 		htzImageUpload
 	},
 	data() {
 		return {
-			product:[],
-			refundMoney:0,
-			refundType:1,
-			remark:'',
+			product: [],
+			refundMoney: 0,
+			refundType: 1,
+			remark: '',
 			// 售后规则默认值,init 拉取订单后会被接口 afterSaleRule 覆盖
 			orderInfo: {
 				afterSaleRule: {
@@ -199,26 +236,27 @@ export default {
 					refundMustImg: 0
 				}
 			},
-			couldRefundPrice:0,
-			unClear:[],
-			refundImgData:[],
-			uploadRefundImg:[],
-			headers:{token:''},
-			needNotice:0
-		};
+			couldRefundPrice: 0,
+			unClear: [],
+			refundImgData: [],
+			uploadRefundImg: [],
+			headers: { token: '' },
+			needNotice: 0
+		}
 	},
 	onLoad() {
 		const token = uni.getStorageSync('token')
 		this.headers.token = token
 	},
-	computed:{
-		...mapGetters(["getLoginInfo","getDictionariesInfo"]),
-		refundPrice(){
+	computed: {
+		...mapGetters(['getLoginInfo', 'getDictionariesInfo']),
+		/** 预计退款:按勾选数量 × 单价汇总,并同步到实际退款输入 */
+		refundPrice() {
 			let price = 0
-			if(this.product){
+			if (this.product) {
 				for (const item of this.product) {
-					if(Number(item.refundCount)>0){
-						let currentPrice = Number(item.refundCount)*Number(item.xhUnitPrice)
+					if (Number(item.refundCount) > 0) {
+						let currentPrice = Number(item.refundCount) * Number(item.xhUnitPrice)
 						currentPrice.toFixed(2)
 						price = Number(price) + Number(currentPrice)
 						price.toFixed(2)
@@ -228,19 +266,34 @@ export default {
 			price = parseFloat(price.toFixed(2))
 			this.refundMoney = price
 			return price
+		},
+		/** 到账提示条样式:线下红、其余蓝 */
+		payTipClass() {
+			if (this.orderInfo.onlinePay == 2 || this.orderInfo.payWay == 2 || Number(this.orderInfo.debt) == 1) {
+				return 'pay-tip--info'
+			}
+			return 'pay-tip--warn'
 		}
 	},
-	watch:{
-	},
+	watch: {},
 	methods: {
-		noticeMe(){
+		noticeMe() {
 			// #ifdef MP-WEIXIN
 			let that = this
-			if(this.getDictionariesInfo && this.getDictionariesInfo.subscribeMessage && this.getDictionariesInfo.subscribeMessage == 1 && this.getDictionariesInfo.hdMiniMessage && this.getDictionariesInfo.hdMiniMessage.afterSale){
+			if (
+				this.getDictionariesInfo &&
+				this.getDictionariesInfo.subscribeMessage &&
+				this.getDictionariesInfo.subscribeMessage == 1 &&
+				this.getDictionariesInfo.hdMiniMessage &&
+				this.getDictionariesInfo.hdMiniMessage.afterSale
+			) {
 				uni.requestSubscribeMessage({
 					tmplIds: [this.getDictionariesInfo.hdMiniMessage.afterSale.msgId],
 					success(res) {
-						if(res[that.getDictionariesInfo.hdMiniMessage.afterSale.msgId] && res[that.getDictionariesInfo.hdMiniMessage.afterSale.msgId] == 'accept'){
+						if (
+							res[that.getDictionariesInfo.hdMiniMessage.afterSale.msgId] &&
+							res[that.getDictionariesInfo.hdMiniMessage.afterSale.msgId] == 'accept'
+						) {
 							that.needNotice = 1
 						}
 					},
@@ -250,22 +303,22 @@ export default {
 					complete() {}
 				})
 			}
-			// #endif	
+			// #endif
 		},
-		getRule(){
-			this.$util.pageTo({url:'/pagesPurchase/afterSale'})
+		getRule() {
+			this.$util.pageTo({ url: '/pagesPurchase/afterSale' })
 		},
 		imgUploadSuccess(res) {
 			var _res = JSON.parse(res.data)
-			if(_res.code == 1){
+			if (_res.code == 1) {
 				this.refundImgData.push(_res.data.smallUrl)
 				this.uploadRefundImg.push(_res.data.shortUrl)
 			}
 		},
-		cancelRefund(){
-			uni.navigateBack({delta: 1});
+		cancelRefund() {
+			uni.navigateBack({ delta: 1 })
 		},
-		confirmRefund(){
+		confirmRefund() {
 			// 无支付时间的订单不允许售后(与后端 assertCanRefund 一致,仅认 payTime)
 			const payTime = (this.orderInfo && this.orderInfo.payTime) || ''
 			if (!payTime || payTime === '0000-00-00 00:00:00') {
@@ -275,48 +328,48 @@ export default {
 			let hasError = false
 			let product = []
 			let that = this
-			this.product.forEach(ele=>{
-				let currentRefundCont = ele.refundCount ? Number(ele.refundCount) :0
+			this.product.forEach((ele) => {
+				let currentRefundCont = ele.refundCount ? Number(ele.refundCount) : 0
 				let currentNum = ele.xhNum ? Number(ele.xhNum) : 0
 				let hasRefundNum = ele.refundNum ? Number(ele.refundNum) : 0
 				let couldRefundNum = Number(currentNum) - Number(hasRefundNum)
-				if(Number(currentRefundCont) > Number(couldRefundNum)){
-					uni.showToast({title:ele.name+' 超过可退数量',icon:'none'})
-					hasError = true;
+				if (Number(currentRefundCont) > Number(couldRefundNum)) {
+					uni.showToast({ title: ele.name + ' 超过可退数量', icon: 'none' })
+					hasError = true
 					return false
 				}
-				if(Number(ele.refundCount)>0){
+				if (Number(ele.refundCount) > 0) {
 					product.push({
-						"productId":ele.productId,
-						"num":ele.refundCount,
-						"unitType":ele.unitType,
-						unitName:ele.xhUnitName,
-						unitType:ele.xhUnitType,
-						unitPrice:ele.xhUnitPrice
+						productId: ele.productId,
+						num: ele.refundCount,
+						unitType: ele.unitType,
+						unitName: ele.xhUnitName,
+						unitType: ele.xhUnitType,
+						unitPrice: ele.xhUnitPrice
 					})
 				}
 			})
-			if(hasError){
+			if (hasError) {
 				return
 			}
-			if(this.$util.isEmpty(product)&&this.refundType==1){
-				uni.showToast({title:'请选择商品',icon:'none'})
-				return;
+			if (this.$util.isEmpty(product) && this.refundType == 1) {
+				uni.showToast({ title: '请选择商品', icon: 'none' })
+				return
 			}
-			if(Number(this.orderInfo.afterSaleRule.refundMustImg) == 1 && this.$util.isEmpty(this.uploadRefundImg)){
-				uni.showToast({title:'请上传照片',icon:'none'})
-				return;
+			if (Number(this.orderInfo.afterSaleRule.refundMustImg) == 1 && this.$util.isEmpty(this.uploadRefundImg)) {
+				uni.showToast({ title: '请上传照片', icon: 'none' })
+				return
 			}
 			let imgData = JSON.stringify(this.uploadRefundImg)
 			let refundParams = {
-				id:this.option.id,
-				product:JSON.stringify(product),
-				price:this.refundMoney,
-				remark:this.remark,
-				refundType:this.refundType,
-				getOriginalItem:1,
-				imgList:imgData
-			};
+				id: this.option.id,
+				product: JSON.stringify(product),
+				price: this.refundMoney,
+				remark: this.remark,
+				refundType: this.refundType,
+				getOriginalItem: 1,
+				imgList: imgData
+			}
 			let topTitle = '提示'
 			let title = '确认提交?'
 			if (this.orderInfo.payWay == 2) {
@@ -328,17 +381,17 @@ export default {
 				topTitle = '特别注意'
 			}
 			that.$util.confirmModal({ title: topTitle, content: title }, () => {
-				uni.showLoading({title: "提交中",mask:true})
-				createRefund(refundParams).then(res => {
-					if(res.code == 1){
-						that.$util.pageTo({url: '/pagesPurchase/refundResult?id='+res.data.id,type:2})
+				uni.showLoading({ title: '提交中', mask: true })
+				createRefund(refundParams).then((res) => {
+					if (res.code == 1) {
+						that.$util.pageTo({ url: '/pagesPurchase/refundResult?id=' + res.data.id, type: 2 })
 					}
 				})
 			})
 		},
 		async init() {
-			//getOriginalItem 取原有的花材结构(小菊的花材结构有变化)
-			const res = await getFullInfo({ id: this.option.id,getOriginalItem:1 })
+			// getOriginalItem 取原有的花材结构(小菊的花材结构有变化)
+			const res = await getFullInfo({ id: this.option.id, getOriginalItem: 1 })
 			const defaultAfterSaleRule = this.orderInfo.afterSaleRule || {}
 			this.orderInfo = res.data
 			this.orderInfo.afterSaleRule = {
@@ -349,422 +402,511 @@ export default {
 			this.couldRefundPrice = this.couldRefundPrice.toFixed(2)
 			this.couldRefundPrice = parseFloat(this.couldRefundPrice)
 
-			this.product = res.data.product.map(ele=>{
-				return {...ele,refundCount:null}
+			this.product = res.data.product.map((ele) => {
+				return { ...ele, refundCount: null }
 			})
 		}
 	}
-};
+}
 </script>
 <style lang="scss" scoped>
 .refund-page {
 	min-height: 100vh;
-	background: #f5f6f8;
-	padding: 20upx 0 200upx;
+	background: #f4f6f8;
+	padding: 24upx 24upx 220upx;
+	box-sizing: border-box;
 }
 
-// 退款方式提示
-.tip-section {
-	margin: 20upx;
-	padding: 20upx;
-	border-radius: 12upx;
-
-	.tip-text {
-		display: block;
-		font-size: 32upx;
-		line-height: 1.5;
-		font-weight: 600;
+/* 顶部引导 */
+.guide-card {
+	background: #fff;
+	border-radius: 20upx;
+	padding: 28upx 28upx 24upx;
+	margin-bottom: 20upx;
+	box-shadow: 0 4upx 16upx rgba(0, 0, 0, 0.04);
+}
 
-		&.online-tip {
-			background: rgba(51, 133, 255, 0.1);
-			color: #3385ff;
-			padding: 15upx;
-			border-radius: 8upx;
-			border-left: 4upx solid #3385ff;
-		}
+.guide-hd {
+	display: flex;
+	align-items: center;
+	margin-bottom: 20upx;
+}
 
-		&.debt-tip {
-			background: rgba(51, 133, 255, 0.1);
-			color: #3385ff;
-			padding: 15upx;
-			border-radius: 8upx;
-			border-left: 4upx solid #3385ff;
-		}
+.guide-badge {
+	padding: 4upx 14upx;
+	margin-right: 12upx;
+	font-size: 22upx;
+	font-weight: 600;
+	color: #049e2c;
+	background: rgba(4, 158, 44, 0.1);
+	border-radius: 8upx;
+}
 
-		&.offline-tip {
-			background: rgba(255, 71, 87, 0.1);
-			color: #ff4757;
-			padding: 15upx;
-			border-radius: 8upx;
-			border-left: 4upx solid #ff4757;
-		}
-	}
+.guide-title {
+	font-size: 30upx;
+	font-weight: 700;
+	color: #222;
 }
 
-// 信息提示样式
-.info-tip {
-	background: #f0f9f7;
-	border: 1upx solid #c6f6d5;
-	border-radius: 12upx;
-	margin: 20upx 20upx 20upx 20upx;
-	padding: 20upx;
+.guide-item {
 	display: flex;
 	align-items: flex-start;
-	gap: 15upx;
-	
-	.info-icon {
-		font-size: 40upx;
-		flex-shrink: 0;
-		line-height: 1;
-		min-width: 50upx;
-	}
-	
-	.info-content {
-		flex: 1;
-		display: flex;
-		flex-direction: column;
-		gap: 8upx;
-	}
-	
-	.info-text {
-		font-size: 32upx;
-		color: #049E2C;
-		line-height: 1.4;
+	margin-top: 16upx;
+
+	&:first-of-type {
+		margin-top: 0;
 	}
-	
-	.info-warning {
-		font-size: 32upx;
+}
+
+.guide-dot {
+	width: 14upx;
+	height: 14upx;
+	margin-top: 14upx;
+	margin-right: 14upx;
+	border-radius: 50%;
+	flex-shrink: 0;
+}
+
+.guide-dot--blue {
+	background: #3385ff;
+}
+
+.guide-dot--green {
+	background: #049e2c;
+}
+
+.guide-text {
+	flex: 1;
+	font-size: 28upx;
+	line-height: 1.55;
+	color: #444;
+}
+
+.guide-em {
+	font-weight: 700;
+}
+
+.guide-em--blue {
+	color: #3385ff;
+}
+
+.guide-em--green {
+	color: #049e2c;
+}
+
+.guide-warn {
+	margin-top: 20upx;
+	padding: 18upx 20upx;
+	background: #fff5f5;
+	border-radius: 12upx;
+	border-left: 6upx solid #e62e45;
+
+	text {
+		font-size: 26upx;
+		line-height: 1.5;
 		color: #c41d2a;
 		font-weight: 600;
-		line-height: 1.5;
 	}
 }
 
-// 卡片样式
-.card-section {
+/* 通用卡片 */
+.card {
 	background: #fff;
-	margin: 0 20upx 20upx;
-	border-radius: 16upx;
-	box-shadow: 0 2upx 12upx rgba(0, 0, 0, 0.08);
+	border-radius: 20upx;
+	margin-bottom: 20upx;
 	overflow: hidden;
+	box-shadow: 0 4upx 16upx rgba(0, 0, 0, 0.04);
 }
 
-// 节标题
-.section-title {
-	padding: 30upx 30upx 20upx;
-	border-bottom: 1upx solid #f0f0f0;
+.card-hd {
 	display: flex;
 	align-items: center;
-	justify-content: space-between;
-	
-	.title-text {
-		font-size: 32upx;
-		font-weight: 600;
-		color: #333;
-	}
+	padding: 28upx 28upx 8upx;
+}
+
+.card-bar {
+	width: 8upx;
+	height: 28upx;
+	margin-right: 14upx;
+	border-radius: 4upx;
+	background: #049e2c;
+	flex-shrink: 0;
+}
+
+.card-title {
+	font-size: 30upx;
+	font-weight: 700;
+	color: #222;
+}
+
+.card-sub {
+	margin-left: 16upx;
+	font-size: 24upx;
+	color: #999;
 }
 
-// 退款方式按钮
-.refund-type-buttons {
-	padding: 30upx 30upx 20upx;
+/* 退款方式芯片:不用 gap,第二项用 margin */
+.type-row {
 	display: flex;
-	gap: 30upx;
-	
-	.type-button {
-		flex: 1;
-		height: 80upx;
-		border-radius: 12upx;
-		font-size: 30upx;
-		font-weight: 500;
-		border: 1upx solid #ddd;
-		background: #f8f9fa;
-		color: #666;
-		transition: all 0.3s ease;
-		
-		&.active {
-			background: linear-gradient(135deg, #049E2C 0%, #06C547 100%);
-			color: #fff;
-			border: none;
-			box-shadow: 0 4upx 12upx rgba(4, 158, 44, 0.3);
-		}
-		
-		&:active:not(.active) {
-			background: #eff5f8;
-		}
-	}
+	padding: 20upx 24upx 28upx;
+}
+
+.type-chip {
+	flex: 1;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+	min-height: 120upx;
+	padding: 20upx 12upx;
+	border-radius: 16upx;
+	background: #f7f8fa;
+	border: 2upx solid #eef0f3;
+	box-sizing: border-box;
+}
+
+.type-chip--second {
+	margin-left: 20upx;
+}
+
+.type-chip--on {
+	background: rgba(4, 158, 44, 0.08);
+	border-color: #049e2c;
+}
+
+.type-chip__name {
+	font-size: 30upx;
+	font-weight: 700;
+	color: #333;
+}
+
+.type-chip--on .type-chip__name {
+	color: #049e2c;
+}
+
+.type-chip__desc {
+	margin-top: 8upx;
+	font-size: 22upx;
+	color: #999;
+}
+
+.type-chip--on .type-chip__desc {
+	color: #049e2c;
 }
 
-// 商品列表
-.product-list {
-	margin-top: 15upx;
-	padding: 0 20upx 20upx;
+/* 商品行 */
+.goods-list {
+	padding: 12upx 20upx 24upx;
 }
 
-.product-row {
+.goods-item {
 	display: flex;
 	align-items: center;
-	justify-content: space-between;
 	padding: 20upx;
-	margin-bottom: 8upx;
-	background: #fafbfc;
-	border-radius: 8upx;
-	border: 1upx solid #eef0f2;
-	
-	&:last-child {
-		margin-bottom: 0;
+	margin-top: 16upx;
+	background: #f8faf9;
+	border-radius: 16upx;
+
+	&:first-child {
+		margin-top: 0;
 	}
 }
 
-.product-basic-info {
+.goods-cover {
+	width: 96upx;
+	height: 96upx;
+	border-radius: 12upx;
+	background: #eee;
+	flex-shrink: 0;
+}
+
+.goods-main {
 	flex: 1;
-	margin-right: 20upx;
-	
-	.product-name {
-		font-size: 32upx;
-		font-weight: 600;
-		color: #333;
-		line-height: 1.3;
-		display: block;
-		margin-bottom: 8upx;
-		overflow: hidden;
-		text-overflow: ellipsis;
-		white-space: nowrap;
-		width: 300upx;
-	}
-	
-	.product-meta {
-		display: flex;
-		gap: 12upx;
-		flex-wrap: wrap;
-		
-		.stock-info {
-			font-size: 26upx;
-			color: #666;
-			background: #f5f5f5;
-			padding: 4upx 8upx;
-			border-radius: 4upx;
-		}
-		
-		.available-info {
-			font-size: 26upx;
-			color: #049E2C;
-			background: rgba(4, 158, 44, 0.1);
-			padding: 4upx 8upx;
-			border-radius: 4upx;
-		}
-	}
+	min-width: 0;
+	margin-left: 18upx;
+	margin-right: 12upx;
+}
+
+.goods-name {
+	display: block;
+	font-size: 28upx;
+	font-weight: 600;
+	color: #222;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
+
+.goods-meta {
+	margin-top: 8upx;
 }
 
-.refund-control {
+.meta-tag {
+	font-size: 22upx;
+	color: #666;
+	background: #fff;
+	padding: 4upx 10upx;
+	border-radius: 6upx;
+}
+
+.goods-avail {
+	display: block;
+	margin-top: 10upx;
+	font-size: 24upx;
+	color: #049e2c;
+	font-weight: 600;
+}
+
+.goods-qty {
 	display: flex;
+	flex-direction: column;
 	align-items: center;
-	gap: 8upx;
-	
-	.input-item {
-		display: flex;
-		align-items: center;
-		gap: 8upx;
-	}
+	flex-shrink: 0;
 }
 
-.refund-input {
+.qty-input {
 	width: 100upx;
-	height: 60upx;
+	height: 64upx;
 	background: #fff;
-	border: 1upx solid #ddd;
-	border-radius: 6upx;
+	border: 2upx solid #dde3e0;
+	border-radius: 12upx;
 	text-align: center;
-	font-size: 26upx;
-	color: #333;
-	font-weight: 500;
-	
-	&:focus {
-		border-color: #049E2C;
-	}
+	font-size: 28upx;
+	font-weight: 600;
+	color: #222;
 }
 
-.unit-label {
-	font-size: 24upx;
-	color: #666;
-	min-width: 40upx;
+.qty-unit {
+	margin-top: 6upx;
+	font-size: 22upx;
+	color: #888;
 }
 
-// 金额信息
-.amount-info {
-	padding: 30upx;
+/* 金额 */
+.amount-list {
+	padding: 8upx 28upx 8upx;
 }
 
 .amount-row {
 	display: flex;
-	justify-content: space-between;
 	align-items: center;
-	padding: 20upx 0;
-	border-bottom: 1upx solid #f0f0f0;
-	
+	justify-content: space-between;
+	padding: 18upx 0;
+	border-bottom: 1upx solid #f2f3f5;
+
 	&:last-child {
 		border-bottom: none;
 	}
-	
-	&.input-row {
-		align-items: flex-start;
-		padding-top: 30upx;
-	}
-	
-	.amount-label {
-		font-size: 28upx;
-		color: #666;
-		
-		&.required::after {
-			content: "*";
-			color: #ff4757;
-			margin-left: 5upx;
-		}
-	}
-	
-	.amount-value {
-		display: flex;
-		align-items: center;
-		
-		.price-text {
-			font-size: 32upx;
-			font-weight: 600;
-			color: #333;
-		}
-		
-		.refunded-text {
-			font-size: 32upx;
-			font-weight: 600;
-			color: #999;
-		}
-		
-		&.available-amount {
-			font-size: 32upx;
-			font-weight: 600;
-			color: #049E2C;
-		}
-		
-		&.estimate-amount {
-			font-size: 32upx;
-			font-weight: 600;
-			color: #049E2C;
-		}
-	}
 }
 
-.amount-input-wrapper {
+.amount-label {
+	font-size: 28upx;
+	color: #666;
+}
+
+.amount-val {
+	font-size: 30upx;
+	font-weight: 600;
+	color: #222;
+}
+
+.amount-val--muted {
+	color: #999;
+}
+
+.amount-val--green {
+	color: #049e2c;
+}
+
+.actual-box {
 	display: flex;
 	align-items: center;
-	background: #fafbfc;
-	border: 1upx solid #ddd;
-	border-radius: 8upx;
-	padding: 0 20upx;
-	width: 200upx;
-	height: 80upx;
-	
-	.currency-symbol {
-		font-size: 28upx;
-		color: #666;
-		margin-right: 10upx;
-	}
-	
-	.amount-input {
-		flex: 1;
-		height: 80upx;
-		font-size: 28upx;
-		color: #333;
-		font-weight: 500;
-		border: none;
-		background: transparent;
-	}
+	justify-content: space-between;
+	margin: 8upx 24upx 28upx;
+	padding: 24upx;
+	background: #f3faf5;
+	border-radius: 16upx;
+	border: 2upx solid rgba(4, 158, 44, 0.18);
 }
 
-// 审核通知
-.notice-section {
-	padding: 30upx;
+.actual-left {
 	display: flex;
-	justify-content: center;
+	align-items: center;
 }
 
-// 备注输入框
-.remark-container {
-	padding: 20upx 30upx 30upx;
+.actual-label {
+	font-size: 28upx;
+	font-weight: 700;
+	color: #222;
 }
 
-.remark-textarea {
-	width: 100%;
-	height: 100upx;
-	background: #fafbfc;
-	border: 1upx solid #ddd;
-	border-radius: 8upx;
-	padding: 15upx;
+.actual-star {
+	margin-left: 6upx;
+	font-size: 28upx;
+	color: #e62e45;
+	font-weight: 700;
+}
+
+.actual-input-wrap {
+	display: flex;
+	align-items: center;
+	min-width: 240upx;
+	height: 72upx;
+	padding: 0 20upx;
+	background: #fff;
+	border-radius: 12upx;
+	border: 2upx solid #d9e8dd;
+	box-sizing: border-box;
+}
+
+.actual-yen {
+	font-size: 30upx;
+	font-weight: 700;
+	color: #049e2c;
+	margin-right: 8upx;
+}
+
+.actual-input {
+	flex: 1;
+	height: 72upx;
+	font-size: 32upx;
+	font-weight: 700;
+	color: #049e2c;
+}
+
+/* 备注 / 上传 */
+.remark-area {
+	display: block;
+	width: auto;
+	height: 160upx;
+	margin: 12upx 24upx 28upx;
+	padding: 20upx;
+	background: #f7f8fa;
+	border-radius: 12upx;
+	border: 2upx solid #eef0f3;
 	font-size: 28upx;
 	color: #333;
-	line-height: 1.2;
+	line-height: 1.5;
 	box-sizing: border-box;
-	resize: none;
 }
 
-// 图片上传区域
-.image-upload-section {
-	padding: 20upx 30upx 30upx;
-	
-	.upload-warning {
-		color: #c41d2a;
-		font-weight: 600;
-		font-size: 30upx;
-		margin-top: 15upx;
-	}
+.upload-body {
+	padding: 12upx 24upx 28upx;
 }
 
-// 底部操作按钮
-.bottom-actions {
-	z-index: 39;
+.upload-tip {
+	margin-top: 16upx;
+}
+
+.upload-tip__warn {
+	display: block;
+	font-size: 26upx;
+	line-height: 1.5;
+	color: #c41d2a;
+	font-weight: 600;
+}
+
+.upload-tip__link {
+	display: inline-block;
+	margin-top: 10upx;
+	font-size: 28upx;
+	font-weight: 700;
+	color: #049e2c;
+	text-decoration: underline;
+}
+
+/* 到账提示 */
+.pay-tip {
+	margin-bottom: 20upx;
+	padding: 22upx 24upx;
+	border-radius: 16upx;
+}
+
+.pay-tip--info {
+	background: rgba(51, 133, 255, 0.1);
+	border-left: 6upx solid #3385ff;
+}
+
+.pay-tip--warn {
+	background: rgba(230, 46, 69, 0.08);
+	border-left: 6upx solid #e62e45;
+}
+
+.pay-tip__text {
+	font-size: 28upx;
+	line-height: 1.5;
+	font-weight: 600;
+}
+
+.pay-tip--info .pay-tip__text {
+	color: #3385ff;
+}
+
+.pay-tip--warn .pay-tip__text {
+	color: #e62e45;
+}
+
+.empty-card {
+	margin-top: 120upx;
+	padding: 60upx 40upx;
+	background: #fff;
+	border-radius: 20upx;
+	text-align: center;
+}
+
+.empty-title {
+	display: block;
+	font-size: 34upx;
+	font-weight: 700;
+	color: #333;
+}
+
+.empty-desc {
+	display: block;
+	margin-top: 16upx;
+	font-size: 26upx;
+	color: #999;
+}
+
+/* 底栏 */
+.footer {
 	position: fixed;
-	bottom: 0;
 	left: 0;
 	right: 0;
-	background: #fff;
-	padding: 30upx;
-	border-top: 1upx solid #eee;
+	bottom: 0;
+	z-index: 39;
 	display: flex;
-	gap: 30upx;
-	box-shadow: 0 -4upx 12upx rgba(0, 0, 0, 0.1);
+	align-items: center;
+	padding: 20upx 24upx;
+	background: #fff;
+	box-shadow: 0 -6upx 24upx rgba(0, 0, 0, 0.06);
+	box-sizing: border-box;
+}
+
+.safe-bottom {
+	padding-bottom: calc(20upx + env(safe-area-inset-bottom));
 }
 
-.action-btn {
+.foot-btn {
 	flex: 1;
 	height: 88upx;
-	border-radius: 12upx;
-	font-size: 32upx;
-	font-weight: 600;
+	line-height: 88upx;
+	border-radius: 44upx;
+	font-size: 30upx;
+	font-weight: 700;
 	border: none;
-	transition: all 0.3s ease;
-	
-	&.cancel-btn {
-		background: #f8f9fa;
-		color: #666;
-		border: 1upx solid #ddd;
-		
-		&:active {
-			background: #e9ecef;
-		}
-	}
-	
-	&.confirm-btn {
-		background: linear-gradient(135deg, #049E2C 0%, #06C547 100%);
-		color: #fff;
-		box-shadow: 0 4upx 12upx rgba(4, 158, 44, 0.3);
-		
-		&:active {
-			transform: translateY(2upx);
-			box-shadow: 0 2upx 8upx rgba(4, 158, 44, 0.3);
-		}
-	}
+	margin: 0;
+	padding: 0;
+}
+
+.foot-btn--ghost {
+	margin-right: 20upx;
+	background: #f3f4f6;
+	color: #666;
 }
 
-// 绿色按钮样式
-.green-btn {
-	background: #049E2C !important;
-	color: white !important;
+.foot-btn--primary {
+	background: #049e2c;
+	color: #fff;
 }
-</style>
+</style>