583 lines
20 KiB
Vue
583 lines
20 KiB
Vue
<template>
|
|
<div class="w-full flex flex-col" :class="{ 'login-form--desktop': variant === 'desktop' }">
|
|
<div
|
|
v-if="variant !== 'desktop' && hasCustomLoginLogoLayout()"
|
|
class="flex flex-col items-center mb-[60px]"
|
|
>
|
|
<img
|
|
:src="getProjectLoginLogo(config.config?.avatar)"
|
|
alt=""
|
|
class="z-100 self-center w-56 h-auto object-contain"
|
|
>
|
|
<div
|
|
v-if="getProjectLoginTaglineLines()"
|
|
class="text-center text-sm text-primary font-medium mt-3 px-2 leading-7 max-w-[18rem]"
|
|
>
|
|
<div v-for="(line, index) in getProjectLoginTaglineLines()" :key="index">
|
|
{{ line }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<img
|
|
v-else-if="variant !== 'desktop'"
|
|
:src="getProjectLoginLogo(config.config?.avatar)"
|
|
alt=""
|
|
:class="[
|
|
'z-100 self-center w-36',
|
|
config.config?.name === 'garoosi'
|
|
? 'h-auto object-contain'
|
|
: 'rounded aspect-square',
|
|
]"
|
|
style="margin-bottom: 60px"
|
|
>
|
|
|
|
<!-- <div class="font-bold text-center text-xl">{{ URLUserType() === 'single' ? 'ورود' : 'ورود همکار' }}</div>-->
|
|
<!-- <div v-if="URLUserType() === 'single'" class="font-bold text-center text-xl">ورود</div>-->
|
|
<!-- <div v-else class="font-bold text-center text-xl">ورود همکار</div>-->
|
|
<a-form
|
|
ref="formRef"
|
|
:model="userFormState"
|
|
:layout="variant === 'desktop' ? 'vertical' : 'horizontal'"
|
|
:class="variant === 'desktop' ? 'dauth-form' : '!mt-5'"
|
|
name="basic"
|
|
@finish="phoneVerification"
|
|
>
|
|
<div v-if="variant === 'desktop'" class="dauth-toggle">
|
|
<button
|
|
type="button"
|
|
class="dauth-toggle__btn"
|
|
:class="{ 'dauth-toggle__btn--active': isSMS }"
|
|
@click="setIsSMS(true)"
|
|
>
|
|
ورود با پیامک
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="dauth-toggle__btn"
|
|
:class="{ 'dauth-toggle__btn--active': !isSMS }"
|
|
@click="setIsSMS(false)"
|
|
>
|
|
ورود با کلمه عبور
|
|
</button>
|
|
</div>
|
|
<div
|
|
v-else
|
|
class="flex justify-evenly w-full px-2 h-11 items-center bg-gray-50 relative rounded mb-5"
|
|
>
|
|
<div
|
|
:class="isSMS ? 'text-primary' : 'text-gray-400'"
|
|
class="w-full text-center z-2"
|
|
@click.stop="setIsSMS(true)"
|
|
>
|
|
ورود با پیامک
|
|
</div>
|
|
<div
|
|
:class="!isSMS ? 'text-primary' : 'text-gray-400'"
|
|
class="w-full text-center z-2"
|
|
@click.stop="setIsSMS(false)"
|
|
>
|
|
ورود با کلمه عبور
|
|
</div>
|
|
<div ref="bganim" :style="useStyle()" class="absolute bg-white h-8 w-1/2 rounded-lg animate right" />
|
|
</div>
|
|
|
|
<!-- <transition name="fade" mode="out-in">-->
|
|
<a-form-item
|
|
v-if="!stepTwoVerify"
|
|
:rules="[required('شماره تلفن'), mobileValidation('شماره تلفن')]"
|
|
:validate-trigger="['change', 'blur']"
|
|
class="home_appear_fade_in_down"
|
|
label="شماره تلفن"
|
|
name="mobile"
|
|
>
|
|
<BasicInput
|
|
v-model:value="userFormState.mobile"
|
|
place-holder="شماره تلفن"
|
|
size="large"
|
|
inputmode="numeric"
|
|
type="tel"
|
|
/>
|
|
</a-form-item>
|
|
<!-- </transition>-->
|
|
<!-- <transition name="fade" mode="out-in">-->
|
|
<a-form-item v-if="!isSMS" :rules="[required('کلمه عبور')]" class="home_appear_fade_in_down" label="کلمه عبور"
|
|
name="password">
|
|
<!-- <BasicInput v-model:value="userFormState.password" size="large" place-holder="کلمه عبور"/>-->
|
|
<AInputPassword v-model:value="userFormState.password" place-holder="کلمه عبور" size="large"/>
|
|
</a-form-item>
|
|
<div v-else-if="!stepTwoVerify" :class="variant === 'desktop' ? 'h-0' : 'h-[90px]'" />
|
|
<div v-else>
|
|
<AFormItem
|
|
:rules="[
|
|
{ required: true, message: 'کد ارسال شده را وارد نمایید' },
|
|
{ min: 4, max: 4, message: 'کد ارسال شده را وارد نمایید' },
|
|
]"
|
|
class="error-token"
|
|
name="token"
|
|
>
|
|
<OtpInput
|
|
ref="refOtpInput"
|
|
:is-input-num="true"
|
|
:num-inputs="4"
|
|
:should-auto-focus="true"
|
|
autocomplete="one-time-code"
|
|
:class="variant === 'desktop' ? 'dauth-otp justify-center' : 'mt-5 justify-center'"
|
|
input-classes="otp-input"
|
|
separator=""
|
|
style="direction: ltr"
|
|
value=""
|
|
@on-change="handleOnChange"
|
|
@on-complete="handleOnComplete"
|
|
/>
|
|
</AFormItem>
|
|
|
|
<div
|
|
v-if="variant === 'desktop'"
|
|
class="dauth-phone-edit"
|
|
>
|
|
<span class="dauth-phone-edit__number">{{ userFormState.mobile }}</span>
|
|
<button type="button" class="dauth-phone-edit__btn" @click="stepTwoVerify = false">
|
|
<span>ویرایش شماره</span>
|
|
<BasicIcon icon="vuesax-linear:edit" size="16" />
|
|
</button>
|
|
</div>
|
|
<div v-else class="flex items-center my-[23px] justify-center">
|
|
<span class="text-gray-400 mt-1">{{ userFormState.mobile }}</span>
|
|
<div class="flex items-center text-gray-700 mr-2" @click="stepTwoVerify = false">
|
|
<span class="ml-1">ویرایش شماره</span>
|
|
<BasicIcon icon="vuesax-linear:edit" size="20" />
|
|
</div>
|
|
</div>
|
|
|
|
<div :class="variant === 'desktop' ? 'dauth-resend' : 'mb-2 w-full'">
|
|
<AButton :disabled="!enableSendAgainCode" class="w-full" type="dashed" @click="reSendCode">
|
|
<div v-if="!enableSendAgainCode" class="flex w-full justify-center">
|
|
<span>ارسال مجدد کد در </span>
|
|
<span class="text-primary mx-1">{{ time }}</span>
|
|
<span> دیگر </span>
|
|
</div>
|
|
<div v-else>
|
|
ارسال مجدد کد تایید
|
|
</div>
|
|
</AButton>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- </transition>-->
|
|
|
|
<div v-if="variant === 'desktop'" class="dauth-actions">
|
|
<BasicButton
|
|
:disabled="loading"
|
|
class="w-full dauth-actions__submit"
|
|
html-type="submit"
|
|
type="primary"
|
|
>
|
|
<a-spin v-if="loading" size="small" />
|
|
<span v-else>{{ !isSMS ? 'ورود' : stepTwoVerify ? 'ورود' : 'ارسال کد' }}</span>
|
|
</BasicButton>
|
|
|
|
<BasicButton
|
|
v-if="getToken() && userStore.userInfo?.finger_print"
|
|
:disabled="loading"
|
|
class="w-full"
|
|
@click="enterFingerPrint"
|
|
>
|
|
ورود با اثر انگشت
|
|
</BasicButton>
|
|
|
|
<template v-if="config.config?.name === 'garoosi'">
|
|
<div v-if="!isTWA()" class="dauth-actions-row">
|
|
<a
|
|
class="dauth-link-btn dauth-link-btn--primary"
|
|
download="Garoosi.apk"
|
|
href="https://garoosigholaktala.ir/apk/Garoosi.apk"
|
|
>
|
|
دانلود اپ اندروید
|
|
</a>
|
|
<button type="button" class="dauth-link-btn" @click="installWebApp">
|
|
نصب نسخه وب اپ
|
|
</button>
|
|
</div>
|
|
<button type="button" class="dauth-link-btn" @click="goToEducate">
|
|
آموزش کار با نرم افزار
|
|
</button>
|
|
<button type="button" class="dauth-link-btn" @click="goToAboutUs">
|
|
درباره ما
|
|
</button>
|
|
</template>
|
|
<div v-else-if="!isTWA() && !!setting.getSettingByKey('apk_download_link')" class="mt-1">
|
|
<a
|
|
class="dauth-link-btn dauth-link-btn--primary !hover:text-primary "
|
|
:href="setting.getSettingByKey('apk_download_link')"
|
|
>
|
|
دانلود اپ اندروید
|
|
</a>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div
|
|
v-if="isRegister && variant === 'desktop'"
|
|
class="dauth-switch"
|
|
>
|
|
<span>حساب کاربری ندارید؟</span>
|
|
<button type="button" class="dauth-switch__link" @click="$emit('register', true)">
|
|
ثبت نام کنید
|
|
</button>
|
|
</div>
|
|
|
|
<a-form-item v-if="variant !== 'desktop'">
|
|
<BasicButton
|
|
:disabled="loading"
|
|
class="w-full py-2"
|
|
html-type="submit"
|
|
type="primary"
|
|
>
|
|
<div>
|
|
<a-spin v-if="loading" size="small" />
|
|
<div v-else>{{ !isSMS ? 'ورود' : stepTwoVerify ? 'ورود' : 'ارسال کد' }}</div>
|
|
</div>
|
|
</BasicButton>
|
|
<BasicButton
|
|
v-if="getToken() && userStore.userInfo?.finger_print"
|
|
:disabled="loading"
|
|
class=" w-full py-2 mt-2"
|
|
@click="enterFingerPrint"
|
|
>
|
|
<div>
|
|
ورود با اثر انگشت
|
|
</div>
|
|
</BasicButton>
|
|
|
|
<template v-if="config.config?.name === 'garoosi'">
|
|
<div v-if="!isTWA()" class="flex w-full gap-2 mt-2">
|
|
<a
|
|
class="flex w-full items-center justify-center rounded py-2 text-white bg-primary border-none cursor-pointer no-underline"
|
|
download="Garoosi.apk"
|
|
href="https://garoosigholaktala.ir/apk/Garoosi.apk"
|
|
>
|
|
<div>دانلود اپ اندروید</div>
|
|
</a>
|
|
<BasicButton type="primary" class="w-full" @click="installWebApp">
|
|
<div>نصب نسخه وب اپ</div>
|
|
</BasicButton>
|
|
</div>
|
|
<BasicButton class="w-full !font-bold mt-2" @click="goToEducate">
|
|
<div class="flex gap-2 items-center">آموزش کار با نرم افزار</div>
|
|
</BasicButton>
|
|
<BasicButton class="mt-2 w-full" icon="" iconSize="18" @click="goToAboutUs">
|
|
<div class="flex">
|
|
<div>درباره ما</div>
|
|
</div>
|
|
</BasicButton>
|
|
</template>
|
|
<div v-else-if="!isTWA() && !!setting.getSettingByKey('apk_download_link')" class=" mt-1">
|
|
<a
|
|
class="dauth-link-btn dauth-link-btn--primary !hover:text-primary "
|
|
:href="setting.getSettingByKey('apk_download_link')"
|
|
>
|
|
دانلود اپ اندروید
|
|
</a>
|
|
</div>
|
|
<div
|
|
v-if="isRegister"
|
|
class="cursor-pointer flex gap-1 justify-center mt-5 text-xs "
|
|
@click="$emit('register', true)"
|
|
>
|
|
اگر حساب کاربری ندارید
|
|
<div class="font-bold text-primary">از این قسمت</div>
|
|
ثبت نام کنید.
|
|
</div>
|
|
</a-form-item>
|
|
<!-- <BasicButton v-if="config.config.name === 'garoosi'" class="w-full !font-bold" @click="goToEducate">
|
|
<div class="flex gap-2 items-center">آموزش کار با نرم افزار</div>
|
|
</BasicButton>-->
|
|
</a-form>
|
|
|
|
<!-- <div v-if="URLUserType() === 'single'" class="fixed bottom-5 left-0 right-0 text-center">
|
|
<a class="w-full text-center"
|
|
href="https://abshode.peransagold.com/">ورود
|
|
همکار</a>
|
|
</div>-->
|
|
<BasicActionSheet
|
|
v-model:show="showPWAInstallGuide"
|
|
:showButton="false"
|
|
@close="showPWAInstallGuide = false"
|
|
>
|
|
<div class="px-4 py-2">
|
|
<h2 class="text-md font-bold text-center mb-6 text-gray-800">
|
|
وب اپلیکیشن گروسی را به صفحه اصلی خود اضافه کنید.
|
|
</h2>
|
|
|
|
<div class="space-y-6 mb-6">
|
|
<div class="flex items-center gap-4">
|
|
<div class="flex-shrink-0 w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center p-2">
|
|
<img :src="shareAppleIcon" alt="Share" class="w-full h-full object-contain"/>
|
|
</div>
|
|
<div class="flex-1">
|
|
<p class="text-sm text-gray-700 leading-relaxed">
|
|
روی دکمه Share در نوار پایین کلیک کنید.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-4">
|
|
<div class="flex-shrink-0 w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center p-2">
|
|
<img :src="addToHomeScreenIcon" alt="Add to Home Screen" class="w-full h-full object-contain"/>
|
|
</div>
|
|
<div class="flex-1">
|
|
<p class="text-sm text-gray-700 leading-relaxed">
|
|
در منوی باز شده در قسمت پایین گزینه Add to Home Screen را انتخاب کنید.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-4">
|
|
<div class="flex-shrink-0 w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
|
|
<span class="text-blue-600 font-bold text-lg">Add</span>
|
|
</div>
|
|
<div class="flex-1">
|
|
<p class="text-sm text-gray-700 leading-relaxed">
|
|
در مرحله آخر در قسمت بالا روی Add کلیک کنید.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<BasicButton
|
|
class="w-full buttonLogin mt-4"
|
|
type="primary"
|
|
@click="proceedWithInstall"
|
|
>
|
|
متوجه شدم
|
|
</BasicButton>
|
|
</div>
|
|
</BasicActionSheet>
|
|
</div>
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
import { mobileValidation, required } from '@/utils/inputRules'
|
|
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
|
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
|
import { authenticateWithFingerprint, getToken, loading, removeToken, setToken, URLUserType } from '@/utils'
|
|
import {computed, reactive, ref, inject, unref} from 'vue'
|
|
import OtpInput from 'vue3-otp-input'
|
|
import type { Login } from '@/models/login'
|
|
import type { FormInstance } from 'ant-design-vue'
|
|
import { message } from 'ant-design-vue'
|
|
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
|
import useCountdownTimer from '@/utils/useCountdownTimer'
|
|
import { loginCustomer, verifyToken } from '@/api/login'
|
|
import router from '@/router'
|
|
import { useUserStore } from '@/store/userStore'
|
|
import { useWalletStore } from '@/store/walletStore'
|
|
import { useSettingsStore } from '@/store/settingsStore'
|
|
import { syncPriceRealtimeChannel } from '@/utils/priceSocket'
|
|
import { setTruth } from '@/app/authBoot'
|
|
import { completeLoginNavigation } from '@/layouts/composables/useMobileScrollReset'
|
|
import {useConfigStore} from "@/store/configStore";
|
|
import {
|
|
getConfigApp,
|
|
getProjectLoginLogo,
|
|
getProjectLoginTaglineLines,
|
|
hasCustomLoginLogoLayout,
|
|
isTWA
|
|
} from "@/utils/config";
|
|
import BasicActionSheet from "@/components/BasicPacks/BasicActionSheet.vue";
|
|
import {getConfig} from "@/api/config";
|
|
import shareAppleIcon from '@/assets/img/share-apple.png'
|
|
import addToHomeScreenIcon from '@/assets/img/Add-to-homeScreen.png'
|
|
import {getProducts} from "@/api/products";
|
|
import {getSettings} from "@/api/configuration";
|
|
import { LOGIN_PAGE_CONTEXT_KEY } from '../composables/useLoginPage'
|
|
|
|
withDefaults(
|
|
defineProps<{
|
|
variant?: 'mobile' | 'desktop'
|
|
}>(),
|
|
{ variant: 'mobile' },
|
|
)
|
|
|
|
defineEmits<{
|
|
register: [val: boolean]
|
|
}>()
|
|
|
|
const loginPageContext = inject(LOGIN_PAGE_CONTEXT_KEY, null)
|
|
const isRegister = computed(() => unref(loginPageContext?.loginForm?.isRegister) ?? false)
|
|
|
|
const config=useConfigStore()
|
|
const { time, onFinish, reset } = useCountdownTimer('00:02:00', 'mm:ss')
|
|
const enableSendAgainCode = ref<boolean>(false)
|
|
const stepTwoVerify = ref<boolean>(false)
|
|
const formRef = ref<FormInstance>()
|
|
const userStore = useUserStore()
|
|
const walletStore = useWalletStore()
|
|
const setting=useSettingsStore()
|
|
const data = reactive(['ورود با پیامک', 'ورود با کلمه عبور'])
|
|
const value = ref(data[0])
|
|
const refOtpInput = ref<InstanceType<typeof OtpInput> | null>(null)
|
|
|
|
const userFormState = reactive<Login>({
|
|
provider: 'customer'
|
|
})
|
|
|
|
//time
|
|
onFinish(() => {
|
|
enableSendAgainCode.value = true
|
|
})
|
|
|
|
async function reSendCode() {
|
|
userFormState.token = undefined
|
|
// refOtpInput.value?.clearInput()
|
|
enableSendAgainCode.value = false
|
|
await loginCustomer(userFormState)
|
|
reset()
|
|
}
|
|
|
|
const isSMS = ref<boolean>(true)
|
|
|
|
function setIsSMS(val: boolean) {
|
|
isSMS.value = val
|
|
if (!val) stepTwoVerify.value = false
|
|
userFormState.token = ''
|
|
userFormState.password = ''
|
|
// console.log(bganim.value.classList)
|
|
// bganim?.value?.classList.add(val?'right':'left')
|
|
// bganim?.value?.style.transform = `translateX(${val ? '0' : '-100'});`
|
|
// bganim?.value?.style.animationDirection = val? 'normal':'reverse'
|
|
// val? bganim?.value?.classList?.add("move") : bganim?.value?.classList?.remove("move")
|
|
// const el = bganim.value?.
|
|
// el.
|
|
}
|
|
|
|
async function enterFingerPrint() {
|
|
const fingerPrint = await authenticateWithFingerprint()
|
|
if (fingerPrint) {
|
|
setTruth()
|
|
await router.push({ name: 'home' })
|
|
} else {
|
|
message.error('خطا در اعتبارسنجی')
|
|
}
|
|
}
|
|
|
|
function useStyle() {
|
|
if (isSMS.value) return 'right: 2%;'
|
|
// if (isDeposit.value) return 'animation-direction: normal'
|
|
// else return 'animation-direction: reverse'
|
|
else return ' right: 98%; transform: translate(100%, 0);'
|
|
}
|
|
|
|
function handleOnChange(value: string) {
|
|
userFormState.token = value
|
|
// formRef.value?.validateFields()
|
|
}
|
|
|
|
async function handleOnComplete(value: string) {
|
|
userFormState.token = value
|
|
phoneVerification()
|
|
}
|
|
|
|
async function login(accessToken: string | undefined) {
|
|
setToken(accessToken)
|
|
syncPriceRealtimeChannel((key) => setting.getSettingByKey(key))
|
|
await userStore.getMyInfo()
|
|
// console.log(URLUserType())
|
|
// console.log(userStore.userInfo?.type)
|
|
/* if (userStore.userInfo?.type === (URLUserType() === 'customer' ? 1 : 2)) {*/
|
|
await walletStore.getMyWallet()
|
|
setTruth()
|
|
await completeLoginNavigation()
|
|
/* } else {
|
|
removeToken()
|
|
userStore.removeInformation()
|
|
message.error('شما مجوز ورود به این بخش را ندارید')
|
|
}*/
|
|
}
|
|
|
|
function phoneVerification() {
|
|
formRef.value?.validateFields().then(async () => {
|
|
try {
|
|
loading.value = true
|
|
if (isSMS.value) {
|
|
if (!stepTwoVerify.value) {
|
|
userFormState.token = undefined
|
|
userFormState.password = undefined
|
|
userFormState.provider = 'customer'
|
|
const { id } = await loginCustomer(userFormState)
|
|
userFormState.id = id
|
|
stepTwoVerify.value = true
|
|
getcode()
|
|
reset()
|
|
} else {
|
|
const { access_token } = await verifyToken(userFormState)
|
|
await login(access_token)
|
|
}
|
|
} else {
|
|
userFormState.token = undefined
|
|
const { access_token } = await loginCustomer(userFormState)
|
|
await login(access_token)
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
})
|
|
}
|
|
const getcode=()=>{
|
|
if ('OTPCredential' in window) {
|
|
console.log('run')
|
|
const ac = new AbortController();
|
|
navigator.credentials
|
|
.get({
|
|
otp: { transport: ['sms'] },
|
|
signal: ac.signal,
|
|
})
|
|
.then((otp) => {
|
|
console.log('otp recived');
|
|
userFormState.token = otp?.code;
|
|
refOtpInput.value.fillInput(otp?.code)
|
|
phoneVerification();
|
|
ac.abort();
|
|
})
|
|
.catch((err) => {
|
|
ac.abort();
|
|
console.log(err);
|
|
});
|
|
} else {
|
|
console.log('not supported');
|
|
}
|
|
}
|
|
|
|
const goToEducate = () => {
|
|
router.push({ name: "educate" })
|
|
}
|
|
|
|
async function goToAboutUs(){
|
|
await router.push('/aboutUs')
|
|
}
|
|
|
|
const showPWAInstallGuide = ref(false)
|
|
async function installWebApp() {
|
|
showPWAInstallGuide.value = true
|
|
}
|
|
|
|
async function proceedWithInstall() {
|
|
showPWAInstallGuide.value = false
|
|
}
|
|
|
|
</script>
|
|
<style lang="less">
|
|
.animate.right {
|
|
right: 0;
|
|
}
|
|
|
|
.animate.right.move {
|
|
right: 100%;
|
|
transform: translate(100%, 0);
|
|
}
|
|
|
|
</style> |