Commit 4477f605da7ff298d6199eaf0454792ecfdeb6ac

Authored by tianwu
1 parent cec216f8

更改打包配置

apps/web-payment/.env.production
1 -VITE_BASE=/ 1 +VITE_BASE = /pages/
2 2
3 # 接口地址 3 # 接口地址
4 -VITE_GLOB_API_URL=https://mock-napi.vben.pro/api 4 +VITE_GLOB_API_URL=http://cashier.test.gszdtop.com
5 5
6 # 是否开启压缩,可以设置为 none, brotli, gzip 6 # 是否开启压缩,可以设置为 none, brotli, gzip
7 VITE_COMPRESS=none 7 VITE_COMPRESS=none
apps/web-payment/src/api/payment.ts
@@ -51,3 +51,30 @@ export async function listUserCards( @@ -51,3 +51,30 @@ export async function listUserCards(
51 `/card/payment/listUserCards?pipelineId=${pipelineId}&userId=${userId}`, 51 `/card/payment/listUserCards?pipelineId=${pipelineId}&userId=${userId}`,
52 ); 52 );
53 } 53 }
  54 +
  55 +/**
  56 + * 查询支付状态
  57 + * @param paymentId
  58 + * @param mode
  59 + * @returns
  60 + */
  61 +export async function paymentState(paymentId: number | string, mode: 'online') {
  62 + return requestClient.post<any>(
  63 + `/payment/cashier/paymentState?paymentId=${paymentId}&mode=${mode}`,
  64 + );
  65 +}
  66 +
  67 +/**
  68 + * 中瑞特供查询
  69 + * @param paymentId
  70 + * @param mode
  71 + * @returns
  72 + */
  73 +export async function zrPaymentState(
  74 + paymentId: number | string,
  75 + mode: 'online',
  76 +) {
  77 + return requestClient.post<any>(
  78 + `/payment/cashier/zrPaymentState?paymentId=${paymentId}&mode=${mode}`,
  79 + );
  80 +}
