cashier.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. <template>
  2. <div class="first" v-loading="loading">
  3. <div class="payment-view">
  4. <div>
  5. <div class="info-wrap">
  6. <el-input
  7. v-model="amount"
  8. style="width: 100%"
  9. placeholder="Please input"
  10. class="input-with-select"
  11. >
  12. <template #append>
  13. <el-select v-model="currency" placeholder="Select" style="width: 115px">
  14. <el-option label="CNY" value="CNY"/>
  15. <el-option label="USD" value="USD"/>
  16. <el-option label="USDM" value="USDM"/>
  17. </el-select>
  18. </template>
  19. </el-input>
  20. <el-col style="text-align: right; margin-top: 12px" :span="24" v-loading="ARS_amount_loading">
  21. Exchange Rate: 1.00{{currency}} = <span style="font-size: 12px">{{ARS_amount}}ARS</span>
  22. </el-col>
  23. <el-col style="text-align: right; margin-top: 12px">
  24. <el-button type="primary" @click="createOrderFn">Submit</el-button>
  25. </el-col>
  26. </div>
  27. <br>
  28. <div v-if="order.payUrl">
  29. <div class="info-wrap">
  30. <div class="trans-no">
  31. <span style="vertical-align: inherit;">
  32. <span style="vertical-align: inherit;">{{ order.orderNo }}</span>
  33. </span>
  34. </div>
  35. <div class="van-divider"></div>
  36. <div class="info-box">
  37. <div class="key">
  38. <span style="vertical-align: inherit;">
  39. <span style="vertical-align: inherit;">Valor</span>
  40. </span>
  41. </div>
  42. <div class="val">
  43. <span style="vertical-align: inherit;">
  44. <span style="vertical-align: inherit;">{{order.amount}} ARS</span>
  45. </span>
  46. </div>
  47. </div>
  48. </div>
  49. <div class="qrcode-wrap">
  50. <p class="tips">
  51. <span style="vertical-align: inherit;">
  52. <span style="vertical-align: inherit;">Por favor, use el pago flash en la nube para escanear
  53. el pago.
  54. </span>
  55. </span>
  56. </p>
  57. <p class="tips">
  58. <span style="vertical-align: inherit;">
  59. <span style="vertical-align: inherit;">Código de pago único, no repita el pago, de lo
  60. contrario causará una entrada Anormal.</span>
  61. </span>
  62. </p>
  63. <div class="qrcode-box">
  64. <div id="qrCodeContent">
  65. <img :src="order.payUrl" id="vaImg" class="vaImg" style="display: inline-block;">
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. </div>
  72. </div>
  73. </template>
  74. <script setup>
  75. import {ref, onMounted, computed, watch} from 'vue'
  76. import {createOrder, getOrder, getConversionFactors} from '@/api'
  77. import {useRoute} from 'vue-router';
  78. import _ from 'lodash'
  79. import md5 from "md5";
  80. import {getRateData} from '@/utils/index.js'
  81. import dayjs from "dayjs";
  82. function getNewOutOrderNo() {
  83. return "PVSTEST" + dayjs().format("YYYYMMDDHHmmss");
  84. }
  85. const loading = ref(false);
  86. const route = useRoute()
  87. const orderNo = route.query.t || ''
  88. const mchId = route.query.mchId || ''
  89. const amount = ref(0)
  90. const ARS_amount = ref(0)
  91. const currency = ref('');
  92. const ARS_amount_loading = ref(false);
  93. import {ElMessage} from 'element-plus';
  94. const basePre = 'data:image/png;base64,';
  95. const order = ref({
  96. orderNo: '',
  97. amount: 0,
  98. payUrl: '',
  99. returnUrl: '',
  100. status: 0
  101. })
  102. const getOrderInfo = async function () {
  103. if(!orderNo) return
  104. const data = await getOrder({
  105. orderNo
  106. });
  107. console.log(data)
  108. order.value.orderNo = data.orderNo;
  109. order.value.amount = data.amount;
  110. order.value.returnUrl = data.returnUrl;
  111. order.value.status = data.status;
  112. order.value.payUrl = basePre + data.payUrl;
  113. if (+order.value.status === 0) {
  114. return;
  115. }
  116. if (+order.value.status === 1) {
  117. ElMessage({message: 'El pedido ha sido pagado y saltará a la página del comerciante', type: 'success'})
  118. }
  119. if (+order.value.status === 2 || +order.status === 3) {
  120. ElMessage({
  121. message: 'El pedido ha expirado, por favor regrese a la página del comerciante para reiniciar',
  122. type: 'warning'
  123. })
  124. }
  125. setTimeout(() => {
  126. window.location = order.value.returnUrl
  127. }, 1000)
  128. }
  129. function convertStringToNumberWithTwoDecimals(input) {
  130. // 将输入转换为浮点数
  131. let number = parseFloat(input);
  132. // 检查转换是否成功,如果失败则默认为0
  133. if (isNaN(number)) {
  134. number = 0;
  135. }
  136. // 将数字格式化为带两位小数的字符串,然后再转换为数字类型
  137. return parseFloat(number.toFixed(2));
  138. }
  139. const getAmount = async () => {
  140. // if(currency.value === 'CNY') {
  141. // return amount.value * 144.38
  142. // }
  143. const res = await getConversionFactors({
  144. currency: currency.value,
  145. amount: Number(amount.value).toFixed(2)
  146. })
  147. return res.amount
  148. }
  149. watch(currency, async () => {
  150. // if(currency.value === 'CNY') return
  151. ARS_amount_loading.value = true
  152. const res = await getConversionFactors({
  153. currency: currency.value,
  154. amount: '1.00'
  155. })
  156. ARS_amount.value = res.amount
  157. ARS_amount_loading.value = false
  158. })
  159. const createOrderFn = async () => {
  160. loading.value = true
  161. if(_.isNumber(amount.value) && amount.value < 1) {
  162. loading.value = false
  163. ElMessage({message: 'Please enter a valid amount', type: 'warning'})
  164. return
  165. }
  166. const formDate = {
  167. mchId: "TEST",
  168. outOrderNo: getNewOutOrderNo(),
  169. notifyUrl: "http://157.175.73.225/api/admin/dj/open/notifyTest",
  170. returnUrl: "https://www.baidu.com",
  171. amount: convertStringToNumberWithTwoDecimals(await getAmount()),
  172. payType: "QRCODE",
  173. userIp: "127.0.0.1",
  174. userId: "test",
  175. currency: 'ARS',
  176. }
  177. if(formDate.amount > 99999999) {
  178. loading.value = false
  179. ElMessage({message: 'Your amount is too large to create a payment order', type: 'warning'})
  180. return
  181. }
  182. // return
  183. const signStr = md5(signSort(formDate) + `&key=${key.value}`)
  184. try {
  185. const res = await createOrder({
  186. ...formDate,
  187. sign: signStr
  188. });
  189. order.value = {
  190. ...res,
  191. amount: formDate.amount,
  192. payUrl: `data:image/png;base64, ${res.hasOwnProperty('qrImage') ? res.qrImage : res?.payUrl}`
  193. }
  194. } catch (err) {
  195. console.log(192, err);
  196. // data.value = JSON.stringify(err);
  197. } finally {
  198. loading.value = false
  199. }
  200. }
  201. const key = ref("32394ae8b550485c53326f10764f8492");
  202. const defaultForm = {
  203. mchId: "TEST",
  204. outOrderNo: getNewOutOrderNo(),
  205. notifyUrl: "http://157.175.73.225/api/admin/dj/open/notifyTest",
  206. returnUrl: "https://www.baidu.com",
  207. amount: 100,
  208. payType: "",
  209. userIp: "127.0.0.1",
  210. userId: "test",
  211. currency: 'USD'
  212. };
  213. const sign = computed(() => {
  214. return md5(signSort(form.value) + `&key=${key.value}`);
  215. });
  216. function signSort(args) {
  217. var keys = Object.keys(args);
  218. keys = keys.sort();
  219. var newArgs = {};
  220. keys.forEach(function (key) {
  221. newArgs[key] = args[key];
  222. });
  223. var string = "";
  224. for (var k in newArgs) {
  225. string += "&" + k + "=" + newArgs[k];
  226. }
  227. string = string.substr(1);
  228. return string;
  229. }
  230. // http://localhost:8001/admin/dj/open/pvs/conversion-factors?currency=USDM&amount=100.00
  231. onMounted(() => {
  232. getOrderInfo()
  233. currency.value = "CNY"
  234. })
  235. </script>
  236. <style scoped lang="less">
  237. .payment-view {
  238. max-width: 550px;
  239. padding: 30px;
  240. margin: 0 auto;
  241. }
  242. .info-wrap {
  243. line-height: 24px;
  244. color: #969799;
  245. border: 1px solid #dde7f0;
  246. border-radius: 8px;
  247. padding: 15px 15px;
  248. }
  249. .trans-no {
  250. text-align: right;
  251. color: #999;
  252. font-size: 12px;
  253. }
  254. .van-divider {
  255. border-top: 1px dashed #dde7f0;
  256. border-color: #dde7f0;
  257. margin: 10px 0;
  258. }
  259. .info-box {
  260. display: flex;
  261. justify-content: space-between;
  262. align-items: center;
  263. }
  264. .key {
  265. font-size: 14px;
  266. color: #222;
  267. }
  268. .val {
  269. font-size: 32px;
  270. font-weight: 700;
  271. color: #222;
  272. }
  273. .qrcode-wrap {
  274. display: flex;
  275. flex-direction: column;
  276. justify-content: center;
  277. align-items: center;
  278. border: 1px solid #dde7f0;
  279. border-radius: 8px;
  280. padding: 15px 15px;
  281. margin-top: 15px;
  282. }
  283. .tips {
  284. text-align: center;
  285. font-size: 14px;
  286. font-weight: 700;
  287. color: #111;
  288. margin-top: 0;
  289. }
  290. .qrcode-box {
  291. position: relative;
  292. width: 244px;
  293. height: 244px;
  294. margin-top: 15px;
  295. }
  296. .vaImg {
  297. width: 240px;
  298. height: 240px;
  299. overflow: hidden;
  300. margin: 0;
  301. }
  302. </style>