Переглянути джерело

```
feat: 集成PayPal支付SDK和二维码生成功能

- 在index.html中添加PayPal JS SDK脚本引入,配置client-id用于支付功能
- 集成qrcode库用于生成二维码功能
- 更新package-lock.json包含所有相关依赖项及其子依赖项
```

zhangningning 1 місяць тому
батько
коміт
f49d3b19b6
5 змінених файлів з 561 додано та 35 видалено
  1. 2 0
      index.html
  2. 306 0
      package-lock.json
  3. 1 0
      package.json
  4. 18 0
      src/api/order.js
  5. 234 35
      src/pages/order/orderConfirm.vue

+ 2 - 0
index.html

@@ -5,6 +5,8 @@
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title></title>
+     <!-- PayPal JS SDK 核心引入,替换为你的 Client ID -->
+    <script src="https://www.paypal.com/sdk/js?client-id=AWTqiGF8Tcnuu_gnZzJ_k4a-LvPFj4IbUh98l2zCKxdngjCth3s2fwH0kcC5G-zjyD2t8ty67O1BV0N-&currency=USD"></script>
   </head>
   <body>
     <div id="app"></div>

+ 306 - 0
package-lock.json

@@ -15,6 +15,7 @@
         "axios": "^1.13.2",
         "element-plus": "^2.11.9",
         "pinia": "^3.0.4",
+        "qrcode": "^1.5.4",
         "react": "^18.3.1",
         "react-dom": "^18.3.1",
         "sass": "^1.94.2",
@@ -2202,6 +2203,30 @@
         "pkcs7": "^1.0.4"
       }
     },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
     "node_modules/argparse": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -2276,6 +2301,15 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/ccount": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
@@ -2331,6 +2365,17 @@
         "url": "https://paulmillr.com/funding/"
       }
     },
+    "node_modules/cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      }
+    },
     "node_modules/clsx": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
@@ -2341,6 +2386,24 @@
         "node": ">=6"
       }
     },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "license": "MIT"
+    },
     "node_modules/combined-stream": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -2413,6 +2476,15 @@
         }
       }
     },
+    "node_modules/decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/decode-named-character-reference": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz",
@@ -2477,6 +2549,12 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/dijkstrajs": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
+      "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
+      "license": "MIT"
+    },
     "node_modules/dom-walk": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
@@ -2527,6 +2605,12 @@
       "integrity": "sha512-eJp3QRe79pjwa+duv+n7+5YsNhRcMl812EcFVwrnRvYKoNPoQb5qxU8DG6Bgwji0akHdp6D4Ln6tYLG58MFSow==",
       "license": "MIT"
     },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "license": "MIT"
+    },
     "node_modules/entities": {
       "version": "4.5.0",
       "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@@ -2678,6 +2762,19 @@
         "node": ">=8"
       }
     },
+    "node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/follow-redirects": {
       "version": "1.15.11",
       "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
@@ -2738,6 +2835,15 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "license": "ISC",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
     "node_modules/get-intrinsic": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -3155,6 +3261,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/is-function": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
@@ -3260,6 +3375,18 @@
       "integrity": "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==",
       "license": "MIT"
     },
+    "node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/lodash": {
       "version": "4.17.21",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -4289,6 +4416,42 @@
       "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
       "license": "MIT"
     },
+    "node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "license": "MIT",
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/parse5": {
       "version": "7.3.0",
       "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
@@ -4313,6 +4476,15 @@
         "url": "https://github.com/fb55/entities?sponsor=1"
       }
     },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/perfect-debounce": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
@@ -4371,6 +4543,15 @@
         "pkcs7": "bin/cli.js"
       }
     },
+    "node_modules/pngjs": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz",
+      "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/postcss": {
       "version": "8.5.6",
       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
@@ -4681,6 +4862,23 @@
         "node": ">=6"
       }
     },
+    "node_modules/qrcode": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
+      "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
+      "license": "MIT",
+      "dependencies": {
+        "dijkstrajs": "^1.0.1",
+        "pngjs": "^5.0.0",
+        "yargs": "^15.3.1"
+      },
+      "bin": {
+        "qrcode": "bin/qrcode"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/react": {
       "version": "18.3.1",
       "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@@ -4970,6 +5168,21 @@
         "url": "https://opencollective.com/unified"
       }
     },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "license": "ISC"
