From ff5f2cea98a13a0f8fd0873ad0a803dff2d482fa Mon Sep 17 00:00:00 2001 From: xiaoma Date: Sun, 8 Feb 2026 22:57:05 +0800 Subject: [PATCH] pay is ok --- .gitignore | 2 + backend/db.sqlite3 | Bin 196608 -> 196608 bytes backend/shop/__pycache__/urls.cpython-312.pyc | Bin 1121 -> 1167 bytes .../shop/__pycache__/views.cpython-312.pyc | Bin 23522 -> 27469 bytes .../shop/__pycache__/views.cpython-313.pyc | Bin 23100 -> 24872 bytes backend/shop/views.py | 141 +++++++++++----- frontend/package-lock.json | 10 ++ frontend/package.json | 1 + frontend/src/api.js | 2 + frontend/src/pages/Payment.jsx | 158 ++++++++++-------- frontend/src/pages/ProductDetail.jsx | 54 ++++-- frontend/src/pages/ServiceDetail.jsx | 8 +- 12 files changed, 254 insertions(+), 122 deletions(-) diff --git a/.gitignore b/.gitignore index 4c1ac06..0e8c4e2 100644 --- a/.gitignore +++ b/.gitignore @@ -209,6 +209,8 @@ logs/ .env.development.local .env.test.local .env.production.local +*.pem +*.p12 # Docker .dockerignore diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 index 79ac30d6c43ec901838c9fa19d37531c9741efde..1d3123d9ce4e02e563ea0535a90339446b5fa41d 100644 GIT binary patch delta 1570 zcmaiz+ix316vll^qgzKNQ3a|BPr87FeZ@zPO zd%JymyZuJ5{_Y1S?M-)e*6V-Xk6ankk5>N}yKri+Gu3>~H%nk%^oCsJU|`L~L+iy% zwqWZoM2n@BxeZUz{tBNMON0^yX!j$Zee9BGYiBP$ju1K z0+k`MVu2!wR=+?0y1CudmeO_nc>JJ!uPs%5$-LCIb@^pelV`_o%SFqXP$C~np%_b* za^(;t0!f5di!>hHBrD7sb(aE3M{cf|wE4!P%L&(d%0kBZdMr#=vkQ^UNv9o8*uw#m zC%$RlJPhGbGyxZaD4r447Q@6T=8EOF*z$bQ&FM_gkzbn=Bf%{uWyATfWm+t*7KtSi z&U%?;(lQzF1*JefdB!v446%S8`{SOXZ)4GySob^K&WQ{k54s)hX}cvlC=N`U1pn?tkIQSvOt zY^zf?7q7>MaYKBZa)PRR`x#@q32f-VPv8K22sWx+>2qMD-{{f*Uvwt*(B8-U=A8%k z4j$ao&%UWN+SP$yz<1yd*i{L4Aj+8+3hg=Fxq6)>sxC&qP-7mI;82KrURPxSFQrXMWtc6(%h+btSEQ8 z4z7Y7@GdAT)?NdBCS!|!RFx4`hE*9-Wl)s?Rr(M1Uo^zM#$MyCN^@FibL`HsSDU_Q z;--ftY`j(VbuJpWF7=Fd=vtb)oi>}kr*ELea_Y)EKf6AA?m~Jc5g`~VKP-t%4FO`v zDa3*x35271Eb3AdnNpcbRs=^`DCm@PSLk)z==Osh$vIf9h$x(?{5JmbV;HV-}Na()+zkc$K z@>i}QNJkJx1y&k-8uE4xf@O%UN`{C%bqlOjl&ERr43Ba;{OGI0>P;2G>kx!-VW0uh zt!DN7St27Y3*1Vm$noO^64eE&Rj4u~+%SrxHHpMxW)&c603r$!;)VWy0Ns5(8o;Bp xL9!rPsj@y;+gWYcHGozT3E~28jYVQ+Z4D)+-Xa#s)c~vxAd+}+vS@g8^>3V4j%5G< delta 289 zcmZo@;Av>!nIO$LX`+lX>m&xf-X9xNTJ#x}H^0=cwofqt1C`>u(4u4`cS9HByowT2 zXZM_n!sKK(6=%c5;KVc%FptR00t+8^C;vPP zTO$J_GhG8CAW|?eu`;%>GBDILF|;tXG~0Y4-$sFpnP)Ns-)-LQJd-yoDzx%!o;;_J znTwf!5(EDo{_XseHVYQC@Uy5e`!Y_RJx8H=+xqR>)-(D!097nu;D5w_n12aS#Wa2v zIc7)3$#dsQO+WOX(TQ1vzhf#plP1u_P`>G{d`vf|NBJ{pP4D1mssYN)na(Z%loTw; f;om+-o+%@MS%h6?I(q?7EKuML+jg09rY9W$t`b@@ diff --git a/backend/shop/__pycache__/urls.cpython-312.pyc b/backend/shop/__pycache__/urls.cpython-312.pyc index e7299a53d48a85154bd2e3bc28c85adc1e89aeda..716190f292ff28709276693df85e9ba0c86a97cf 100644 GIT binary patch delta 480 zcmaFJ(a*_unwOW00SMlkwr2`4Pvn!(u480in9h*GkiwY5kjogwn9CH!l*=5&%m@-= z%3;Z6jba6|nNwJDCi+U&=kiAJ=JG}HF)}bQq_VCCnFRz<{Hgp|iV!w3nZlaNzM2Ul z!pML_4O=P)K{f2DTwpczK(lZf#F5HP&>+rK9)ud87noDHQh8Ij*YK=nhBy-}#+%BQ z!iOTpn8KgRnIa&8CMXD0&II(A(&Q3GRaT)&Ax+`Q^BCm?H5qU5x}>HhmgbZM<(HPE z7H!_kD9y+yJozS*tg={9YH>+?T2W$dYI%N9wq6lfMR5@u&;_?x%Q92TizhQOE3+2y s0|h1cbCCn@;2t>EOJ0$03G2@^#A|> delta 427 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 U6~E{dFx9;oOj7T!1;~&82f6pYZvX%Q delta 7261 zcmai33sh5Qwmv5>67nJ>;gRqN4}r*A1QGFpF9a!8u@$YFrksF5Uj1|8gC<5>Z%bQR zasJMTQ>tj&DIIO4gHxHAPTSjd&DGwiO$seEwX2<32JzlCYjoI z6tavXv-M$Q`0=%)n5*NoN7)^V9E%*8wxS4?i#f{dC=oFZEvMsRIX!3Kj9eTSKOlm8 z0w?DZ2gIC-GYdT?E@|eTJabRsQaKB7r1=J9Eew}_mgO=A#7-6j#&Vh50xpZo=5jde zfaLtbbE2?PftJhVarsVmu9qtq5S=ePCz<7uaz!odIX3*v6(42J&Db2d?^x_ma*JmA z*8y=yDTs~{=2F5fK3_Udp_VJ-mdy2>FQ21TGu+an3|HY`TifWr%Jei}97X%Yis~iY zGVo3LtjtPo`J4nn%L;DgT+dxHSAoo`yJc#ZiWtzh8fa^P#?R=JS1p^>vX)ynCsWX} zo~xegxl79ikW}-3v{VXOYJs+Kz7}@*$VcMm*oWjU2hTe@T3k)i8JFTM3VurXeU}Mv zg5hU8&oCaw!#0aNB9EA3InjXFBYlN^o^4>P;`*&taZuLo;P-TLK?!H)?ex4fJx>;t zxEyWGK}naL-$T+s97#vW00_$V?zfW`mrDi@7K?>WOKWqj&`yA#D+S;%b6sifUptuT zSMD0xH@fyR7f|lr#UC0r=v~uR)Rdw z%d$)dD*;Z|3J=qYPP*&zvL2Qc{lAjZkSUg%^M-Ts@EEV$Bd5oeaTR@R@0J7N?aY2QgW;1R0y7!1z$@ib zBhOrnNBkng>39q<;qpl7H%fDZ^pF%JT!HX_)_!(Bb5B|EUMVM;KQ=PiW>J%9I};w= zFmtE(sXh>Oo9X>(vn0rLC(=%JBGsz%Xph=cm_+oTJ{Z;cNUNiXcLin5&Nkjbg3@Lu zaq&S>r;B7EgQT_7*+EiihbFx;ia5I3>`jiK)Ws8LS5UF;K$D}3cXoCJrCr3?!3V`a z2x{A#_SoQgpPhHu_Bsxdhh3t38|wK*1)L{=c9bpL@a`#~43FuaiAi{#MFT66Rc=u3v5 z>jAn?TSzlwygr$F6MM~=*q<}FW;pwEW5uX_GCkw9tTS0J=k#s-Ud+TT`!>Zoky0E; zDfTbgB|XY7m2s1%1rw(HfGOW!u<`PeEn}wpCrph2Q=@-7@85S|%ye+VA$muCvA-jrR)unFP z1pfIjM^lq2`mjt_6EFQJsvO#vqpMW4M&?Sqv?fh)B}oolS27i~vC=E~rdqZ1W3?38 z9~%|5rQ(lMRJBFoj~BAoE|S)kj;x4fS=la-OLo(BdOp&8Probv5$xp<90<(-Rx#N% zQeu#@?Cz1J#sq~@;Aui~47I1|Au&VKMcpYEld(6b3L03qVRl2~lZnur5}op|vfSMUU0sYmQhdr2KFNnfhokG)YXot+%K2-KEh^a-xm zE-*U?=_IyxS4%Lei*$1CCY~Gx0uhXR0$H?S2iTk)@Pc*lF7iCm(Kkf!lJE-o@bOV( zml21{-Np+JB8}L62Ec`hE%I7Xb%suxgQS57Y#YhXsF5gf55(N{-Dng&l6^wGU@rf1 zGWz@M1R6A{X;N;q6w=vw1-0gs(x2qK6cgFCIL!d0Lk~+Wn+=#-d~2CwqGRGFv6E>M z?TTlZog&!uMP4!HaiaE!IMrS-gvcSMX}K5^Y^2?wzJv9Msi-$m0+|iD=UEZ!k-W&f zB#J0x86LMi;ez}$n*Rw(vU6~Nk3`qduFnn=|ygAbLNFy8|(e%=678f#9GCh)O)|=;z zG<%|OK2(=$Sm=r3lIE+P$Cexs3JG1-nu=*_9Sf?!op@o=>SIaqyb&oL`Hvmtk$V+f zszM8ga- zJt|Nmi7?#uH6hr6GpPiIB)4PjqVrF2)jTq|dAN zL~{#0Y7^tt@C(B8gyKgtOV{$4(1Z)h0azk>C`TXT(VowpWr^{`&=|8Jhs)c$1j4M6 z%k#w8W`o3|gr~TO3{OmJA(T)i`emUyJKv*)$ra3Bz7EYi?-t_Zg=I4)E`l|i35AAv z1uItqi)!>O=1S+UX_JU$n#5kQSG1pjx?*kyvuB}*Jq!c2Ml1yQT$tqxE-#vI)pn-0 zo?jFh10&MBx_KjtReWiL=+V(LC2@67RcO7sL%LoPzW=B;nJ;OhR|n@6ZJXH}J5S=0 zy9G)-v8_u5$6Z;hS~Z^<@yh(D7OEOSKU6iseNMl%++9ga%B;Evw$xQv3hiCa!e(cO z)3v9No+_(Ycn~JyP6N34!pZ3i7b+~*N1vN|;lfn!ksCihI(^~N)LV~F{p>eWBR{p! zYh@<(G5USk{XVONya7YVn+O*Wh5_nt;_0{&C)c z&~Yz>aZ_)+92yv!e(%NUGrc$7csJDd+|6J1PG2|@`bqEfua8dswr~2imqQnxM0da@ z&4h{9N1qROPsR20g`PPLh6)*34jHD?O`06^*~(;}8+X3xH_wKi`)TNvqc{4Vtgv*t zc^f1_&H)*6dABCd5`J*;kW!ZiqZ%Gqvu0gGLonL05AvCfKiK8y)^FWXRo_sxW^2u+ z`hpn-@-HBnJc;&TP9h!vJk2>dH=Yv1I(-&5*5;P*cxvwKO4UB%-d6k zkGM_1Fg5VY8>e5zKna_A?9$ZWJE3=u!7^hgU@V2+=m#gcGvF~ilQ3&oNLb+1iMK;f z{T5aMe1WxyI{_1KI5vLd*H_+}zW8c)a)Yy_!_K>j!?F*`;$~-)9gAyAv)$R|;GD-{ zc?j;{Zme#@I>WM1&#~h-UN{|k=kd_!Xoba^Of~`!=?4hPp(t<0q6AL05EVjQPw>zj zjEcn0F?^Cbc}Kg89LKh7pS{iPa8dhmeLlfTC@62Tx3yuJ5{!nGA-rq9liw4Rz#GSr zK41_kAt;qru1N6_iXHeqkUE4j2xkGTdV=K*`5i!z-5X^01ywG4v%?lK|f>6L*#MZ9?f>AsaIGp1^P}ND`?So3m2D2nx$nZSYWbeW~EB0)KIpU$c5#zJ{J&xzl%B zA=SzbSKo?Z9%ftE30qsh);4bI7}s|OY#o7Z5Baw>`gc6kSM_?@FzYX^{j8|ApY6}+ zU(_!fH2z%UzkhSUu-R|xI9wOdcV3ey{HnCUyulQIbkVq^_>PQGX?yk`JM{FSF>UI& z(sB*W*fB2Oc^w;>gWFzPu=C8$;mqL@|AHm{%<@sOUsE|QUw%z%_9x{JH;rp6{PK!h zGHP0t;Y;&JFCLea-jb9{i>{lC#>|TX@`N5~&%rOXhHEOF->~}qrSIqZW9!FNo380o z2NlB^T=%LkP@r8YoZ_TNv%TJaM){mJ>dg>;V z(@r;@Z1iW9jU_MXsh>2ZoX$C!Gq`-rRNS-iI+|8EtQtBry8H6R%gg<-+s9QqzSWxg zou6s5hsrKgyk0TfHkP}_U%m6Q+?}^1vASAzGCpG>z90}^FytPOFa0*XU?SaD5=bu@ zUNe?n-XArYT{2uX+~Ut((XYCeku~TU%UIkmziwIZn)-}-!crWt6c0E0EyZJ&75&ml zv*mQ<$;zR!&&xyAkK2I?jkukK$ro>V-UlyY)uo75>uA{`4)M zCpBD8NcLMQMk_}P{3$i#3AJ~88pdE5bdBqC{iJN8f8I|#Gj6|AH^p!k82%!A)O~YyDnui+wnzC{E z61rynf_5iF{D%ceb%nA&Bw6dF%)iN2XT$AE!Rq9?Qs$3JB|Q8wJ|3|&y9x%iWEDfTRvLeEu^7}{5*icN{)tC}iilR^BchJ}Yu4N^dQrdm(it8-=h zKr7ija;ntCX+tsc;8z z!CuH%;K2VsHF44}pq*eWGhV~2P1>-5Df>1+;tcZ-GXrr&IN3f7^e z;XlO-euFG7fWK=2W>V>;Uxkw|LB(519^JpKTtZ4=j~?FkAX`GC8mrl7=%&Uj<(wT= z^l)RkuK~pg2}MXaLUNP1-S9n0iny3;0ES=`6oUBK39_5rwWrPbNKo9)l?G*wj;2n| z5mfAP9N?TS4*19=b$4~ae7q?32>`2hZc;%}*WU2ac`K4pHBH~1F1o|e_1m|>WKV5h z%sxFbw*6Nu%=XELRFX7dwtoS}*F{8vgC0e|=?haOopi)@WE;3z$YnhCKZ}3~&8-2L zI{oVOg|jz)N2g8=K*jJj5-$S$U4=xUTnkq$@bP3$!E?xVgg*UnvJWK*THV43L0m|v zEl4kr>aDTlAIKsM#-d0_?c^0~2}Vs}>lngM5U_>_N*{GQ$U*WFcAP>ujqnk|&k<@7 za8;}osyY7=IJiJ6M%s1+A)O04eE2B1M#%1h&5hJ%H-b~$_B{5zk+b%HhmpOL$a4WE~^$;HSdf|m?LkLx2L-`!l*aD}BO&x6q?}K-w?Lntwe}jV$ z@4;Up=U2$2`VsMKhA9khFk!oYJfWbxvK_upwK-Oh9GDUOF|I-y* LPqls^L4W)&7}(}2 diff --git a/backend/shop/__pycache__/views.cpython-313.pyc b/backend/shop/__pycache__/views.cpython-313.pyc index a98b40acd64285f880f9a58f6e107cb096c006fb..7e83a1020e809bed2ec4b5fa8ddc9f81aede99e8 100644 GIT binary patch delta 5015 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 H>puD~cj0fj delta 3773 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" } }, + "node_modules/qrcode.react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz", + "integrity": "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react": { "version": "19.2.4", "resolved": "https://registry.npmmirror.com/react/-/react-19.2.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 0712903..ff054a8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "axios": "^1.13.4", "framer-motion": "^12.29.2", "jszip": "^3.10.1", + "qrcode.react": "^4.2.0", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router-dom": "^7.13.0", diff --git a/frontend/src/api.js b/frontend/src/api.js index 29ea1d0..0ca8e3f 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -10,7 +10,9 @@ const api = axios.create({ export const getConfigs = () => api.get('/configs/'); export const createOrder = (data) => api.post('/orders/', data); +export const nativePay = (data) => api.post('/pay/', data); export const getOrder = (id) => api.get(`/orders/${id}/`); +export const queryOrderStatus = (id) => api.get(`/orders/${id}/query_status/`); export const initiatePayment = (orderId) => api.post(`/orders/${orderId}/initiate_payment/`); export const confirmPayment = (orderId) => api.post(`/orders/${orderId}/confirm_payment/`); diff --git a/frontend/src/pages/Payment.jsx b/frontend/src/pages/Payment.jsx index 500665f..ffcff0e 100644 --- a/frontend/src/pages/Payment.jsx +++ b/frontend/src/pages/Payment.jsx @@ -1,26 +1,65 @@ import React, { useEffect, useState } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; -import { Button, message, Result, Spin, QRCode } from 'antd'; +import { useParams, useNavigate, useLocation } from 'react-router-dom'; +import { Button, message, Result, Spin } from 'antd'; import { WechatOutlined, AlipayCircleOutlined, CheckCircleOutlined } from '@ant-design/icons'; -import { getOrder, initiatePayment, confirmPayment } from '../api'; +import { QRCodeSVG } from 'qrcode.react'; +import { getOrder, initiatePayment, confirmPayment, nativePay, queryOrderStatus } from '../api'; import './Payment.css'; const Payment = () => { - const { orderId } = useParams(); + const { orderId: initialOrderId } = useParams(); const navigate = useNavigate(); - const [order, setOrder] = useState(null); - const [loading, setLoading] = useState(true); - const [paying, setPaying] = useState(false); + const location = useLocation(); + const [currentOrderId, setCurrentOrderId] = useState(location.state?.order_id || initialOrderId); + const [order, setOrder] = useState(location.state?.orderInfo || null); + const [codeUrl, setCodeUrl] = useState(location.state?.codeUrl || null); + const [loading, setLoading] = useState(!location.state?.orderInfo && !location.state?.codeUrl); + const [paying, setPaying] = useState(!!location.state?.codeUrl); const [paySuccess, setPaySuccess] = useState(false); const [paymentMethod, setPaymentMethod] = useState('wechat'); useEffect(() => { - fetchOrder(); - }, [orderId]); + if (codeUrl && !paying) { + setPaying(true); + } + }, [codeUrl]); + + useEffect(() => { + console.log('Payment page state:', { currentOrderId, order, codeUrl, paying }); + if (!order && !codeUrl) { + fetchOrder(); + } + }, [currentOrderId]); + + useEffect(() => { + if (paying && !codeUrl && order) { + handlePay(); + } + }, [paying, codeUrl, order]); + + // 轮询订单状态 + useEffect(() => { + let timer; + if (paying && !paySuccess) { + timer = setInterval(async () => { + try { + const response = await queryOrderStatus(currentOrderId); + if (response.data.status === 'paid') { + setPaySuccess(true); + setPaying(false); + clearInterval(timer); + } + } catch (error) { + console.error('Check payment status failed:', error); + } + }, 3000); + } + return () => clearInterval(timer); + }, [paying, paySuccess, currentOrderId]); const fetchOrder = async () => { try { - const response = await getOrder(orderId); + const response = await getOrder(currentOrderId); setOrder(response.data); } catch (error) { console.error('Failed to fetch order:', error); @@ -38,69 +77,41 @@ const Payment = () => { return; } + if (codeUrl) { + setPaying(true); + return; + } + + if (!order) { + message.error('正在加载订单信息,请稍后...'); + return; + } + setPaying(true); try { - // 1. 获取微信支付参数 - const response = await initiatePayment(orderId); - const payData = response.data; - - if (typeof WeixinJSBridge === 'undefined') { - message.warning('请在微信内置浏览器中打开以完成支付'); - setPaying(false); - return; - } - - // 2. 调用微信支付 - const onBridgeReady = () => { - window.WeixinJSBridge.invoke( - 'getBrandWCPayRequest', { - "appId": payData.appId, // 公众号名称,由商户传入 - "timeStamp": payData.timeStamp, // 时间戳,自1970年以来的秒数 - "nonceStr": payData.nonceStr, // 随机串 - "package": payData.package, - "signType": payData.signType, // 微信签名方式: - "paySign": payData.paySign // 微信签名 - }, - function(res) { - setPaying(false); - if (res.err_msg == "get_brand_wcpay_request:ok") { - message.success('支付成功!'); - setPaySuccess(true); - // 这里可以再次调用后端查询接口确认状态,但通常 JSAPI 回调 ok 即可认为成功 - // 为了保险,可以去轮询一下后端状态,或者直接展示成功页 - } else if (res.err_msg == "get_brand_wcpay_request:cancel") { - message.info('支付已取消'); - } else { - message.error('支付失败,请重试'); - console.error('WeChat Pay Error:', res); - } - } - ); + const orderData = { + goodid: order.config || order.goodid, + quantity: order.quantity, + customer_name: order.customer_name, + phone_number: order.phone_number, + shipping_address: order.shipping_address, + ref_code: order.ref_code }; - - if (typeof window.WeixinJSBridge == "undefined") { - if (document.addEventListener) { - document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); - } else if (document.attachEvent) { - document.attachEvent('WeixinJSBridgeReady', onBridgeReady); - document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); - } - } else { - onBridgeReady(); + + const response = await nativePay(orderData); + setCodeUrl(response.data.code_url); + if (response.data.order_id) { + setCurrentOrderId(response.data.order_id); } - + message.success('支付二维码已生成'); } catch (error) { console.error(error); - if (error.response && error.response.data && error.response.data.error) { - message.error(error.response.data.error); - } else { - message.error('支付发起失败,请稍后重试'); - } + message.error('生成支付二维码失败,请重试'); setPaying(false); } }; - if (loading) return
; + if (loading) return
; if (paySuccess) { return ( @@ -109,7 +120,7 @@ const Payment = () => { status="success" icon={} title={支付成功} - subTitle={订单 {orderId} 已完成支付,我们将尽快为您发货。} + subTitle={订单 {currentOrderId} 已完成支付,我们将尽快为您发货。} extra={[