apps/web-payment/src/views/payment/index.vue
@@ -5,6 +5,7 @@ import { useRoute, useRouter } from &#39;vue-router&#39;; @@ -5,6 +5,7 @@ import { useRoute, useRouter } from &#39;vue-router&#39;;
5 import { fenToYuan } from '@vben/utils'; 5 import { fenToYuan } from '@vben/utils';
6 6
7 import { 7 import {
  8 + Close,
8 CreditCard, 9 CreditCard,
9 SuccessFilled, 10 SuccessFilled,
10 Wallet, 11 Wallet,
@@ -13,7 +14,13 @@ import { @@ -13,7 +14,13 @@ import {
13 import { ElButton, ElDialog, ElIcon, ElMessage, ElRadio } from 'element-plus'; 14 import { ElButton, ElDialog, ElIcon, ElMessage, ElRadio } from 'element-plus';
14 import qs from 'qs'; 15 import qs from 'qs';
15 16
16 -import { getOpenId, listUserCards, orderInfo, orderPayment } from '#/api'; 17 +import {
  18 + getOpenId,
  19 + listUserCards,
  20 + orderInfo,
  21 + orderPayment,
  22 + zrPaymentState,
  23 +} from '#/api';
17 import EnvironmentDetector from '#/composables/environmentDetector'; 24 import EnvironmentDetector from '#/composables/environmentDetector';
18 25
19 import PasswordInput from './component/PasswordInput.vue'; 26 import PasswordInput from './component/PasswordInput.vue';
@@ -49,7 +56,7 @@ const REDIRECT_CHANNEL_ID = 29; @@ -49,7 +56,7 @@ const REDIRECT_CHANNEL_ID = 29;
49 56
50 // 检查参数是否有效 57 // 检查参数是否有效
51 const hasValidParams = computed(() => { 58 const hasValidParams = computed(() => {
52 - return !!(token.value && code.value); 59 + return !!(token.value || code.value);
53 }); 60 });
54 61
55 const cardList = ref<Card[]>([]); 62 const cardList = ref<Card[]>([]);
@@ -118,28 +125,23 @@ const getPaymentIcon = (channelName: string) =&gt; { @@ -118,28 +125,23 @@ const getPaymentIcon = (channelName: string) =&gt; {
118 } 125 }
119 }; 126 };
120 127
121 -const jumpTest = () => {  
122 - // jWeixin.miniProgram.redirectTo({  
123 - // url: `/packageA/pages/wePay/index?amount=${displayAmount.value}&businessType=3&redirect=${true}`,  
124 - // });  
125 - router.push({  
126 - path: '/paymentSuccess',  
127 - query: {  
128 - amount: displayAmount.value,  
129 - success: 'true',  
130 - payType: '园区卡支付',  
131 - },  
132 - }); 128 +// 判断是否是园区卡支付
  129 +const isCardPayment = (pipeline: Pipeline) => {
  130 + const channelName = pipeline.channelName.toLowerCase();
  131 + return channelName.includes('园区卡') || channelName.includes('卡');
133 }; 132 };
134 133
135 // 获取支付方式描述 134 // 获取支付方式描述
136 const getPaymentDesc = (pipeline: Pipeline) => { 135 const getPaymentDesc = (pipeline: Pipeline) => {
  136 + // 只有当前选中的支付方式是园区卡支付,且已选择卡时,才显示卡号
137 if ( 137 if (
138 pipeline.pipelineId === currentPaymentMethod.value && 138 pipeline.pipelineId === currentPaymentMethod.value &&
  139 + isCardPayment(pipeline) &&
139 selectedCard.value 140 selectedCard.value
140 ) { 141 ) {
141 return `卡号:${selectedCard.value.cardNo}`; 142 return `卡号:${selectedCard.value.cardNo}`;
142 } 143 }
  144 +
143 const channelName = pipeline.channelName.toLowerCase(); 145 const channelName = pipeline.channelName.toLowerCase();
144 if (channelName.includes('微信')) { 146 if (channelName.includes('微信')) {
145 return '推荐使用'; 147 return '推荐使用';
@@ -181,6 +183,9 @@ const handlepayBtnShowClick = async (pipeline: Pipeline) =&gt; { @@ -181,6 +183,9 @@ const handlepayBtnShowClick = async (pipeline: Pipeline) =&gt; {
181 } 183 }
182 showCardDialog.value = true; 184 showCardDialog.value = true;
183 } else { 185 } else {
  186 + // 切换到其他支付方式时,清空已选择的园区卡
  187 + selectedCard.value = null;
  188 +
184 if (pipeline.channelId === REDIRECT_CHANNEL_ID) { 189 if (pipeline.channelId === REDIRECT_CHANNEL_ID) {
185 payBtnShow.value = true; 190 payBtnShow.value = true;
186 return; 191 return;
@@ -192,7 +197,7 @@ const handlepayBtnShowClick = async (pipeline: Pipeline) =&gt; { @@ -192,7 +197,7 @@ const handlepayBtnShowClick = async (pipeline: Pipeline) =&gt; {
192 const handleCardSelect = (card: Card) => { 197 const handleCardSelect = (card: Card) => {
193 selectedCard.value = card; 198 selectedCard.value = card;
194 showCardDialog.value = false; 199 showCardDialog.value = false;
195 - ElMessage.success(`已选择 ${card.name} 的园区卡`); 200 + // ElMessage.success(`已选择 ${card.name} 的园区卡`);
196 payBtnShow.value = true; 201 payBtnShow.value = true;
197 }; 202 };
198 203
@@ -203,7 +208,6 @@ const handlePasswordCancel = () =&gt; { @@ -203,7 +208,6 @@ const handlePasswordCancel = () =&gt; {
203 }; 208 };
204 209
205 const handlePasswordComplete = async (password: string) => { 210 const handlePasswordComplete = async (password: string) => {
206 - showPasswordDialog.value = false;  
207 try { 211 try {
208 const params = { 212 const params = {
209 tradeId: orderInfoData.value.tradeId, 213 tradeId: orderInfoData.value.tradeId,
@@ -216,14 +220,17 @@ const handlePasswordComplete = async (password: string) =&gt; { @@ -216,14 +220,17 @@ const handlePasswordComplete = async (password: string) =&gt; {
216 }; 220 };
217 221
218 const data = await orderPayment(params); 222 const data = await orderPayment(params);
219 - router.push({  
220 - path: '/paymentSuccess',  
221 - query: {  
222 - amount: displayAmount.value,  
223 - success: 'true',  
224 - payType: '园区卡支付',  
225 - },  
226 - }); 223 + // 园区卡支付成功开始轮询结果
  224 + checkPayResult(data.paymentId);
  225 + // router.push({
  226 + // path: '/paymentSuccess',
  227 + // query: {
  228 + // amount: displayAmount.value,
  229 + // payee: orderInfoData.value.mchName,
  230 + // success: 'true',
  231 + // payType: '园区卡支付',
  232 + // },
  233 + // });
227 } catch (error) { 234 } catch (error) {
228 errorMessage.value = error?.message || '支付失败'; 235 errorMessage.value = error?.message || '支付失败';
229 payErrorDialog.value = true; 236 payErrorDialog.value = true;
@@ -251,11 +258,10 @@ const queryPayment = async () =&gt; { @@ -251,11 +258,10 @@ const queryPayment = async () =&gt; {
251 payType: currentPayType.value.channelName, 258 payType: currentPayType.value.channelName,
252 redirect: true, 259 redirect: true,
253 payee: orderInfoData.value.mchName, 260 payee: orderInfoData.value.mchName,
254 - redirectUrl: orderInfoData.value.redirectUrl,  
255 }; 261 };
256 const queryString = qs.stringify(params); 262 const queryString = qs.stringify(params);
257 if (typeof jWeixin !== 'undefined' && jWeixin.miniProgram) { 263 if (typeof jWeixin !== 'undefined' && jWeixin.miniProgram) {
258 - jWeixin.miniProgram.navigateTo({ 264 + jWeixin.miniProgram.redirectTo({
259 url: `/packageA/pages/wxPay/index?${queryString}`, 265 url: `/packageA/pages/wxPay/index?${queryString}`,
260 }); 266 });
261 loading.value = false; 267 loading.value = false;
@@ -276,7 +282,6 @@ const queryPayment = async () =&gt; { @@ -276,7 +282,6 @@ const queryPayment = async () =&gt; {
276 goods: orderInfoData.value.goods, 282 goods: orderInfoData.value.goods,
277 amount: orderInfoData.value.amount, 283 amount: orderInfoData.value.amount,
278 payType: currentPayType.value.channelName, 284 payType: currentPayType.value.channelName,
279 - redirectUrl: orderInfoData.value.redirectUrl,  
280 payee: orderInfoData.value.mchName, 285 payee: orderInfoData.value.mchName,
281 }; 286 };
282 const queryString = qs.stringify(pramsData); 287 const queryString = qs.stringify(pramsData);
@@ -312,17 +317,17 @@ const handlePay = async () =&gt; { @@ -312,17 +317,17 @@ const handlePay = async () =&gt; {
312 } 317 }
313 318
314 const channelName = currentPayType.value.channelName.toLowerCase(); 319 const channelName = currentPayType.value.channelName.toLowerCase();
315 - const isCardPayment = 320 + const isCardPaymentMethod =
316 channelName.includes('园区卡') || channelName.includes('卡支付'); 321 channelName.includes('园区卡') || channelName.includes('卡支付');
317 322
318 - if (isCardPayment && !selectedCard.value) { 323 + if (isCardPaymentMethod && !selectedCard.value) {
319 ElMessage.warning('请先选择园区卡'); 324 ElMessage.warning('请先选择园区卡');
320 return; 325 return;
321 } 326 }
322 327
323 loading.value = true; 328 loading.value = true;
324 329
325 - if (isCardPayment) { 330 + if (isCardPaymentMethod) {
326 // 园区卡支付逻辑 331 // 园区卡支付逻辑
327 try { 332 try {
328 showPasswordDialog.value = true; 333 showPasswordDialog.value = true;
@@ -345,6 +350,12 @@ const handleCloseDialog = () =&gt; { @@ -345,6 +350,12 @@ const handleCloseDialog = () =&gt; {
345 payBtnShow.value = false; 350 payBtnShow.value = false;
346 }; 351 };
347 352
  353 +// 点击遮罩层关闭
  354 +const handleMaskClick = () => {
  355 + showCardDialog.value = false;
  356 + payBtnShow.value = false;
  357 +};
  358 +
348 // 获取订单信息 支付方式等数据 359 // 获取订单信息 支付方式等数据
349 const getOrderInfo = async () => { 360 const getOrderInfo = async () => {
350 try { 361 try {
@@ -378,6 +389,86 @@ const getListUserCards = async () =&gt; { @@ -378,6 +389,86 @@ const getListUserCards = async () =&gt; {
378 } 389 }
379 }; 390 };
380 391
  392 +let pollTimer: any = null;
  393 +let pollCount = 0;
  394 +// 最大轮询次数
  395 +const maxPollCount = 30;
  396 +// 轮询间隔(毫秒)
  397 +const pollInterval = 2000;
  398 +
  399 +const stopPollingPayResult = () => {
  400 + showPasswordDialog.value = false;
  401 + if (pollTimer) {
  402 + clearTimeout(pollTimer);
  403 + pollTimer = null;
  404 + }
  405 + pollCount = 0;
  406 +};
  407 +
  408 +const paySuccessHandler = (data: any) => {
  409 + router.replace({
  410 + path: '/paymentSuccess',
  411 + query: {
  412 + amount: displayAmount.value,
  413 + payee: orderInfoData.value.mchName,
  414 + success: 'true',
  415 + payType: '园区卡支付',
  416 + redirectUrl: data.redirectUrl,
  417 + },
  418 + });
  419 +};
  420 +
  421 +const payFailHandler = (msg: any) => {};
  422 +
  423 +const payTimeoutHandler = () => {
  424 + // errorMessage: '支付结果查询超时,请稍后在订单中查看支付状态'
  425 +};
  426 +
  427 +const checkPayResult = async (paymentId: number | string) => {
  428 + try {
  429 + const data = await zrPaymentState(paymentId, 'online');
  430 + if (data?.state === 4) {
  431 + stopPollingPayResult();
  432 + paySuccessHandler(data);
  433 + } else if (data?.state === 6) {
  434 + // 支付失败
  435 + stopPollingPayResult();
  436 + payFailHandler(data?.message || '支付失败');
  437 + } else {
  438 + pollCount++;
  439 + if (pollCount < maxPollCount) {
  440 + pollTimer = setTimeout(() => {
  441 + checkPayResult(paymentId);
  442 + }, pollInterval);
  443 + } else {
  444 + // 超过最大轮询次数,停止轮询
  445 + console.log('支付结果查询超时');
  446 + stopPollingPayResult();
  447 + payTimeoutHandler();
  448 + }
  449 + }
  450 + } catch (error) {
  451 + ElMessage.error(JSON.stringify(error));
  452 + console.error('支付结果查询失败:', error);
  453 + if (error?.code === 'E504') {
  454 + stopPollingPayResult();
  455 + payFailHandler(error?.msg || '支付失败');
  456 + } else {
  457 + // 查询失败,继续轮询
  458 + pollCount++;
  459 +
  460 + if (pollCount < maxPollCount) {
  461 + pollTimer = setTimeout(() => {
  462 + checkPayResult(paymentId);
  463 + }, pollInterval);
  464 + } else {
  465 + stopPollingPayResult();
  466 + payTimeoutHandler();
  467 + }
  468 + }
  469 + }
  470 +};
  471 +
381 const init = async () => { 472 const init = async () => {
382 token.value = (route.query?.token as string) || ''; 473 token.value = (route.query?.token as string) || '';
383 openId.value = (route.query?.openId as string) || ''; 474 openId.value = (route.query?.openId as string) || '';
@@ -547,39 +638,51 @@ init(); @@ -547,39 +638,51 @@ init();
547 </div> 638 </div>
548 </div> 639 </div>
549 640
550 - <!-- 园区卡选择弹窗 -->  
551 - <ElDialog  
552 - v-model="showCardDialog"  
553 - title="选择园区卡"  
554 - width="90%"  
555 - :style="{ maxWidth: '500px' }"  
556 - class="card-dialog"  
557 - :close-on-click-modal="false"  
558 - >  
559 - <div class="card-list-dialog">  
560 - <div  
561 - v-for="card in cardList"  
562 - :key="card.cardNo"  
563 - class="card-item-dialog"  
564 - @click="handleCardSelect(card)"  
565 - >  
566 - <div class="card-item-info">  
567 - <p class="card-holder">{{ card.name }}</p>  
568 - <p class="card-number">{{ card.cardNo }}</p> 641 + <!-- 园区卡选择底部弹出层 -->
  642 + <transition name="fade">
  643 + <div
  644 + v-if="showCardDialog"
  645 + class="bottom-sheet-mask"
  646 + @click="handleMaskClick"
  647 + ></div>
  648 + </transition>
  649 + <transition name="slide-up">
  650 + <div v-if="showCardDialog" class="bottom-sheet">
  651 + <div class="bottom-sheet-header">
  652 + <h3 class="bottom-sheet-title">选择园区卡</h3>
  653 + <div class="bottom-sheet-close" @click="handleCloseDialog">
  654 + <ElIcon :size="24" color="#6b7280">
  655 + <Close />
  656 + </ElIcon>
569 </div> 657 </div>
570 - <div class="card-balance">  
571 - <p class="balance-label">余额</p>  
572 - <p class="balance-value">¥{{ card.amount }}</p> 658 + </div>
  659 + <div class="bottom-sheet-body">
  660 + <div class="card-list">
  661 + <div
  662 + v-for="card in cardList"
  663 + :key="card.cardNo"
  664 + class="card-item"
  665 + @click="handleCardSelect(card)"
  666 + >
  667 + <div class="card-item-info">
  668 + <p class="card-holder">{{ card.name }}</p>
  669 + <p class="card-number">{{ card.cardNo }}</p>
  670 + </div>
  671 + <div class="card-balance">
  672 + <p class="balance-label">余额</p>
  673 + <p class="balance-value">¥{{ fenToYuan(card.amount) }}</p>
  674 + </div>
  675 + </div>
  676 + <div v-if="cardList.length === 0" class="empty-card">
  677 + <p>暂无可用园区卡</p>
  678 + </div>
573 </div> 679 </div>
574 </div> 680 </div>
575 - <div v-if="cardList.length === 0" class="empty-card">  
576 - <p>暂无可用园区卡</p> 681 + <div class="bottom-sheet-footer">
  682 + <button class="cancel-button" @click="handleCloseDialog">取消</button>
577 </div> 683 </div>
578 </div> 684 </div>
579 - <template #footer>  
580 - <ElButton @click="handleCloseDialog">取消</ElButton>  
581 - </template>  
582 - </ElDialog> 685 + </transition>
583 686
584 <ElDialog 687 <ElDialog
585 v-model="payErrorDialog" 688 v-model="payErrorDialog"
@@ -680,6 +783,28 @@ init(); @@ -680,6 +783,28 @@ init();
680 } 783 }
681 } 784 }
682 785
  786 +// 遮罩层动画
  787 +.fade-enter-active,
  788 +.fade-leave-active {
  789 + transition: opacity 0.3s ease;
  790 +}
  791 +
  792 +.fade-enter-from,
  793 +.fade-leave-to {
  794 + opacity: 0;
  795 +}
  796 +
  797 +// 底部弹出动画
  798 +.slide-up-enter-active,
  799 +.slide-up-leave-active {
  800 + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  801 +}
  802 +
  803 +.slide-up-enter-from,
  804 +.slide-up-leave-to {
  805 + transform: translateY(100%);
  806 +}
  807 +
683 .cashier-container { 808 .cashier-container {
684 min-height: 100vh; 809 min-height: 100vh;
685 background: linear-gradient( 810 background: linear-gradient(
@@ -994,90 +1119,201 @@ init(); @@ -994,90 +1119,201 @@ init();
994 } 1119 }
995 } 1120 }
996 1121
997 -// 园区卡选择弹窗  
998 -.card-dialog {  
999 - :deep(.el-dialog__header) {  
1000 - padding: 20px 24px; 1122 +// 底部弹出层样式
  1123 +.bottom-sheet-mask {
  1124 + position: fixed;
  1125 + inset: 0;
  1126 + z-index: 1000;
  1127 + background-color: rgb(0 0 0 / 50%);
  1128 +}
  1129 +
  1130 +.bottom-sheet {
  1131 + position: fixed;
  1132 + right: 0;
  1133 + bottom: 0;
  1134 + left: 0;
  1135 + z-index: 1001;
  1136 + display: flex;
  1137 + flex-direction: column;
  1138 + max-height: 70vh;
  1139 + background: #fff;
  1140 + border-radius: 16px 16px 0 0;
  1141 + box-shadow: 0 -4px 20px rgb(0 0 0 / 10%);
  1142 +
  1143 + .bottom-sheet-header {
  1144 + display: flex;
  1145 + flex-shrink: 0;
  1146 + align-items: center;
  1147 + justify-content: space-between;
  1148 + padding: 20px 24px 16px;
1001 border-bottom: 1px solid #f0f0f0; 1149 border-bottom: 1px solid #f0f0f0;
1002 - }  
1003 1150
1004 - :deep(.el-dialog__title) {  
1005 - font-size: 18px;  
1006 - font-weight: 600;  
1007 - color: #1f2937; 1151 + .bottom-sheet-title {
  1152 + margin: 0;
  1153 + font-size: 18px;
  1154 + font-weight: 600;
  1155 + color: #1f2937;
  1156 + }
  1157 +
  1158 + .bottom-sheet-close {
  1159 + display: flex;
  1160 + align-items: center;
  1161 + justify-content: center;
  1162 + width: 32px;
  1163 + height: 32px;
  1164 + cursor: pointer;
  1165 + border-radius: 50%;
  1166 + transition: background-color 0.2s;
  1167 +
  1168 + &:hover {
  1169 + background-color: #f3f4f6;
  1170 + }
  1171 +
  1172 + &:active {
  1173 + background-color: #e5e7eb;
  1174 + }
  1175 + }
1008 } 1176 }
1009 1177
1010 - :deep(.el-dialog__body) {  
1011 - padding: 24px; 1178 + .bottom-sheet-body {
  1179 + flex: 1;
  1180 + overflow: hidden;
1012 } 1181 }
1013 -}  
1014 1182
1015 -.card-list-dialog {  
1016 - display: flex;  
1017 - flex-direction: column;  
1018 - gap: 12px;  
1019 - max-height: 400px;  
1020 - overflow-y: auto; 1183 + .card-list {
  1184 + display: flex;
  1185 + flex-direction: column;
  1186 + gap: 12px;
  1187 + max-height: calc(70vh - 160px);
  1188 + padding: 36px 24px;
  1189 + overflow-y: auto;
  1190 + -webkit-overflow-scrolling: touch;
  1191 +
  1192 + &::-webkit-scrollbar {
  1193 + width: 4px;
  1194 + }
1021 1195
1022 - .empty-card {  
1023 - padding: 40px 20px;  
1024 - color: #9ca3af;  
1025 - text-align: center;  
1026 - }  
1027 -} 1196 + &::-webkit-scrollbar-thumb {
  1197 + background-color: rgb(0 0 0 / 20%);
  1198 + border-radius: 2px;
  1199 + }
1028 1200
1029 -.card-item-dialog {  
1030 - display: flex;  
1031 - align-items: center;  
1032 - justify-content: space-between;  
1033 - padding: 16px;  
1034 - cursor: pointer;  
1035 - background: linear-gradient(135deg, #f0fdf4 0%, #d1fae5 100%);  
1036 - border: 2px solid transparent;  
1037 - border-radius: 12px;  
1038 - transition: all 0.3s ease;  
1039 -  
1040 - &:hover {  
1041 - background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);  
1042 - border-color: #10b981;  
1043 - box-shadow: 0 4px 12px rgb(16 185 129 / 20%);  
1044 - transform: translateY(-2px); 1201 + &::-webkit-scrollbar-track {
  1202 + background-color: transparent;
  1203 + }
  1204 +
  1205 + .empty-card {
  1206 + padding: 40px 20px;
  1207 + color: #9ca3af;
  1208 + text-align: center;
  1209 + }
1045 } 1210 }
1046 1211
1047 - .card-item-info {  
1048 - .card-holder {  
1049 - margin: 0 0 4px;  
1050 - font-size: 16px;  
1051 - font-weight: 600;  
1052 - color: #1f2937; 1212 + .card-item {
  1213 + display: flex;
  1214 + flex-shrink: 0;
  1215 + align-items: center;
  1216 + justify-content: space-between;
  1217 + padding: 16px;
  1218 + cursor: pointer;
  1219 + background: #fff;
  1220 + border: 2px solid #f0f0f0;
  1221 + border-radius: 12px;
  1222 + transition: all 0.3s ease;
  1223 +
  1224 + &:hover {
  1225 + background: linear-gradient(135deg, #fff9f1 0%, #ffe9d4 100%);
  1226 + border-color: #ea4200;
  1227 + box-shadow: 0 4px 12px rgb(234 66 0 / 20%);
  1228 + transform: translateY(-2px);
1053 } 1229 }
1054 1230
1055 - .card-number {  
1056 - margin: 0;  
1057 - font-family: 'Courier New', monospace;  
1058 - font-size: 13px;  
1059 - color: #6b7280; 1231 + &:active {
  1232 + background: linear-gradient(135deg, #ffe9d4 0%, #ffd9b8 100%);
  1233 + transform: translateY(0);
  1234 + }
  1235 +
  1236 + .card-item-info {
  1237 + .card-holder {
  1238 + margin: 0 0 4px;
  1239 + font-size: 16px;
  1240 + font-weight: 600;
  1241 + color: #1f2937;
  1242 + }
  1243 +
  1244 + .card-number {
  1245 + margin: 0;
  1246 + font-family: 'Courier New', monospace;
  1247 + font-size: 16px;
  1248 + color: #6b7280;
  1249 + }
  1250 + }
  1251 +
  1252 + .card-balance {
  1253 + text-align: right;
  1254 +
  1255 + .balance-label {
  1256 + margin: 0 0 4px;
  1257 + font-size: 12px;
  1258 + color: #6b7280;
  1259 + }
  1260 +
  1261 + .balance-value {
  1262 + margin: 0;
  1263 + font-size: 18px;
  1264 + font-weight: bold;
  1265 + color: #ea4200;
  1266 + }
1060 } 1267 }
1061 } 1268 }
1062 1269
1063 - .card-balance {  
1064 - text-align: right; 1270 + .bottom-sheet-footer {
  1271 + flex-shrink: 0;
  1272 + padding: 16px 24px;
  1273 + padding-bottom: calc(16px + env(safe-area-inset-bottom));
  1274 + border-top: 1px solid #f0f0f0;
1065 1275
1066 - .balance-label {  
1067 - margin: 0 0 4px;  
1068 - font-size: 12px; 1276 + .cancel-button {
  1277 + width: 100%;
  1278 + height: 44px;
  1279 + font-size: 16px;
  1280 + font-weight: 600;
1069 color: #6b7280; 1281 color: #6b7280;
1070 - } 1282 + cursor: pointer;
  1283 + background: #f3f4f6;
  1284 + border: none;
  1285 + border-radius: 8px;
  1286 + transition: all 0.2s;
  1287 +
  1288 + &:hover {
  1289 + background: #e5e7eb;
  1290 + }
1071 1291
1072 - .balance-value {  
1073 - margin: 0;  
1074 - font-size: 18px;  
1075 - font-weight: bold;  
1076 - color: #10b981; 1292 + &:active {
  1293 + transform: scale(0.98);
  1294 + }
1077 } 1295 }
1078 } 1296 }
1079 } 1297 }
1080 1298
  1299 +// 原有的card-dialog样式(用于错误提示弹窗)
  1300 +.card-dialog {
  1301 + :deep(.el-dialog__header) {
  1302 + padding: 20px 24px;
  1303 + border-bottom: 1px solid #f0f0f0;
  1304 + }
  1305 +
  1306 + :deep(.el-dialog__title) {
  1307 + font-size: 18px;
  1308 + font-weight: 600;
  1309 + color: #1f2937;
  1310 + }
  1311 +
  1312 + :deep(.el-dialog__body) {
  1313 + padding: 24px;
  1314 + }
  1315 +}
  1316 +
1081 // 成功对话框 1317 // 成功对话框
1082 .success-dialog { 1318 .success-dialog {
1083 :deep(.el-dialog__body) { 1319 :deep(.el-dialog__body) {
apps/web-payment/src/views/payment/paySuccess.vue
@@ -16,7 +16,9 @@ const init = async () =&gt; { @@ -16,7 +16,9 @@ const init = async () =&gt; {
16 }; 16 };
17 17
18 const handleBack = () => { 18 const handleBack = () => {
19 - if ( 19 + if (queryData.value.redirectUrl) {
  20 + window.location.href = queryData.value.redirectUrl;
  21 + } else if (
20 typeof jWeixin !== 'undefined' && 22 typeof jWeixin !== 'undefined' &&
21 jWeixin.miniProgram && 23 jWeixin.miniProgram &&
22 detector.value?.env.isMiniProgram 24 detector.value?.env.isMiniProgram
@@ -25,6 +27,15 @@ const handleBack = () =&gt; { @@ -25,6 +27,15 @@ const handleBack = () =&gt; {
25 url: `/pages/newhome/newhome`, 27 url: `/pages/newhome/newhome`,
26 }); 28 });
27 } 29 }
  30 + // if (
  31 + // typeof jWeixin !== 'undefined' &&
  32 + // jWeixin.miniProgram &&
  33 + // detector.value?.env.isMiniProgram
  34 + // ) {
  35 + // jWeixin.miniProgram.switchTab({
  36 + // url: `/pages/newhome/newhome`,
  37 + // });
  38 + // }
28 }; 39 };
29 40
30 onMounted(() => { 41 onMounted(() => {
@@ -35,7 +46,6 @@ onMounted(() =&gt; { @@ -35,7 +46,6 @@ onMounted(() =&gt; {
35 46
36 <template> 47 <template>
37 <div class="cashier-container" v-loading="loadLoading"> 48 <div class="cashier-container" v-loading="loadLoading">
38 - {{ detector?.env }}  
39 <!-- 正常支付界面 --> 49 <!-- 正常支付界面 -->
40 <div class="cashier-wrapper"> 50 <div class="cashier-wrapper">
41 <div class="pt-[40px]"> 51 <div class="pt-[40px]">
@@ -52,6 +62,12 @@ onMounted(() =&gt; { @@ -52,6 +62,12 @@ onMounted(() =&gt; {
52 <div>支付金额</div> 62 <div>支付金额</div>
53 <div>{{ queryData?.amount }} 元</div> 63 <div>{{ queryData?.amount }} 元</div>
54 </div> 64 </div>
  65 + <div class="flex justify-between">
  66 + <div>收款方</div>
  67 + <div class="w-[70%] break-words">
  68 + {{ queryData?.payee }}
  69 + </div>
  70 + </div>
55 <div class="mt-10 flex justify-between"> 71 <div class="mt-10 flex justify-between">
56 <ElButton 72 <ElButton
57 class="pay-button" 73 class="pay-button"
apps/web-payment/vite.config.mts
@@ -6,6 +6,7 @@ export default defineConfig(async () =&gt; { @@ -6,6 +6,7 @@ export default defineConfig(async () =&gt; {
6 return { 6 return {
7 application: {}, 7 application: {},
8 vite: { 8 vite: {
  9 + base: '/pages/',
9 plugins: [ 10 plugins: [
10 ElementPlus({ 11 ElementPlus({
11 format: 'esm', 12 format: 'esm',
@@ -17,7 +18,7 @@ export default defineConfig(async () =&gt; { @@ -17,7 +18,7 @@ export default defineConfig(async () =&gt; {
17 changeOrigin: true, 18 changeOrigin: true,
18 rewrite: (path) => path.replace(/^\/api/, ''), 19 rewrite: (path) => path.replace(/^\/api/, ''),
19 // mock代理目标地址 20 // mock代理目标地址
20 - target: 'http://10.28.3.34:8686', 21 + target: 'http://cashier.test.gszdtop.com',
21 ws: true, 22 ws: true,
22 }, 23 },
23 }, 24 },