+    },
     "node_modules/rfdc": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
@@ -5053,6 +5266,12 @@
         "loose-envify": "^1.1.0"
       }
     },
+    "node_modules/set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+      "license": "ISC"
+    },
     "node_modules/source-map-js": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -5081,6 +5300,20 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/stringify-entities": {
       "version": "4.0.4",
       "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
@@ -5095,6 +5328,18 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/superjson": {
       "version": "2.2.6",
       "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz",
@@ -5772,6 +6017,26 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
+    "node_modules/which-module": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
+      "license": "ISC"
+    },
+    "node_modules/wrap-ansi": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/y-prosemirror": {
       "version": "1.3.7",
       "resolved": "https://registry.npmjs.org/y-prosemirror/-/y-prosemirror-1.3.7.tgz",
@@ -5816,6 +6081,47 @@
         "yjs": "^13.0.0"
       }
     },
+    "node_modules/y18n": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+      "license": "ISC"
+    },
+    "node_modules/yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+      "license": "MIT",
+      "dependencies": {
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "license": "ISC",
+      "dependencies": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/yjs": {
       "version": "13.6.27",
       "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.27.tgz",

+ 1 - 0
package.json

@@ -26,6 +26,7 @@
     "vue": "^3.5.24",
     "vue-i18n": "^9.14.5",
     "vue-react-wrapper": "^0.3.1",
+    "qrcode": "^1.5.4",
     "vue-router": "^4.6.3"
   },
   "devDependencies": {

+ 18 - 0
src/api/order.js

@@ -0,0 +1,18 @@
+import request from './request.js'
+
+// 计算汇率
+export function calRate(data = {}) {
+  return request.get('/config/calRate',data)
+}
+// 创建订单
+export function createOrder(data = {}) {
+  return request.post('/order/createOrder',data)
+}
+// 支付结果
+export function payResult(data = {}) {
+  return request.post('/order/payResult/'+data.id)
+}
+// 查询汇率01-对公账户 02-提现 03-系统货币 04-米币设置
+export function payConfigDearch(data = {}) {
+  return request.get('/config/search/'+data.id)
+}

+ 234 - 35
src/pages/order/orderConfirm.vue

@@ -13,30 +13,45 @@
       </div>
       <div class="border border_radius_8 mt10">
         <div class="flex-between order_table padding16">
-          <div class="flex_2 flex-center font_size18">订单信息</div>
-          <div class="flex_1 flex-center font_size18">米币</div>
-          <div class="flex_1 flex-center font_size18">有效期</div>
-          <div class="flex_1 flex-center font_size18">价格</div>
+          <div class="flex_1 font_size18">订单信息</div>
+          <div class="flex_1 font_size18">金额(元)</div>
+          <div class="flex_1 font_size18">
+            数量
+            ({{orderInfo.orderType === 'bm_recharge' ? $t('common.baomibi') : $t('common.mibi')}})
+          </div>
         </div>
         <div>
           <div class="flex-between padding16">
-            <div class="flex_2 flex-center font_size18">
-              <div class="flex-between">
+            <div class="flex_1 font_size18">
+              <!-- <div class="flex-between">
                 <img src="" alt="" style="width: 160px; height: 90px;" class="bg_color_f5">
                 <div class="ml10">
                   <div class="font_size16 bold">UI界面设计教程</div>
                   <el-button type="primary" size="mini" plain class="mt5">技能标签</el-button>
                 </div>
+              </div> -->
+              <div class="flex-column">
+                <div class="gap10 cursor-pointer" @click="orderInfo.orderType = 'bm_recharge';handleOrderAmtChange()">
+                  <div class="checkType" :class="{'active': orderInfo.orderType === 'bm_recharge'}"></div>
+                  <div class="font_size16">充值{{$t('common.baomibi')}}</div>
+                </div>
+                <div class="gap10 cursor-pointer mt20" @click="orderInfo.orderType = 'm_recharge';handleOrderAmtChange()">
+                  <div class="checkType" :class="{'active': orderInfo.orderType === 'm_recharge'}"></div>
+                  <div class="font_size16">充值{{$t('common.mibi')}}</div>
+                </div>
               </div>
+
             </div>
-            <div class="flex_1 flex-center font_size18">
-              2999
-            </div>
-            <div class="flex_1 flex-center font_size18">
-              永久
+            <div class="flex_1 font_size18">
+              <div>
+                <el-input-number v-model="orderInfo.orderAmt" :min="0" :max="1000" :step="1" class="w100" 
+                @change="handleOrderAmtChange"
+                />
+              </div>
+              <div class="font_size16 color_price" v-if="message_recharge">{{message_recharge}}</div>
             </div>
-            <div class="flex_1 flex-center font_size18 color_price">
-             ¥23
+            <div class="flex_1 font_size18 color_price">
+             {{orderInfo.orderNum}}
             </div>
           </div>
         </div>
@@ -48,11 +63,11 @@
         <div class="font_size20 bold">{{$t('common.payWay')}}</div>
       </div>
       <div class="gap10 mt20">
-        <div class="gap10 cursor-pointer" @click="payType = 1">
+        <div class="gap10 cursor-pointer" @click="payType = 1;pageRedirectionData='';orderInfo.payMethod = 'alipay'">
           <div class="checkType" :class="{'active': payType === 1}"></div>
           <div class="font_size16">个人支付</div>
         </div>
-        <div class="gap10 cursor-pointer" @click="payType = 2">
+        <div class="gap10 cursor-pointer" @click="payType = 2;orderInfo.payMethod = 'bank_transfer';pageRedirectionData='';payConfigDearchFn();">
           <div class="checkType" :class="{'active': payType === 2}"></div>
           <div class="font_size16">对公支付</div>
         </div>
@@ -60,42 +75,49 @@
       <!-- 个人支付 -->
       <div class="mt20" v-if="payType === 1">
         <div class="gap10">
-          <div class="payway flex_1 gap5" :class="{'active': payWay === 1}" @click="payWay = 1">
+          <div class="payway flex_1 gap5" 
+          :class="{'active': orderInfo.payMethod === 'alipay'}" 
+          @click="orderInfo.payMethod = 'alipay';pageRedirectionData=''">
             <div class="checkType"></div>
             <img :src="zhifubaoIcon" alt="" style="width: 40px; height: 40px;">
             <div class="font_size16">支付宝支付</div>
           </div>
-          <div class="payway flex_1 gap5" @click="payWay = 2">
-            <div class="checkType" :class="{'active': payWay === 2}"></div>
+          <div class="payway flex_1 gap5" 
+          :class="{'active': orderInfo.payMethod === 'wechat_pay'}" 
+          @click="orderInfo.payMethod = 'wechat_pay';pageRedirectionData=''">
+            <div class="checkType"></div>
             <img :src="weixinIcon" alt="" style="width: 40px; height: 40px;">
             <div class="font_size16">微信支付</div>
           </div>
-          <div class="payway flex_1 gap5" @click="payWay = 3">
-            <div class="checkType" :class="{'active': payWay === 3}"></div>
+          <div class="payway flex_1 gap5" 
+          :class="{'active': orderInfo.payMethod === 'union_pay'}" 
+          @click="orderInfo.payMethod = 'union_pay';pageRedirectionData=''">
+            <div class="checkType"></div>
             <img :src="yinlianIcon" alt="" style="width: 40px; height: 40px;">
             <div class="font_size16">银联支付</div>
           </div>
-          <div class="payway flex_1 gap5" @click="payWay = 4">
-            <div class="checkType" :class="{'active': payWay === 4}"></div>
+          <div class="payway flex_1 gap5" 
+          :class="{'active': orderInfo.payMethod === 'paypal'}" 
+          @click="orderInfo.payMethod = 'paypal';pageRedirectionData=''">
+            <div class="checkType"></div>
             <img :src="paypalIcon" alt="" style="width: 40px; height: 40px;">
             <div class="font_size16">PayPal支付</div>
           </div>
         </div>
-        <div class="mt20">
+        <!-- <div class="mt20">
           <div class="bold font_size18">米币</div>
           <div class="gap10 mt10">
             <div class="checkType"></div>
             <div class="font_size16">可用米币 <span class="color_price bold">2999</span></div>
             <div class="font_size16 color_price">(抵扣¥1.00)</div>
           </div>
-        </div>
+        </div> -->
       </div>
       <!-- 对公支付 -->
       <div class="mt20" v-if="payType === 2">
         <div class="flex-between order_table padding16">
-          <div class="flex_1 font_size16">收款方:XXXX有限公司</div>
-          <div class="flex_1 font_size16">收款方银行账号:************ 1234</div>
-          <div class="flex_1 font_size16">收款方开户银行:****支行</div>
+          <div class="flex_1 font_size16" v-for="item in BusinessAccount" :key="item.id">
+            {{item.configName}}:{{item.configValue}}</div>
         </div>
         <div class="mt20">
           <div class="bold font_size18">付款凭证</div>
@@ -116,18 +138,52 @@
       </div>
       <div class="mt20 flex-center-between" style="width: 300px;">
         <div class="font_size18">总价:</div>
-        <div class="font_size16 bold">¥239.2</div>
+        <div class="font_size16 bold">¥{{orderInfo.orderAmt}}</div>
       </div>
       <div class="mt20 flex-center-between" style="width: 300px;">
         <div class="font_size18">需付金额:</div>
-        <div class="font_size24 bold color_price">¥239.2</div>
+        <div class="font_size24 bold color_price">¥{{orderInfo.orderAmt}}</div>
       </div>
-      <div style="display: inline-block;" class="mt20" @click="payNowFn">
+      <div style="display: inline-block;" class="mt20" @click="payNowFn" v-loading="loading">
         <div class="gap5 gradient border_radius_4 cursor-pointer zhifu">
           <img :src="qianbaoIcon" alt="" style="width:13px;height:15px">
           <div>{{$t('common.payNow')}}</div>
         </div>
       </div>
+      <!-- 支付二维码 -->
+      <div class="payment-qrcode mt20">
+        <img 
+          :src="pageRedirectionData"
+          v-if="pageRedirectionData && orderInfo.payMethod == 'wechat_pay'"
+          class="qrcode-image"
+        />
+        <iframe style="width:100%;"
+          v-if="pageRedirectionData && orderInfo.payMethod == 'alipay'"
+          :srcdoc="pageRedirectionData"
+          frameborder="no"
+          border="0"
+          marginwidth="0"
+          marginheight="0"
+          scrolling="no"
+          width="200"
+          height="200"
+          class="qrcode-iframe"
+        ></iframe>
+        <iframe style="width:100%;height:100vh"
+          v-if="pageRedirectionData && orderInfo.payMethod == 'union_pay'"
+          :srcdoc="pageRedirectionData"
+          frameborder="no"
+          border="0"
+          marginwidth="0"
+          marginheight="0"
+          scrolling="no"
+          width="200"
+          height="200"
+          class="qrcode-iframe"
+        ></iframe>
+        <!-- PayPal 支付按钮挂载容器(必须唯一ID) -->
+        <div id="paypal-button-container" v-if="pageRedirectionData && orderInfo.payMethod == 'paypal'"></div>
+      </div>
       <div class="mt20 font_size14">录播和体验课课程属于虚拟商品,购买后无特殊原因,不支持退款</div>
       <div class="mt20 gap10 cursor-pointer" @click="agreement = !agreement">
         <div class="checkType" :class="{'active': agreement}"></div>
@@ -145,10 +201,12 @@ import qianbaoIcon from '@/assets/imgs/pay/qianbao.png'
 
 
 import FileUploader from '@/components/FileUploader.vue'
+import { calRate, createOrder,payResult,payConfigDearch } from '@/api/order.js'
+import qrcode from 'qrcode'
 
 
 
-import { ref } from 'vue'
+import { reactive, ref, onBeforeUnmount, nextTick } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import DGTMessage from '@/utils/message'
 //获取参数
@@ -160,11 +218,31 @@ const id = ref(query.id || '');
 //
 // 支付方式
 const payType = ref(1);//支付类型 1:个人支付 2:对公支付
-const payWay = ref(1);//支付方式 1:支付宝支付 2:对公支付
 // 协议
 const agreement = ref(false);//是否同意协议
 // 付款凭证
 const images = ref([]);//付款凭证
+// 加载状态
+const loading = ref(false);//是否加载中
+
+//支付信息
+const orderId = ref('');//订单id
+const message_recharge = ref('');//充值提示信息
+const orderInfo = reactive({
+  payMethod: 'alipay',////alipay,wechat_pay,union_pay,paypal,bank_transfer,MI,BMI
+  orderType: 'bm_recharge',////m_recharge,bm_recharge,workflow_purchase,course_purchase,member_recharge,mi_mall,exchange_mi,exchange_bmi
+  productId:'',
+  orderNum:0,
+  orderAmt:0,//输入的金额
+})
+const pageRedirectionData = ref('');//支付二维码
+
+
+//关闭页面时清除定时器
+// 关闭页面时清除定时器
+onBeforeUnmount(() => {
+  stopPolling();
+});
 
 
 
@@ -174,13 +252,134 @@ const payNowFn = () => {
     DGTMessage.warning('请先同意协议')
     return
   }
-  // 调用支付接口
-  DGTMessage.success('支付成功')
+  loading.value = true;
+  createOrder(orderInfo).then(res => {
+    if(res.code === 200){
+      orderId.value = res.data?.orderId || '';
+      const payData = res.data?.payData || {};
+      // DGTMessage.success('支付成功')
+      //回退
+      // router.back()
+      switch(orderInfo.payMethod){
+        case 'alipay':
+          pageRedirectionData.value = payData.pageRedirectionData || '';
+          setTimeout
+          (() => {
+            loading.value = false;
+          }, 1000);
+          break;
+        case 'wechat_pay':
+          qrcode.toDataURL(payData.codeUrl, (err, url) => {
+            if (err) {
+              console.error(err)
+            } else {
+              pageRedirectionData.value = url
+            }
+          })
+          loading.value = false;
+          break;
+        case 'union_pay':
+          pageRedirectionData.value = payData || '';
+          loading.value = false;
+          break;
+        case 'paypal':
+          pageRedirectionData.value = payData.body || '';
+          nextTick(() => {
+            pay_paypal();
+          })
+          break;
+        case 'bank_transfer':
+          break;
+      }
+      startPolling();
+    }
+  }).catch(() => {
+    loading.value = false;
+  })
   //回退
-  router.back()
+  // router.back()
 };
 
 
