登录叶细胞
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
"element-plus": "^2.4.4",
|
"element-plus": "^2.4.4",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persistedstate": "^3.2.1",
|
"pinia-plugin-persistedstate": "^3.2.1",
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
|
|||||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -9,6 +9,7 @@ specifiers:
|
|||||||
element-plus: ^2.4.4
|
element-plus: ^2.4.4
|
||||||
lodash-es: ^4.17.21
|
lodash-es: ^4.17.21
|
||||||
mitt: ^3.0.1
|
mitt: ^3.0.1
|
||||||
|
nprogress: ^0.2.0
|
||||||
pinia: ^2.1.7
|
pinia: ^2.1.7
|
||||||
pinia-plugin-persistedstate: ^3.2.1
|
pinia-plugin-persistedstate: ^3.2.1
|
||||||
sass: ^1.69.5
|
sass: ^1.69.5
|
||||||
@@ -25,6 +26,7 @@ dependencies:
|
|||||||
element-plus: 2.4.4_vue@3.3.13
|
element-plus: 2.4.4_vue@3.3.13
|
||||||
lodash-es: 4.17.21
|
lodash-es: 4.17.21
|
||||||
mitt: 3.0.1
|
mitt: 3.0.1
|
||||||
|
nprogress: 0.2.0
|
||||||
pinia: 2.1.7_dembj2eby4ermcojoe7jay3m6m
|
pinia: 2.1.7_dembj2eby4ermcojoe7jay3m6m
|
||||||
pinia-plugin-persistedstate: 3.2.1_pinia@2.1.7
|
pinia-plugin-persistedstate: 3.2.1_pinia@2.1.7
|
||||||
screenfull: 6.0.2
|
screenfull: 6.0.2
|
||||||
@@ -860,6 +862,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==}
|
resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/nprogress/0.2.0:
|
||||||
|
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/path-browserify/1.0.1:
|
/path-browserify/1.0.1:
|
||||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|||||||
BIN
src/assets/avatar.png
Normal file
BIN
src/assets/avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 424 B |
BIN
src/assets/bg.jpg
Normal file
BIN
src/assets/bg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/login-header.png
Normal file
BIN
src/assets/login-header.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -1,198 +1,198 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-config-drawer">
|
<div class='layout-config-drawer'>
|
||||||
<el-drawer
|
<el-drawer
|
||||||
:model-value="configStore.layout.showDrawer"
|
:model-value='configStore.layout.showDrawer'
|
||||||
title="布局配置"
|
title='布局配置'
|
||||||
size="310px"
|
size='310px'
|
||||||
@close="onCloseDrawer"
|
@close='onCloseDrawer'
|
||||||
>
|
>
|
||||||
<el-scrollbar class="layout-mode-style-scrollbar">
|
<el-scrollbar class='layout-mode-style-scrollbar'>
|
||||||
<el-form ref="formRef" :model="configStore.layout">
|
<el-form ref='formRef' :model='configStore.layout'>
|
||||||
<div class="layout-mode-styles-box">
|
<div class='layout-mode-styles-box'>
|
||||||
<el-divider border-style="dashed">全局</el-divider>
|
<el-divider border-style='dashed'>全局</el-divider>
|
||||||
<div class="layout-mode-box-style">
|
<div class='layout-mode-box-style'>
|
||||||
<el-row class="layout-mode-box-style-row" :gutter="10">
|
<el-row class='layout-mode-box-style-row' :gutter='10'>
|
||||||
<el-col :span="12">
|
<el-col :span='12'>
|
||||||
<div
|
<div
|
||||||
@click="setLayoutMode('Default')"
|
@click="setLayoutMode('Default')"
|
||||||
class="layout-mode-style default"
|
class='layout-mode-style default'
|
||||||
:class="configStore.layout.layoutMode == 'Default' ? 'active' : ''"
|
:class="configStore.layout.layoutMode == 'Default' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<div class="layout-mode-style-box">
|
<div class='layout-mode-style-box'>
|
||||||
<div class="layout-mode-style-aside"></div>
|
<div class='layout-mode-style-aside'></div>
|
||||||
<div class="layout-mode-style-container-box">
|
<div class='layout-mode-style-container-box'>
|
||||||
<div class="layout-mode-style-header"></div>
|
<div class='layout-mode-style-header'></div>
|
||||||
<div class="layout-mode-style-container"></div>
|
<div class='layout-mode-style-container'></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-mode-style-name">默认</div>
|
<div class='layout-mode-style-name'>默认</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span='12'>
|
||||||
<div
|
<div
|
||||||
@click="setLayoutMode('Classic')"
|
@click="setLayoutMode('Classic')"
|
||||||
class="layout-mode-style classic"
|
class='layout-mode-style classic'
|
||||||
:class="configStore.layout.layoutMode == 'Classic' ? 'active' : ''"
|
:class="configStore.layout.layoutMode == 'Classic' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<div class="layout-mode-style-box">
|
<div class='layout-mode-style-box'>
|
||||||
<div class="layout-mode-style-aside"></div>
|
<div class='layout-mode-style-aside'></div>
|
||||||
<div class="layout-mode-style-container-box">
|
<div class='layout-mode-style-container-box'>
|
||||||
<div class="layout-mode-style-header"></div>
|
<div class='layout-mode-style-header'></div>
|
||||||
<div class="layout-mode-style-container"></div>
|
<div class='layout-mode-style-container'></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-mode-style-name">经典</div>
|
<div class='layout-mode-style-name'>经典</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="10">
|
<el-row :gutter='10'>
|
||||||
<el-col :span="12">
|
<el-col :span='12'>
|
||||||
<div
|
<div
|
||||||
@click="setLayoutMode('Streamline')"
|
@click="setLayoutMode('Streamline')"
|
||||||
class="layout-mode-style streamline"
|
class='layout-mode-style streamline'
|
||||||
:class="configStore.layout.layoutMode == 'Streamline' ? 'active' : ''"
|
:class="configStore.layout.layoutMode == 'Streamline' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<div class="layout-mode-style-box">
|
<div class='layout-mode-style-box'>
|
||||||
<div class="layout-mode-style-container-box">
|
<div class='layout-mode-style-container-box'>
|
||||||
<div class="layout-mode-style-header"></div>
|
<div class='layout-mode-style-header'></div>
|
||||||
<div class="layout-mode-style-container"></div>
|
<div class='layout-mode-style-container'></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-mode-style-name">单栏</div>
|
<div class='layout-mode-style-name'>单栏</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span='12'>
|
||||||
<div
|
<div
|
||||||
@click="setLayoutMode('Double')"
|
@click="setLayoutMode('Double')"
|
||||||
class="layout-mode-style double"
|
class='layout-mode-style double'
|
||||||
:class="configStore.layout.layoutMode == 'Double' ? 'active' : ''"
|
:class="configStore.layout.layoutMode == 'Double' ? 'active' : ''"
|
||||||
>
|
>
|
||||||
<div class="layout-mode-style-box">
|
<div class='layout-mode-style-box'>
|
||||||
<div class="layout-mode-style-aside"></div>
|
<div class='layout-mode-style-aside'></div>
|
||||||
<div class="layout-mode-style-container-box">
|
<div class='layout-mode-style-container-box'>
|
||||||
<div class="layout-mode-style-header"></div>
|
<div class='layout-mode-style-header'></div>
|
||||||
<div class="layout-mode-style-container"></div>
|
<div class='layout-mode-style-container'></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-mode-style-name">双栏</div>
|
<div class='layout-mode-style-name'>双栏</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<el-divider border-style="dashed">全局</el-divider>
|
<el-divider border-style='dashed'>全局</el-divider>
|
||||||
<div class="layout-config-global">
|
<div class='layout-config-global'>
|
||||||
<el-form-item label="'后台页面切换动画">
|
<el-form-item label="'后台页面切换动画">
|
||||||
<el-select
|
<el-select
|
||||||
@change="onCommitState($event, 'mainAnimation')"
|
@change="onCommitState($event, 'mainAnimation')"
|
||||||
:model-value="configStore.layout.mainAnimation"
|
:model-value='configStore.layout.mainAnimation'
|
||||||
:placeholder="'layouts.Please select an animation name'"
|
:placeholder="'layouts.Please select an animation name'"
|
||||||
>
|
>
|
||||||
<el-option label="slide-right" value="slide-right"></el-option>
|
<el-option label='slide-right' value='slide-right'></el-option>
|
||||||
<el-option label="slide-left" value="slide-left"></el-option>
|
<el-option label='slide-left' value='slide-left'></el-option>
|
||||||
<el-option label="el-fade-in-linear" value="el-fade-in-linear"></el-option>
|
<el-option label='el-fade-in-linear' value='el-fade-in-linear'></el-option>
|
||||||
<el-option label="el-fade-in" value="el-fade-in"></el-option>
|
<el-option label='el-fade-in' value='el-fade-in'></el-option>
|
||||||
<el-option label="el-zoom-in-center" value="el-zoom-in-center"></el-option>
|
<el-option label='el-zoom-in-center' value='el-zoom-in-center'></el-option>
|
||||||
<el-option label="el-zoom-in-top" value="el-zoom-in-top"></el-option>
|
<el-option label='el-zoom-in-top' value='el-zoom-in-top'></el-option>
|
||||||
<el-option label="el-zoom-in-bottom" value="el-zoom-in-bottom"></el-option>
|
<el-option label='el-zoom-in-bottom' value='el-zoom-in-bottom'></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-divider border-style="dashed">侧边栏</el-divider>
|
<el-divider border-style='dashed'>侧边栏</el-divider>
|
||||||
<div class="layout-config-aside">
|
<div class='layout-config-aside'>
|
||||||
<el-form-item label="侧边菜单栏背景色">
|
<el-form-item label='侧边菜单栏背景色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'menuBackground')"
|
@change="onCommitColorState($event, 'menuBackground')"
|
||||||
:model-value="configStore.getColorVal('menuBackground')"
|
:model-value="configStore.getColorVal('menuBackground')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="侧边菜单文字颜色">
|
<el-form-item label='侧边菜单文字颜色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'menuColor')"
|
@change="onCommitColorState($event, 'menuColor')"
|
||||||
:model-value="configStore.getColorVal('menuColor')"
|
:model-value="configStore.getColorVal('menuColor')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="侧边菜单激活项背景色">
|
<el-form-item label='侧边菜单激活项背景色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'menuActiveBackground')"
|
@change="onCommitColorState($event, 'menuActiveBackground')"
|
||||||
:model-value="configStore.getColorVal('menuActiveBackground')"
|
:model-value="configStore.getColorVal('menuActiveBackground')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="侧边菜单激活项文字色">
|
<el-form-item label='侧边菜单激活项文字色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'menuActiveColor')"
|
@change="onCommitColorState($event, 'menuActiveColor')"
|
||||||
:model-value="configStore.getColorVal('menuActiveColor')"
|
:model-value="configStore.getColorVal('menuActiveColor')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="显示侧边菜单顶栏(LOGO栏)">
|
<el-form-item label='显示侧边菜单顶栏(LOGO栏)'>
|
||||||
<el-switch
|
<el-switch
|
||||||
@change="onCommitState($event, 'menuShowTopBar')"
|
@change="onCommitState($event, 'menuShowTopBar')"
|
||||||
:model-value="configStore.layout.menuShowTopBar"
|
:model-value='configStore.layout.menuShowTopBar'
|
||||||
></el-switch>
|
></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="侧边菜单顶栏背景色">
|
<el-form-item label='侧边菜单顶栏背景色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'menuTopBarBackground')"
|
@change="onCommitColorState($event, 'menuTopBarBackground')"
|
||||||
:model-value="configStore.getColorVal('menuTopBarBackground')"
|
:model-value="configStore.getColorVal('menuTopBarBackground')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="侧边菜单宽度(展开时)">
|
<el-form-item label='侧边菜单宽度(展开时)'>
|
||||||
<el-input
|
<el-input
|
||||||
@input="onCommitState($event, 'menuWidth')"
|
@input="onCommitState($event, 'menuWidth')"
|
||||||
type="number"
|
type='number'
|
||||||
:step="10"
|
:step='10'
|
||||||
:model-value="configStore.layout.menuWidth"
|
:model-value='configStore.layout.menuWidth'
|
||||||
>
|
>
|
||||||
<template #append>px</template>
|
<template #append>px</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="侧边菜单默认图标">
|
<el-form-item label='侧边菜单默认图标'>
|
||||||
<IconSelector
|
<IconSelector
|
||||||
@change="onCommitMenuDefaultIcon($event, 'menuDefaultIcon')"
|
@change="onCommitMenuDefaultIcon($event, 'menuDefaultIcon')"
|
||||||
:model-value="configStore.layout.menuDefaultIcon"
|
:model-value='configStore.layout.menuDefaultIcon'
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="侧边菜单水平折叠">
|
<el-form-item label='侧边菜单水平折叠'>
|
||||||
<el-switch
|
<el-switch
|
||||||
@change="onCommitState($event, 'menuCollapse')"
|
@change="onCommitState($event, 'menuCollapse')"
|
||||||
:model-value="configStore.layout.menuCollapse"
|
:model-value='configStore.layout.menuCollapse'
|
||||||
></el-switch>
|
></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="侧边菜单手风琴">
|
<el-form-item label='侧边菜单手风琴'>
|
||||||
<el-switch
|
<el-switch
|
||||||
@change="onCommitState($event, 'menuUniqueOpened')"
|
@change="onCommitState($event, 'menuUniqueOpened')"
|
||||||
:model-value="configStore.layout.menuUniqueOpened"
|
:model-value='configStore.layout.menuUniqueOpened'
|
||||||
></el-switch>
|
></el-switch>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-divider border-style="dashed">顶栏</el-divider>
|
<el-divider border-style='dashed'>顶栏</el-divider>
|
||||||
<div class="layout-config-aside">
|
<div class='layout-config-aside'>
|
||||||
<el-form-item label="顶栏背景色">
|
<el-form-item label='顶栏背景色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'headerBarBackground')"
|
@change="onCommitColorState($event, 'headerBarBackground')"
|
||||||
:model-value="configStore.getColorVal('headerBarBackground')"
|
:model-value="configStore.getColorVal('headerBarBackground')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="顶栏文字色">
|
<el-form-item label='顶栏文字色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'headerBarTabColor')"
|
@change="onCommitColorState($event, 'headerBarTabColor')"
|
||||||
:model-value="configStore.getColorVal('headerBarTabColor')"
|
:model-value="configStore.getColorVal('headerBarTabColor')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="顶栏悬停时背景色">
|
<el-form-item label='顶栏悬停时背景色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'headerBarHoverBackground')"
|
@change="onCommitColorState($event, 'headerBarHoverBackground')"
|
||||||
:model-value="configStore.getColorVal('headerBarHoverBackground')"
|
:model-value="configStore.getColorVal('headerBarHoverBackground')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="顶栏菜单激活项背景色">
|
<el-form-item label='顶栏菜单激活项背景色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'headerBarTabActiveBackground')"
|
@change="onCommitColorState($event, 'headerBarTabActiveBackground')"
|
||||||
:model-value="configStore.getColorVal('headerBarTabActiveBackground')"
|
:model-value="configStore.getColorVal('headerBarTabActiveBackground')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="顶栏菜单激活项文字色">
|
<el-form-item label='顶栏菜单激活项文字色'>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
@change="onCommitColorState($event, 'headerBarTabActiveColor')"
|
@change="onCommitColorState($event, 'headerBarTabActiveColor')"
|
||||||
:model-value="configStore.getColorVal('headerBarTabActiveColor')"
|
:model-value="configStore.getColorVal('headerBarTabActiveColor')"
|
||||||
@@ -200,14 +200,12 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
<el-popconfirm
|
<el-popconfirm
|
||||||
@confirm="restoreDefault"
|
@confirm='restoreDefault'
|
||||||
:title="
|
title='确定要恢复全部配置到默认值吗?'
|
||||||
'layouts.Are you sure you want to restore all configurations to the default values?'
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<div class="ba-center">
|
<div class='ba-center'>
|
||||||
<el-button class="w80" type="info">恢复默认</el-button>
|
<el-button class='w80' type='info'>恢复默认</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
@@ -218,7 +216,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang='ts'>
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
import { useNavTabs } from '@/stores/navTabs'
|
import { useNavTabs } from '@/stores/navTabs'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
@@ -271,34 +269,42 @@ const restoreDefault = () => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang='scss'>
|
||||||
.layout-config-drawer :deep(.el-input__inner) {
|
.layout-config-drawer :deep(.el-input__inner) {
|
||||||
padding: 0 0 0 6px;
|
padding: 0 0 0 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-config-drawer :deep(.el-input-group__append) {
|
.layout-config-drawer :deep(.el-input-group__append) {
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-config-drawer :deep(.el-drawer__header) {
|
.layout-config-drawer :deep(.el-drawer__header) {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-config-drawer :deep(.el-drawer__body) {
|
.layout-config-drawer :deep(.el-drawer__body) {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-styles-box {
|
.layout-mode-styles-box {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-box-style-row {
|
.layout-mode-box-style-row {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style {
|
.layout-mode-style {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
border: 1px solid var(--el-border-color-light);
|
border: 1px solid var(--el-border-color-light);
|
||||||
border-radius: var(--el-border-radius-small);
|
border-radius: var(--el-border-radius-small);
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&.active {
|
&.active {
|
||||||
border: 1px solid var(--el-color-primary);
|
border: 1px solid var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-name {
|
.layout-mode-style-name {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -310,6 +316,7 @@ const restoreDefault = () => {
|
|||||||
width: 50px;
|
width: 50px;
|
||||||
border: 1px solid var(--el-color-primary-light-3);
|
border: 1px solid var(--el-color-primary-light-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-box {
|
.layout-mode-style-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -317,24 +324,29 @@ const restoreDefault = () => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.default {
|
&.default {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.layout-mode-style-aside {
|
.layout-mode-style-aside {
|
||||||
width: 18%;
|
width: 18%;
|
||||||
height: 90%;
|
height: 90%;
|
||||||
background-color: var(--el-border-color-lighter);
|
background-color: var(--el-border-color-lighter);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-container-box {
|
.layout-mode-style-container-box {
|
||||||
width: 68%;
|
width: 68%;
|
||||||
height: 90%;
|
height: 90%;
|
||||||
margin-left: 4%;
|
margin-left: 4%;
|
||||||
|
|
||||||
.layout-mode-style-header {
|
.layout-mode-style-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 10%;
|
height: 10%;
|
||||||
background-color: var(--el-border-color-lighter);
|
background-color: var(--el-border-color-lighter);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-container {
|
.layout-mode-style-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 85%;
|
height: 85%;
|
||||||
@@ -343,23 +355,28 @@ const restoreDefault = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.classic {
|
&.classic {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.layout-mode-style-aside {
|
.layout-mode-style-aside {
|
||||||
width: 18%;
|
width: 18%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: var(--el-border-color-lighter);
|
background-color: var(--el-border-color-lighter);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-container-box {
|
.layout-mode-style-container-box {
|
||||||
width: 82%;
|
width: 82%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.layout-mode-style-header {
|
.layout-mode-style-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 10%;
|
height: 10%;
|
||||||
background-color: var(--el-border-color);
|
background-color: var(--el-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-container {
|
.layout-mode-style-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 90%;
|
height: 90%;
|
||||||
@@ -367,18 +384,22 @@ const restoreDefault = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.streamline {
|
&.streamline {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.layout-mode-style-container-box {
|
.layout-mode-style-container-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.layout-mode-style-header {
|
.layout-mode-style-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 10%;
|
height: 10%;
|
||||||
background-color: var(--el-border-color);
|
background-color: var(--el-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-container {
|
.layout-mode-style-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 90%;
|
height: 90%;
|
||||||
@@ -386,23 +407,28 @@ const restoreDefault = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.double {
|
&.double {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.layout-mode-style-aside {
|
.layout-mode-style-aside {
|
||||||
width: 18%;
|
width: 18%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: var(--el-border-color);
|
background-color: var(--el-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-container-box {
|
.layout-mode-style-container-box {
|
||||||
width: 82%;
|
width: 82%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.layout-mode-style-header {
|
.layout-mode-style-header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 10%;
|
height: 10%;
|
||||||
background-color: var(--el-border-color);
|
background-color: var(--el-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-mode-style-container {
|
.layout-mode-style-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 90%;
|
height: 90%;
|
||||||
@@ -411,6 +437,7 @@ const restoreDefault = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.w80 {
|
.w80 {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="nav-menus" :class="configStore.layout.layoutMode">
|
<div class="nav-menus" :class="configStore.layout.layoutMode">
|
||||||
<router-link class="h100" target="_blank" title="'Home'" to="/">
|
|
||||||
<div class="nav-menu-item">
|
|
||||||
<Icon
|
|
||||||
:color="configStore.getColorVal('headerBarTabColor')"
|
|
||||||
class="nav-menu-icon"
|
|
||||||
name="el-icon-Monitor"
|
|
||||||
size="18"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</router-link>
|
|
||||||
<div @click="onFullScreen" class="nav-menu-item" :class="state.isFullScreen ? 'hover' : ''">
|
<div @click="onFullScreen" class="nav-menu-item" :class="state.isFullScreen ? 'hover' : ''">
|
||||||
<Icon
|
<Icon
|
||||||
:color="configStore.getColorVal('headerBarTabColor')"
|
:color="configStore.getColorVal('headerBarTabColor')"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="config.layout.layoutMode"></component>
|
<component :is='config.layout.layoutMode'></component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang='ts'>
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
import { useNavTabs } from '@/stores/navTabs'
|
import { useNavTabs } from '@/stores/navTabs'
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-main class="layout-main">
|
<el-main class='layout-main'>
|
||||||
<el-scrollbar class="layout-main-scrollbar" :style="layoutMainScrollbarStyle()" ref="mainScrollbarRef">
|
<el-scrollbar class='layout-main-scrollbar' :style='layoutMainScrollbarStyle()' ref='mainScrollbarRef'>
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot='{ Component }'>
|
||||||
<transition :name="config.layout.mainAnimation" mode="out-in">
|
<transition :name='config.layout.mainAnimation' mode='out-in'>
|
||||||
<keep-alive :include="state.keepAliveComponentNameList">
|
<keep-alive :include='state.keepAliveComponentNameList'>
|
||||||
<component :is="Component" :key="state.componentKey" />
|
<div class='default-main'>
|
||||||
|
<component :is='Component' :key='state.componentKey' />
|
||||||
|
</div>
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
@@ -12,7 +14,7 @@
|
|||||||
</el-main>
|
</el-main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang='ts'>
|
||||||
import { ref, reactive, onMounted, watch, onBeforeMount, onUnmounted, nextTick, provide } from 'vue'
|
import { ref, reactive, onMounted, watch, onBeforeMount, onUnmounted, nextTick, provide } from 'vue'
|
||||||
import { useRoute, type RouteLocationNormalized } from 'vue-router'
|
import { useRoute, type RouteLocationNormalized } from 'vue-router'
|
||||||
import { mainHeight as layoutMainScrollbarStyle } from '@/utils/layout'
|
import { mainHeight as layoutMainScrollbarStyle } from '@/utils/layout'
|
||||||
@@ -22,7 +24,7 @@ import { useNavTabs } from '@/stores/navTabs'
|
|||||||
import type { ScrollbarInstance } from 'element-plus'
|
import type { ScrollbarInstance } from 'element-plus'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'layout/main',
|
name: 'layout/main'
|
||||||
})
|
})
|
||||||
|
|
||||||
const { proxy } = useCurrentInstance()
|
const { proxy } = useCurrentInstance()
|
||||||
@@ -37,10 +39,10 @@ const state: {
|
|||||||
keepAliveComponentNameList: string[]
|
keepAliveComponentNameList: string[]
|
||||||
} = reactive({
|
} = reactive({
|
||||||
componentKey: route.path,
|
componentKey: route.path,
|
||||||
keepAliveComponentNameList: [],
|
keepAliveComponentNameList: []
|
||||||
})
|
})
|
||||||
|
|
||||||
const addKeepAliveComponentName = function (keepAliveName: string | undefined) {
|
const addKeepAliveComponentName = function(keepAliveName: string | undefined) {
|
||||||
if (keepAliveName) {
|
if (keepAliveName) {
|
||||||
let exist = state.keepAliveComponentNameList.find((name: string) => {
|
let exist = state.keepAliveComponentNameList.find((name: string) => {
|
||||||
return name === keepAliveName
|
return name === keepAliveName
|
||||||
@@ -89,13 +91,14 @@ watch(
|
|||||||
provide('mainScrollbarRef', mainScrollbarRef)
|
provide('mainScrollbarRef', mainScrollbarRef)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang='scss'>
|
||||||
.layout-container .layout-main {
|
.layout-container .layout-main {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-main-scrollbar {
|
.layout-main-scrollbar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
@@ -1,75 +1,31 @@
|
|||||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
import staticRoutes from '@/router/static'
|
import staticRoutes from '@/router/static'
|
||||||
|
import { useConfig } from '@/stores/config'
|
||||||
|
import NProgress from 'nprogress'
|
||||||
|
import { loading } from '@/utils/loading'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
routes: staticRoutes
|
routes: staticRoutes
|
||||||
})
|
})
|
||||||
|
|
||||||
// router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
// NProgress.configure({ showSpinner: false })
|
NProgress.configure({ showSpinner: false })
|
||||||
// NProgress.start()
|
NProgress.start()
|
||||||
// if (!window.existLoading) {
|
if (!window.existLoading) {
|
||||||
// loading.show()
|
loading.show()
|
||||||
// window.existLoading = true
|
window.existLoading = true
|
||||||
// }
|
}
|
||||||
|
console.log(to)
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
// // 按需动态加载页面的语言包-start
|
// 路由加载后
|
||||||
// let loadPath: string[] = []
|
router.afterEach(() => {
|
||||||
// const config = useConfig()
|
if (window.existLoading) {
|
||||||
// if (to.path in langAutoLoadMap) {
|
loading.hide()
|
||||||
// loadPath.push(...langAutoLoadMap[to.path as keyof typeof langAutoLoadMap])
|
}
|
||||||
// }
|
NProgress.done()
|
||||||
// let prefix = ''
|
})
|
||||||
// if (isAdminApp(to.fullPath)) {
|
|
||||||
// prefix = './backend/' + config.lang.defaultLang
|
|
||||||
|
|
||||||
// // 去除 path 中的 /admin
|
|
||||||
// const adminPath = to.path.slice(to.path.indexOf(adminBaseRoutePath) + adminBaseRoutePath.length)
|
|
||||||
// if (adminPath) loadPath.push(prefix + adminPath + '.ts')
|
|
||||||
// } else {
|
|
||||||
// prefix = './frontend/' + config.lang.defaultLang
|
|
||||||
// loadPath.push(prefix + to.path + '.ts')
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 根据路由 name 加载的语言包
|
|
||||||
// if (to.name) {
|
|
||||||
// loadPath.push(prefix + '/' + to.name.toString() + '.ts')
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!window.loadLangHandle.publicMessageLoaded) window.loadLangHandle.publicMessageLoaded = []
|
|
||||||
// const publicMessagePath = prefix + '.ts'
|
|
||||||
// if (!window.loadLangHandle.publicMessageLoaded.includes(publicMessagePath)) {
|
|
||||||
// loadPath.push(publicMessagePath)
|
|
||||||
// window.loadLangHandle.publicMessageLoaded.push(publicMessagePath)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 去重
|
|
||||||
// loadPath = uniq(loadPath)
|
|
||||||
|
|
||||||
// for (const key in loadPath) {
|
|
||||||
// loadPath[key] = loadPath[key].replaceAll('${lang}', config.lang.defaultLang)
|
|
||||||
// if (loadPath[key] in window.loadLangHandle) {
|
|
||||||
// window.loadLangHandle[loadPath[key]]().then((res: { default: anyObj }) => {
|
|
||||||
// const pathName = loadPath[key].slice(
|
|
||||||
// loadPath[key].lastIndexOf(prefix) + (prefix.length + 1),
|
|
||||||
// loadPath[key].lastIndexOf('.')
|
|
||||||
// )
|
|
||||||
// mergeMessage(res.default, pathName)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // 动态加载语言包-end
|
|
||||||
|
|
||||||
// next()
|
|
||||||
// })
|
|
||||||
|
|
||||||
// // 路由加载后
|
|
||||||
// router.afterEach(() => {
|
|
||||||
// if (window.existLoading) {
|
|
||||||
// loading.hide()
|
|
||||||
// }
|
|
||||||
// NProgress.done()
|
|
||||||
// })
|
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
@@ -34,6 +34,14 @@ export const adminBaseRoute = {
|
|||||||
*/
|
*/
|
||||||
const staticRoutes: Array<RouteRecordRaw> = [
|
const staticRoutes: Array<RouteRecordRaw> = [
|
||||||
adminBaseRoute,
|
adminBaseRoute,
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
redirect: (to) => {
|
||||||
|
return {
|
||||||
|
name: 'adminMainLoading'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// 管理员登录页 - 不放在 adminBaseRoute.children 因为登录页不需要使用后台的布局
|
// 管理员登录页 - 不放在 adminBaseRoute.children 因为登录页不需要使用后台的布局
|
||||||
path: '/login',
|
path: '/login',
|
||||||
@@ -43,7 +51,6 @@ const staticRoutes: Array<RouteRecordRaw> = [
|
|||||||
title: pageTitle('login')
|
title: pageTitle('login')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/:path(.*)*',
|
path: '/:path(.*)*',
|
||||||
redirect: '/404'
|
redirect: '/404'
|
||||||
@@ -56,6 +63,21 @@ const staticRoutes: Array<RouteRecordRaw> = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: pageTitle('notFound') // 页面不存在
|
title: pageTitle('notFound') // 页面不存在
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 后台找不到页面了-可能是路由未加载上
|
||||||
|
path: adminBaseRoutePath + ':path(.*)*',
|
||||||
|
redirect: (to) => {
|
||||||
|
return {
|
||||||
|
name: 'adminMainLoading',
|
||||||
|
params: {
|
||||||
|
to: JSON.stringify({
|
||||||
|
path: to.path,
|
||||||
|
query: to.query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
54
src/styles/loading.scss
Normal file
54
src/styles/loading.scss
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
.block-loading {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9990;
|
||||||
|
background-color: var(--ba-bg-color);
|
||||||
|
}
|
||||||
|
.block-loading .block-loading-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
.block-loading .block-loading-box-warp {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item {
|
||||||
|
width: 33.333333%;
|
||||||
|
height: 33.333333%;
|
||||||
|
background: #409eff;
|
||||||
|
float: left;
|
||||||
|
animation: block-loading-animation 1.2s infinite ease;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(7) {
|
||||||
|
animation-delay: 0s;
|
||||||
|
}
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(4),
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(8) {
|
||||||
|
animation-delay: 0.1s;
|
||||||
|
}
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(1),
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(5),
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(9) {
|
||||||
|
animation-delay: 0.2s;
|
||||||
|
}
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(2),
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(6) {
|
||||||
|
animation-delay: 0.3s;
|
||||||
|
}
|
||||||
|
.block-loading .block-loading-box-warp .block-loading-box-item:nth-child(3) {
|
||||||
|
animation-delay: 0.4s;
|
||||||
|
}
|
||||||
|
@keyframes block-loading-animation {
|
||||||
|
0%,
|
||||||
|
70%,
|
||||||
|
100% {
|
||||||
|
transform: scale3D(1, 1, 1);
|
||||||
|
}
|
||||||
|
35% {
|
||||||
|
transform: scale3D(0, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/utils/loading.ts
Normal file
34
src/utils/loading.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { nextTick } from 'vue'
|
||||||
|
import '@/styles/loading.scss'
|
||||||
|
|
||||||
|
export const loading = {
|
||||||
|
show: () => {
|
||||||
|
const bodys: Element = document.body
|
||||||
|
const div = document.createElement('div')
|
||||||
|
div.className = 'block-loading'
|
||||||
|
div.innerHTML = `
|
||||||
|
<div class="block-loading-box">
|
||||||
|
<div class="block-loading-box-warp">
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
<div class="block-loading-box-item"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
bodys.insertBefore(div, bodys.childNodes[0])
|
||||||
|
},
|
||||||
|
hide: () => {
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const el = document.querySelector('.block-loading')
|
||||||
|
el && el.parentNode?.removeChild(el)
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
104
src/utils/pageBubble.ts
Normal file
104
src/utils/pageBubble.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// 页面气泡效果
|
||||||
|
|
||||||
|
const bubble: {
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
bubbleEl: any
|
||||||
|
canvas: any
|
||||||
|
ctx: any
|
||||||
|
circles: any[]
|
||||||
|
animate: boolean
|
||||||
|
requestId: any
|
||||||
|
} = {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
bubbleEl: null,
|
||||||
|
canvas: null,
|
||||||
|
ctx: {},
|
||||||
|
circles: [],
|
||||||
|
animate: true,
|
||||||
|
requestId: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const init = function (): void {
|
||||||
|
bubble.width = window.innerWidth
|
||||||
|
bubble.height = window.innerHeight
|
||||||
|
|
||||||
|
bubble.bubbleEl = document.getElementById('bubble')
|
||||||
|
bubble.bubbleEl.style.height = bubble.height + 'px'
|
||||||
|
|
||||||
|
bubble.canvas = document.getElementById('bubble-canvas')
|
||||||
|
bubble.canvas.width = bubble.width
|
||||||
|
bubble.canvas.height = bubble.height
|
||||||
|
bubble.ctx = bubble.canvas.getContext('2d')
|
||||||
|
|
||||||
|
// create particles
|
||||||
|
bubble.circles = []
|
||||||
|
for (let x = 0; x < bubble.width * 0.5; x++) {
|
||||||
|
const c = new Circle()
|
||||||
|
bubble.circles.push(c)
|
||||||
|
}
|
||||||
|
animate()
|
||||||
|
addListeners()
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollCheck() {
|
||||||
|
bubble.animate = document.body.scrollTop > bubble.height ? false : true
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
bubble.width = window.innerWidth
|
||||||
|
bubble.height = window.innerHeight
|
||||||
|
bubble.bubbleEl.style.height = bubble.height + 'px'
|
||||||
|
bubble.canvas.width = bubble.width
|
||||||
|
bubble.canvas.height = bubble.height
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
if (bubble.animate) {
|
||||||
|
bubble.ctx.clearRect(0, 0, bubble.width, bubble.height)
|
||||||
|
for (const i in bubble.circles) {
|
||||||
|
bubble.circles[i].draw()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bubble.requestId = requestAnimationFrame(animate)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Circle {
|
||||||
|
pos: {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
alpha: number
|
||||||
|
scale: number
|
||||||
|
velocity: number
|
||||||
|
draw: () => void
|
||||||
|
constructor() {
|
||||||
|
this.pos = {
|
||||||
|
x: Math.random() * bubble.width,
|
||||||
|
y: bubble.height + Math.random() * 100,
|
||||||
|
}
|
||||||
|
this.alpha = 0.1 + Math.random() * 0.3
|
||||||
|
this.scale = 0.1 + Math.random() * 0.3
|
||||||
|
this.velocity = Math.random()
|
||||||
|
this.draw = function () {
|
||||||
|
this.pos.y -= this.velocity
|
||||||
|
this.alpha -= 0.0005
|
||||||
|
bubble.ctx.beginPath()
|
||||||
|
bubble.ctx.arc(this.pos.x, this.pos.y, this.scale * 10, 0, 2 * Math.PI, false)
|
||||||
|
bubble.ctx.fillStyle = 'rgba(255,255,255,' + this.alpha + ')'
|
||||||
|
bubble.ctx.fill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addListeners() {
|
||||||
|
window.addEventListener('scroll', scrollCheck)
|
||||||
|
window.addEventListener('resize', resize)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeListeners() {
|
||||||
|
window.removeEventListener('scroll', scrollCheck)
|
||||||
|
window.removeEventListener('resize', resize)
|
||||||
|
cancelAnimationFrame(bubble.requestId)
|
||||||
|
}
|
||||||
@@ -22,14 +22,14 @@ export const routePush = async (to: RouteLocationRaw) => {
|
|||||||
type: 'error'
|
type: 'error'
|
||||||
})
|
})
|
||||||
} else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {
|
} else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {
|
||||||
ElNotification({
|
// ElNotification({
|
||||||
message: 'utils.Navigation failed, it is at the navigation target position!',
|
// message: '已在目标页',
|
||||||
type: 'warning'
|
// type: 'warning'
|
||||||
})
|
// })
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElNotification({
|
ElNotification({
|
||||||
message: 'utils.Navigation failed, invalid route!',
|
message: '导航失败,路由无效',
|
||||||
type: 'error'
|
type: 'error'
|
||||||
})
|
})
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|||||||
@@ -1,78 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form :model="form" label-width="120px">
|
123123
|
||||||
<el-form-item label="Activity name">
|
</template>
|
||||||
<el-input v-model="form.name" />
|
|
||||||
</el-form-item>
|
<script lang='ts' setup>
|
||||||
<el-form-item label="Activity zone">
|
|
||||||
<el-select v-model="form.region" placeholder="please select your zone">
|
</script>
|
||||||
<el-option label="Zone one" value="shanghai" />
|
|
||||||
<el-option label="Zone two" value="beijing" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="Activity time">
|
|
||||||
<el-col :span="11">
|
|
||||||
<el-date-picker
|
|
||||||
v-model="form.date1"
|
|
||||||
type="date"
|
|
||||||
placeholder="Pick a date"
|
|
||||||
style="width: 100%"
|
|
||||||
/>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="2" class="text-center">
|
|
||||||
<span class="text-gray-500">-</span>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="11">
|
|
||||||
<el-time-picker
|
|
||||||
v-model="form.date2"
|
|
||||||
placeholder="Pick a time"
|
|
||||||
style="width: 100%"
|
|
||||||
/>
|
|
||||||
</el-col>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="Instant delivery">
|
|
||||||
<el-switch v-model="form.delivery" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="Activity type">
|
|
||||||
<el-checkbox-group v-model="form.type">
|
|
||||||
<el-checkbox label="Online activities" name="type" />
|
|
||||||
<el-checkbox label="Promotion activities" name="type" />
|
|
||||||
<el-checkbox label="Offline activities" name="type" />
|
|
||||||
<el-checkbox label="Simple brand exposure" name="type" />
|
|
||||||
</el-checkbox-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="Resources">
|
|
||||||
<el-radio-group v-model="form.resource">
|
|
||||||
<el-radio label="Sponsor" />
|
|
||||||
<el-radio label="Venue" />
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="Activity form">
|
|
||||||
<el-input v-model="form.desc" type="textarea" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="onSubmit">Create</el-button>
|
|
||||||
<el-button>Cancel</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { reactive } from 'vue'
|
|
||||||
|
|
||||||
// do not use same name with ref
|
|
||||||
const form = reactive({
|
|
||||||
name: '',
|
|
||||||
region: '',
|
|
||||||
date1: '',
|
|
||||||
date2: '',
|
|
||||||
delivery: false,
|
|
||||||
type: [],
|
|
||||||
resource: '',
|
|
||||||
desc: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
const onSubmit = () => {
|
|
||||||
console.log('submit!')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@@ -1 +1,213 @@
|
|||||||
<template>login</template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<div @contextmenu.stop='' id='bubble' class='bubble'>
|
||||||
|
<canvas id='bubble-canvas' class='bubble-canvas'></canvas>
|
||||||
|
</div>
|
||||||
|
<div class='login'>
|
||||||
|
<div class='login-box'>
|
||||||
|
<div class='head'>
|
||||||
|
<img src='@/assets/login-header.png' alt='' />
|
||||||
|
</div>
|
||||||
|
<div class='form'>
|
||||||
|
<img class='profile-avatar' src='@/assets/avatar.png' alt='' />
|
||||||
|
<div class='content'>
|
||||||
|
<el-form @keyup.enter='onSubmit()' ref='formRef' size='large' :model='form'>
|
||||||
|
<el-form-item prop='username'>
|
||||||
|
<el-input
|
||||||
|
ref='usernameRef'
|
||||||
|
type='text'
|
||||||
|
clearable
|
||||||
|
v-model='form.username'
|
||||||
|
placeholder='请输入账号'
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<Icon name='fa fa-user' class='form-item-icon' size='16'
|
||||||
|
color='var(--el-input-icon-color)' />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop='password'>
|
||||||
|
<el-input
|
||||||
|
ref='passwordRef'
|
||||||
|
v-model='form.password'
|
||||||
|
type='password'
|
||||||
|
placeholder='请输入密码'
|
||||||
|
show-password
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<Icon name='fa fa-unlock-alt' class='form-item-icon' size='16'
|
||||||
|
color='var(--el-input-icon-color)' />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
:loading='state.submitLoading'
|
||||||
|
class='submit-button'
|
||||||
|
round
|
||||||
|
type='primary'
|
||||||
|
size='large'
|
||||||
|
@click='onSubmit()'
|
||||||
|
>
|
||||||
|
登录
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts'>
|
||||||
|
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
|
||||||
|
import * as pageBubble from '@/utils/pageBubble'
|
||||||
|
import type { FormInstance, InputInstance } from 'element-plus'
|
||||||
|
|
||||||
|
let timer: number
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const usernameRef = ref<InputInstance>()
|
||||||
|
const passwordRef = ref<InputInstance>()
|
||||||
|
const state = reactive({
|
||||||
|
showCaptcha: false,
|
||||||
|
submitLoading: false
|
||||||
|
})
|
||||||
|
const form = reactive({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const focusInput = () => {
|
||||||
|
if (form.username === '') {
|
||||||
|
usernameRef.value!.focus()
|
||||||
|
} else if (form.password === '') {
|
||||||
|
passwordRef.value!.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
timer = window.setTimeout(() => {
|
||||||
|
pageBubble.init()
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearTimeout(timer)
|
||||||
|
pageBubble.removeListeners()
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSubmit = (captchaInfo = '') => {
|
||||||
|
state.submitLoading = true
|
||||||
|
setTimeout(() => {
|
||||||
|
state.submitLoading = false
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='scss'>
|
||||||
|
.switch-language {
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
overflow: hidden;
|
||||||
|
background: url(@/assets/bg.jpg) repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item-icon {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
display: flex;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
overflow: hidden;
|
||||||
|
width: 430px;
|
||||||
|
padding: 0;
|
||||||
|
background: var(--ba-bg-color-overlay);
|
||||||
|
margin-bottom: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head {
|
||||||
|
background: #ccccff;
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
width: 430px;
|
||||||
|
margin: 0 auto;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.profile-avatar {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 4px solid var(--ba-bg-color-overlay);
|
||||||
|
top: -50px;
|
||||||
|
right: calc(50% - 50px);
|
||||||
|
z-index: 2;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 100px 40px 40px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-button {
|
||||||
|
width: 100%;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
font-weight: 300;
|
||||||
|
margin-top: 15px;
|
||||||
|
--el-button-bg-color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 720px) {
|
||||||
|
.login {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.login-box {
|
||||||
|
width: 340px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chang-lang :deep(.el-dropdown-menu__item) {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content :deep(.el-input__prefix) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-height: 800px) {
|
||||||
|
.login .login-box {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user