item.tsx 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import {
  2. Button,
  3. Cell,
  4. CellGroup,
  5. Field,
  6. Popup,
  7. Radio,
  8. RadioGroup,
  9. showToast
  10. } from 'vant';
  11. import { defineComponent, reactive } from 'vue';
  12. import styles from './item.module.less';
  13. import icon_order from '../image/icon_order.svg';
  14. import {
  15. api_userPaymentOrderCancelPayment,
  16. api_userPaymentOrderDetail,
  17. api_userPaymentOrderRefundPayment,
  18. api_userPaymentOrderUnpaid,
  19. type_OrderTypes
  20. } from '../api';
  21. import { postMessage } from '@/helpers/native-message';
  22. import { state } from '@/state';
  23. export default defineComponent({
  24. name: 'collection-record-item',
  25. props: {
  26. item: {
  27. type: Object,
  28. default: () => ({})
  29. }
  30. },
  31. emits: ['refund', 'close'],
  32. setup(props, { emit }) {
  33. const data = reactive({
  34. open: false,
  35. order: {} as any,
  36. confirmLoading: false,
  37. cancelOrderLoading: false
  38. });
  39. const forms = reactive({
  40. refundReason: '',
  41. refundReasonDes: ''
  42. });
  43. const handleOpenDetail = () => {
  44. if (props.item?.orderNo) {
  45. const url = `${location.origin}${
  46. location.pathname
  47. }#/collection-record-detail?orderNo=${props.item?.orderNo}${
  48. props.item.isRefund
  49. ? '&userRefundOrderId=' + props.item.userRefundOrderId
  50. : ''
  51. }`;
  52. console.log('🚀 ~ url:', url);
  53. postMessage({
  54. api: 'openWebView',
  55. content: {
  56. url,
  57. orientation: 1,
  58. isHideTitle: false
  59. }
  60. });
  61. }
  62. };
  63. const getDetails = async (item: any) => {
  64. if (!item.orderNo) return;
  65. const res = await api_userPaymentOrderDetail(item.orderNo);
  66. if (res?.code === 200) {
  67. data.order = res.data;
  68. }
  69. };
  70. /** 申请退款 */
  71. const handleCancel = async () => {
  72. await api_userPaymentOrderRefundPayment({
  73. merOrderNo: data.order.orderNo,
  74. serviceCharge: true,
  75. paymentClient: 'STUDENT',
  76. userId: state.user?.data?.id,
  77. refundReason:
  78. forms.refundReason === '其他原因'
  79. ? forms.refundReasonDes
  80. : forms.refundReason,
  81. userPaymentOrderId: data.order.id,
  82. userRefundOrderDetails: data.order.goodsInfos
  83. ? data.order.goodsInfos
  84. .filter((n: any) => n.goodsType !== 'VIP')
  85. .map((goods: any) => ({
  86. userPaymentOrderDetailId: goods.id,
  87. num: goods.goodsNum
  88. }))
  89. : []
  90. });
  91. showToast('申请退款成功');
  92. data.open = false;
  93. emit('close');
  94. emit('refund');
  95. };
  96. /** 继续支付 */
  97. const onConfirmOrder = async () => {
  98. console.log(props.item);
  99. data.confirmLoading = true;
  100. const res = await api_userPaymentOrderUnpaid({
  101. orderNo: props.item.orderNo,
  102. paymentType: props.item.orderType
  103. });
  104. data.confirmLoading = false;
  105. if (res?.code === 200) {
  106. const paymentConfig = res.data.paymentConfig;
  107. const url =
  108. location.origin +
  109. location.pathname +
  110. '#/order-detail?orderNo=' +
  111. paymentConfig.orderNo +
  112. '&config=' +
  113. encodeURIComponent(JSON.stringify(paymentConfig.paymentConfig));
  114. console.log('🚀 ~ url:', url);
  115. postMessage({
  116. api: 'openWebView',
  117. content: {
  118. url,
  119. orientation: 1,
  120. isHideTitle: false
  121. }
  122. });
  123. }
  124. };
  125. /** 取消订单 */
  126. const handleCancelOrder = async () => {
  127. data.cancelOrderLoading = true;
  128. try {
  129. await api_userPaymentOrderCancelPayment(props.item.orderNo);
  130. setTimeout(() => {
  131. showToast('取消成功');
  132. emit('close');
  133. }, 100);
  134. } catch {
  135. //
  136. }
  137. data.cancelOrderLoading = false;
  138. };
  139. return () => (
  140. <div class={styles.item}>
  141. <CellGroup inset>
  142. <Cell center>
  143. {{
  144. title: () => (
  145. <div class={styles.time}>{props.item.createTime}</div>
  146. ),
  147. value: () => (
  148. <div
  149. class={[styles.state]}
  150. style={{ color: props.item.statusColor }}>
  151. {props.item.statusName}
  152. </div>
  153. )
  154. }}
  155. </Cell>
  156. <Cell center isLink onClick={() => handleOpenDetail()}>
  157. {{
  158. icon: () => <img class={styles.icon} src={icon_order} />,
  159. title: () => (
  160. <div class={styles.name}>
  161. {type_OrderTypes[props.item.orderType]}
  162. </div>
  163. ),
  164. value: () => (
  165. <div class={styles.price}>
  166. ¥
  167. <span style={{ fontSize: '0.42667rem' }}>
  168. {props.item.paymentCashAmount}
  169. </span>
  170. </div>
  171. )
  172. }}
  173. </Cell>
  174. {['WAIT_PAY', 'PAYING'].includes(props.item.status) &&
  175. props.item.orderType !== 'SCHOOL_REGISTER' && (
  176. <div class={styles.btns}>
  177. <Button
  178. style={{ margin: '0 11px 0 auto' }}
  179. round
  180. size="small"
  181. loading={data.cancelOrderLoading}
  182. onClick={() => handleCancelOrder()}>
  183. 取消支付
  184. </Button>
  185. <Button
  186. round
  187. size="small"
  188. loading={data.confirmLoading}
  189. onClick={() => onConfirmOrder()}>
  190. 立即支付
  191. </Button>
  192. </div>
  193. )}
  194. {props.item.refundable && (
  195. <div
  196. class={[styles.btns, styles.cancelBtn]}
  197. onClick={() => {
  198. data.open = true;
  199. getDetails(props.item);
  200. }}>
  201. 申请退款
  202. </div>
  203. )}
  204. </CellGroup>
  205. <Popup
  206. teleport="body"
  207. v-model:show={data.open}
  208. class={['popup-custom', 'van-scale']}
  209. transition="van-scale">
  210. <div class={styles.cancelBox}>
  211. <div class={styles.boxContent}>
  212. <div class={styles.title}>
  213. <div class={styles.titleTag}></div> 申请退款
  214. </div>
  215. <div class={styles.des}>
  216. 您将要发起退款,退款需承担千分之六的手续费,确认退款后款项将原路返还到您的付款账户中。
  217. </div>
  218. <div class={styles.radioTitle}>
  219. <span style={{ color: 'rgba(244, 69, 65, 1)' }}>*</span>
  220. 请选择您的退款原因
  221. </div>
  222. <RadioGroup v-model={forms.refundReason}>
  223. <Cell>
  224. {{
  225. title: () => (
  226. <div>
  227. <Radio name="价格太贵了">价格太贵了</Radio>
  228. </div>
  229. )
  230. }}
  231. </Cell>
  232. <Cell>
  233. {{
  234. title: () => (
  235. <div>
  236. <Radio name="不喜欢/不想要">不喜欢/不想要</Radio>
  237. </div>
  238. )
  239. }}
  240. </Cell>
  241. <Cell>
  242. {{
  243. title: () => (
  244. <div>
  245. <Radio name="七天无理由退货">七天无理由退货</Radio>
  246. </div>
  247. )
  248. }}
  249. </Cell>
  250. <Cell>
  251. {{
  252. title: () => (
  253. <div>
  254. <Radio name="其他原因">其他原因</Radio>
  255. </div>
  256. )
  257. }}
  258. </Cell>
  259. </RadioGroup>
  260. <div
  261. class={styles.radioDes}
  262. style={{
  263. display: forms.refundReason === '其他原因' ? '' : 'none'
  264. }}>
  265. <Field
  266. v-model={forms.refundReasonDes}
  267. rows="2"
  268. autosize
  269. label=""
  270. type="textarea"
  271. maxlength="50"
  272. placeholder="在这里填写退款原因"
  273. />
  274. </div>
  275. </div>
  276. <div class={styles.radioBtns}>
  277. <Button
  278. block
  279. onClick={() => {
  280. if (!forms.refundReason) {
  281. showToast('请选择退款原因');
  282. return;
  283. }
  284. if (
  285. forms.refundReason === '其他原因' &&
  286. !forms.refundReasonDes
  287. ) {
  288. showToast('请输入退款原因');
  289. return;
  290. }
  291. handleCancel();
  292. }}>
  293. 确认退款
  294. </Button>
  295. <Button
  296. block
  297. type="primary"
  298. plain
  299. onClick={() => (data.open = false)}>
  300. 取消
  301. </Button>
  302. </div>
  303. </div>
  304. </Popup>
  305. </div>
  306. );
  307. }
  308. });