Payment.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. <template>
  2. <div class="payment" v-if="data">
  3. <ul class="payment-left">
  4. <li
  5. v-for="(itemP, indexP) in payList"
  6. :key="indexP"
  7. @click="handleChangePay(itemP.type)"
  8. :class="[payType === itemP.type ? 'active' : '']"
  9. >
  10. <img :src="itemP.img" />
  11. <span>{{ itemP.label }}</span>
  12. </li>
  13. </ul>
  14. <div class="payment-right">
  15. <i class="el-icon-close" @click="closeDialogue"></i>
  16. <h2>{{ data.name || data.cn_title || data.iss_name }}</h2>
  17. <h3>{{ data.org_name || "中报二十一世纪(北京)传媒科技有限公司" }}</h3>
  18. <p class="price">
  19. ¥{{
  20. data.hasOwnProperty("price_discount")
  21. ? data.price_discount
  22. : payAmount || data.price | cutMoneyFiter
  23. }}
  24. </p>
  25. <template v-if="payType === 'dui'">
  26. <el-input
  27. class="code"
  28. placeholder="在此输入兑换码"
  29. v-model="codeValue"
  30. maxlength="20"
  31. ></el-input>
  32. <a class="exchange" @click="handleExchange">兑换</a>
  33. <b class="tips">输入兑换码</b>
  34. </template>
  35. <div v-else v-loading="loading">
  36. <canvas
  37. id="QRCode_header"
  38. style="width: 338px; height: 338px; cursor: pointer"
  39. @click="handleRefresh"
  40. ></canvas>
  41. </div>
  42. <template v-if="payType === 'wei'">
  43. <b class="tips">请使用微信扫一扫</b>
  44. </template>
  45. <template v-else-if="payType === 'zhi'">
  46. <b class="tips">请使用支付宝扫一扫</b>
  47. </template>
  48. </div>
  49. <div class="toPage" v-if="showToPage">
  50. 此兑换码包含多种商品,请到个人中心统一兑换。<a @click="toPage">去兑换</a>
  51. <i class="el-icon-error" @click="showToPage = !showToPage"></i>
  52. </div>
  53. </div>
  54. </template>
  55. <script>
  56. //这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  57. //例如:import 《组件名称》from ‘《组件路径》';
  58. import { cutMoneyFiter } from "@/utils/defined";
  59. import { getLogin } from "@/api/ajax";
  60. import QRCode from "qrcode";
  61. export default {
  62. //import引入的组件需要注入到对象中才能使用
  63. components: {},
  64. props: ["data", "payWay", "qr_code_url", "orderId", "order_amount"],
  65. filters: {
  66. cutMoneyFiter,
  67. },
  68. data() {
  69. //这里存放数据
  70. return {
  71. payList: [
  72. // {
  73. // img: require("../../../assets/duihuanma.png"),
  74. // label: "兑换码",
  75. // type: "dui",
  76. // },
  77. {
  78. img: require("../../../assets/weixin.png"),
  79. label: "微信支付",
  80. type: "wei",
  81. },
  82. {
  83. img: require("../../../assets/zhifubao.png"),
  84. label: "支付宝",
  85. type: "zhi",
  86. },
  87. ], // 支付方式
  88. payType: "dui",
  89. codeValue: "", // 兑换码的值
  90. codeImg: "",
  91. payCode: {
  92. wei: "http://localhost:9970/#/people_manage",
  93. zhi: "http://localhost:9970/#/organize_manage",
  94. },
  95. opts: {
  96. errorCorrectionLevel: "H", //容错级别
  97. type: "image/png", //生成的二维码类型
  98. quality: 1, //二维码质量
  99. margin: 0, //二维码留白边距
  100. width: 330, //宽
  101. height: 330, //高
  102. text: "", //二维码内容
  103. color: {
  104. dark: "#333333", //前景色
  105. light: "#fff", //背景色
  106. },
  107. },
  108. timer: null,
  109. loading: false,
  110. payAmount: this.order_amount ? this.order_amount : null,
  111. showToPage: false, // 多条兑换码跳转去个人中心
  112. messageSuccess: null,
  113. };
  114. },
  115. //计算属性 类似于data概念
  116. computed: {},
  117. //监控data中数据变化
  118. watch: {
  119. // data:{
  120. // handler(val, oldVal) {
  121. // const _this = this;
  122. // if (val) {
  123. //
  124. // }
  125. // },
  126. // // 深度观察监听
  127. // deep: true,
  128. // },
  129. },
  130. //方法集合
  131. methods: {
  132. // 支付方式
  133. handleChangePay(type) {
  134. this.payType = type;
  135. clearInterval(this.timer);
  136. if (type === "dui") {
  137. return false;
  138. }
  139. this.timer = setInterval(() => {
  140. this.getOrderStatus();
  141. }, 5000);
  142. this.loading = true;
  143. let MethodName = "/ShopServer/Client/OrderManager/UpdateOrderPayType";
  144. let data = {
  145. id: this.orderId,
  146. pay_type:
  147. this.payType === "wei" ? 3 : this.payType === "zhi" ? 4 : null,
  148. };
  149. getLogin(MethodName, data).then((res) => {
  150. if (res.status === 1) {
  151. this.payCode[this.payType] = res.qr_code_url;
  152. this.payAmount = res.order_amount;
  153. this.createQRCode();
  154. }
  155. });
  156. },
  157. createQRCode() {
  158. let msg = document.getElementById("QRCode_header");
  159. setTimeout(() => {
  160. QRCode.toCanvas(
  161. msg,
  162. this.payCode[this.payType],
  163. this.opts,
  164. function (error) {
  165. if (error) {
  166. console.log("二维码加载失败", error);
  167. this.$message.error("二维码加载失败");
  168. }
  169. }
  170. );
  171. this.loading = false;
  172. }, 1000);
  173. },
  174. closeDialogue() {
  175. clearInterval(this.timer);
  176. this.$emit("handleClose");
  177. },
  178. // 兑换
  179. handleExchange() {
  180. let MethodName = "/ShopServer/Client/OrderManager/UpdateOrderPayType";
  181. let data = {
  182. id: this.orderId,
  183. pay_type: 5,
  184. discount_code: this.codeValue.trim(),
  185. };
  186. getLogin(MethodName, data).then((res) => {
  187. if (res.status === 1) {
  188. if (this.$emit("handleSuccess")) {
  189. this.$emit("handleSuccess");
  190. } else {
  191. this.$emit("handleClose");
  192. }
  193. } else if (res.status === -6) {
  194. this.showToPage = true;
  195. }
  196. });
  197. },
  198. // 跳转到个人中心-兑换码
  199. toPage() {
  200. this.$router.push({
  201. path: "/peraonal",
  202. query: {
  203. headerConfig: this.$route.query.headerConfig
  204. ? this.$route.query.headerConfig
  205. : "",
  206. type: encodeURIComponent("duihuanma"),
  207. codeId: encodeURIComponent(this.codeValue.trim()),
  208. },
  209. });
  210. },
  211. handleRefresh() {
  212. let MethodName = "/ShopServer/Client/OrderManager/GetOrderNewPayQRCode";
  213. let data = {
  214. id: this.orderId,
  215. };
  216. getLogin(MethodName, data).then((res) => {
  217. if (res.status === 1) {
  218. this.payCode[this.payType] = res.qr_code_url;
  219. this.createQRCode();
  220. }
  221. });
  222. // this.payCode = {
  223. // wei: 'https://baidu.com',
  224. // zhi: 'https://xdf.cn'
  225. // }
  226. // this.createQRCode()
  227. },
  228. getOrderStatus() {
  229. let MethodName = "/ShopServer/Client/OrderManager/GetOrderPayStatus";
  230. let data = {
  231. id: this.orderId,
  232. };
  233. getLogin(MethodName, data).then((res) => {
  234. if (res.status === 1) {
  235. if (res.is_success === "true") {
  236. this.messageSuccess = this.$message({
  237. type: "success",
  238. showClose: true,
  239. dangerouslyUseHTMLString: true,
  240. offset: 200,
  241. message:
  242. "您已购买成功,点击【<a style='text-decoration: underline;' onclick=handleToShlef()>书架</a>】跳转查看。",
  243. duration: 15000,
  244. });
  245. clearInterval(this.timer);
  246. if (this.$emit("handleSuccess")) {
  247. this.$emit("handleSuccess");
  248. } else {
  249. this.$emit("handleClose");
  250. }
  251. }
  252. }
  253. });
  254. },
  255. handleToShlef() {
  256. this.messageSuccess.close();
  257. this.$router.push({ path: "/bookShelf" });
  258. },
  259. },
  260. //生命周期 - 创建完成(可以访问当前this实例)
  261. created() {
  262. console.log("2025-09-19");
  263. this.payType = this.payWay;
  264. },
  265. //生命周期 - 挂载完成(可以访问DOM元素)
  266. mounted() {
  267. if (this.qr_code_url) {
  268. this.payCode[this.payType] = this.qr_code_url;
  269. this.createQRCode();
  270. this.timer = null;
  271. this.timer = setInterval(() => {
  272. this.getOrderStatus();
  273. }, 5000);
  274. }
  275. window.handleToShlef = this.handleToShlef;
  276. },
  277. //生命周期-创建之前
  278. beforeCreated() {},
  279. //生命周期-挂载之前
  280. beforeMount() {},
  281. //生命周期-更新之前
  282. beforUpdate() {},
  283. //生命周期-更新之后
  284. updated() {},
  285. //生命周期-销毁之前
  286. beforeDestory() {},
  287. //生命周期-销毁完成
  288. destoryed() {},
  289. //如果页面有keep-alive缓存功能,这个函数会触发
  290. activated() {},
  291. };
  292. </script>
  293. <style lang="scss" scoped>
  294. /* @import url(); 引入css类 */
  295. .payment {
  296. display: flex;
  297. &-left {
  298. background: #f5f5f5;
  299. width: 216px;
  300. padding: 24px;
  301. list-style: none;
  302. margin: 0;
  303. li {
  304. border: 1px solid #ebebeb;
  305. border-radius: 8px;
  306. background: #ffffff;
  307. margin-bottom: 16px;
  308. cursor: pointer;
  309. padding: 16px 24px;
  310. display: flex;
  311. align-items: center;
  312. img {
  313. width: 24px;
  314. margin-right: 8px;
  315. }
  316. span {
  317. color: rgba(0, 0, 0, 0.88);
  318. font-weight: 400;
  319. font-size: 18px;
  320. line-height: 26px;
  321. }
  322. &:hover {
  323. background: #eef3ff;
  324. }
  325. &.active {
  326. border-color: #3459d2;
  327. background: #eef3ff;
  328. }
  329. }
  330. }
  331. &-right {
  332. flex: 1;
  333. background: #ffffff;
  334. box-shadow: 0px 6px 30px 5px rgba(0, 0, 0, 0.05),
  335. 0px 16px 24px 2px rgba(0, 0, 0, 0.04),
  336. 0px 8px 10px -5px rgba(0, 0, 0, 0.08);
  337. position: relative;
  338. padding: 64px 80px;
  339. text-align: center;
  340. .el-icon-close {
  341. position: absolute;
  342. right: 16px;
  343. top: 16px;
  344. width: 16px;
  345. cursor: pointer;
  346. }
  347. h2 {
  348. margin: 0 0 2px 0;
  349. color: rgba(0, 0, 0, 0.88);
  350. font-weight: 400;
  351. font-size: 24px;
  352. line-height: 32px;
  353. }
  354. h3 {
  355. font-weight: 500;
  356. font-size: 14px;
  357. line-height: 22px;
  358. color: rgba(0, 0, 0, 0.4);
  359. margin: 0;
  360. }
  361. .price {
  362. font-weight: 700;
  363. font-size: 64px;
  364. line-height: 72px;
  365. color: #ec5e41;
  366. margin: 40px 0;
  367. }
  368. .code {
  369. height: 248px;
  370. width: 336px;
  371. background: #f5f5f5;
  372. border: 1px solid #ebebeb;
  373. border-radius: 16px;
  374. overflow: hidden;
  375. display: flex;
  376. align-items: center;
  377. align-content: center;
  378. }
  379. .exchange {
  380. background: #3459d2;
  381. border-radius: 40px;
  382. padding: 8px 40px;
  383. display: inline-block;
  384. margin-top: 40px;
  385. color: #ffffff;
  386. font-weight: 400;
  387. font-size: 24px;
  388. line-height: 32px;
  389. }
  390. .tips {
  391. font-weight: 400;
  392. font-size: 16px;
  393. line-height: 24px;
  394. color: rgba(0, 0, 0, 0.4);
  395. display: block;
  396. margin-top: 40px;
  397. }
  398. #QRCode_header {
  399. border: 1px solid #ebebeb;
  400. padding: 8px;
  401. }
  402. }
  403. }
  404. .toPage {
  405. position: fixed;
  406. top: 50%;
  407. left: 50%;
  408. width: 442px;
  409. height: 40px;
  410. margin-left: -221px;
  411. margin-top: -20px;
  412. border-radius: 4px;
  413. background: #000;
  414. padding: 8px 12px;
  415. z-index: 999;
  416. color: #fff;
  417. text-align: center;
  418. font-size: 16px;
  419. font-weight: 400;
  420. line-height: 24px;
  421. a {
  422. color: #20f53b;
  423. margin-left: 8px;
  424. }
  425. .el-icon-error {
  426. position: absolute;
  427. width: 24px;
  428. height: 24px;
  429. top: -12px;
  430. right: -12px;
  431. cursor: pointer;
  432. color: #000;
  433. }
  434. }
  435. </style>
  436. <style lang="scss">
  437. .payment {
  438. .code {
  439. .el-input__inner {
  440. border: none;
  441. background: none;
  442. height: 100%;
  443. text-align: center;
  444. color: rgba(0, 0, 0, 1);
  445. font-weight: 400;
  446. font-size: 20px;
  447. line-height: 28px;
  448. }
  449. }
  450. }
  451. </style>