apply-refund.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. <template>
  2. <view class="apply-refund-page">
  3. <refund-step-one
  4. v-if="currentStep === 1"
  5. :goods-list="mergedGoods"
  6. :refund-type.sync="refundType"
  7. :reason-list="reasonList"
  8. :status-list="statusList"
  9. @next="handleStepOneNext"
  10. />
  11. <refund-step-two
  12. v-if="currentStep === 2"
  13. :selected-goods="selectedGoods"
  14. :refund-type="refundType"
  15. :default-address="address"
  16. :reason-list="reasonList"
  17. :status-list="statusList"
  18. @back="currentStep = 1"
  19. @submit="handleSubmit"
  20. />
  21. </view>
  22. </template>
  23. <script>
  24. import RefundStepOne from '../components/refund-step-one.vue';
  25. import RefundStepTwo from '../components/refund-step-two.vue';
  26. export default {
  27. components: {
  28. RefundStepOne,
  29. RefundStepTwo
  30. },
  31. data() {
  32. return {
  33. orderId: '',
  34. targetDetailOrderId: '',
  35. isModify: false,
  36. refundOrderId: '',
  37. orderInfo: null,
  38. mergedGoods: [], // 合并了 applyRefundPre 返回的字段
  39. selectedGoods: [], // Step1 选中的商品及其状态/原因
  40. refundType: '1', // 1: 退货退款, 2: 仅退款
  41. currentStep: 1,
  42. reasonList: [],
  43. statusList: [
  44. { value: '1', label: '未收到货' },
  45. { value: '2', label: '已收到货' }
  46. ],
  47. address: {} // 默认取件地址
  48. };
  49. },
  50. onLoad(options) {
  51. this.getRefundReasons();
  52. if (options.isModify == '1' && options.refundOrderId) {
  53. this.isModify = true;
  54. this.refundOrderId = options.refundOrderId;
  55. // 修改模式暂且保留老逻辑的兼容,由于需求只给了正常流程,先重点处理正常流程
  56. this.loadRefundDetail();
  57. } else if (options.orderId) {
  58. this.orderId = options.orderId;
  59. if (options.detailOrderId) {
  60. this.targetDetailOrderId = options.detailOrderId;
  61. }
  62. this.loadOrderDetail();
  63. }
  64. },
  65. onShow() {
  66. // 如果在第二步去了地址选择页,返回后更新地址
  67. let selectAddr = uni.getStorageSync("selectAddr");
  68. if (selectAddr) {
  69. this.address = selectAddr;
  70. uni.removeStorageSync("selectAddr");
  71. }
  72. },
  73. watch: {
  74. refundType(newVal) {
  75. // 切换退款类型时重新拉取预览数据
  76. if (this.orderInfo && !this.isModify) {
  77. this.fetchPreRefundData();
  78. }
  79. }
  80. },
  81. methods: {
  82. getRefundReasons() {
  83. uni.$u.http.get("/token/common/getDictOptions?type=shop_order_complaints_options").then(res => {
  84. if (res.code === 200) {
  85. this.reasonList = res.data.map(item => ({
  86. value: item.dictValue || item.dictLabel,
  87. label: item.dictLabel
  88. }));
  89. }
  90. });
  91. },
  92. loadOrderDetail() {
  93. this.$u.api.getShopOrderDetailAjax({ orderId: this.orderId }).then(res => {
  94. if (res.code === 200) {
  95. this.orderInfo = res.data;
  96. // 根据订单状态设置默认售后类型
  97. if (this.orderInfo.status == '3') { // 待收货
  98. this.refundType = '1';
  99. } else {
  100. this.refundType = '1';
  101. }
  102. this.address = {
  103. id: this.orderInfo.receiverAddressId,
  104. name: this.orderInfo.receiverName,
  105. mobile: this.orderInfo.receiverMobile,
  106. fullAddress: this.orderInfo.receiverAddress,
  107. };
  108. this.fetchPreRefundData();
  109. }
  110. });
  111. },
  112. fetchPreRefundData() {
  113. if (!this.orderInfo || !this.orderInfo.detailVoList) return;
  114. // 此时全量传入后端进行校验
  115. const detailOrderIdList = this.orderInfo.detailVoList.map(item => item.detailOrderId || item.id);
  116. if (detailOrderIdList.length === 0) {
  117. this.buildMergedGoods({});
  118. return;
  119. }
  120. this.$u.api.applyRefundPreAjax({
  121. orderId: this.orderId,
  122. detailOrderIdList: detailOrderIdList,
  123. refundType: this.refundType
  124. }).then(res => {
  125. if (res.code === 200) {
  126. const preDataMap = {};
  127. res.data.forEach(item => {
  128. preDataMap[item.detailOrderId] = item;
  129. });
  130. this.buildMergedGoods(preDataMap);
  131. }
  132. });
  133. },
  134. buildMergedGoods(preDataMap) {
  135. // 保留已选中的状态,如果是第一次则按 targetDetailOrderId 选中
  136. const isFirst = this.mergedGoods.length === 0;
  137. this.mergedGoods = this.orderInfo.detailVoList.map(item => {
  138. const id = item.detailOrderId || item.id;
  139. const preData = preDataMap[id] || {};
  140. // 查找是否已经存在
  141. const existing = this.mergedGoods.find(m => (m.detailOrderId || m.id) === id);
  142. // 根据后端返回的字段和当前退款类型判断是否可选
  143. let isDisabled = false;
  144. if (this.refundType === '1') {
  145. // 退货退款
  146. isDisabled = preData.canRefund === 0;
  147. } else if (this.refundType === '2') {
  148. // 仅退款
  149. isDisabled = preData.canRefundOnlyMoney === 0;
  150. }
  151. let checked = true;
  152. if (isDisabled) {
  153. checked = false;
  154. } else if (isFirst && this.targetDetailOrderId) {
  155. checked = (String(id) === String(this.targetDetailOrderId));
  156. } else if (existing) {
  157. checked = existing.checked;
  158. }
  159. return {
  160. ...item,
  161. ...preData, // 合并新接口的字段:canRefundNum, canRefundMoney, canModifyNum, canModifyMoney
  162. disabled: isDisabled,
  163. checked: checked,
  164. refundNum: preData.canRefundNum || item.num,
  165. refundMoney: preData.canRefundMoney || 0,
  166. shopStatus: existing ? existing.shopStatus : '',
  167. shopStatusText: existing ? existing.shopStatusText : '',
  168. refundReason: existing ? existing.refundReason : '',
  169. refundReasonText: existing ? existing.refundReasonText : '',
  170. description: existing ? existing.description : '',
  171. fileUrlList: existing ? existing.fileUrlList : []
  172. };
  173. });
  174. },
  175. loadRefundDetail() {
  176. // 修改模式的兼容逻辑(如果需要的话,按原有代码逻辑映射到新组件数据结构)
  177. this.$u.api.getNewRefundOrderDetailAjax({
  178. refundOrderId: this.refundOrderId
  179. }).then(res => {
  180. if (res.code === 200) {
  181. const data = res.data;
  182. this.orderId = data.originOrderId;
  183. this.refundType = String(data.refundType);
  184. this.mergedGoods = [{
  185. ...data,
  186. id: data.detailOrderId,
  187. checked: true,
  188. refundNum: data.refundNum || 1,
  189. refundMoney: data.refundMoney || 0,
  190. shopStatus: String(data.shopStatus),
  191. shopStatusText: String(data.shopStatus) === '1' ? '未收到货' : '已收到货',
  192. refundReason: data.refundReason,
  193. refundReasonText: data.refundReason,
  194. description: data.description || '',
  195. fileUrlList: data.fileUrlList || [],
  196. // 假装可以修改,修改模式后端未返回canModify,暂设1
  197. canModifyMoney: 1,
  198. canModifyNum: 1,
  199. canRefundMoney: data.refundMoney || 0,
  200. canRefundNum: data.refundNum || 1
  201. }];
  202. this.address = {
  203. id: data.sendAddressId,
  204. name: data.sendName,
  205. mobile: data.sendMobile,
  206. fullAddress: data.sendAddress,
  207. };
  208. }
  209. });
  210. },
  211. handleStepOneNext(payload) {
  212. this.selectedGoods = payload.selectedGoods;
  213. this.currentStep = 2;
  214. },
  215. handleSubmit(payload) {
  216. const { goodsList, returnMethod, address } = payload;
  217. let params = {};
  218. if (this.isModify) {
  219. // 修改申请,只针对单件商品,取选中的第一件商品数据
  220. const item = goodsList[0];
  221. params = {
  222. orderId: this.orderId,
  223. refundOrderId: this.refundOrderId,
  224. refundType: this.refundType,
  225. sendType: returnMethod || '',
  226. addressId: (address && address.id) ? address.id : '',
  227. refundNum: item.refundNum,
  228. refundMoney: item.refundMoney,
  229. shopStatus: item.shopStatus,
  230. refundReason: item.refundReason,
  231. description: item.description,
  232. fileUrlList: item.fileUrlList || []
  233. };
  234. } else {
  235. // 正常申请售后,可能是多件商品
  236. const refundDetailList = goodsList.map(item => ({
  237. detailOrderId: item.detailOrderId || item.id,
  238. num: item.refundNum,
  239. refundMoney: item.refundMoney,
  240. shopStatus: item.shopStatus,
  241. refundReason: item.refundReason,
  242. description: item.description,
  243. fileUrlList: item.fileUrlList || []
  244. }));
  245. params = {
  246. orderId: this.orderId,
  247. refundDetailList: refundDetailList,
  248. refundType: this.refundType,
  249. sendType: returnMethod || '',
  250. addressId: (address && address.id) ? address.id : ''
  251. };
  252. }
  253. // 如果是退货退款(1) 并且是上门取件(1),传递地址对象(兼容旧逻辑)
  254. if (this.refundType === '1' && returnMethod === '1' && address) {
  255. params.address = address;
  256. }
  257. const api = this.isModify ? this.$u.api.refundApplyModifyAjax : this.$u.api.applyRefundAjax;
  258. uni.showLoading({ title: '提交中' });
  259. api(params).then(res => {
  260. uni.hideLoading();
  261. if (res.code === 200) {
  262. this.$u.toast(this.isModify ? '修改成功' : '提交成功');
  263. setTimeout(() => {
  264. uni.navigateBack();
  265. }, 1500);
  266. } else {
  267. this.$u.toast(res.msg || (this.isModify ? '修改失败' : '提交失败'));
  268. }
  269. }).catch(() => {
  270. uni.hideLoading();
  271. });
  272. }
  273. }
  274. }
  275. </script>
  276. <style lang="scss" scoped>
  277. .apply-refund-page {
  278. min-height: 100vh;
  279. background-color: #f5f5f5;
  280. }
  281. </style>