refund-processing.ts 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. import { getAfterSaleDetailMethod, cancelAfterSaleMethod, applyAfterSaleMethod, updateAfterSaleMethod } from "../../request";
  2. // progress 数字转页面状态
  3. const progressToState: Record<string, string> = {
  4. '0': 'processing',
  5. '1': 'revoked',
  6. '2': 'rejected',
  7. '3': 'approved',
  8. '4': 'completed',
  9. };
  10. Page({
  11. data: {
  12. id: '',
  13. recordId: '',
  14. aftersaleId: '',
  15. pageTitle: '商家处理',
  16. refundState: '',
  17. days: '00',
  18. hours: '00',
  19. minutes: '00',
  20. seconds: '00',
  21. goods: {
  22. name: "",
  23. meta1: "",
  24. price: "",
  25. image: "",
  26. },
  27. refundDetail: {
  28. reason: "",
  29. amount: "",
  30. finishTime: "",
  31. applyTime: "",
  32. refundNo: "",
  33. updateTime:""
  34. },
  35. // 协商历史标题和内容
  36. negotiateTitle: "",
  37. negotiateContent: "",
  38. // 拒绝状态处理截止时间
  39. handleEndTime: "",
  40. refundDestination: {
  41. type: '退回微信',
  42. account: '',
  43. },
  44. // 弹窗状态
  45. refundReasonPopupVisible: false,
  46. refundConfirmPopupVisible: false,
  47. refundProofPopupVisible: false,
  48. refundStatus: '',
  49. refundAction: '', // 'modify' 修改申请 | 'reApply' 再次申请
  50. refundMaxAmount: '0',
  51. refundProofImages: [] as string[],
  52. refundDesc: '',
  53. // 接口提交所需原始字段
  54. rawDetail: {} as any,
  55. },
  56. timer: null as any,
  57. onLoad(options: any) {
  58. if (options.id) {
  59. this.setData({ id: options.id, recordId: options.recordId || '' });
  60. this.loadDetail(options.id);
  61. }
  62. },
  63. onShow() {
  64. if (this.data.id && this.data.refundState) {
  65. this.loadDetail(this.data.id);
  66. }
  67. },
  68. async loadDetail(id: string) {
  69. wx.showLoading({ title: '加载中' });
  70. try {
  71. const res = await getAfterSaleDetailMethod(id);
  72. const detail = (res as any)?.data;
  73. if (!detail) return;
  74. const refundState = progressToState[String(detail.progress)] || 'processing';
  75. this.setData({
  76. rawDetail: detail,
  77. aftersaleId: detail.id || '',
  78. refundState,
  79. goods: {
  80. name: detail.conditioningProgramName || '',
  81. meta1: detail.convertDose ? `${detail.convertDose}${detail.convertUnit || '次'}` : '',
  82. price: String(detail.applyAmount || 0),
  83. image: detail.conditioningProgramPhoto || '',
  84. },
  85. refundDetail: {
  86. reason: detail.reason || '',
  87. amount: String(detail.applyAmount || 0),
  88. finishTime: detail.finishTime || '',
  89. applyTime: detail.applyTime || '',
  90. refundNo: detail.ref || '',
  91. updateTime:detail.updateTime || ''
  92. },
  93. negotiateTitle: detail.title || '',
  94. negotiateContent: (() => {
  95. const c = detail.content || '';
  96. try { if (c && JSON.parse(c)) return ''; } catch (e) { /* 不是JSON,保留原文 */ }
  97. return c;
  98. })(),
  99. handleEndTime: detail.handleEndTime || '',
  100. refundMaxAmount: String(detail.applyAmount || 0),
  101. refundProofImages: detail.voucherImgs || [],
  102. refundDesc: detail.remark || '',
  103. });
  104. this.updatePageTitle();
  105. if (refundState === 'processing' || refundState === 'rejected') {
  106. this.startCountdown();
  107. }
  108. } catch (error: any) {
  109. wx.showToast({ title: error.errMsg || '获取详情失败', icon: 'none' });
  110. }
  111. wx.hideLoading();
  112. },
  113. updatePageTitle() {
  114. let title = '商家处理';
  115. if (this.data.refundState === 'revoked') {
  116. title = '撤销申请';
  117. } else if (this.data.refundState === 'completed') {
  118. title = '退款完成';
  119. }
  120. this.setData({ pageTitle: title });
  121. },
  122. onUnload() {
  123. if (this.timer) {
  124. clearInterval(this.timer);
  125. }
  126. },
  127. startCountdown() {
  128. if (this.timer) clearInterval(this.timer);
  129. const setTime = (diff: number) => {
  130. if (diff <= 0) {
  131. this.setData({ days: '00', hours: '00', minutes: '00', seconds: '00' });
  132. if (this.timer) {
  133. clearInterval(this.timer);
  134. this.timer = null;
  135. }
  136. // 拒绝状态倒计时结束,清除截止时间,触发按钮切换
  137. if (this.data.refundState === 'rejected' && this.data.handleEndTime) {
  138. this.setData({ handleEndTime: '' });
  139. }
  140. return;
  141. }
  142. const d = Math.floor(diff / (1000 * 60 * 60 * 24));
  143. const h = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  144. const m = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
  145. const s = Math.floor((diff % (1000 * 60)) / 1000);
  146. this.setData({
  147. days: d < 10 ? '0' + d : String(d),
  148. hours: h < 10 ? '0' + h : String(h),
  149. minutes: m < 10 ? '0' + m : String(m),
  150. seconds: s < 10 ? '0' + s : String(s),
  151. });
  152. };
  153. if (this.data.refundState === 'rejected' && this.data.handleEndTime) {
  154. // rejected:倒计时到处理截止时间
  155. const target = new Date(this.data.handleEndTime.replace(/-/g, '/')).getTime();
  156. const update = () => setTime(target - new Date().getTime());
  157. update();
  158. this.timer = setInterval(update, 1000);
  159. } else {
  160. // processing:已过去的时间
  161. const applyTime = new Date(this.data.refundDetail.applyTime.replace(/-/g, '/')).getTime();
  162. const update = () => setTime(new Date().getTime() - applyTime);
  163. update();
  164. this.timer = setInterval(update, 1000);
  165. }
  166. },
  167. // 修改申请:打开确认弹窗
  168. onModify() {
  169. this.setData({ refundAction: 'modify', refundConfirmPopupVisible: true });
  170. },
  171. onRefundConfirmClose() {
  172. this.setData({ refundConfirmPopupVisible: false });
  173. },
  174. onChangeRefundStatus(e: any) {
  175. this.setData({ refundStatus: e.detail.status });
  176. },
  177. onOpenRefundReasonAgain() {
  178. this.setData({
  179. refundConfirmPopupVisible: false,
  180. refundReasonPopupVisible: true
  181. });
  182. },
  183. onOpenRefundProofEditor() {
  184. this.setData({
  185. refundConfirmPopupVisible: false,
  186. refundProofPopupVisible: true
  187. });
  188. },
  189. onRefundAmountConfirm(e: any) {
  190. this.setData({
  191. ['refundDetail.amount']: e.detail.amount
  192. });
  193. },
  194. async onSubmitRefundApply() {
  195. if (!this.data.refundProofImages.length) {
  196. wx.showToast({ title: '请上传凭证图片', icon: 'none' });
  197. return;
  198. }
  199. wx.showLoading({ title: '正在提交' });
  200. const { rawDetail, refundStatus, refundDetail, refundProofImages, refundDesc, recordId, id, aftersaleId, refundAction } = this.data;
  201. const params = {
  202. patientConditioningRecordId: recordId,
  203. patientConditioningProgramId: id,
  204. type: rawDetail.type,
  205. ...(rawDetail.sellType === '1' ? { receiptStatus: refundStatus || rawDetail.receiptStatus } : {}),
  206. reason: refundDetail.reason,
  207. applyAmount: Number(refundDetail.amount) || 0,
  208. voucherImgs: refundProofImages,
  209. remark: refundDesc,
  210. };
  211. try {
  212. if (refundAction === 'modify') {
  213. await updateAfterSaleMethod(Number(aftersaleId), params);
  214. } else {
  215. await applyAfterSaleMethod(params);
  216. }
  217. this.setData({ refundConfirmPopupVisible: false });
  218. wx.navigateTo({
  219. url: '/module/order/pages/refund-success/refund-success'
  220. });
  221. } catch (error: any) {
  222. wx.showToast({ title: error.errMsg || '提交失败', icon: 'none' });
  223. }
  224. wx.hideLoading();
  225. },
  226. onRefundReasonPopupClose() {
  227. this.setData({ refundReasonPopupVisible: false });
  228. },
  229. onRefundReasonNext(e: any) {
  230. this.setData({
  231. ['refundDetail.reason']: e.detail.reason,
  232. refundReasonPopupVisible: false,
  233. refundConfirmPopupVisible: true
  234. });
  235. },
  236. onRefundProofPopupClose() {
  237. this.setData({ refundProofPopupVisible: false, refundConfirmPopupVisible: true });
  238. },
  239. onRefundProofSubmit(e: any) {
  240. this.setData({
  241. refundProofImages: e.detail.images,
  242. refundDesc: e.detail.desc || '',
  243. refundProofPopupVisible: false,
  244. refundConfirmPopupVisible: true
  245. });
  246. },
  247. onViewHistory() {
  248. wx.navigateTo({
  249. url: `/module/order/pages/negotiation-history/negotiation-history?id=${this.data.aftersaleId}`
  250. });
  251. },
  252. onCopyRefundNo() {
  253. wx.setClipboardData({
  254. data: this.data.refundDetail.refundNo,
  255. success: () => {
  256. wx.showToast({ title: '已复制', icon: 'none' });
  257. }
  258. });
  259. },
  260. onCallService() {
  261. wx.makePhoneCall({
  262. phoneNumber: '400-123-4567',
  263. fail: () => { }
  264. });
  265. },
  266. onReApply() {
  267. this.setData({ refundAction: 'reApply', refundConfirmPopupVisible: true });
  268. },
  269. onRevoke() {
  270. wx.showModal({
  271. title: '撤销退款申请',
  272. content: '撤销退款申请后,可以再次发起退款申请(总共可发起2次)',
  273. confirmText: '确定撤销',
  274. cancelText: '暂不撤销',
  275. success: async (res) => {
  276. if (res.confirm) {
  277. try {
  278. await cancelAfterSaleMethod(Number(this.data.aftersaleId));
  279. wx.showToast({ title: '已撤销', icon: 'success' });
  280. setTimeout(() => {
  281. wx.redirectTo({
  282. url: '/module/article/pages/success-page/success-page?title=撤销退款申请成功'
  283. });
  284. }, 1500);
  285. } catch (error: any) {
  286. wx.showToast({ title: error.errMsg || '撤销失败', icon: 'none' });
  287. }
  288. }
  289. }
  290. });
  291. }
  292. });