style: lint格式化文件
This commit is contained in:
@ -1,98 +1,97 @@
|
||||
<template>
|
||||
<PageWrapper title="关于">
|
||||
<template #headerContent>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="flex-1">
|
||||
<a :href="GITHUB_URL" target="_blank">{{ name }}</a>
|
||||
是一个基于Vue3.0、Vite、 Ant-Design-Vue 、TypeScript
|
||||
的后台解决方案,目标是为中大型项目开发,提供现成的开箱解决方案及丰富的示例,原则上不会限制任何代码用于商用。
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<Description @register="infoRegister" class="enter-y" />
|
||||
<Description @register="register" class="my-4 enter-y" />
|
||||
<Description @register="registerDev" class="enter-y" />
|
||||
</PageWrapper>
|
||||
<PageWrapper title="关于">
|
||||
<template #headerContent>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="flex-1">
|
||||
<a :href="GITHUB_URL" target="_blank">{{ name }}</a>
|
||||
是一个基于Vue3.0、Vite、 Ant-Design-Vue 、TypeScript 的后台解决方案,目标是为中大型项目开发,提供现成的开箱解决方案及丰富的示例,原则上不会限制任何代码用于商用。
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<Description @register="infoRegister" class="enter-y" />
|
||||
<Description @register="register" class="my-4 enter-y" />
|
||||
<Description @register="registerDev" class="enter-y" />
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { h } from 'vue';
|
||||
import { Tag } from 'ant-design-vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Description, DescItem, useDescription } from '/@/components/Description/index';
|
||||
import { GITHUB_URL, SITE_URL, DOC_URL } from '/@/settings/siteSetting';
|
||||
import { h } from 'vue';
|
||||
import { Tag } from 'ant-design-vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Description, DescItem, useDescription } from '/@/components/Description/index';
|
||||
import { GITHUB_URL, SITE_URL, DOC_URL } from '/@/settings/siteSetting';
|
||||
|
||||
const { pkg, lastBuildTime } = __APP_INFO__;
|
||||
const { pkg, lastBuildTime } = __APP_INFO__;
|
||||
|
||||
const { dependencies, devDependencies, name, version } = pkg;
|
||||
const { dependencies, devDependencies, name, version } = pkg;
|
||||
|
||||
const schema: DescItem[] = [];
|
||||
const devSchema: DescItem[] = [];
|
||||
const schema: DescItem[] = [];
|
||||
const devSchema: DescItem[] = [];
|
||||
|
||||
const commonTagRender = (color: string) => (curVal) => h(Tag, { color }, () => curVal);
|
||||
const commonLinkRender = (text: string) => (href) => h('a', { href, target: '_blank' }, text);
|
||||
const commonTagRender = (color: string) => (curVal) => h(Tag, { color }, () => curVal);
|
||||
const commonLinkRender = (text: string) => (href) => h('a', { href, target: '_blank' }, text);
|
||||
|
||||
const infoSchema: DescItem[] = [
|
||||
{
|
||||
label: '版本',
|
||||
field: 'version',
|
||||
render: commonTagRender('blue'),
|
||||
},
|
||||
{
|
||||
label: '最后编译时间',
|
||||
field: 'lastBuildTime',
|
||||
render: commonTagRender('blue'),
|
||||
},
|
||||
{
|
||||
label: '文档地址',
|
||||
field: 'doc',
|
||||
render: commonLinkRender('文档地址'),
|
||||
},
|
||||
{
|
||||
label: '预览地址',
|
||||
field: 'preview',
|
||||
render: commonLinkRender('预览地址'),
|
||||
},
|
||||
{
|
||||
label: 'Github',
|
||||
field: 'github',
|
||||
render: commonLinkRender('Github'),
|
||||
},
|
||||
];
|
||||
const infoSchema: DescItem[] = [
|
||||
{
|
||||
label: '版本',
|
||||
field: 'version',
|
||||
render: commonTagRender('blue')
|
||||
},
|
||||
{
|
||||
label: '最后编译时间',
|
||||
field: 'lastBuildTime',
|
||||
render: commonTagRender('blue')
|
||||
},
|
||||
{
|
||||
label: '文档地址',
|
||||
field: 'doc',
|
||||
render: commonLinkRender('文档地址')
|
||||
},
|
||||
{
|
||||
label: '预览地址',
|
||||
field: 'preview',
|
||||
render: commonLinkRender('预览地址')
|
||||
},
|
||||
{
|
||||
label: 'Github',
|
||||
field: 'github',
|
||||
render: commonLinkRender('Github')
|
||||
}
|
||||
];
|
||||
|
||||
const infoData = {
|
||||
version,
|
||||
lastBuildTime,
|
||||
doc: DOC_URL,
|
||||
preview: SITE_URL,
|
||||
github: GITHUB_URL,
|
||||
};
|
||||
const infoData = {
|
||||
version,
|
||||
lastBuildTime,
|
||||
doc: DOC_URL,
|
||||
preview: SITE_URL,
|
||||
github: GITHUB_URL
|
||||
};
|
||||
|
||||
Object.keys(dependencies).forEach((key) => {
|
||||
schema.push({ field: key, label: key });
|
||||
});
|
||||
Object.keys(dependencies).forEach((key) => {
|
||||
schema.push({ field: key, label: key });
|
||||
});
|
||||
|
||||
Object.keys(devDependencies).forEach((key) => {
|
||||
devSchema.push({ field: key, label: key });
|
||||
});
|
||||
Object.keys(devDependencies).forEach((key) => {
|
||||
devSchema.push({ field: key, label: key });
|
||||
});
|
||||
|
||||
const [register] = useDescription({
|
||||
title: '生产环境依赖',
|
||||
data: dependencies,
|
||||
schema: schema,
|
||||
column: 3,
|
||||
});
|
||||
const [register] = useDescription({
|
||||
title: '生产环境依赖',
|
||||
data: dependencies,
|
||||
schema: schema,
|
||||
column: 3
|
||||
});
|
||||
|
||||
const [registerDev] = useDescription({
|
||||
title: '开发环境依赖',
|
||||
data: devDependencies,
|
||||
schema: devSchema,
|
||||
column: 3,
|
||||
});
|
||||
const [registerDev] = useDescription({
|
||||
title: '开发环境依赖',
|
||||
data: devDependencies,
|
||||
schema: devSchema,
|
||||
column: 3
|
||||
});
|
||||
|
||||
const [infoRegister] = useDescription({
|
||||
title: '项目信息',
|
||||
data: infoData,
|
||||
schema: infoSchema,
|
||||
column: 2,
|
||||
});
|
||||
const [infoRegister] = useDescription({
|
||||
title: '项目信息',
|
||||
data: infoData,
|
||||
schema: infoSchema,
|
||||
column: 2
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,27 +1,27 @@
|
||||
<template>
|
||||
<BasicModal :width="800" :title="t('sys.errorLog.tableActionDesc')" v-bind="$attrs">
|
||||
<Description :data="info" @register="register" />
|
||||
</BasicModal>
|
||||
<BasicModal :width="800" :title="t('sys.errorLog.tableActionDesc')" v-bind="$attrs">
|
||||
<Description :data="info" @register="register" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from 'vue';
|
||||
import type { ErrorLogInfo } from '/#/store';
|
||||
import { BasicModal } from '/@/components/Modal/index';
|
||||
import { Description, useDescription } from '/@/components/Description/index';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { getDescSchema } from './data';
|
||||
import type { PropType } from 'vue';
|
||||
import type { ErrorLogInfo } from '/#/store';
|
||||
import { BasicModal } from '/@/components/Modal/index';
|
||||
import { Description, useDescription } from '/@/components/Description/index';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { getDescSchema } from './data';
|
||||
|
||||
defineProps({
|
||||
info: {
|
||||
type: Object as PropType<ErrorLogInfo>,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
defineProps({
|
||||
info: {
|
||||
type: Object as PropType<ErrorLogInfo>,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
const [register] = useDescription({
|
||||
column: 2,
|
||||
schema: getDescSchema()!,
|
||||
});
|
||||
const [register] = useDescription({
|
||||
column: 2,
|
||||
schema: getDescSchema()!
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -6,62 +6,53 @@ import { useI18n } from '/@/hooks/web/useI18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
export function getColumns(): BasicColumn[] {
|
||||
return [
|
||||
{
|
||||
dataIndex: 'type',
|
||||
title: t('sys.errorLog.tableColumnType'),
|
||||
width: 80,
|
||||
customRender: ({ text }) => {
|
||||
const color =
|
||||
text === ErrorTypeEnum.VUE
|
||||
? 'green'
|
||||
: text === ErrorTypeEnum.RESOURCE
|
||||
? 'cyan'
|
||||
: text === ErrorTypeEnum.PROMISE
|
||||
? 'blue'
|
||||
: ErrorTypeEnum.AJAX
|
||||
? 'red'
|
||||
: 'purple';
|
||||
return <Tag color={color}>{() => text}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'url',
|
||||
title: 'URL',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
dataIndex: 'time',
|
||||
title: t('sys.errorLog.tableColumnDate'),
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
dataIndex: 'file',
|
||||
title: t('sys.errorLog.tableColumnFile'),
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: 'Name',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
dataIndex: 'message',
|
||||
title: t('sys.errorLog.tableColumnMsg'),
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
dataIndex: 'stack',
|
||||
title: t('sys.errorLog.tableColumnStackMsg'),
|
||||
},
|
||||
];
|
||||
return [
|
||||
{
|
||||
dataIndex: 'type',
|
||||
title: t('sys.errorLog.tableColumnType'),
|
||||
width: 80,
|
||||
customRender: ({ text }) => {
|
||||
const color = text === ErrorTypeEnum.VUE ? 'green' : text === ErrorTypeEnum.RESOURCE ? 'cyan' : text === ErrorTypeEnum.PROMISE ? 'blue' : ErrorTypeEnum.AJAX ? 'red' : 'purple';
|
||||
return <Tag color={color}>{() => text}</Tag>;
|
||||
}
|
||||
},
|
||||
{
|
||||
dataIndex: 'url',
|
||||
title: 'URL',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
dataIndex: 'time',
|
||||
title: t('sys.errorLog.tableColumnDate'),
|
||||
width: 160
|
||||
},
|
||||
{
|
||||
dataIndex: 'file',
|
||||
title: t('sys.errorLog.tableColumnFile'),
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: 'Name',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
dataIndex: 'message',
|
||||
title: t('sys.errorLog.tableColumnMsg'),
|
||||
width: 300
|
||||
},
|
||||
{
|
||||
dataIndex: 'stack',
|
||||
title: t('sys.errorLog.tableColumnStackMsg')
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export function getDescSchema(): any {
|
||||
return getColumns().map((column) => {
|
||||
return {
|
||||
field: column.dataIndex!,
|
||||
label: column.title,
|
||||
};
|
||||
});
|
||||
return getColumns().map((column) => {
|
||||
return {
|
||||
field: column.dataIndex!,
|
||||
label: column.title
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,92 +1,88 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<template v-for="src in imgList" :key="src">
|
||||
<img :src="src" v-show="false" />
|
||||
</template>
|
||||
<DetailModal :info="rowInfo" @register="registerModal" />
|
||||
<BasicTable @register="register" class="error-handle-table">
|
||||
<template #toolbar>
|
||||
<a-button @click="fireVueError" type="primary">
|
||||
{{ t('sys.errorLog.fireVueError') }}
|
||||
</a-button>
|
||||
<a-button @click="fireResourceError" type="primary">
|
||||
{{ t('sys.errorLog.fireResourceError') }}
|
||||
</a-button>
|
||||
<a-button @click="fireAjaxError" type="primary">
|
||||
{{ t('sys.errorLog.fireAjaxError') }}
|
||||
</a-button>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{ label: t('sys.errorLog.tableActionDesc'), onClick: handleDetail.bind(null, record) },
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<template v-for="src in imgList" :key="src">
|
||||
<img :src="src" v-show="false" />
|
||||
</template>
|
||||
<DetailModal :info="rowInfo" @register="registerModal" />
|
||||
<BasicTable @register="register" class="error-handle-table">
|
||||
<template #toolbar>
|
||||
<a-button @click="fireVueError" type="primary">
|
||||
{{ t('sys.errorLog.fireVueError') }}
|
||||
</a-button>
|
||||
<a-button @click="fireResourceError" type="primary">
|
||||
{{ t('sys.errorLog.fireResourceError') }}
|
||||
</a-button>
|
||||
<a-button @click="fireAjaxError" type="primary">
|
||||
{{ t('sys.errorLog.fireAjaxError') }}
|
||||
</a-button>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="[{ label: t('sys.errorLog.tableActionDesc'), onClick: handleDetail.bind(null, record) }]" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { ErrorLogInfo } from '/#/store';
|
||||
import { watch, ref, nextTick } from 'vue';
|
||||
import DetailModal from './DetailModal.vue';
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table/index';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useErrorLogStore } from '/@/store/modules/errorLog';
|
||||
import { fireErrorApi } from '/@/api/demo/error';
|
||||
import { getColumns } from './data';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import type { ErrorLogInfo } from '/#/store';
|
||||
import { watch, ref, nextTick } from 'vue';
|
||||
import DetailModal from './DetailModal.vue';
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table/index';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useErrorLogStore } from '/@/store/modules/errorLog';
|
||||
import { fireErrorApi } from '/@/api/demo/error';
|
||||
import { getColumns } from './data';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
const rowInfo = ref<ErrorLogInfo>();
|
||||
const imgList = ref<string[]>([]);
|
||||
const rowInfo = ref<ErrorLogInfo>();
|
||||
const imgList = ref<string[]>([]);
|
||||
|
||||
const { t } = useI18n();
|
||||
const errorLogStore = useErrorLogStore();
|
||||
const [register, { setTableData }] = useTable({
|
||||
title: t('sys.errorLog.tableTitle'),
|
||||
columns: getColumns(),
|
||||
actionColumn: {
|
||||
width: 80,
|
||||
title: 'Action',
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' },
|
||||
},
|
||||
});
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const { t } = useI18n();
|
||||
const errorLogStore = useErrorLogStore();
|
||||
const [register, { setTableData }] = useTable({
|
||||
title: t('sys.errorLog.tableTitle'),
|
||||
columns: getColumns(),
|
||||
actionColumn: {
|
||||
width: 80,
|
||||
title: 'Action',
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' }
|
||||
}
|
||||
});
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
watch(
|
||||
() => errorLogStore.getErrorLogInfoList,
|
||||
(list) => {
|
||||
nextTick(() => {
|
||||
setTableData(cloneDeep(list));
|
||||
});
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
const { createMessage } = useMessage();
|
||||
if (import.meta.env.DEV) {
|
||||
createMessage.info(t('sys.errorLog.enableMessage'));
|
||||
}
|
||||
// 查看详情
|
||||
function handleDetail(row: ErrorLogInfo) {
|
||||
rowInfo.value = row;
|
||||
openModal(true);
|
||||
}
|
||||
watch(
|
||||
() => errorLogStore.getErrorLogInfoList,
|
||||
(list) => {
|
||||
nextTick(() => {
|
||||
setTableData(cloneDeep(list));
|
||||
});
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
const { createMessage } = useMessage();
|
||||
if (import.meta.env.DEV) {
|
||||
createMessage.info(t('sys.errorLog.enableMessage'));
|
||||
}
|
||||
// 查看详情
|
||||
function handleDetail(row: ErrorLogInfo) {
|
||||
rowInfo.value = row;
|
||||
openModal(true);
|
||||
}
|
||||
|
||||
function fireVueError() {
|
||||
throw new Error('fire vue error!');
|
||||
}
|
||||
function fireVueError() {
|
||||
throw new Error('fire vue error!');
|
||||
}
|
||||
|
||||
function fireResourceError() {
|
||||
imgList.value.push(`${new Date().getTime()}.png`);
|
||||
}
|
||||
function fireResourceError() {
|
||||
imgList.value.push(`${new Date().getTime()}.png`);
|
||||
}
|
||||
|
||||
async function fireAjaxError() {
|
||||
await fireErrorApi();
|
||||
}
|
||||
async function fireAjaxError() {
|
||||
await fireErrorApi();
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,148 +1,143 @@
|
||||
<script lang="tsx">
|
||||
import type { PropType } from 'vue';
|
||||
import { Result, Button } from 'ant-design-vue';
|
||||
import { defineComponent, ref, computed, unref } from 'vue';
|
||||
import { ExceptionEnum } from '/@/enums/exceptionEnum';
|
||||
import notDataSvg from '/@/assets/svg/no-data.svg';
|
||||
import netWorkSvg from '/@/assets/svg/net-error.svg';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useGo, useRedo } from '/@/hooks/web/usePage';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
import type { PropType } from 'vue';
|
||||
import { Result, Button } from 'ant-design-vue';
|
||||
import { defineComponent, ref, computed, unref } from 'vue';
|
||||
import { ExceptionEnum } from '/@/enums/exceptionEnum';
|
||||
import notDataSvg from '/@/assets/svg/no-data.svg';
|
||||
import netWorkSvg from '/@/assets/svg/net-error.svg';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useGo, useRedo } from '/@/hooks/web/usePage';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
|
||||
interface MapValue {
|
||||
title: string;
|
||||
subTitle: string;
|
||||
btnText?: string;
|
||||
icon?: string;
|
||||
handler?: Fn;
|
||||
status?: string;
|
||||
}
|
||||
interface MapValue {
|
||||
title: string;
|
||||
subTitle: string;
|
||||
btnText?: string;
|
||||
icon?: string;
|
||||
handler?: Fn;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ErrorPage',
|
||||
props: {
|
||||
// 状态码
|
||||
status: {
|
||||
type: Number as PropType<number>,
|
||||
default: ExceptionEnum.PAGE_NOT_FOUND,
|
||||
},
|
||||
export default defineComponent({
|
||||
name: 'ErrorPage',
|
||||
props: {
|
||||
// 状态码
|
||||
status: {
|
||||
type: Number as PropType<number>,
|
||||
default: ExceptionEnum.PAGE_NOT_FOUND
|
||||
},
|
||||
|
||||
title: {
|
||||
type: String as PropType<string>,
|
||||
default: '',
|
||||
},
|
||||
title: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
},
|
||||
|
||||
subTitle: {
|
||||
type: String as PropType<string>,
|
||||
default: '',
|
||||
},
|
||||
subTitle: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
},
|
||||
|
||||
full: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const statusMapRef = ref(new Map<string | number, MapValue>());
|
||||
full: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const statusMapRef = ref(new Map<string | number, MapValue>());
|
||||
|
||||
const { query } = useRoute();
|
||||
const go = useGo();
|
||||
const redo = useRedo();
|
||||
const { t } = useI18n();
|
||||
const { prefixCls } = useDesign('app-exception-page');
|
||||
const { query } = useRoute();
|
||||
const go = useGo();
|
||||
const redo = useRedo();
|
||||
const { t } = useI18n();
|
||||
const { prefixCls } = useDesign('app-exception-page');
|
||||
|
||||
const getStatus = computed(() => {
|
||||
const { status: routeStatus } = query;
|
||||
const { status } = props;
|
||||
return Number(routeStatus) || status;
|
||||
});
|
||||
const getStatus = computed(() => {
|
||||
const { status: routeStatus } = query;
|
||||
const { status } = props;
|
||||
return Number(routeStatus) || status;
|
||||
});
|
||||
|
||||
const getMapValue = computed((): MapValue => {
|
||||
return unref(statusMapRef).get(unref(getStatus)) as MapValue;
|
||||
});
|
||||
const getMapValue = computed((): MapValue => {
|
||||
return unref(statusMapRef).get(unref(getStatus)) as MapValue;
|
||||
});
|
||||
|
||||
const backLoginI18n = t('返回登录');
|
||||
const backHomeI18n = t('返回首页');
|
||||
const backLoginI18n = t('返回登录');
|
||||
const backHomeI18n = t('返回首页');
|
||||
|
||||
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, {
|
||||
title: '403',
|
||||
status: `${ExceptionEnum.PAGE_NOT_ACCESS}`,
|
||||
subTitle: t('抱歉,您无权访问此页面。'),
|
||||
btnText: props.full ? backLoginI18n : backHomeI18n,
|
||||
handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
|
||||
});
|
||||
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, {
|
||||
title: '403',
|
||||
status: `${ExceptionEnum.PAGE_NOT_ACCESS}`,
|
||||
subTitle: t('抱歉,您无权访问此页面。'),
|
||||
btnText: props.full ? backLoginI18n : backHomeI18n,
|
||||
handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go())
|
||||
});
|
||||
|
||||
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, {
|
||||
title: '404',
|
||||
status: `${ExceptionEnum.PAGE_NOT_FOUND}`,
|
||||
subTitle: t('抱歉,您访问的页面不存在。'),
|
||||
btnText: props.full ? backLoginI18n : backHomeI18n,
|
||||
handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
|
||||
});
|
||||
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, {
|
||||
title: '404',
|
||||
status: `${ExceptionEnum.PAGE_NOT_FOUND}`,
|
||||
subTitle: t('抱歉,您访问的页面不存在。'),
|
||||
btnText: props.full ? backLoginI18n : backHomeI18n,
|
||||
handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go())
|
||||
});
|
||||
|
||||
unref(statusMapRef).set(ExceptionEnum.ERROR, {
|
||||
title: '500',
|
||||
status: `${ExceptionEnum.ERROR}`,
|
||||
subTitle: t('抱歉,服务器报告错误。'),
|
||||
btnText: backHomeI18n,
|
||||
handler: () => go(),
|
||||
});
|
||||
unref(statusMapRef).set(ExceptionEnum.ERROR, {
|
||||
title: '500',
|
||||
status: `${ExceptionEnum.ERROR}`,
|
||||
subTitle: t('抱歉,服务器报告错误。'),
|
||||
btnText: backHomeI18n,
|
||||
handler: () => go()
|
||||
});
|
||||
|
||||
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, {
|
||||
title: t('当前页无数据'),
|
||||
subTitle: '',
|
||||
btnText: t('刷新'),
|
||||
handler: () => redo(),
|
||||
icon: notDataSvg,
|
||||
});
|
||||
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, {
|
||||
title: t('当前页无数据'),
|
||||
subTitle: '',
|
||||
btnText: t('刷新'),
|
||||
handler: () => redo(),
|
||||
icon: notDataSvg
|
||||
});
|
||||
|
||||
unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, {
|
||||
title: t('网络错误'),
|
||||
subTitle: t('抱歉,您的网络连接已断开,请检查您的网络!'),
|
||||
btnText: t('刷新'),
|
||||
handler: () => redo(),
|
||||
icon: netWorkSvg,
|
||||
});
|
||||
unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, {
|
||||
title: t('网络错误'),
|
||||
subTitle: t('抱歉,您的网络连接已断开,请检查您的网络!'),
|
||||
btnText: t('刷新'),
|
||||
handler: () => redo(),
|
||||
icon: netWorkSvg
|
||||
});
|
||||
|
||||
return () => {
|
||||
const { title, subTitle, btnText, icon, handler, status } = unref(getMapValue) || {};
|
||||
return (
|
||||
<Result
|
||||
class={prefixCls}
|
||||
status={status as any}
|
||||
title={props.title || title}
|
||||
sub-title={props.subTitle || subTitle}
|
||||
>
|
||||
{{
|
||||
extra: () =>
|
||||
btnText && (
|
||||
<Button type="primary" onClick={handler}>
|
||||
{() => btnText}
|
||||
</Button>
|
||||
),
|
||||
icon: () => (icon ? <img src={icon} /> : null),
|
||||
}}
|
||||
</Result>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
return () => {
|
||||
const { title, subTitle, btnText, icon, handler, status } = unref(getMapValue) || {};
|
||||
return (
|
||||
<Result class={prefixCls} status={status as any} title={props.title || title} sub-title={props.subTitle || subTitle}>
|
||||
{{
|
||||
extra: () =>
|
||||
btnText && (
|
||||
<Button type="primary" onClick={handler}>
|
||||
{() => btnText}
|
||||
</Button>
|
||||
),
|
||||
icon: () => (icon ? <img src={icon} /> : null)
|
||||
}}
|
||||
</Result>
|
||||
);
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-app-exception-page';
|
||||
@prefix-cls: ~'@{namespace}-app-exception-page';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.ant-result-icon {
|
||||
img {
|
||||
max-width: 400px;
|
||||
max-height: 300px;
|
||||
}
|
||||
.ant-result-icon {
|
||||
img {
|
||||
max-width: 400px;
|
||||
max-height: 300px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'FrameBlank',
|
||||
});
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'FrameBlank'
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,90 +1,85 @@
|
||||
<template>
|
||||
<div :class="prefixCls" :style="getWrapStyle">
|
||||
<Spin :spinning="loading" size="large" :style="getWrapStyle">
|
||||
<iframe
|
||||
:src="frameSrc"
|
||||
:class="`${prefixCls}__main`"
|
||||
ref="frameRef"
|
||||
@load="hideLoading"
|
||||
></iframe>
|
||||
</Spin>
|
||||
</div>
|
||||
<div :class="prefixCls" :style="getWrapStyle">
|
||||
<Spin :spinning="loading" size="large" :style="getWrapStyle">
|
||||
<iframe :src="frameSrc" :class="`${prefixCls}__main`" ref="frameRef" @load="hideLoading"></iframe>
|
||||
</Spin>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { ref, unref, computed } from 'vue';
|
||||
import { Spin } from 'ant-design-vue';
|
||||
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { ref, unref, computed } from 'vue';
|
||||
import { Spin } from 'ant-design-vue';
|
||||
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLayoutHeight } from '/@/layouts/default/content/useContentViewHeight';
|
||||
|
||||
defineProps({
|
||||
frameSrc: propTypes.string.def(''),
|
||||
});
|
||||
defineProps({
|
||||
frameSrc: propTypes.string.def('')
|
||||
});
|
||||
|
||||
const loading = ref(true);
|
||||
const topRef = ref(50);
|
||||
const heightRef = ref(window.innerHeight);
|
||||
const frameRef = ref<HTMLFrameElement>();
|
||||
const { headerHeightRef } = useLayoutHeight();
|
||||
const loading = ref(true);
|
||||
const topRef = ref(50);
|
||||
const heightRef = ref(window.innerHeight);
|
||||
const frameRef = ref<HTMLFrameElement>();
|
||||
const { headerHeightRef } = useLayoutHeight();
|
||||
|
||||
const { prefixCls } = useDesign('iframe-page');
|
||||
useWindowSizeFn(calcHeight, 150, { immediate: true });
|
||||
const { prefixCls } = useDesign('iframe-page');
|
||||
useWindowSizeFn(calcHeight, 150, { immediate: true });
|
||||
|
||||
const getWrapStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
height: `${unref(heightRef)}px`,
|
||||
};
|
||||
});
|
||||
const getWrapStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
height: `${unref(heightRef)}px`
|
||||
};
|
||||
});
|
||||
|
||||
function calcHeight() {
|
||||
const iframe = unref(frameRef);
|
||||
if (!iframe) {
|
||||
return;
|
||||
function calcHeight() {
|
||||
const iframe = unref(frameRef);
|
||||
if (!iframe) {
|
||||
return;
|
||||
}
|
||||
const top = headerHeightRef.value;
|
||||
topRef.value = top;
|
||||
heightRef.value = window.innerHeight - top;
|
||||
const clientHeight = document.documentElement.clientHeight - top;
|
||||
iframe.style.height = `${clientHeight}px`;
|
||||
}
|
||||
const top = headerHeightRef.value;
|
||||
topRef.value = top;
|
||||
heightRef.value = window.innerHeight - top;
|
||||
const clientHeight = document.documentElement.clientHeight - top;
|
||||
iframe.style.height = `${clientHeight}px`;
|
||||
}
|
||||
|
||||
function hideLoading() {
|
||||
loading.value = false;
|
||||
calcHeight();
|
||||
}
|
||||
function hideLoading() {
|
||||
loading.value = false;
|
||||
calcHeight();
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-iframe-page';
|
||||
@prefix-cls: ~'@{namespace}-iframe-page';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.ant-spin-nested-loading {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
.@{prefix-cls} {
|
||||
.ant-spin-nested-loading {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
.ant-spin-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
.ant-spin-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: @component-background;
|
||||
border: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
&__mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: @component-background;
|
||||
border: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,116 +1,86 @@
|
||||
<template>
|
||||
<div
|
||||
:class="prefixCls"
|
||||
class="fixed inset-0 flex h-screen w-screen bg-black items-center justify-center"
|
||||
>
|
||||
<div
|
||||
:class="`${prefixCls}__unlock`"
|
||||
class="absolute top-0 left-1/2 flex pt-5 h-16 items-center justify-center sm:text-md xl:text-xl text-white flex-col cursor-pointer transform translate-x-1/2"
|
||||
@click="handleShowForm(false)"
|
||||
v-show="showDate"
|
||||
>
|
||||
<LockOutlined />
|
||||
<span>{{ t('解锁') }}</span>
|
||||
</div>
|
||||
<div :class="prefixCls" class="fixed inset-0 flex h-screen w-screen bg-black items-center justify-center">
|
||||
<div
|
||||
:class="`${prefixCls}__unlock`"
|
||||
class="absolute top-0 left-1/2 flex pt-5 h-16 items-center justify-center sm:text-md xl:text-xl text-white flex-col cursor-pointer transform translate-x-1/2"
|
||||
@click="handleShowForm(false)"
|
||||
v-show="showDate"
|
||||
>
|
||||
<LockOutlined />
|
||||
<span>{{ t('解锁') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col w-screen h-screen justify-center items-center">
|
||||
<!-- 第一行:logo和系统名 -->
|
||||
<div :class="`${prefixCls}__logo-row`" class="flex items-center justify-center mb-8">
|
||||
<img :src="logoConfig.menuLogoUrl || logo" width="144" style="height: 144px" />
|
||||
<div :class="`${prefixCls}__sysname-box`" class="ml-4">
|
||||
{{ sysName }}
|
||||
<div class="flex flex-col w-screen h-screen justify-center items-center">
|
||||
<!-- 第一行:logo和系统名 -->
|
||||
<div :class="`${prefixCls}__logo-row`" class="flex items-center justify-center mb-8">
|
||||
<img :src="logoConfig.menuLogoUrl || logo" width="144" style="height: 144px" />
|
||||
<div :class="`${prefixCls}__sysname-box`" class="ml-4">
|
||||
{{ sysName }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 第二行:hour和minute并排 -->
|
||||
<div class="flex items-center justify-center">
|
||||
<div :class="`${prefixCls}__hour`" class="relative mr-5 md:mr-20">
|
||||
<span>{{ hour }}</span>
|
||||
<span class="meridiem absolute left-5 top-5 text-md xl:text-xl" v-show="showDate">
|
||||
{{ meridiem }}
|
||||
</span>
|
||||
</div>
|
||||
<div :class="`${prefixCls}__minute`">
|
||||
<span> {{ minute }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 新增:lockErrorMsg 显示 -->
|
||||
<div v-if="lockErrorMsg" style="margin-top: 16px; color: #ff4d4f; font-size: 1.2rem">
|
||||
{{ lockErrorMsg }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 第二行:hour和minute并排 -->
|
||||
<div class="flex items-center justify-center">
|
||||
<div :class="`${prefixCls}__hour`" class="relative mr-5 md:mr-20">
|
||||
<span>{{ hour }}</span>
|
||||
<span class="meridiem absolute left-5 top-5 text-md xl:text-xl" v-show="showDate">
|
||||
{{ meridiem }}
|
||||
</span>
|
||||
</div>
|
||||
<div :class="`${prefixCls}__minute`">
|
||||
<span> {{ minute }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 新增:lockErrorMsg 显示 -->
|
||||
<div v-if="lockErrorMsg" style="margin-top: 16px; color: #ff4d4f; font-size: 1.2rem;">
|
||||
{{ lockErrorMsg }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<transition name="fade-slide">
|
||||
<div :class="`${prefixCls}-entry`" v-show="!showDate">
|
||||
<div :class="`${prefixCls}-entry-content`">
|
||||
<div :class="`${prefixCls}-entry__header enter-x`">
|
||||
<img :src="userinfo.avatar || headerImg" :class="`${prefixCls}-entry__header-img`" />
|
||||
<p :class="`${prefixCls}-entry__header-name`">
|
||||
{{ userinfo.name }}
|
||||
</p>
|
||||
<p :class="`${prefixCls}-entry__header-name`">
|
||||
{{ userinfo.mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') }}
|
||||
</p>
|
||||
</div>
|
||||
<template v-if="loginType === 'password'">
|
||||
<InputPassword
|
||||
:placeholder="t('登录密码')"
|
||||
class="enter-x"
|
||||
v-model:value="password"
|
||||
@pressEnter="handleLogin"
|
||||
/>
|
||||
<span :class="`${prefixCls}-entry__err-msg enter-x`" v-if="errMsg">
|
||||
{{ t('请重新登录') }}
|
||||
</span>
|
||||
</template>
|
||||
<div v-else>
|
||||
<Input v-model:value="formData.code" :placeholder="t('验证码')" class="enter-x" size="small" style="height: 58px;">
|
||||
<template #suffix>
|
||||
<Button type="link" class="f-16" @click="getLoginCode" size="small" :disabled="codeButtonDisabled">
|
||||
{{ getCodeButtonName }}
|
||||
</Button>
|
||||
</template>
|
||||
</Input>
|
||||
</div>
|
||||
<div style="margin-top: 10px">
|
||||
<a-button :style="{ 'border-radius': '8px' }" block class="sub-button" type="primary" @click="handleLogin">
|
||||
解锁
|
||||
</a-button>
|
||||
</div>
|
||||
<div :class="`${prefixCls}-entry__footer enter-x`">
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
class="mt-2 mr-2 enter-x"
|
||||
:disabled="loading"
|
||||
style="font-size: 1.2rem;"
|
||||
@click="handleShowForm(true)"
|
||||
>
|
||||
<!-- 返回锁屏界面 -->
|
||||
{{ t('取消') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
class="mt-2 mr-2 enter-x"
|
||||
:disabled="loading"
|
||||
style="font-size: 1.2rem;"
|
||||
@click="goLogin"
|
||||
>
|
||||
{{ t('返回登录界面') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
class="mt-2"
|
||||
type="link"
|
||||
size="small"
|
||||
style="font-size: 1.2rem;"
|
||||
@click="changeLoginType"
|
||||
:loading="loading">
|
||||
{{ loginType == 'sms' ? t('密码解锁') : t('短信解锁') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="back_login">
|
||||
<transition name="fade-slide">
|
||||
<div :class="`${prefixCls}-entry`" v-show="!showDate">
|
||||
<div :class="`${prefixCls}-entry-content`">
|
||||
<div :class="`${prefixCls}-entry__header enter-x`">
|
||||
<img :src="userinfo.avatar || headerImg" :class="`${prefixCls}-entry__header-img`" />
|
||||
<p :class="`${prefixCls}-entry__header-name`">
|
||||
{{ userinfo.name }}
|
||||
</p>
|
||||
<p :class="`${prefixCls}-entry__header-name`">
|
||||
{{ userinfo.mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') }}
|
||||
</p>
|
||||
</div>
|
||||
<template v-if="loginType === 'password'">
|
||||
<InputPassword :placeholder="t('登录密码')" class="enter-x" v-model:value="password" @pressEnter="handleLogin" />
|
||||
<span :class="`${prefixCls}-entry__err-msg enter-x`" v-if="errMsg">
|
||||
{{ t('请重新登录') }}
|
||||
</span>
|
||||
</template>
|
||||
<div v-else>
|
||||
<Input v-model:value="formData.code" :placeholder="t('验证码')" class="enter-x" size="small" style="height: 58px">
|
||||
<template #suffix>
|
||||
<Button type="link" class="f-16" @click="getLoginCode" size="small" :disabled="codeButtonDisabled">
|
||||
{{ getCodeButtonName }}
|
||||
</Button>
|
||||
</template>
|
||||
</Input>
|
||||
</div>
|
||||
<div style="margin-top: 10px">
|
||||
<a-button :style="{ 'border-radius': '8px' }" block class="sub-button" type="primary" @click="handleLogin"> 解锁 </a-button>
|
||||
</div>
|
||||
<div :class="`${prefixCls}-entry__footer enter-x`">
|
||||
<a-button type="link" size="small" class="mt-2 mr-2 enter-x" :disabled="loading" style="font-size: 1.2rem" @click="handleShowForm(true)">
|
||||
<!-- 返回锁屏界面 -->
|
||||
{{ t('取消') }}
|
||||
</a-button>
|
||||
<a-button type="link" size="small" class="mt-2 mr-2 enter-x" :disabled="loading" style="font-size: 1.2rem" @click="goLogin">
|
||||
{{ t('返回登录界面') }}
|
||||
</a-button>
|
||||
<a-button class="mt-2" type="link" size="small" style="font-size: 1.2rem" @click="changeLoginType" :loading="loading">
|
||||
{{ loginType == 'sms' ? t('密码解锁') : t('短信解锁') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="back_login">
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@ -121,326 +91,314 @@
|
||||
{{ t('返回登录界面') }}
|
||||
</a-button>
|
||||
</div> -->
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<div class="absolute bottom-5 w-full text-gray-300 xl:text-xl 2xl:text-3xl text-center enter-y">
|
||||
<div class="text-5xl mb-4 enter-x" v-show="!showDate">
|
||||
{{ hour }}:{{ minute }} <span class="text-3xl">{{ meridiem }}</span>
|
||||
</div>
|
||||
<div class="text-2xl">{{ year }}/{{ month }}/{{ day }} {{ week }}</div>
|
||||
</div>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
:maskClosable="false"
|
||||
centered
|
||||
title="请完成下列验证后继续"
|
||||
width="20%"
|
||||
cancelText=""
|
||||
>
|
||||
<div class="login-modal-content">
|
||||
<div class="refresh" @click="refreshTodo">
|
||||
刷新
|
||||
<a-icon :spin="refreshLoading" icon="ant-design:redo-outlined" class="redo-outlined" />
|
||||
</div>
|
||||
<a-image
|
||||
:width="200"
|
||||
:src="imgObj.imgBase64 || ''"
|
||||
/>
|
||||
<a-input v-model:value="imgCode" :placeholder="t('验证码')" size="large" />
|
||||
<div class="absolute bottom-5 w-full text-gray-300 xl:text-xl 2xl:text-3xl text-center enter-y">
|
||||
<div class="text-5xl mb-4 enter-x" v-show="!showDate">
|
||||
{{ hour }}:{{ minute }} <span class="text-3xl">{{ meridiem }}</span>
|
||||
</div>
|
||||
<div class="text-2xl">{{ year }}/{{ month }}/{{ day }} {{ week }}</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
<a-modal v-model:visible="visible" @ok="handleOk" @cancel="handleCancel" :maskClosable="false" centered title="请完成下列验证后继续" width="20%" cancelText="">
|
||||
<div class="login-modal-content">
|
||||
<div class="refresh" @click="refreshTodo">
|
||||
刷新
|
||||
<a-icon :spin="refreshLoading" icon="ant-design:redo-outlined" class="redo-outlined" />
|
||||
</div>
|
||||
<a-image :width="200" :src="imgObj.imgBase64 || ''" />
|
||||
<a-input v-model:value="imgCode" :placeholder="t('验证码')" size="large" />
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { Input } from 'ant-design-vue';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useLockStore } from '/@/store/modules/lock';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useNow } from './useNow';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { LockOutlined } from '@ant-design/icons-vue';
|
||||
import headerImg from '/@/assets/images/header.jpg';
|
||||
|
||||
import { useAppStore } from '/@/store/modules/app';
|
||||
import logo from '/@/assets/images/logo_geg.png';
|
||||
import { getMobileLoginCode, getMobileLoginImg } from '/@/api/system/login';
|
||||
import { ref, computed } from 'vue';
|
||||
import { Input } from 'ant-design-vue';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useLockStore } from '/@/store/modules/lock';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useNow } from './useNow';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { LockOutlined } from '@ant-design/icons-vue';
|
||||
import headerImg from '/@/assets/images/header.jpg';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const logoConfig = appStore.getLogoConfig;
|
||||
const sysName = ref(import.meta.env.VITE_SYSTEM_NAME);
|
||||
|
||||
const InputPassword = Input.Password;
|
||||
import { useAppStore } from '/@/store/modules/app';
|
||||
import logo from '/@/assets/images/logo_geg.png';
|
||||
import { getMobileLoginCode, getMobileLoginImg } from '/@/api/system/login';
|
||||
|
||||
const password = ref('');
|
||||
const captchaCode = ref('');
|
||||
const formData = ref({
|
||||
code: ''
|
||||
});
|
||||
const imgBase64 = ref('');
|
||||
const loginType = ref('password');
|
||||
const loading = ref(false);
|
||||
const errMsg = ref(false);
|
||||
const showDate = ref(true);
|
||||
const appStore = useAppStore();
|
||||
const logoConfig = appStore.getLogoConfig;
|
||||
const sysName = ref(import.meta.env.VITE_SYSTEM_NAME);
|
||||
|
||||
const lockErrorMsg = computed(() => lockStore.getLockInfo?.msg || '');
|
||||
const InputPassword = Input.Password;
|
||||
|
||||
const { prefixCls } = useDesign('lock-page');
|
||||
const lockStore = useLockStore();
|
||||
const userStore = useUserStore();
|
||||
const getCodeButtonName = ref('获取验证码')
|
||||
const codeButtonDisabled = ref(false)
|
||||
const countdown = ref(60)
|
||||
const visible = ref(false);
|
||||
const refreshLoading = ref(false);
|
||||
const imgCode = ref('');
|
||||
const imgObj = ref({
|
||||
imgBase64: ''
|
||||
})
|
||||
let setCodeInterval = null
|
||||
const password = ref('');
|
||||
const captchaCode = ref('');
|
||||
const formData = ref({
|
||||
code: ''
|
||||
});
|
||||
const imgBase64 = ref('');
|
||||
const loginType = ref('password');
|
||||
const loading = ref(false);
|
||||
const errMsg = ref(false);
|
||||
const showDate = ref(true);
|
||||
|
||||
const { hour, month, minute, meridiem, year, day, week } = useNow(true);
|
||||
const lockErrorMsg = computed(() => lockStore.getLockInfo?.msg || '');
|
||||
|
||||
const { t } = useI18n();
|
||||
const { prefixCls } = useDesign('lock-page');
|
||||
const lockStore = useLockStore();
|
||||
const userStore = useUserStore();
|
||||
const getCodeButtonName = ref('获取验证码');
|
||||
const codeButtonDisabled = ref(false);
|
||||
const countdown = ref(60);
|
||||
const visible = ref(false);
|
||||
const refreshLoading = ref(false);
|
||||
const imgCode = ref('');
|
||||
const imgObj = ref({
|
||||
imgBase64: ''
|
||||
});
|
||||
let setCodeInterval = null;
|
||||
|
||||
const userinfo = computed(() => {
|
||||
return userStore.getUserInfo || {};
|
||||
});
|
||||
const { hour, month, minute, meridiem, year, day, week } = useNow(true);
|
||||
|
||||
/**
|
||||
* @description: unLock
|
||||
*/
|
||||
async function unLock() {
|
||||
if (!password.value) {
|
||||
return;
|
||||
const { t } = useI18n();
|
||||
|
||||
const userinfo = computed(() => {
|
||||
return userStore.getUserInfo || {};
|
||||
});
|
||||
|
||||
/**
|
||||
* @description: unLock
|
||||
*/
|
||||
async function unLock() {
|
||||
if (!password.value) {
|
||||
return;
|
||||
}
|
||||
let pwd = password.value;
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await lockStore.unLock(pwd);
|
||||
errMsg.value = !res;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
let pwd = password.value;
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await lockStore.unLock(pwd);
|
||||
errMsg.value = !res;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
|
||||
function goLogin() {
|
||||
userStore.logout(true);
|
||||
lockStore.resetLockInfo();
|
||||
}
|
||||
}
|
||||
|
||||
function goLogin() {
|
||||
userStore.logout(true);
|
||||
lockStore.resetLockInfo();
|
||||
}
|
||||
|
||||
function handleShowForm(show = false) {
|
||||
showDate.value = show;
|
||||
}
|
||||
|
||||
const getLoginCode = async () => {
|
||||
countdown.value = 60
|
||||
visible.value = true
|
||||
imgCode.value = ''
|
||||
await onMobileLoginImg()
|
||||
}
|
||||
|
||||
async function onMobileLoginImg() {
|
||||
imgObj.value = await getMobileLoginImg({account: userinfo.value.mobile})
|
||||
}
|
||||
|
||||
async function refreshTodo() {
|
||||
refreshLoading.value = true
|
||||
await onMobileLoginImg()
|
||||
refreshLoading.value = false
|
||||
}
|
||||
|
||||
async function handleOk() {
|
||||
await getMobileLoginCode({captchaCode: imgCode.value ,mobile: userinfo.value.mobile})
|
||||
setCodeInterval = setInterval(updateCountdown, 1000);
|
||||
onVisible()
|
||||
}
|
||||
|
||||
function updateCountdown() {
|
||||
if (countdown.value === 0) {
|
||||
getCodeButtonName.value = '获取验证码';
|
||||
codeButtonDisabled.value = false;
|
||||
clearInterval(setCodeInterval)
|
||||
} else {
|
||||
countdown.value--;
|
||||
getCodeButtonName.value = countdown.value + ' 秒后可重发';
|
||||
codeButtonDisabled.value = true;
|
||||
function handleShowForm(show = false) {
|
||||
showDate.value = show;
|
||||
}
|
||||
}
|
||||
|
||||
function onVisible () {
|
||||
visible.value = false
|
||||
imgObj.value.imgBase64 = ''
|
||||
}
|
||||
const getLoginCode = async () => {
|
||||
countdown.value = 60;
|
||||
visible.value = true;
|
||||
imgCode.value = '';
|
||||
await onMobileLoginImg();
|
||||
};
|
||||
|
||||
function handleCancel() {
|
||||
onVisible()
|
||||
}
|
||||
|
||||
function changeLoginType () {
|
||||
loginType.value = loginType.value == 'password' ? 'sms' : 'password'
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: unLockByPhone
|
||||
*/
|
||||
async function unLockByPhone() {
|
||||
if (!formData.value.code) {
|
||||
return;
|
||||
async function onMobileLoginImg() {
|
||||
imgObj.value = await getMobileLoginImg({ account: userinfo.value.mobile });
|
||||
}
|
||||
let code = formData.value.code;
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await lockStore.unLockByPhone(code);
|
||||
errMsg.value = !res;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleLogin() {
|
||||
const obj = {
|
||||
password: unLock,
|
||||
sms: unLockByPhone,
|
||||
async function refreshTodo() {
|
||||
refreshLoading.value = true;
|
||||
await onMobileLoginImg();
|
||||
refreshLoading.value = false;
|
||||
}
|
||||
|
||||
async function handleOk() {
|
||||
await getMobileLoginCode({ captchaCode: imgCode.value, mobile: userinfo.value.mobile });
|
||||
setCodeInterval = setInterval(updateCountdown, 1000);
|
||||
onVisible();
|
||||
}
|
||||
|
||||
function updateCountdown() {
|
||||
if (countdown.value === 0) {
|
||||
getCodeButtonName.value = '获取验证码';
|
||||
codeButtonDisabled.value = false;
|
||||
clearInterval(setCodeInterval);
|
||||
} else {
|
||||
countdown.value--;
|
||||
getCodeButtonName.value = countdown.value + ' 秒后可重发';
|
||||
codeButtonDisabled.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onVisible() {
|
||||
visible.value = false;
|
||||
imgObj.value.imgBase64 = '';
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
onVisible();
|
||||
}
|
||||
|
||||
function changeLoginType() {
|
||||
loginType.value = loginType.value == 'password' ? 'sms' : 'password';
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: unLockByPhone
|
||||
*/
|
||||
async function unLockByPhone() {
|
||||
if (!formData.value.code) {
|
||||
return;
|
||||
}
|
||||
let code = formData.value.code;
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await lockStore.unLockByPhone(code);
|
||||
errMsg.value = !res;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleLogin() {
|
||||
const obj = {
|
||||
password: unLock,
|
||||
sms: unLockByPhone
|
||||
};
|
||||
obj[loginType.value]();
|
||||
}
|
||||
obj[loginType.value]()
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-lock-page';
|
||||
@prefix-cls: ~'@{namespace}-lock-page';
|
||||
|
||||
.@{prefix-cls} {
|
||||
z-index: 999;
|
||||
// 新增或修改背景色
|
||||
background: linear-gradient(180deg, #00356d 0%, rgb(0 53 109 / 0%) 100%), linear-gradient(180deg, #0074d3 2%, #011853 100%);
|
||||
|
||||
&__unlock {
|
||||
transform: translate(-50%, 0);
|
||||
.@{prefix-cls} {
|
||||
z-index: 999;
|
||||
// 新增或修改背景色
|
||||
background: linear-gradient(180deg, #00356d 0%, rgb(0 53 109 / 0%) 100%), linear-gradient(180deg, #0074d3 2%, #011853 100%);
|
||||
|
||||
&__unlock {
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
&__hour,
|
||||
&__minute {
|
||||
display: flex;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
background-color: linear-gradient(180deg, #00356d 0%, rgb(0 53 109 / 0%) 100%), linear-gradient(180deg, #0074d3 2%, #011853 100%);
|
||||
border-radius: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
@media screen and (max-width: @screen-md) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: @screen-md) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: @screen-sm) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 90px;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: @screen-lg) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 220px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: @screen-xl) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 260px;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: @screen-2xl) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 320px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__logo-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
img {
|
||||
width: 144px;
|
||||
height: 144px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
&__sysname-box {
|
||||
font-size: 6rem;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&-entry {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgb(0 0 0 / 50%);
|
||||
backdrop-filter: blur(8px);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-content {
|
||||
width: 390px;
|
||||
}
|
||||
|
||||
&__header {
|
||||
text-align: center;
|
||||
|
||||
&-img {
|
||||
width: 70px;
|
||||
margin: 0 auto;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&-name {
|
||||
margin-top: 5px;
|
||||
font-weight: 500;
|
||||
color: #bababa;
|
||||
}
|
||||
}
|
||||
|
||||
&__err-msg {
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
color: @error-color;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__hour,
|
||||
&__minute {
|
||||
display: flex;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
background-color: linear-gradient(180deg, #00356d 0%, rgb(0 53 109 / 0%) 100%), linear-gradient(180deg, #0074d3 2%, #011853 100%);
|
||||
border-radius: 30px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
@media screen and (max-width: @screen-md) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: @screen-md) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: @screen-sm) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 90px;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: @screen-lg) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 220px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: @screen-xl) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 260px;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: @screen-2xl) {
|
||||
span:not(.meridiem) {
|
||||
font-size: 320px;
|
||||
}
|
||||
}
|
||||
.back_login {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
&__logo-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
img {
|
||||
width: 144px;
|
||||
height: 144px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
&__sysname-box {
|
||||
font-size: 6rem;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&-entry {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgb(0 0 0 / 50%);
|
||||
backdrop-filter: blur(8px);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-content {
|
||||
width: 390px;
|
||||
}
|
||||
|
||||
&__header {
|
||||
.login-modal-content {
|
||||
text-align: center;
|
||||
|
||||
&-img {
|
||||
width: 70px;
|
||||
margin: 0 auto;
|
||||
border-radius: 50%;
|
||||
.refresh {
|
||||
text-align: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-name {
|
||||
margin-top: 5px;
|
||||
font-weight: 500;
|
||||
color: #bababa;
|
||||
}
|
||||
}
|
||||
|
||||
&__err-msg {
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
color: @error-color;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
.back_login {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
.login-modal-content {
|
||||
text-align: center;
|
||||
.refresh {
|
||||
text-align: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<transition name="fade-bottom" mode="out-in">
|
||||
<LockPage v-if="getIsLock" />
|
||||
</transition>
|
||||
<transition name="fade-bottom" mode="out-in">
|
||||
<LockPage v-if="getIsLock" />
|
||||
</transition>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import LockPage from './LockPage.vue';
|
||||
import { useLockStore } from '/@/store/modules/lock';
|
||||
import { computed } from 'vue';
|
||||
import LockPage from './LockPage.vue';
|
||||
import { useLockStore } from '/@/store/modules/lock';
|
||||
|
||||
const lockStore = useLockStore();
|
||||
const getIsLock = computed(() => lockStore?.getLockInfo?.isLock ?? false);
|
||||
const lockStore = useLockStore();
|
||||
const getIsLock = computed(() => lockStore?.getLockInfo?.isLock ?? false);
|
||||
</script>
|
||||
|
||||
@ -1,56 +1,56 @@
|
||||
<template>
|
||||
<template v-if="getShow">
|
||||
<LoginFormTitle class="enter-x" />
|
||||
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef">
|
||||
<FormItem name="account" class="enter-x">
|
||||
<Input size="large" v-model:value="formData.account" :placeholder="t('账号')" />
|
||||
</FormItem>
|
||||
<template v-if="getShow">
|
||||
<LoginFormTitle class="enter-x" />
|
||||
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef">
|
||||
<FormItem name="account" class="enter-x">
|
||||
<Input size="large" v-model:value="formData.account" :placeholder="t('账号')" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem name="mobile" class="enter-x">
|
||||
<Input size="large" v-model:value="formData.mobile" :placeholder="t('手机号码')" />
|
||||
</FormItem>
|
||||
<FormItem name="sms" class="enter-x">
|
||||
<CountdownInput size="large" v-model:value="formData.sms" :placeholder="t('短信验证码')" />
|
||||
</FormItem>
|
||||
<FormItem name="mobile" class="enter-x">
|
||||
<Input size="large" v-model:value="formData.mobile" :placeholder="t('手机号码')" />
|
||||
</FormItem>
|
||||
<FormItem name="sms" class="enter-x">
|
||||
<CountdownInput size="large" v-model:value="formData.sms" :placeholder="t('短信验证码')" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem class="enter-x">
|
||||
<Button type="primary" size="large" block @click="handleReset" :loading="loading">
|
||||
{{ t('重置') }}
|
||||
</Button>
|
||||
<Button size="large" block class="mt-4" @click="handleBackLogin">
|
||||
{{ t('返回') }}
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</template>
|
||||
<FormItem class="enter-x">
|
||||
<Button type="primary" size="large" block @click="handleReset" :loading="loading">
|
||||
{{ t('重置') }}
|
||||
</Button>
|
||||
<Button size="large" block class="mt-4" @click="handleBackLogin">
|
||||
{{ t('返回') }}
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</template>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, computed, unref } from 'vue';
|
||||
import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { Form, Input, Button } from 'ant-design-vue';
|
||||
import { CountdownInput } from '/@/components/CountDown';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useLoginState, useFormRules, LoginStateEnum } from './useLogin';
|
||||
import { reactive, ref, computed, unref } from 'vue';
|
||||
import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { Form, Input, Button } from 'ant-design-vue';
|
||||
import { CountdownInput } from '/@/components/CountDown';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useLoginState, useFormRules, LoginStateEnum } from './useLogin';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { t } = useI18n();
|
||||
const { handleBackLogin, getLoginState } = useLoginState();
|
||||
const { getFormRules } = useFormRules();
|
||||
const FormItem = Form.Item;
|
||||
const { t } = useI18n();
|
||||
const { handleBackLogin, getLoginState } = useLoginState();
|
||||
const { getFormRules } = useFormRules();
|
||||
|
||||
const formRef = ref();
|
||||
const loading = ref(false);
|
||||
const formRef = ref();
|
||||
const loading = ref(false);
|
||||
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
mobile: '',
|
||||
sms: '',
|
||||
});
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
mobile: '',
|
||||
sms: ''
|
||||
});
|
||||
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.RESET_PASSWORD);
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.RESET_PASSWORD);
|
||||
|
||||
async function handleReset() {
|
||||
const form = unref(formRef);
|
||||
if (!form) return;
|
||||
await form.resetFields();
|
||||
}
|
||||
async function handleReset() {
|
||||
const form = unref(formRef);
|
||||
if (!form) return;
|
||||
await form.resetFields();
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,306 +1,302 @@
|
||||
<template>
|
||||
<div :class="prefixCls" class="login-box relative w-full h-full">
|
||||
<div class="login-left-box">
|
||||
<div class="logo-box" v-if="show">
|
||||
<a href="https://fcdma.gdyditc.com/" target="_blank">
|
||||
<img :src="logoConfig.loginLogoUrl || logopng" />
|
||||
</a>
|
||||
</div>
|
||||
<img :src="logoConfig.backgroundLogoUrl || logobg" class="h-full" />
|
||||
<div :class="prefixCls" class="login-box relative w-full h-full">
|
||||
<div class="login-left-box">
|
||||
<div class="logo-box" v-if="show">
|
||||
<a href="https://fcdma.gdyditc.com/" target="_blank">
|
||||
<img :src="logoConfig.loginLogoUrl || logopng" />
|
||||
</a>
|
||||
</div>
|
||||
<img :src="logoConfig.backgroundLogoUrl || logobg" class="h-full" />
|
||||
</div>
|
||||
<div class="fixed-tool">
|
||||
<AppDarkModeToggle v-if="!sessionTimeout" />
|
||||
<AppLocalePicker class="text-white px-4" :showText="false" v-if="!sessionTimeout && showLocale" />
|
||||
</div>
|
||||
<div class="right-box">
|
||||
<div class="login-left-title">
|
||||
<div class="title">{{ t('欢迎登录') }}</div>
|
||||
<div class="sub-title">{{ t('全代码开发平台') }}</div>
|
||||
</div>
|
||||
<div :class="`${prefixCls}-form`">
|
||||
<LoginForm />
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-top-box">
|
||||
<img src="../../../assets/images/login-right.gif" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="fixed-tool">
|
||||
<AppDarkModeToggle v-if="!sessionTimeout" />
|
||||
<AppLocalePicker
|
||||
class="text-white px-4"
|
||||
:showText="false"
|
||||
v-if="!sessionTimeout && showLocale"
|
||||
/>
|
||||
</div>
|
||||
<div class="right-box">
|
||||
<div class="login-left-title">
|
||||
<div class="title">{{ t('欢迎登录') }}</div>
|
||||
<div class="sub-title">{{ t('全代码开发平台') }}</div>
|
||||
</div>
|
||||
<div :class="`${prefixCls}-form`">
|
||||
<LoginForm />
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-top-box">
|
||||
<img src="../../../assets/images/login-right.gif" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
// import { computed } from 'vue';
|
||||
import { AppLocalePicker, AppDarkModeToggle } from '/@/components/Application';
|
||||
import LoginForm from './LoginForm.vue';
|
||||
// import { useGlobSetting } from '/@/hooks/setting';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLocaleStore } from '/@/store/modules/locale';
|
||||
import { useAppStore } from '/@/store/modules/app';
|
||||
import logopng from '/@/assets/images/logo-dark.png';
|
||||
import logobg from '/@/assets/images/login-left.gif';
|
||||
import { getLogoInfo } from '/@/api/system/login';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { LogoConfig } from '/#/config';
|
||||
// import { computed } from 'vue';
|
||||
import { AppLocalePicker, AppDarkModeToggle } from '/@/components/Application';
|
||||
import LoginForm from './LoginForm.vue';
|
||||
// import { useGlobSetting } from '/@/hooks/setting';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLocaleStore } from '/@/store/modules/locale';
|
||||
import { useAppStore } from '/@/store/modules/app';
|
||||
import logopng from '/@/assets/images/logo-dark.png';
|
||||
import logobg from '/@/assets/images/login-left.gif';
|
||||
import { getLogoInfo } from '/@/api/system/login';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { LogoConfig } from '/#/config';
|
||||
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
const { createErrorModal } = useMessage();
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
const { createErrorModal } = useMessage();
|
||||
|
||||
onMounted(() => {
|
||||
let logoutInfoData = JSON.parse(sessionStorage.getItem('logoutInfoData') as string);
|
||||
if (logoutInfoData) {
|
||||
createErrorModal({ title: t('错误提示'), content: logoutInfoData.logoutMessage });
|
||||
sessionStorage.removeItem('logoutInfoData');
|
||||
}
|
||||
})
|
||||
onMounted(() => {
|
||||
let logoutInfoData = JSON.parse(sessionStorage.getItem('logoutInfoData') as string);
|
||||
if (logoutInfoData) {
|
||||
createErrorModal({ title: t('错误提示'), content: logoutInfoData.logoutMessage });
|
||||
sessionStorage.removeItem('logoutInfoData');
|
||||
}
|
||||
});
|
||||
|
||||
const appStore = useAppStore();
|
||||
defineProps({
|
||||
sessionTimeout: {
|
||||
type: Boolean,
|
||||
},
|
||||
});
|
||||
const appStore = useAppStore();
|
||||
defineProps({
|
||||
sessionTimeout: {
|
||||
type: Boolean
|
||||
}
|
||||
});
|
||||
|
||||
// const globSetting = useGlobSetting();
|
||||
const { prefixCls } = useDesign('login');
|
||||
const { t } = useI18n();
|
||||
const localeStore = useLocaleStore();
|
||||
const showLocale = localeStore.getShowPicker;
|
||||
// const title = computed(() => globSetting?.title ?? '');
|
||||
// const globSetting = useGlobSetting();
|
||||
const { prefixCls } = useDesign('login');
|
||||
const { t } = useI18n();
|
||||
const localeStore = useLocaleStore();
|
||||
const showLocale = localeStore.getShowPicker;
|
||||
// const title = computed(() => globSetting?.title ?? '');
|
||||
|
||||
let logoConfig = ref<LogoConfig>({});
|
||||
let show = ref(false);
|
||||
getLogoInfo().then((res) => {
|
||||
show.value = true;
|
||||
logoConfig.value = {
|
||||
companyName: res.companyName,
|
||||
shortName: res.shortName,
|
||||
refreshLogoUrl: res.refreshLogoUrl,
|
||||
backgroundLogoUrl: res.backgroundLogoUrl,
|
||||
designerLogoUrl: res.designerLogoUrl,
|
||||
loginLogoUrl: res.loginLogoUrl,
|
||||
menuLogoUrl: res.menuLogoUrl,
|
||||
};
|
||||
appStore.setLogoConfig(logoConfig.value);
|
||||
});
|
||||
let logoConfig = ref<LogoConfig>({});
|
||||
let show = ref(false);
|
||||
getLogoInfo().then((res) => {
|
||||
show.value = true;
|
||||
logoConfig.value = {
|
||||
companyName: res.companyName,
|
||||
shortName: res.shortName,
|
||||
refreshLogoUrl: res.refreshLogoUrl,
|
||||
backgroundLogoUrl: res.backgroundLogoUrl,
|
||||
designerLogoUrl: res.designerLogoUrl,
|
||||
loginLogoUrl: res.loginLogoUrl,
|
||||
menuLogoUrl: res.menuLogoUrl
|
||||
};
|
||||
appStore.setLogoConfig(logoConfig.value);
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-login';
|
||||
@logo-prefix-cls: ~'@{namespace}-app-logo';
|
||||
@countdown-prefix-cls: ~'@{namespace}-countdown-input';
|
||||
@dark-bg: linear-gradient(to bottom, #364876, #112049);
|
||||
@prefix-cls: ~'@{namespace}-login';
|
||||
@logo-prefix-cls: ~'@{namespace}-app-logo';
|
||||
@countdown-prefix-cls: ~'@{namespace}-countdown-input';
|
||||
@dark-bg: linear-gradient(to bottom, #364876, #112049);
|
||||
|
||||
.vben-login-form {
|
||||
padding: 180px 100px 40px;
|
||||
}
|
||||
.vben-login-form {
|
||||
padding: 180px 100px 40px;
|
||||
}
|
||||
|
||||
.login-box {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.logo-box {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 40px;
|
||||
}
|
||||
|
||||
.logo-box img {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.login-left-title {
|
||||
position: relative;
|
||||
top: 120px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
.login-left-title .title {
|
||||
font-size: 20px;
|
||||
border: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.login-left-title .sub-title {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
color: #5e95ff;
|
||||
}
|
||||
|
||||
.login-box .right-box {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.fixed-tool {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
top: 40px;
|
||||
display: flex;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.right-top-box {
|
||||
width: 400px;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] {
|
||||
.login-box {
|
||||
background: @dark-bg;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.logo-box {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 40px;
|
||||
}
|
||||
|
||||
.logo-box img {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.login-left-title {
|
||||
border: none;
|
||||
position: relative;
|
||||
top: 120px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
.login-left-title .title {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
border: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.login-left-title .sub-title {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
color: #5e95ff;
|
||||
}
|
||||
|
||||
.login-box .right-box {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.fixed-tool {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
top: 40px;
|
||||
display: flex;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.right-top-box {
|
||||
width: 400px;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] {
|
||||
.login-box {
|
||||
background: @dark-bg;
|
||||
}
|
||||
|
||||
.login-left-title {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.login-left-title .title {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
background-color: @dark-bg;
|
||||
|
||||
// &::before {
|
||||
// background-image: url(/@/assets/svg/login-bg-dark.svg);
|
||||
// }
|
||||
|
||||
.ant-input,
|
||||
.ant-input-password {
|
||||
background-color: #232a3b;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper {
|
||||
border-color: #525e7c;
|
||||
background-color: #232a3b;
|
||||
}
|
||||
|
||||
.ant-checkbox-inner {
|
||||
border-color: #525e7c;
|
||||
}
|
||||
|
||||
.ant-btn:not(.ant-btn-link, .ant-btn-primary) {
|
||||
border: 1px solid #4a5569;
|
||||
}
|
||||
|
||||
&-form {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.app-iconify {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
input.fix-auto-fill,
|
||||
.fix-auto-fill input {
|
||||
-webkit-text-fill-color: #c9d1d9 !important;
|
||||
box-shadow: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
background-color: @dark-bg;
|
||||
min-height: 100%;
|
||||
overflow: hidden;
|
||||
@media (max-width: @screen-xl) {
|
||||
background-color: @dark-bg;
|
||||
|
||||
// &::before {
|
||||
// background-image: url(/@/assets/svg/login-bg-dark.svg);
|
||||
// }
|
||||
|
||||
.ant-input,
|
||||
.ant-input-password {
|
||||
background-color: #232a3b;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper {
|
||||
border-color: #525e7c;
|
||||
background-color: #232a3b;
|
||||
}
|
||||
|
||||
.ant-checkbox-inner {
|
||||
border-color: #525e7c;
|
||||
}
|
||||
|
||||
.ant-btn:not(.ant-btn-link, .ant-btn-primary) {
|
||||
border: 1px solid #4a5569;
|
||||
}
|
||||
|
||||
&-form {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.app-iconify {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
input.fix-auto-fill,
|
||||
.fix-auto-fill input {
|
||||
-webkit-text-fill-color: #c9d1d9 !important;
|
||||
box-shadow: inherit !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
min-height: 100%;
|
||||
overflow: hidden;
|
||||
@media (max-width: @screen-xl) {
|
||||
background-color: @dark-bg;
|
||||
|
||||
.@{prefix-cls}-form {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-left: -48%;
|
||||
// background-image: url(/@/assets/svg/login-bg.svg);
|
||||
background-position: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: auto 100%;
|
||||
content: '';
|
||||
@media (max-width: @screen-xl) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.@{logo-prefix-cls} {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
height: 30px;
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
.@{logo-prefix-cls} {
|
||||
display: flex;
|
||||
width: 60%;
|
||||
height: 80px;
|
||||
|
||||
&__title {
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
.@{prefix-cls}-form {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 48px;
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-left: -48%;
|
||||
// background-image: url(/@/assets/svg/login-bg.svg);
|
||||
background-position: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: auto 100%;
|
||||
content: '';
|
||||
@media (max-width: @screen-xl) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-sign-in-way {
|
||||
.anticon {
|
||||
font-size: 22px;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
.@{logo-prefix-cls} {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
height: 30px;
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
.@{logo-prefix-cls} {
|
||||
display: flex;
|
||||
width: 60%;
|
||||
height: 80px;
|
||||
|
||||
&__title {
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 48px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-sign-in-way {
|
||||
.anticon {
|
||||
font-size: 22px;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input:not([type='checkbox']) {
|
||||
min-width: 360px;
|
||||
|
||||
@media (max-width: @screen-xl) {
|
||||
min-width: 320px;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-lg) {
|
||||
min-width: 260px;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-md) {
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-sm) {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
.@{countdown-prefix-cls} input {
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.ant-divider-inner-text {
|
||||
font-size: 12px;
|
||||
color: @text-color-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input:not([type='checkbox']) {
|
||||
min-width: 360px;
|
||||
|
||||
@media (max-width: @screen-xl) {
|
||||
min-width: 320px;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-lg) {
|
||||
min-width: 260px;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-md) {
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-sm) {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
.@{countdown-prefix-cls} input {
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.ant-divider-inner-text {
|
||||
font-size: 12px;
|
||||
color: @text-color-secondary;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,63 +1,41 @@
|
||||
<template>
|
||||
<Form
|
||||
class="p-4 enter-x form-box"
|
||||
:model="formData"
|
||||
:rules="getFormRules"
|
||||
ref="formRef"
|
||||
v-show="getShow"
|
||||
@keypress.enter="handleLogin"
|
||||
>
|
||||
<div>
|
||||
<FormItem name="account" class="enter-x">
|
||||
<label class="form-title"> {{ t('账号') }}</label>
|
||||
<Input
|
||||
size="large"
|
||||
v-model:value="formData.account"
|
||||
:placeholder="t('账号')"
|
||||
class="fix-auto-fill"
|
||||
style="height: 58px"
|
||||
><template #prefix>
|
||||
<IconFontSymbol icon="yonghu-xianxing" class="user-icon" />
|
||||
</template>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem name="password" class="enter-x">
|
||||
<label class="form-title"> {{ t('密码') }}</label>
|
||||
<InputPassword
|
||||
size="large"
|
||||
visibilityToggle
|
||||
v-model:value="formData.password"
|
||||
:placeholder="t('密码')"
|
||||
style="height: 58px"
|
||||
><template #prefix>
|
||||
<IconFontSymbol icon="mima" class="user-icon" />
|
||||
</template>
|
||||
</InputPassword>
|
||||
</FormItem>
|
||||
<Form class="p-4 enter-x form-box" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow" @keypress.enter="handleLogin">
|
||||
<div>
|
||||
<FormItem name="account" class="enter-x">
|
||||
<label class="form-title"> {{ t('账号') }}</label>
|
||||
<Input size="large" v-model:value="formData.account" :placeholder="t('账号')" class="fix-auto-fill" style="height: 58px"
|
||||
><template #prefix>
|
||||
<IconFontSymbol icon="yonghu-xianxing" class="user-icon" />
|
||||
</template>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<FormItem name="password" class="enter-x">
|
||||
<label class="form-title"> {{ t('密码') }}</label>
|
||||
<InputPassword size="large" visibilityToggle v-model:value="formData.password" :placeholder="t('密码')" style="height: 58px"
|
||||
><template #prefix>
|
||||
<IconFontSymbol icon="mima" class="user-icon" />
|
||||
</template>
|
||||
</InputPassword>
|
||||
</FormItem>
|
||||
|
||||
<FormItem v-if="getAppEnvConfig().VITE_GLOB_TENANT_ENABLED" name="tenantCode" class="enter-x">
|
||||
<label class="form-title"> {{ t('租户码') }}</label>
|
||||
<Input
|
||||
size="large"
|
||||
visibilityToggle
|
||||
v-model:value="formData.tenantCode"
|
||||
:placeholder="t('租户码')"
|
||||
style="height: 58px"
|
||||
><template #prefix>
|
||||
<IconFontSymbol icon="mima" class="user-icon" />
|
||||
</template>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<ARow class="enter-x">
|
||||
<ACol :span="12">
|
||||
<FormItem>
|
||||
<!-- No logic, you need to deal with it yourself -->
|
||||
<Checkbox v-model:checked="rememberMe" size="small" class="f-16">
|
||||
{{ t('记住我') }}
|
||||
</Checkbox>
|
||||
</FormItem>
|
||||
</ACol>
|
||||
<!-- <ACol :span="12">
|
||||
<FormItem v-if="getAppEnvConfig().VITE_GLOB_TENANT_ENABLED" name="tenantCode" class="enter-x">
|
||||
<label class="form-title"> {{ t('租户码') }}</label>
|
||||
<Input size="large" visibilityToggle v-model:value="formData.tenantCode" :placeholder="t('租户码')" style="height: 58px"
|
||||
><template #prefix>
|
||||
<IconFontSymbol icon="mima" class="user-icon" />
|
||||
</template>
|
||||
</Input>
|
||||
</FormItem>
|
||||
<ARow class="enter-x">
|
||||
<ACol :span="12">
|
||||
<FormItem>
|
||||
<!-- No logic, you need to deal with it yourself -->
|
||||
<Checkbox v-model:checked="rememberMe" size="small" class="f-16">
|
||||
{{ t('记住我') }}
|
||||
</Checkbox>
|
||||
</FormItem>
|
||||
</ACol>
|
||||
<!-- <ACol :span="12">
|
||||
<FormItem :style="{ 'text-align': 'right' }">
|
||||
No logic, you need to deal with it yourself
|
||||
<Button type="link" size="small" @click="setLoginState(LoginStateEnum.RESET_PASSWORD)">
|
||||
@ -65,24 +43,17 @@
|
||||
</Button>
|
||||
</FormItem>
|
||||
</ACol> -->
|
||||
</ARow>
|
||||
</ARow>
|
||||
|
||||
<FormItem class="enter-x">
|
||||
<Button
|
||||
type="primary"
|
||||
class="sub-button"
|
||||
block
|
||||
@click="handleLogin"
|
||||
:loading="loading"
|
||||
:style="{ 'border-radius': '35px' }"
|
||||
>
|
||||
{{ t('登录') }}
|
||||
</Button>
|
||||
<!-- <Button size="large" class="mt-4 enter-x" block @click="handleRegister">
|
||||
<FormItem class="enter-x">
|
||||
<Button type="primary" class="sub-button" block @click="handleLogin" :loading="loading" :style="{ 'border-radius': '35px' }">
|
||||
{{ t('登录') }}
|
||||
</Button>
|
||||
<!-- <Button size="large" class="mt-4 enter-x" block @click="handleRegister">
|
||||
{{ t('注册') }}
|
||||
</Button> -->
|
||||
</FormItem>
|
||||
<!-- <ARow class="enter-x">
|
||||
</FormItem>
|
||||
<!-- <ARow class="enter-x">
|
||||
<ACol :md="8" :xs="24">
|
||||
<Button block @click="setLoginState(LoginStateEnum.MOBILE)">
|
||||
{{ t('手机登录') }}
|
||||
@ -100,236 +71,235 @@
|
||||
</ACol>
|
||||
</ARow> -->
|
||||
|
||||
<a-divider class="enter-x">{{ t('其他登录方式') }}</a-divider>
|
||||
</div>
|
||||
<!-- <div style="height: 1000px; width: 800px" v-else>
|
||||
<a-divider class="enter-x">{{ t('其他登录方式') }}</a-divider>
|
||||
</div>
|
||||
<!-- <div style="height: 1000px; width: 800px" v-else>
|
||||
<iframe id="iframeId" style="height: 100%; width: 100%" :src="authorizeUrl"></iframe>
|
||||
</div> -->
|
||||
|
||||
<div class="flex justify-evenly enter-x" :class="`${prefixCls}-sign-in-way`">
|
||||
<WechatFilled @click="oauthLogin('wechat_enterprise')" />
|
||||
<DingtalkCircleFilled @click="oauthLogin('dingtalk')" />
|
||||
</div>
|
||||
</Form>
|
||||
<div class="flex justify-evenly enter-x" :class="`${prefixCls}-sign-in-way`">
|
||||
<WechatFilled @click="oauthLogin('wechat_enterprise')" />
|
||||
<DingtalkCircleFilled @click="oauthLogin('dingtalk')" />
|
||||
</div>
|
||||
</Form>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, unref, computed, onMounted } from 'vue';
|
||||
import { reactive, ref, unref, computed, onMounted } from 'vue';
|
||||
|
||||
import { Checkbox, Form, Input, Row, Col, Button } from 'ant-design-vue';
|
||||
import { WechatFilled, DingtalkCircleFilled } from '@ant-design/icons-vue';
|
||||
// import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { Checkbox, Form, Input, Row, Col, Button } from 'ant-design-vue';
|
||||
import { WechatFilled, DingtalkCircleFilled } from '@ant-design/icons-vue';
|
||||
// import LoginFormTitle from './LoginFormTitle.vue';
|
||||
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { Base64 } from 'js-base64';
|
||||
//import { onKeyStroke } from '@vueuse/core';
|
||||
import IconFontSymbol from '/@/components/IconFontSymbol/Index.vue';
|
||||
import { getOauthAuthorizeUrl } from '/@/api/system/login';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getAppEnvConfig } from '/@/utils/env';
|
||||
// import { nextTick } from 'vue';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { Base64 } from 'js-base64';
|
||||
//import { onKeyStroke } from '@vueuse/core';
|
||||
import IconFontSymbol from '/@/components/IconFontSymbol/Index.vue';
|
||||
import { getOauthAuthorizeUrl } from '/@/api/system/login';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getAppEnvConfig } from '/@/utils/env';
|
||||
// import { nextTick } from 'vue';
|
||||
|
||||
const ACol = Col;
|
||||
const ARow = Row;
|
||||
const FormItem = Form.Item;
|
||||
const InputPassword = Input.Password;
|
||||
const { t } = useI18n();
|
||||
const { notification, createErrorModal } = useMessage();
|
||||
const { prefixCls } = useDesign('login');
|
||||
const userStore = useUserStore();
|
||||
const ACol = Col;
|
||||
const ARow = Row;
|
||||
const FormItem = Form.Item;
|
||||
const InputPassword = Input.Password;
|
||||
const { t } = useI18n();
|
||||
const { notification, createErrorModal } = useMessage();
|
||||
const { prefixCls } = useDesign('login');
|
||||
const userStore = useUserStore();
|
||||
|
||||
const { currentRoute } = useRouter();
|
||||
const { currentRoute } = useRouter();
|
||||
|
||||
const { getLoginState } = useLoginState();
|
||||
const { getFormRules } = useFormRules();
|
||||
const { getLoginState } = useLoginState();
|
||||
const { getFormRules } = useFormRules();
|
||||
|
||||
const formRef = ref();
|
||||
// const iframeRef = ref();
|
||||
const loading = ref(false);
|
||||
const rememberMe = ref(false);
|
||||
const formRef = ref();
|
||||
// const iframeRef = ref();
|
||||
const loading = ref(false);
|
||||
const rememberMe = ref(false);
|
||||
|
||||
const showFlag = ref(false);
|
||||
const authorizeUrl = ref('');
|
||||
const showFlag = ref(false);
|
||||
const authorizeUrl = ref('');
|
||||
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
password: '',
|
||||
tenantCode: 'system',
|
||||
});
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
password: '',
|
||||
tenantCode: 'system'
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
//如果是第三方登录跳转回来 会携带token
|
||||
if (currentRoute.value.query.token) {
|
||||
try {
|
||||
loading.value = true;
|
||||
const userInfo = await userStore.oauthLogin({
|
||||
token: currentRoute.value.query.token as string,
|
||||
mode: 'none', //不要默认的错误提示
|
||||
});
|
||||
if (userInfo) {
|
||||
notification.success({
|
||||
message: t('登录成功'),
|
||||
description: `${t('欢迎回来')}: ${userInfo.name}`,
|
||||
duration: 3,
|
||||
});
|
||||
onMounted(async () => {
|
||||
//如果是第三方登录跳转回来 会携带token
|
||||
if (currentRoute.value.query.token) {
|
||||
try {
|
||||
loading.value = true;
|
||||
const userInfo = await userStore.oauthLogin({
|
||||
token: currentRoute.value.query.token as string,
|
||||
mode: 'none' //不要默认的错误提示
|
||||
});
|
||||
if (userInfo) {
|
||||
notification.success({
|
||||
message: t('登录成功'),
|
||||
description: `${t('欢迎回来')}: ${userInfo.name}`,
|
||||
duration: 3
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
createErrorModal({
|
||||
title: t('错误提示'),
|
||||
content: (error as unknown as Error).message || t('网络异常,请检查您的网络连接是否正常!'),
|
||||
getContainer: () => document.body.querySelector(`.${prefixCls}`) || document.body
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
createErrorModal({
|
||||
title: t('错误提示'),
|
||||
content:
|
||||
(error as unknown as Error).message || t('网络异常,请检查您的网络连接是否正常!'),
|
||||
getContainer: () => document.body.querySelector(`.${prefixCls}`) || document.body,
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
//如果第三方登录 登录错误 会携带错误信息
|
||||
if (currentRoute.value.query.error) {
|
||||
createErrorModal({
|
||||
title: t('错误提示'),
|
||||
content: t(currentRoute.value.query.error as string),
|
||||
getContainer: () => document.body.querySelector(`.${prefixCls}`) || document.body,
|
||||
});
|
||||
}
|
||||
const loginInfo = window.localStorage.getItem('USER__LOGIN__INFO__');
|
||||
if (loginInfo) {
|
||||
formData.account = Base64.decode(JSON.parse(loginInfo).account);
|
||||
formData.password = Base64.decode(JSON.parse(loginInfo).password);
|
||||
}
|
||||
});
|
||||
|
||||
const { validForm } = useFormValid(formRef);
|
||||
|
||||
//onKeyStroke('Enter', handleLogin);
|
||||
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN);
|
||||
|
||||
async function handleLogin() {
|
||||
const data = await validForm();
|
||||
if (!data) return;
|
||||
try {
|
||||
loading.value = true;
|
||||
const userInfo = await userStore.login({
|
||||
password: data.password,
|
||||
userName: data.account,
|
||||
tenantCode: data.tenantCode,
|
||||
deviceType: 0, //pc-0,app-1
|
||||
mode: 'none', //不要默认的错误提示
|
||||
});
|
||||
if (userInfo) {
|
||||
notification.success({
|
||||
message: t('登录成功'),
|
||||
description: `${t('欢迎回来')}: ${userInfo.name}`,
|
||||
duration: 3,
|
||||
});
|
||||
if (rememberMe.value) {
|
||||
const info = {
|
||||
account: Base64.encode(data.account),
|
||||
password: Base64.encode(data.password),
|
||||
};
|
||||
window.localStorage.setItem('USER__LOGIN__INFO__', JSON.stringify(info));
|
||||
} else {
|
||||
window.localStorage.removeItem('USER__LOGIN__INFO__');
|
||||
//如果第三方登录 登录错误 会携带错误信息
|
||||
if (currentRoute.value.query.error) {
|
||||
createErrorModal({
|
||||
title: t('错误提示'),
|
||||
content: t(currentRoute.value.query.error as string),
|
||||
getContainer: () => document.body.querySelector(`.${prefixCls}`) || document.body
|
||||
});
|
||||
}
|
||||
const loginInfo = window.localStorage.getItem('USER__LOGIN__INFO__');
|
||||
if (loginInfo) {
|
||||
formData.account = Base64.decode(JSON.parse(loginInfo).account);
|
||||
formData.password = Base64.decode(JSON.parse(loginInfo).password);
|
||||
}
|
||||
});
|
||||
|
||||
const { validForm } = useFormValid(formRef);
|
||||
|
||||
//onKeyStroke('Enter', handleLogin);
|
||||
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN);
|
||||
|
||||
async function handleLogin() {
|
||||
const data = await validForm();
|
||||
if (!data) return;
|
||||
try {
|
||||
loading.value = true;
|
||||
const userInfo = await userStore.login({
|
||||
password: data.password,
|
||||
userName: data.account,
|
||||
tenantCode: data.tenantCode,
|
||||
deviceType: 0, //pc-0,app-1
|
||||
mode: 'none' //不要默认的错误提示
|
||||
});
|
||||
if (userInfo) {
|
||||
notification.success({
|
||||
message: t('登录成功'),
|
||||
description: `${t('欢迎回来')}: ${userInfo.name}`,
|
||||
duration: 3
|
||||
});
|
||||
if (rememberMe.value) {
|
||||
const info = {
|
||||
account: Base64.encode(data.account),
|
||||
password: Base64.encode(data.password)
|
||||
};
|
||||
window.localStorage.setItem('USER__LOGIN__INFO__', JSON.stringify(info));
|
||||
} else {
|
||||
window.localStorage.removeItem('USER__LOGIN__INFO__');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
createErrorModal({
|
||||
title: t('错误提示'),
|
||||
content: (error as unknown as Error).message || t('网络异常,请检查您的网络连接是否正常!'),
|
||||
getContainer: () => document.body.querySelector(`.${prefixCls}`) || document.body
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
createErrorModal({
|
||||
title: t('错误提示'),
|
||||
content: (error as unknown as Error).message || t('网络异常,请检查您的网络连接是否正常!'),
|
||||
getContainer: () => document.body.querySelector(`.${prefixCls}`) || document.body,
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function oauthLogin(source: string) {
|
||||
showFlag.value = true;
|
||||
authorizeUrl.value = await getOauthAuthorizeUrl(source);
|
||||
window.location.href = authorizeUrl.value;
|
||||
// let iframe = document.getElementById('iframeId');
|
||||
// console.log(iframe, 'sssssssssss');
|
||||
// var MutationObserver = window.MutationObserver;
|
||||
// // 创建一个观察器实例
|
||||
// var observer = new MutationObserver((item) => {
|
||||
// iframeChange(item);
|
||||
// });
|
||||
// // 观察器的配置
|
||||
// var options = {
|
||||
// childList: true, // 子节点的变动(指新增,删除或者更改) Boolean
|
||||
// attributes: true, // 属性的变动 Boolean
|
||||
// subtree: true, //表示是否将该观察器应用于该节点的所有后代节点 Boolean
|
||||
// attributeOldValue: true, // 表示观察attributes变动时,是否需要记录变动前的属性 Boolean
|
||||
// characterData: true, // 节点内容或节点文本的变动 Boolean
|
||||
// // attributeFilter: ['src'], // 表示需要观察的特定属性 Array,如['class','src', 'style']
|
||||
// };
|
||||
async function oauthLogin(source: string) {
|
||||
showFlag.value = true;
|
||||
authorizeUrl.value = await getOauthAuthorizeUrl(source);
|
||||
window.location.href = authorizeUrl.value;
|
||||
// let iframe = document.getElementById('iframeId');
|
||||
// console.log(iframe, 'sssssssssss');
|
||||
// var MutationObserver = window.MutationObserver;
|
||||
// // 创建一个观察器实例
|
||||
// var observer = new MutationObserver((item) => {
|
||||
// iframeChange(item);
|
||||
// });
|
||||
// // 观察器的配置
|
||||
// var options = {
|
||||
// childList: true, // 子节点的变动(指新增,删除或者更改) Boolean
|
||||
// attributes: true, // 属性的变动 Boolean
|
||||
// subtree: true, //表示是否将该观察器应用于该节点的所有后代节点 Boolean
|
||||
// attributeOldValue: true, // 表示观察attributes变动时,是否需要记录变动前的属性 Boolean
|
||||
// characterData: true, // 节点内容或节点文本的变动 Boolean
|
||||
// // attributeFilter: ['src'], // 表示需要观察的特定属性 Array,如['class','src', 'style']
|
||||
// };
|
||||
|
||||
// // console.log('formRef', iframe.contentWindow.document);
|
||||
// // console.log('formRef', iframe.contentWindow.document);
|
||||
|
||||
// // 开始观察目标节点
|
||||
// function iframeChange(item) {
|
||||
// console.log(item, '节点发生变化');
|
||||
// }
|
||||
// observer.observe(document, options);
|
||||
}
|
||||
// // 开始观察目标节点
|
||||
// function iframeChange(item) {
|
||||
// console.log(item, '节点发生变化');
|
||||
// }
|
||||
// observer.observe(document, options);
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.form-box {
|
||||
font-size: 16px;
|
||||
}
|
||||
.form-box {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.f-16 {
|
||||
font-size: 16px;
|
||||
}
|
||||
.f-16 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
:deep(.ant-checkbox-inner) {
|
||||
border-color: #ced5f2;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 0;
|
||||
}
|
||||
:deep(.ant-checkbox-inner) {
|
||||
border-color: #ced5f2;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item input[type='checkbox']) {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
:deep(.ant-form-item input[type='checkbox']) {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
line-height: 40px;
|
||||
}
|
||||
.form-title {
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.sub-button {
|
||||
height: 60px;
|
||||
font-size: 20px;
|
||||
}
|
||||
.sub-button {
|
||||
height: 60px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.ant-form label {
|
||||
font-size: 16px;
|
||||
}
|
||||
.ant-form label {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.user-icon {
|
||||
font-size: 26px;
|
||||
margin-right: 8px;
|
||||
color: #707c92;
|
||||
}
|
||||
.user-icon {
|
||||
font-size: 26px;
|
||||
margin-right: 8px;
|
||||
color: #707c92;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper {
|
||||
border-color: #ced5f2;
|
||||
border-style: none none solid;
|
||||
}
|
||||
.ant-input-affix-wrapper {
|
||||
border-color: #ced5f2;
|
||||
border-style: none none solid;
|
||||
}
|
||||
|
||||
:deep(.ant-input-password-icon) {
|
||||
font-size: 20px;
|
||||
color: #707c92;
|
||||
margin-right: 8px;
|
||||
}
|
||||
:deep(.ant-input-password-icon) {
|
||||
font-size: 20px;
|
||||
color: #707c92;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
:deep(.ant-input-affix-wrapper-lg) {
|
||||
padding-left: 0;
|
||||
}
|
||||
:deep(.ant-input-affix-wrapper-lg) {
|
||||
padding-left: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,25 +1,25 @@
|
||||
<template>
|
||||
<h2 class="mb-3 text-2xl font-bold text-center xl:text-3xl enter-x xl:text-left">
|
||||
{{ getFormTitle }}
|
||||
</h2>
|
||||
<h2 class="mb-3 text-2xl font-bold text-center xl:text-3xl enter-x xl:text-left">
|
||||
{{ getFormTitle }}
|
||||
</h2>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, unref } from 'vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { LoginStateEnum, useLoginState } from './useLogin';
|
||||
import { computed, unref } from 'vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { LoginStateEnum, useLoginState } from './useLogin';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
const { getLoginState } = useLoginState();
|
||||
const { getLoginState } = useLoginState();
|
||||
|
||||
const getFormTitle = computed(() => {
|
||||
const titleObj = {
|
||||
[LoginStateEnum.RESET_PASSWORD]: t('重置密码'),
|
||||
[LoginStateEnum.LOGIN]: t('登录'),
|
||||
[LoginStateEnum.REGISTER]: t('注册'),
|
||||
[LoginStateEnum.MOBILE]: t('手机登录'),
|
||||
[LoginStateEnum.QR_CODE]: t('二维码登录'),
|
||||
};
|
||||
return titleObj[unref(getLoginState)];
|
||||
});
|
||||
const getFormTitle = computed(() => {
|
||||
const titleObj = {
|
||||
[LoginStateEnum.RESET_PASSWORD]: t('重置密码'),
|
||||
[LoginStateEnum.LOGIN]: t('登录'),
|
||||
[LoginStateEnum.REGISTER]: t('注册'),
|
||||
[LoginStateEnum.MOBILE]: t('手机登录'),
|
||||
[LoginStateEnum.QR_CODE]: t('二维码登录')
|
||||
};
|
||||
return titleObj[unref(getLoginState)];
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,63 +1,53 @@
|
||||
<template>
|
||||
<template v-if="getShow">
|
||||
<LoginFormTitle class="enter-x" />
|
||||
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef">
|
||||
<FormItem name="mobile" class="enter-x">
|
||||
<Input
|
||||
size="large"
|
||||
v-model:value="formData.mobile"
|
||||
:placeholder="t('手机号码')"
|
||||
class="fix-auto-fill"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem name="sms" class="enter-x">
|
||||
<CountdownInput
|
||||
size="large"
|
||||
class="fix-auto-fill"
|
||||
v-model:value="formData.sms"
|
||||
:placeholder="t('短信验证码')"
|
||||
/>
|
||||
</FormItem>
|
||||
<template v-if="getShow">
|
||||
<LoginFormTitle class="enter-x" />
|
||||
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef">
|
||||
<FormItem name="mobile" class="enter-x">
|
||||
<Input size="large" v-model:value="formData.mobile" :placeholder="t('手机号码')" class="fix-auto-fill" />
|
||||
</FormItem>
|
||||
<FormItem name="sms" class="enter-x">
|
||||
<CountdownInput size="large" class="fix-auto-fill" v-model:value="formData.sms" :placeholder="t('短信验证码')" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem class="enter-x">
|
||||
<Button type="primary" size="large" block @click="handleLogin" :loading="loading">
|
||||
{{ t('登录') }}
|
||||
</Button>
|
||||
<Button size="large" block class="mt-4" @click="handleBackLogin">
|
||||
{{ t('返回') }}
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</template>
|
||||
<FormItem class="enter-x">
|
||||
<Button type="primary" size="large" block @click="handleLogin" :loading="loading">
|
||||
{{ t('登录') }}
|
||||
</Button>
|
||||
<Button size="large" block class="mt-4" @click="handleBackLogin">
|
||||
{{ t('返回') }}
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</template>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, computed, unref } from 'vue';
|
||||
import { Form, Input, Button } from 'ant-design-vue';
|
||||
import { CountdownInput } from '/@/components/CountDown';
|
||||
import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useLoginState, useFormRules, useFormValid, LoginStateEnum } from './useLogin';
|
||||
import { reactive, ref, computed, unref } from 'vue';
|
||||
import { Form, Input, Button } from 'ant-design-vue';
|
||||
import { CountdownInput } from '/@/components/CountDown';
|
||||
import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useLoginState, useFormRules, useFormValid, LoginStateEnum } from './useLogin';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { t } = useI18n();
|
||||
const { handleBackLogin, getLoginState } = useLoginState();
|
||||
const { getFormRules } = useFormRules();
|
||||
const FormItem = Form.Item;
|
||||
const { t } = useI18n();
|
||||
const { handleBackLogin, getLoginState } = useLoginState();
|
||||
const { getFormRules } = useFormRules();
|
||||
|
||||
const formRef = ref();
|
||||
const loading = ref(false);
|
||||
const formRef = ref();
|
||||
const loading = ref(false);
|
||||
|
||||
const formData = reactive({
|
||||
mobile: '',
|
||||
sms: '',
|
||||
});
|
||||
const formData = reactive({
|
||||
mobile: '',
|
||||
sms: ''
|
||||
});
|
||||
|
||||
const { validForm } = useFormValid(formRef);
|
||||
const { validForm } = useFormValid(formRef);
|
||||
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.MOBILE);
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.MOBILE);
|
||||
|
||||
async function handleLogin() {
|
||||
const data = await validForm();
|
||||
if (!data) return;
|
||||
console.log(data);
|
||||
}
|
||||
async function handleLogin() {
|
||||
const data = await validForm();
|
||||
if (!data) return;
|
||||
console.log(data);
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,31 +1,27 @@
|
||||
<template>
|
||||
<template v-if="getShow">
|
||||
<LoginFormTitle class="enter-x" />
|
||||
<div class="enter-x min-w-64 min-h-64">
|
||||
<QrCode
|
||||
:value="qrCodeUrl"
|
||||
class="enter-x flex justify-center xl:justify-start"
|
||||
:width="280"
|
||||
/>
|
||||
<Divider class="enter-x">{{ t('扫码后点击"确认",即可完成登录') }}</Divider>
|
||||
<Button size="large" block class="mt-4 enter-x" @click="handleBackLogin">
|
||||
{{ t('返回') }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="getShow">
|
||||
<LoginFormTitle class="enter-x" />
|
||||
<div class="enter-x min-w-64 min-h-64">
|
||||
<QrCode :value="qrCodeUrl" class="enter-x flex justify-center xl:justify-start" :width="280" />
|
||||
<Divider class="enter-x">{{ t('扫码后点击"确认",即可完成登录') }}</Divider>
|
||||
<Button size="large" block class="mt-4 enter-x" @click="handleBackLogin">
|
||||
{{ t('返回') }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, unref } from 'vue';
|
||||
import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { Button, Divider } from 'ant-design-vue';
|
||||
import { QrCode } from '/@/components/Qrcode/index';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useLoginState, LoginStateEnum } from './useLogin';
|
||||
import { computed, unref } from 'vue';
|
||||
import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { Button, Divider } from 'ant-design-vue';
|
||||
import { QrCode } from '/@/components/Qrcode/index';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useLoginState, LoginStateEnum } from './useLogin';
|
||||
|
||||
const qrCodeUrl = 'https://vvbin.cn/next/login';
|
||||
const qrCodeUrl = 'https://vvbin.cn/next/login';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { handleBackLogin, getLoginState } = useLoginState();
|
||||
const { t } = useI18n();
|
||||
const { handleBackLogin, getLoginState } = useLoginState();
|
||||
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE);
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.QR_CODE);
|
||||
</script>
|
||||
|
||||
@ -1,100 +1,73 @@
|
||||
<template>
|
||||
<template v-if="getShow">
|
||||
<LoginFormTitle class="enter-x" />
|
||||
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef">
|
||||
<FormItem name="account" class="enter-x">
|
||||
<Input
|
||||
class="fix-auto-fill"
|
||||
size="large"
|
||||
v-model:value="formData.account"
|
||||
:placeholder="t('账号')"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem name="mobile" class="enter-x">
|
||||
<Input
|
||||
size="large"
|
||||
v-model:value="formData.mobile"
|
||||
:placeholder="t('手机号码')"
|
||||
class="fix-auto-fill"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem name="sms" class="enter-x">
|
||||
<CountdownInput
|
||||
size="large"
|
||||
class="fix-auto-fill"
|
||||
v-model:value="formData.sms"
|
||||
:placeholder="t('短信验证码')"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem name="password" class="enter-x">
|
||||
<StrengthMeter size="large" v-model:value="formData.password" :placeholder="t('mima')" />
|
||||
</FormItem>
|
||||
<FormItem name="confirmPassword" class="enter-x">
|
||||
<InputPassword
|
||||
size="large"
|
||||
visibilityToggle
|
||||
v-model:value="formData.confirmPassword"
|
||||
:placeholder="t('确认密码')"
|
||||
/>
|
||||
</FormItem>
|
||||
<template v-if="getShow">
|
||||
<LoginFormTitle class="enter-x" />
|
||||
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef">
|
||||
<FormItem name="account" class="enter-x">
|
||||
<Input class="fix-auto-fill" size="large" v-model:value="formData.account" :placeholder="t('账号')" />
|
||||
</FormItem>
|
||||
<FormItem name="mobile" class="enter-x">
|
||||
<Input size="large" v-model:value="formData.mobile" :placeholder="t('手机号码')" class="fix-auto-fill" />
|
||||
</FormItem>
|
||||
<FormItem name="sms" class="enter-x">
|
||||
<CountdownInput size="large" class="fix-auto-fill" v-model:value="formData.sms" :placeholder="t('短信验证码')" />
|
||||
</FormItem>
|
||||
<FormItem name="password" class="enter-x">
|
||||
<StrengthMeter size="large" v-model:value="formData.password" :placeholder="t('mima')" />
|
||||
</FormItem>
|
||||
<FormItem name="confirmPassword" class="enter-x">
|
||||
<InputPassword size="large" visibilityToggle v-model:value="formData.confirmPassword" :placeholder="t('确认密码')" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem class="enter-x" name="policy">
|
||||
<!-- No logic, you need to deal with it yourself -->
|
||||
<Checkbox v-model:checked="formData.policy" size="small">
|
||||
{{ t('我同意xxx隐私政策') }}
|
||||
</Checkbox>
|
||||
</FormItem>
|
||||
<FormItem class="enter-x" name="policy">
|
||||
<!-- No logic, you need to deal with it yourself -->
|
||||
<Checkbox v-model:checked="formData.policy" size="small">
|
||||
{{ t('我同意xxx隐私政策') }}
|
||||
</Checkbox>
|
||||
</FormItem>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
class="enter-x"
|
||||
size="large"
|
||||
block
|
||||
@click="handleRegister"
|
||||
:loading="loading"
|
||||
>
|
||||
{{ t('注册') }}
|
||||
</Button>
|
||||
<Button size="large" block class="mt-4 enter-x" @click="handleBackLogin">
|
||||
{{ t('返回') }}
|
||||
</Button>
|
||||
</Form>
|
||||
</template>
|
||||
<Button type="primary" class="enter-x" size="large" block @click="handleRegister" :loading="loading">
|
||||
{{ t('注册') }}
|
||||
</Button>
|
||||
<Button size="large" block class="mt-4 enter-x" @click="handleBackLogin">
|
||||
{{ t('返回') }}
|
||||
</Button>
|
||||
</Form>
|
||||
</template>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, unref, computed } from 'vue';
|
||||
import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { Form, Input, Button, Checkbox } from 'ant-design-vue';
|
||||
import { StrengthMeter } from '/@/components/StrengthMeter';
|
||||
import { CountdownInput } from '/@/components/CountDown';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useLoginState, useFormRules, useFormValid, LoginStateEnum } from './useLogin';
|
||||
import { reactive, ref, unref, computed } from 'vue';
|
||||
import LoginFormTitle from './LoginFormTitle.vue';
|
||||
import { Form, Input, Button, Checkbox } from 'ant-design-vue';
|
||||
import { StrengthMeter } from '/@/components/StrengthMeter';
|
||||
import { CountdownInput } from '/@/components/CountDown';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useLoginState, useFormRules, useFormValid, LoginStateEnum } from './useLogin';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const InputPassword = Input.Password;
|
||||
const { t } = useI18n();
|
||||
const { handleBackLogin, getLoginState } = useLoginState();
|
||||
const FormItem = Form.Item;
|
||||
const InputPassword = Input.Password;
|
||||
const { t } = useI18n();
|
||||
const { handleBackLogin, getLoginState } = useLoginState();
|
||||
|
||||
const formRef = ref();
|
||||
const loading = ref(false);
|
||||
const formRef = ref();
|
||||
const loading = ref(false);
|
||||
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
mobile: '',
|
||||
sms: '',
|
||||
policy: false,
|
||||
});
|
||||
const formData = reactive({
|
||||
account: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
mobile: '',
|
||||
sms: '',
|
||||
policy: false
|
||||
});
|
||||
|
||||
const { getFormRules } = useFormRules(formData);
|
||||
const { validForm } = useFormValid(formRef);
|
||||
const { getFormRules } = useFormRules(formData);
|
||||
const { validForm } = useFormValid(formRef);
|
||||
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER);
|
||||
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER);
|
||||
|
||||
async function handleRegister() {
|
||||
const data = await validForm();
|
||||
if (!data) return;
|
||||
console.log(data);
|
||||
}
|
||||
async function handleRegister() {
|
||||
const data = await validForm();
|
||||
if (!data) return;
|
||||
console.log(data);
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
<template>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { unref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { unref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const { currentRoute, replace } = useRouter();
|
||||
const { currentRoute, replace } = useRouter();
|
||||
|
||||
const { params, query } = unref(currentRoute);
|
||||
const { path, _redirect_type = 'path' } = params;
|
||||
const { params, query } = unref(currentRoute);
|
||||
const { path, _redirect_type = 'path' } = params;
|
||||
|
||||
Reflect.deleteProperty(params, '_redirect_type');
|
||||
Reflect.deleteProperty(params, 'path');
|
||||
Reflect.deleteProperty(params, '_redirect_type');
|
||||
Reflect.deleteProperty(params, 'path');
|
||||
|
||||
const _path = Array.isArray(path) ? path.join('/') : path;
|
||||
const _path = Array.isArray(path) ? path.join('/') : path;
|
||||
|
||||
if (_redirect_type === 'name') {
|
||||
replace({
|
||||
name: _path,
|
||||
query,
|
||||
params,
|
||||
});
|
||||
} else {
|
||||
replace({
|
||||
path: _path.startsWith('/') ? _path : '/' + _path,
|
||||
query,
|
||||
});
|
||||
}
|
||||
if (_redirect_type === 'name') {
|
||||
replace({
|
||||
name: _path,
|
||||
query,
|
||||
params
|
||||
});
|
||||
} else {
|
||||
replace({
|
||||
path: _path.startsWith('/') ? _path : '/' + _path,
|
||||
query
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user