+// 支付状态轮询相关
+const pollingTimer = ref(null)
+const isPolling = ref(false)
+const maxPollingAttempts = 30 // 最大轮询次数
+const pollingAttempts = ref(0)
+const pollingInterval = 3000
+
+// 启动轮询
+const startPolling = () => {
+  if (isPolling.value) return
+  console.log('启动轮询', orderId.value)
+  isPolling.value = true
+  pollingAttempts.value = 0
+  pollingTimer.value = setInterval(() => {
+    payResult({id:orderId.value}).then((res) => {
+      if (res.code == 200 && res.data) {
+        DGTMessage.success('支付成功!')
+        stopPolling()
+      }
+    })
+  }, pollingInterval)
+}
+
+// 停止轮询
+const stopPolling = () => {
+  if (pollingTimer.value) {
+    clearInterval(pollingTimer.value)
+    pollingTimer.value = null
+  }
+  isPolling.value = false
+}
+
+const pay_paypal = () => {
+  //清除上次支付按钮
+  document.getElementById('paypal-button-container').innerHTML = '';
+  loading.value = false;
+  paypal.Buttons({
+    createOrder: (data, actions) => {
+      return "06S82458P0047241R"
+    },
+    onApprove: (data, actions) => {
+      return actions.order.capture().then((details) => {
+        DGTMessage.success('支付成功!')
+        stopPolling()
+      });
+    }
+  }).render('#paypal-button-container');
+}
+
+// 计算汇率
+const handleOrderAmtChange = () => {
+  if(orderInfo.orderAmt){
+    calRate({
+      orderType: orderInfo.orderType,
+      orderNum: orderInfo.orderAmt,
+    }).then(res => {
+      if(res.code === 200){
+        orderInfo.orderNum = res.data?.targetAmount || 0;
+        message_recharge.value = res.data?.message || 0;
+      }
+    })
+  }else{
+    orderInfo.orderNum = 0;
+    message_recharge.value = '';
+  }
+};
+// 查询汇率01-对公账户 02-提现 03-系统货币 04-米币设置
+const BusinessAccount = ref([]);
+const payConfigDearchFn = () => {
+  payConfigDearch({
+    id: "01",//01-对公账户 02-提现 03-系统货币 04-米币设置
+  }).then(res => {
+    if(res.code === 200){
+      BusinessAccount.value = res.data || [];
+    }
+  })
+}
+
+
 
 </script>
 <style scoped lang="scss">