apply-refund.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. // status <= 3: 仅退款;status > 3: 退货退款
  98. if (this.orderInfo.status <= 3) {
  99. this.refundType = '2'; // 仅退款
  100. } else {
  101. this.refundType = '1'; // 退货退款
  102. }
  103. this.address = {
  104. id: this.orderInfo.receiverAddressId,
  105. name: this.orderInfo.receiverName,
  106. mobile: this.orderInfo.receiverMobile,
  107. fullAddress: this.orderInfo.receiverAddress,
  108. };
  109. this.fetchPreRefundData();
  110. }
  111. });
  112. },
  113. fetchPreRefundData() {
  114. if (!this.orderInfo || !this.orderInfo.detailVoList) return;
  115. // 此时全量传入后端进行校验
  116. const detailOrderIdList = this.orderInfo.detailVoList.map(item => item.detailOrderId || item.id);
  117. if (detailOrderIdList.length === 0) {
  118. this.buildMergedGoods({});
  119. return;
  120. }
  121. this.$u.api.applyRefundPreAjax({
  122. orderId: this.orderId,
  123. detailOrderIdList: detailOrderIdList,
  124. refundType: this.refundType
  125. }).then(res => {
  126. if (res.code === 200) {
  127. const preDataMap = {};
  128. res.data.forEach(item => {
  129. preDataMap[item.detailOrderId] = item;
  130. });
  131. this.buildMergedGoods(preDataMap);
  132. }
  133. });
  134. },
  135. buildMergedGoods(preDataMap) {
  136. // 保留已选中的状态,如果是第一次则按 targetDetailOrderId 选中
  137. const isFirst = this.mergedGoods.length === 0;
  138. this.mergedGoods = this.orderInfo.detailVoList.map(item => {
  139. const id = item.detailOrderId || item.id;
  140. const preData = preDataMap[id] || {};
  141. // 查找是否已经存在
  142. const existing = this.mergedGoods.find(m => (m.detailOrderId || m.id) === id);
  143. // 根据后端返回的字段和当前退款类型判断是否可选
  144. let isDisabled = false;
  145. if (this.refundType === '1') {
  146. // 退货退款
  147. isDisabled = preData.canRefund === 0;
  148. } else if (this.refundType === '2') {
  149. // 仅退款
  150. isDisabled = preData.canRefundOnlyMoney === 0;
  151. }
  152. let checked = true;
  153. if (isDisabled) {
  154. checked = false;
  155. } else if (isFirst && this.targetDetailOrderId) {
  156. checked = (String(id) === String(this.targetDetailOrderId));
  157. } else if (existing) {
  158. checked = existing.checked;
  159. }
  160. return {
  161. ...item,
  162. ...preData, // 合并新接口的字段:canRefundNum, canRefundMoney, canModifyNum, canModifyMoney
  163. disabled: isDisabled,
  164. checked: checked,
  165. refundNum: preData.canRefundNum || item.num,
  166. refundMoney: preData.canRefundMoney || 0,
  167. shopStatus: existing ? existing.shopStatus : '',
  168. shopStatusText: existing ? existing.shopStatusText : '',
  169. refundReason: existing ? existing.refundReason : '',
  170. refundReasonText: existing ? existing.refundReasonText : '',
  171. description: existing ? existing.description : '',
  172. fileUrlList: existing ? existing.fileUrlList : []
  173. };
  174. });
  175. },
  176. loadRefundDetail() {
  177. // 修改模式的兼容逻辑(如果需要的话,按原有代码逻辑映射到新组件数据结构)
  178. this.$u.api.getNewRefundOrderDetailAjax({
  179. refundOrderId: this.refundOrderId
  180. }).then(res => {
  181. if (res.code === 200) {
  182. const data = res.data;
  183. this.orderId = data.originOrderId;
  184. this.refundType = String(data.refundType);
  185. this.mergedGoods = [{
  186. ...data,
  187. id: data.detailOrderId,
  188. checked: true,
  189. refundNum: data.refundNum || 1,
  190. refundMoney: data.refundMoney || 0,
  191. shopStatus: String(data.shopStatus),
  192. shopStatusText: String(data.shopStatus) === '1' ? '未收到货' : '已收到货',
  193. refundReason: data.refundReason,
  194. refundReasonText: data.refundReason,
  195. description: data.description || '',
  196. fileUrlList: data.fileUrlList || [],
  197. // 假装可以修改,修改模式后端未返回canModify,暂设1
  198. canModifyMoney: 1,
  199. canModifyNum: 1,
  200. canRefundMoney: data.refundMoney || 0,
  201. canRefundNum: data.refundNum || 1
  202. }];
  203. this.address = {
  204. id: data.sendAddressId,
  205. name: data.sendName,
  206. mobile: data.sendMobile,
  207. fullAddress: data.sendAddress,
  208. };
  209. }
  210. });
  211. },
  212. handleStepOneNext(payload) {
  213. this.selectedGoods = payload.selectedGoods;
  214. this.currentStep = 2;
  215. },
  216. handleSubmit(payload) {
  217. const { goodsList, returnMethod, address } = payload;
  218. let params = {};
  219. if (this.isModify) {
  220. // 修改申请,只针对单件商品,取选中的第一件商品数据
  221. const item = goodsList[0];
  222. params = {
  223. orderId: this.orderId,
  224. refundOrderId: this.refundOrderId,
  225. refundType: this.refundType,
  226. sendType: returnMethod || '',
  227. addressId: (address && address.id) ? address.id : '',
  228. refundNum: item.refundNum,
  229. refundMoney: item.refundMoney,
  230. shopStatus: item.shopStatus,
  231. refundReason: item.refundReason,
  232. description: item.description,
  233. fileUrlList: item.fileUrlList || []
  234. };
  235. } else {
  236. // 正常申请售后,可能是多件商品
  237. const refundDetailList = goodsList.map(item => ({
  238. detailOrderId: item.detailOrderId || item.id,
  239. num: item.refundNum,
  240. refundMoney: item.refundMoney,
  241. shopStatus: item.shopStatus,
  242. refundReason: item.refundReason,
  243. description: item.description,
  244. fileUrlList: item.fileUrlList || []
  245. }));
  246. params = {
  247. orderId: this.orderId,
  248. refundDetailList: refundDetailList,
  249. refundType: this.refundType,
  250. sendType: returnMethod || '',
  251. addressId: (address && address.id) ? address.id : ''
  252. };
  253. }
  254. // 如果是退货退款(1) 并且是上门取件(1),传递地址对象(兼容旧逻辑)
  255. if (this.refundType === '1' && returnMethod === '1' && address) {
  256. params.address = address;
  257. }
  258. const api = this.isModify ? this.$u.api.refundApplyModifyAjax : this.$u.api.applyRefundAjax;
  259. uni.showLoading({ title: '提交中' });
  260. api(params).then(res => {
  261. uni.hideLoading();
  262. if (res.code === 200) {
  263. this.$u.toast(this.isModify ? '修改成功' : '提交成功');
  264. setTimeout(() => {
  265. uni.navigateBack();
  266. }, 1500);
  267. } else {
  268. this.$u.toast(res.msg || (this.isModify ? '修改失败' : '提交失败'));
  269. }
  270. }).catch(() => {
  271. uni.hideLoading();
  272. });
  273. }
  274. }
  275. }
  276. </script>
  277. <style lang="scss" scoped>
  278. .apply-refund-page {
  279. min-height: 100vh;
  280. background-color: #f5f5f5;
  281. }
  282. </style>