You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
240 lines
7.6 KiB
240 lines
7.6 KiB
<template>
|
|
<q-layout
|
|
view="hhh lpr lff"
|
|
:style="{
|
|
'min-width': $gc.theme.minWidth + 'px',
|
|
'background-image': 'url(' + $gc.theme.login.bgImage + ')',
|
|
'background-position': 'center center',
|
|
'background-repeat': 'no-repeat',
|
|
'background-size': 'cover',
|
|
'background-attachment': 'fixed',
|
|
}"
|
|
>
|
|
<q-header>
|
|
<q-toolbar
|
|
:style="{
|
|
'min-width': $gc.theme.minWidth + 'px',
|
|
height: $gc.theme.topper.height + 'px',
|
|
color: $gc.theme.topper.color,
|
|
'background-color': $gc.theme.topper.bgColor,
|
|
}"
|
|
>
|
|
<!-- logo icon -->
|
|
<q-img
|
|
:src="$gc.theme.topper.logo"
|
|
:width="$gc.theme.topper.logoWidth + 'px'"
|
|
:height="$gc.theme.topper.logoHeight + 'px'"
|
|
:style="{
|
|
'min-width': $gc.theme.topper.logoWidth + 'px',
|
|
}"
|
|
/>
|
|
|
|
<!-- application name-->
|
|
<div
|
|
v-if="$gc.theme.topper.showTitle"
|
|
class="q-px-md text-h5"
|
|
:style="{
|
|
color: $gc.theme.topper.titleColor,
|
|
overflow: 'hidden',
|
|
'text-overflow': 'ellipsis',
|
|
'white-space': 'nowrap',
|
|
}"
|
|
>
|
|
{{ $t('application.title') }}
|
|
</div>
|
|
|
|
<!-- space -->
|
|
<q-space />
|
|
|
|
<!-- profile dropdown action-->
|
|
<q-btn stretch flat no-caps stack inline :title="$t('language')">
|
|
<div class="row items-center">
|
|
<q-icon left name="language" size="md" />
|
|
<div class="text-left">{{ $t('language') }}</div>
|
|
</div>
|
|
<q-menu>
|
|
<q-list>
|
|
<q-item v-for="lang in $gc.setting.i18n.availableLocales" :key="lang" v-close-popup clickable @click="changeLanguage(lang)">
|
|
<q-item-section>
|
|
<q-item-label>
|
|
{{ $t('language.' + lang) }}
|
|
</q-item-label>
|
|
</q-item-section>
|
|
</q-item>
|
|
</q-list>
|
|
</q-menu>
|
|
</q-btn>
|
|
</q-toolbar>
|
|
</q-header>
|
|
|
|
<q-page-container>
|
|
<div>
|
|
<div style="height: 100px"></div>
|
|
<div class="row">
|
|
<div class="col-xs-1 col-sm-5 col-md-7"></div>
|
|
<div class="col-xs-10 col-sm-6 col-md-4">
|
|
<q-form :action="gc.webContextPath + 'login'" method="post" @reset="loginFormReset" @submit.prevent="loginFormSubmit">
|
|
<q-card>
|
|
<q-item>
|
|
<q-item-section avatar>
|
|
<q-icon name="verified_user" size="50px" color="primary"> </q-icon>
|
|
</q-item-section>
|
|
|
|
<q-item-section>
|
|
<q-item-label class="text-h6">{{ $t('security.login.title') }}</q-item-label>
|
|
</q-item-section>
|
|
</q-item>
|
|
|
|
<q-separator />
|
|
|
|
<q-card-section v-if="$gc.loginError" class="q-px-lg">
|
|
<div class="row">
|
|
<div class="col-2 row justify-center items-center">
|
|
<q-icon name="warning" size="lg" color="negative" />
|
|
</div>
|
|
<div class="col-10 text-negative text-subtitle2 row justify-start items-center">
|
|
{{ $t('security.login.message.error') }}
|
|
</div>
|
|
</div>
|
|
</q-card-section>
|
|
|
|
<q-card-section class="q-px-lg">
|
|
<q-input
|
|
v-model="username"
|
|
name="username"
|
|
outlined
|
|
:label="$t('security.login.username.placeholder')"
|
|
autofocus
|
|
clearable
|
|
tabindex="1"
|
|
hint=""
|
|
lazy-rules
|
|
:rules="[(val: any) => (val && val.length > 0) || '']"
|
|
>
|
|
<template #before>
|
|
<q-icon name="account_circle" size="40px" color="secondary" />
|
|
</template>
|
|
</q-input>
|
|
<q-input
|
|
v-model="password"
|
|
name="password"
|
|
:type="isPassword ? 'password' : 'text'"
|
|
autocomplete="false"
|
|
outlined
|
|
:label="$t('security.login.password.placeholder')"
|
|
clearable
|
|
tabindex="2"
|
|
lazy-rules
|
|
:rules="[(val: any) => (val && val.length > 0) || '']"
|
|
>
|
|
<template #before>
|
|
<q-icon name="key" size="40px" color="secondary" />
|
|
</template>
|
|
<template #append>
|
|
<q-icon :name="isPassword ? 'visibility_off' : 'visibility'" class="cursor-pointer" @click="isPassword = !isPassword" />
|
|
</template>
|
|
</q-input>
|
|
</q-card-section>
|
|
|
|
<q-card-actions align="right" class="q-px-lg">
|
|
<div class="q-gutter-md">
|
|
<q-btn type="submit" :label="$t('login')" no-caps rounded color="primary" tabindex="3" style="width: 100px"> </q-btn>
|
|
<q-btn type="reset" :label="$t('reset')" no-caps rounded color="secondary" tabindex="4" style="width: 100px"></q-btn>
|
|
</div>
|
|
</q-card-actions>
|
|
|
|
<q-card-actions align="right" class="q-px-md"> </q-card-actions>
|
|
</q-card>
|
|
</q-form>
|
|
</div>
|
|
<div class="col-1"></div>
|
|
</div>
|
|
</div>
|
|
</q-page-container>
|
|
|
|
<q-footer v-if="$gc.theme.footer.show">
|
|
<div
|
|
class="row justify-center items-center"
|
|
:style="{
|
|
height: $gc.theme.footer.height + 'px',
|
|
color: $gc.theme.footer.color,
|
|
'background-color': $gc.theme.footer.bgColor,
|
|
}"
|
|
>
|
|
<div>{{ $t('application.copyright') }}</div>
|
|
</div>
|
|
</q-footer>
|
|
</q-layout>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import { ref, nextTick } from 'vue';
|
|
import { useQuasar, dom } from 'quasar';
|
|
import { gc, i18n } from './plugin';
|
|
|
|
const quasar = useQuasar();
|
|
const { ready } = dom;
|
|
|
|
const username = ref('');
|
|
const password = ref('');
|
|
const isPassword = ref(true);
|
|
|
|
const changeLanguage = (locale) => {
|
|
i18n.global.locale.value = locale;
|
|
setTitile(i18n.global.t('application.title'));
|
|
};
|
|
|
|
const loginFormReset = () => {
|
|
username.value = '';
|
|
password.value = '';
|
|
};
|
|
|
|
const loginFormSubmit = (event) => {
|
|
if (gc.theme.login.encodePassword) {
|
|
password.value = encodeBase64(password.value);
|
|
nextTick(() => {
|
|
event.target.submit();
|
|
});
|
|
} else {
|
|
event.target.submit();
|
|
}
|
|
};
|
|
|
|
const encodeBase64 = (text: string): string => {
|
|
return '{BASE64}' + window.btoa(encodeURIComponent(text));
|
|
};
|
|
|
|
/**
|
|
* 设置页面标题
|
|
* @param title 页面标题
|
|
*/
|
|
const setTitile = (title) => {
|
|
if (title) {
|
|
document.title = title;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 设置页面 icon
|
|
* @param iconUrl 页面 icon url 地址
|
|
*/
|
|
const setFavicon = (favicon) => {
|
|
if (favicon) {
|
|
let faviconElement: HTMLLinkElement = document.querySelector("link[rel*='icon']") as HTMLLinkElement;
|
|
if (faviconElement) {
|
|
console.log(faviconElement.href);
|
|
faviconElement.href = favicon;
|
|
} else {
|
|
faviconElement = document.createElement('link');
|
|
faviconElement.rel = 'shortcut icon';
|
|
faviconElement.href = favicon;
|
|
document.getElementsByTagName('head')[0].appendChild(faviconElement);
|
|
}
|
|
}
|
|
};
|
|
|
|
ready(function () {
|
|
setTitile(i18n.global.t('application.title'));
|
|
setFavicon(gc.theme.favicon);
|
|
quasar?.dark?.set(gc.theme.dark);
|
|
});
|
|
</script>
|
|
|