mirror of
https://gitee.com/log4j/pig-ui.git
synced 2024-12-22 21:22:33 +08:00
'admin-22.11.16:发布v2.3.0,具体更新内容查看CHANGELOG.md'
This commit is contained in:
parent
aba9f3947d
commit
cdf1b715df
21
CHANGELOG.md
21
CHANGELOG.md
@ -2,6 +2,27 @@
|
|||||||
|
|
||||||
🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等,适配手机、平板、pc 的后台开源免费模板库(vue2.x 请切换 vue-prev-admin 分支)
|
🎉🎉🔥 `vue-next-admin` 基于 vue3.x 、Typescript、vite、Element plus 等,适配手机、平板、pc 的后台开源免费模板库(vue2.x 请切换 vue-prev-admin 分支)
|
||||||
|
|
||||||
|
## 2.3.0
|
||||||
|
|
||||||
|
`2022.11.16`
|
||||||
|
|
||||||
|
- 🌟 更新 依赖更新最新版本
|
||||||
|
- 🎉 新增 新版登录页
|
||||||
|
- 🎉 新增 tagsview 鼠标中键 `关闭当前 tagsview`
|
||||||
|
- 🎉 新增 `分栏菜单鼠标悬停预加载`。[分栏模式如何去掉鼠标悬浮父级菜单,分栏菜单自动加载的功能啊](https://gitee.com/lyt-top/vue-next-admin/issues/I5RUY7)。操作路径:`布局配置 -> 分栏设置`
|
||||||
|
- 🐞 修复 [vue-i18n](https://vue-i18n.intlify.dev/api/general.html#createi18n) 报错,[!39 修复 i18n 兼容性问题](https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/39/files),感谢[@随心](https://toscode.gitee.com/jiangqiang1996)
|
||||||
|
- 🐞 修复 顶栏搜索功能点击蒙蔽弹窗不关闭
|
||||||
|
- 🐞 修复 [!38 fix: bug refreshRouterViewKey 值为 null 导致路由缓存第一次无效](https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/38/files),感谢[@P)](https://toscode.gitee.com/foxp8y)
|
||||||
|
- 🐞 修复 `路由参数 -> 普通路由/动态路由` 国际化演示时,`tagsView` 和 `浏览器标题` 显示异常。[演示中:路由参数界面 -> 动态路由,国际化显示时面包屑、浏览器标题有 bug](https://gitee.com/lyt-top/vue-next-admin/issues/I5JRJG)
|
||||||
|
- 🐞 修复 `路由参数 -> 普通路由/动态路由` 动态设置 `tagsViewName` 时,`tagsView 右键菜单刷新` 功能失效(也就是路由后面有参数时,query、params)。[普通或动态路由新建页面后点击 tagview 刷新无效](https://gitee.com/lyt-top/vue-next-admin/issues/I5K3YO),感谢[@dejavuuuuu](https://gitee.com/zc19951010)
|
||||||
|
- 🐞 修复 [表单(el-form)中,字体图标偏移问题](https://gitee.com/lyt-top/vue-next-admin/issues/I5K1PM)
|
||||||
|
- 🐞 修复 路由 `router.addRoute` 时,一直提示 `No match found for location with path 'xxx'`
|
||||||
|
- 🎯 优化 全局 `getCurrentInstance` 替换成 [`provide/inject`](https://cn.vuejs.org/api/application.html#app-provide) 或通过 `ref` 处理
|
||||||
|
- 🎯 优化 引入组件方式 `(import xxx from xxx)` 改成 `defineAsyncComponent(() => import(xxx))`
|
||||||
|
- 🎯 优化 页面高度 100% 问题,重写布局配置 `界面设置 -> 固定 Header` 多余的 `el-scrollbar` 逻辑、重写各界面需 `计算属性 computed` 设置动态高度问题(改为 css `flex` 设置自适应高度,具体查看文档:[设置可视区高度 100%](https://lyt-top.gitee.io/vue-next-admin-doc-preview/config/otherIssues/#%E8%AE%BE%E7%BD%AE%E5%8F%AF%E8%A7%86%E5%8C%BA%E9%AB%98%E5%BA%A6-100)。[!31 修复页面样式无法通过百分比设置的问题](https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/31),感谢[@LostDeer](https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/31/files)。`(改动较大,删除多余代码)`
|
||||||
|
- 🎯 优化 [wangeditor](https://www.wangeditor.com/) 组件,`@wangeditor/editor-for-vue`。可自行修改,组件位置:`/src/components/editor`。相关 Issues:[wangeditor 编辑器多个菜单不能回弹](https://gitee.com/lyt-top/vue-next-admin/issues/I5M5H7)
|
||||||
|
- 🌈 重构 外链、内嵌 iframe 逻辑 + 美化,iframe 支持缓存
|
||||||
|
|
||||||
## 2.2.0
|
## 2.2.0
|
||||||
|
|
||||||
`2022.07.10`
|
`2022.07.10`
|
||||||
|
@ -68,10 +68,13 @@ cnpm run dev
|
|||||||
cnpm run build
|
cnpm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 📚 开发文档
|
||||||
|
|
||||||
|
- 查看开发文档:<a href="https://lyt-top.gitee.io/vue-next-admin-doc-preview" target="_blank">vue-next-admin-doc</a>
|
||||||
|
|
||||||
#### 💯 学习交流加 QQ 群
|
#### 💯 学习交流加 QQ 群
|
||||||
|
|
||||||
- 若加群了没同意(一般秒过),那就是群满了(500 人群),请换一个群试试。群会定期清理半年(6 个月)未发言的群友,资源有限,请谅解。建议勿加多群,可能会误伤!
|
- 若加群了没同意(一般秒过),那就是群满了(500 人群),请换一个群试试。群会定期清理半年(6 个月)未发言的群友,资源有限,请谅解。建议勿加多群,可能会误伤!微信群由于只有 `7天有效` 就不放这里了。
|
||||||
- 查看开发文档:<a href="https://lyt-top.gitee.io/vue-next-admin-doc-preview" target="_blank">vue-next-admin-doc</a>
|
|
||||||
- 群号码:
|
- 群号码:
|
||||||
1 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi">665452019</a>
|
1 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi">665452019</a>
|
||||||
2 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=zVfy3gNy7pNWVK3kMduDzwU369PZg2fw&jump_from=webapi">766356862</a>
|
2 群:<a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=zVfy3gNy7pNWVK3kMduDzwU369PZg2fw&jump_from=webapi">766356862</a>
|
||||||
|
2680
package-lock.json
generated
2680
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
50
package.json
50
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-next-admin",
|
"name": "vue-next-admin",
|
||||||
"version": "2.2.0",
|
"version": "2.3.0",
|
||||||
"description": "vue3 vite next admin template",
|
"description": "vue3 vite next admin template",
|
||||||
"author": "lyt_20201208",
|
"author": "lyt_20201208",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -10,48 +10,48 @@
|
|||||||
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
|
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.0.6",
|
"@element-plus/icons-vue": "^2.0.10",
|
||||||
"@wangeditor/editor": "^5.1.11",
|
"@wangeditor/editor-for-vue": "^5.1.11",
|
||||||
"axios": "^0.27.2",
|
"axios": "^1.1.3",
|
||||||
"countup.js": "^2.3.2",
|
"countup.js": "^2.3.2",
|
||||||
"cropperjs": "^1.5.12",
|
"cropperjs": "^1.5.12",
|
||||||
"echarts": "^5.3.3",
|
"echarts": "^5.4.0",
|
||||||
"echarts-gl": "^2.0.9",
|
"echarts-gl": "^2.0.9",
|
||||||
"echarts-wordcloud": "^2.0.0",
|
"echarts-wordcloud": "^2.0.0",
|
||||||
"element-plus": "^2.2.9",
|
"element-plus": "^2.2.21",
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
"jsplumb": "^2.15.6",
|
"jsplumb": "^2.15.6",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.0.16",
|
"pinia": "^2.0.23",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"qrcodejs2-fixes": "^0.0.2",
|
"qrcodejs2-fixes": "^0.0.2",
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"sortablejs": "^1.15.0",
|
"sortablejs": "^1.15.0",
|
||||||
"splitpanes": "^3.1.1",
|
"splitpanes": "^3.1.5",
|
||||||
"vue": "^3.2.37",
|
"vue": "^3.2.45",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.1.10",
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-router": "^4.1.2"
|
"vue-router": "^4.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.0.6",
|
"@types/node": "^18.11.9",
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"@types/sortablejs": "^1.13.0",
|
"@types/sortablejs": "^1.15.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.30.7",
|
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
||||||
"@typescript-eslint/parser": "^5.30.7",
|
"@typescript-eslint/parser": "^5.43.0",
|
||||||
"@vitejs/plugin-vue": "^2.3.3",
|
"@vitejs/plugin-vue": "^3.2.0",
|
||||||
"@vue/compiler-sfc": "^3.2.37",
|
"@vue/compiler-sfc": "^3.2.45",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.3",
|
||||||
"eslint": "^8.20.0",
|
"eslint": "^8.27.0",
|
||||||
"eslint-plugin-vue": "^9.2.0",
|
"eslint-plugin-vue": "^9.7.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"sass": "^1.53.0",
|
"sass": "^1.56.1",
|
||||||
"sass-loader": "^13.0.2",
|
"sass-loader": "^13.2.0",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.9.3",
|
||||||
"vite": "^2.9.14",
|
"vite": "^3.2.4",
|
||||||
"vue-eslint-parser": "^9.0.3"
|
"vue-eslint-parser": "^9.1.0"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
|
41
src/App.vue
41
src/App.vue
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-config-provider :size="getGlobalComponentSize" :locale="i18nLocale">
|
<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
|
||||||
<router-view v-show="themeConfig.lockScreenTime > 1" />
|
<router-view v-show="themeConfig.lockScreenTime > 1" />
|
||||||
<LockScreen v-if="themeConfig.isLockScreen" />
|
<LockScreen v-if="themeConfig.isLockScreen" />
|
||||||
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
|
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
|
||||||
@ -8,39 +8,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, ref, getCurrentInstance, onBeforeMount, onMounted, onUnmounted, nextTick, defineComponent, watch, reactive, toRefs } from 'vue';
|
import { defineAsyncComponent, computed, ref, onBeforeMount, onMounted, onUnmounted, nextTick, defineComponent, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import other from '/@/utils/other';
|
import other from '/@/utils/other';
|
||||||
import { Local, Session } from '/@/utils/storage';
|
import { Local, Session } from '/@/utils/storage';
|
||||||
|
import mittBus from '/@/utils/mitt';
|
||||||
import setIntroduction from '/@/utils/setIconfont';
|
import setIntroduction from '/@/utils/setIconfont';
|
||||||
import LockScreen from '/@/layout/lockScreen/index.vue';
|
|
||||||
import Setings from '/@/layout/navBars/breadcrumb/setings.vue';
|
|
||||||
import CloseFull from '/@/layout/navBars/breadcrumb/closeFull.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components: { LockScreen, Setings, CloseFull },
|
components: {
|
||||||
|
LockScreen: defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue')),
|
||||||
|
Setings: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue')),
|
||||||
|
CloseFull: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const { messages, locale } = useI18n();
|
||||||
const setingsRef = ref();
|
const setingsRef = ref();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const stores = useTagsViewRoutes();
|
const stores = useTagsViewRoutes();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const state = reactive({
|
|
||||||
i18nLocale: null,
|
|
||||||
});
|
|
||||||
// 获取全局组件大小
|
// 获取全局组件大小
|
||||||
const getGlobalComponentSize = computed(() => {
|
const getGlobalComponentSize = computed(() => {
|
||||||
return other.globalComponentSize();
|
return other.globalComponentSize();
|
||||||
});
|
});
|
||||||
// 布局配置弹窗打开
|
// 获取全局 i18n
|
||||||
const openSetingsDrawer = () => {
|
const getGlobalI18n = computed(() => {
|
||||||
setingsRef.value.openDrawer();
|
return messages.value[locale.value];
|
||||||
};
|
});
|
||||||
// 设置初始化,防止刷新时恢复默认
|
// 设置初始化,防止刷新时恢复默认
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
// 设置批量第三方 icon 图标
|
// 设置批量第三方 icon 图标
|
||||||
@ -52,12 +52,8 @@ export default defineComponent({
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
// 监听布局配置弹窗点击打开
|
// 监听布局配置弹窗点击打开
|
||||||
proxy.mittBus.on('openSetingsDrawer', () => {
|
mittBus.on('openSetingsDrawer', () => {
|
||||||
openSetingsDrawer();
|
setingsRef.value.openDrawer();
|
||||||
});
|
|
||||||
// 设置 i18n,App.vue 中的 el-config-provider
|
|
||||||
proxy.mittBus.on('getI18nConfig', (locale: string) => {
|
|
||||||
(state.i18nLocale as string | null) = locale;
|
|
||||||
});
|
});
|
||||||
// 获取缓存中的布局配置
|
// 获取缓存中的布局配置
|
||||||
if (Local.get('themeConfig')) {
|
if (Local.get('themeConfig')) {
|
||||||
@ -72,8 +68,7 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
// 页面销毁时,关闭监听布局配置/i18n监听
|
// 页面销毁时,关闭监听布局配置/i18n监听
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
proxy.mittBus.off('openSetingsDrawer', () => {});
|
mittBus.off('openSetingsDrawer', () => {});
|
||||||
proxy.mittBus.off('getI18nConfig', () => {});
|
|
||||||
});
|
});
|
||||||
// 监听路由的变化,设置网站标题
|
// 监听路由的变化,设置网站标题
|
||||||
watch(
|
watch(
|
||||||
@ -89,7 +84,7 @@ export default defineComponent({
|
|||||||
themeConfig,
|
themeConfig,
|
||||||
setingsRef,
|
setingsRef,
|
||||||
getGlobalComponentSize,
|
getGlobalComponentSize,
|
||||||
...toRefs(state),
|
getGlobalI18n,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
19
src/assets/login-bg.svg
Normal file
19
src/assets/login-bg.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.4 KiB |
1
src/assets/login-main.svg
Normal file
1
src/assets/login-main.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 36 KiB |
@ -1,40 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
<div ref="editorToolbar"></div>
|
<Toolbar :editor="editorRef" :mode="mode" />
|
||||||
<div ref="editorContent" :style="{ height }"></div>
|
<Editor :mode="mode" :defaultConfig="editorConfig" :style="{ height }" v-model="editorVal" @onCreated="handleCreated" @onChange="handleChange" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, onMounted, watch, defineComponent } from 'vue';
|
// https://www.wangeditor.com/v5/for-frame.html#vue3
|
||||||
import { createEditor, createToolbar, IEditorConfig, IToolbarConfig, IDomEditor } from '@wangeditor/editor';
|
|
||||||
import '@wangeditor/editor/dist/css/style.css';
|
import '@wangeditor/editor/dist/css/style.css';
|
||||||
import { toolbarKeys } from './toolbar';
|
import { defineComponent, reactive, toRefs, shallowRef, watch, onBeforeUnmount } from 'vue';
|
||||||
|
import { Toolbar, Editor } from '@wangeditor/editor-for-vue';
|
||||||
// 定义接口来定义对象的类型
|
|
||||||
interface WangeditorState {
|
|
||||||
editorToolbar: HTMLDivElement | null;
|
|
||||||
editorContent: HTMLDivElement | null;
|
|
||||||
editor: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'wngEditor',
|
name: 'wngEditor',
|
||||||
|
components: { Toolbar, Editor },
|
||||||
props: {
|
props: {
|
||||||
// 节点 id
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: () => 'wangeditor',
|
|
||||||
},
|
|
||||||
// 是否禁用
|
// 是否禁用
|
||||||
isDisable: {
|
disable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => false,
|
default: () => true,
|
||||||
},
|
},
|
||||||
// 内容框默认 placeholder
|
// 内容框默认 placeholder
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => '请输入内容',
|
default: () => '请输入内容...',
|
||||||
},
|
},
|
||||||
// 双向绑定:双向绑定值,字段名为固定,改了之后将不生效
|
// 双向绑定:双向绑定值,字段名为固定,改了之后将不生效
|
||||||
// 参考:https://v3.cn.vuejs.org/guide/migration/v-model.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5
|
// 参考:https://v3.cn.vuejs.org/guide/migration/v-model.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5
|
||||||
@ -52,62 +41,46 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const state = reactive<WangeditorState>({
|
const editorRef = shallowRef();
|
||||||
editorToolbar: null,
|
const state = reactive({
|
||||||
editor: null,
|
editorConfig: {
|
||||||
editorContent: null,
|
placeholder: props.placeholder,
|
||||||
|
},
|
||||||
|
editorVal: props.modelValue,
|
||||||
});
|
});
|
||||||
// 富文本配置
|
// 编辑器回调函数
|
||||||
const wangeditorConfig = () => {
|
const handleCreated = (editor: any) => {
|
||||||
const editorConfig: Partial<IEditorConfig> = { MENU_CONF: {} };
|
editorRef.value = editor;
|
||||||
props.isDisable ? (editorConfig.readOnly = true) : (editorConfig.readOnly = false);
|
|
||||||
editorConfig.placeholder = props.placeholder;
|
|
||||||
editorConfig.onChange = (editor: IDomEditor) => {
|
|
||||||
// console.log('content', editor.children);
|
|
||||||
// console.log('html', editor.getHtml());
|
|
||||||
emit('update:modelValue', editor.getHtml());
|
|
||||||
};
|
|
||||||
(<any>editorConfig).MENU_CONF['uploadImage'] = {
|
|
||||||
base64LimitSize: 10 * 1024 * 1024,
|
|
||||||
};
|
|
||||||
return editorConfig;
|
|
||||||
};
|
};
|
||||||
//
|
// 编辑器内容改变时
|
||||||
const toolbarConfig = () => {
|
const handleChange = (editor: any) => {
|
||||||
const toolbarConfig: Partial<IToolbarConfig> = {};
|
// console.log(editor.getText());
|
||||||
toolbarConfig.toolbarKeys = toolbarKeys;
|
// console.log(editor.getHtml());
|
||||||
return toolbarConfig;
|
emit('update:modelValue', editor.getHtml());
|
||||||
};
|
};
|
||||||
// 初始化富文本
|
// 监听是否禁用改变
|
||||||
// https://www.wangeditor.com/
|
|
||||||
const initWangeditor = () => {
|
|
||||||
state.editor = createEditor({
|
|
||||||
html: props.modelValue,
|
|
||||||
selector: state.editorContent!,
|
|
||||||
config: wangeditorConfig(),
|
|
||||||
mode: props.mode,
|
|
||||||
});
|
|
||||||
createToolbar({
|
|
||||||
editor: state.editor,
|
|
||||||
selector: state.editorToolbar!,
|
|
||||||
mode: props.mode,
|
|
||||||
config: toolbarConfig(),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// 页面加载时
|
|
||||||
onMounted(() => {
|
|
||||||
initWangeditor();
|
|
||||||
});
|
|
||||||
// 监听双向绑定值的改变
|
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I4LM7I
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I4LM7I
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.disable,
|
||||||
(value) => {
|
(bool) => {
|
||||||
state.editor.clear();
|
const editor = editorRef.value;
|
||||||
state.editor.dangerouslyInsertHtml(value);
|
if (editor == null) return;
|
||||||
|
bool ? editor.disable() : editor.enable();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// 页面销毁时
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
const editor = editorRef.value;
|
||||||
|
if (editor == null) return;
|
||||||
|
editor.destroy();
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
|
editorRef,
|
||||||
|
handleCreated,
|
||||||
|
handleChange,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
/**
|
|
||||||
* 工具栏配置
|
|
||||||
*/
|
|
||||||
export const toolbarKeys = [
|
|
||||||
'headerSelect',
|
|
||||||
'blockquote',
|
|
||||||
'|',
|
|
||||||
'bold',
|
|
||||||
'underline',
|
|
||||||
'italic',
|
|
||||||
{
|
|
||||||
key: 'group-more-style',
|
|
||||||
title: '更多',
|
|
||||||
iconSvg:
|
|
||||||
'<svg viewBox="0 0 1024 1024"><path d="M204.8 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M505.6 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M806.4 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path></svg>',
|
|
||||||
menuKeys: ['through', 'code', 'sup', 'sub', 'clearStyle'],
|
|
||||||
},
|
|
||||||
'color',
|
|
||||||
'bgColor',
|
|
||||||
'|',
|
|
||||||
'fontSize',
|
|
||||||
'fontFamily',
|
|
||||||
'lineHeight',
|
|
||||||
'|',
|
|
||||||
'bulletedList',
|
|
||||||
'numberedList',
|
|
||||||
'todo',
|
|
||||||
{
|
|
||||||
key: 'group-justify',
|
|
||||||
title: '对齐',
|
|
||||||
iconSvg:
|
|
||||||
'<svg viewBox="0 0 1024 1024"><path d="M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z"></path></svg>',
|
|
||||||
menuKeys: ['justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'group-indent',
|
|
||||||
title: '缩进',
|
|
||||||
iconSvg:
|
|
||||||
'<svg viewBox="0 0 1024 1024"><path d="M0 64h1024v128H0z m384 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384zM0 832h1024v128H0z m0-128V320l256 192z"></path></svg>',
|
|
||||||
menuKeys: ['indent', 'delIndent'],
|
|
||||||
},
|
|
||||||
'|',
|
|
||||||
'emotion',
|
|
||||||
'insertLink',
|
|
||||||
{
|
|
||||||
key: 'group-image',
|
|
||||||
title: '图片',
|
|
||||||
iconSvg:
|
|
||||||
'<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>',
|
|
||||||
menuKeys: ['uploadImage'],
|
|
||||||
},
|
|
||||||
'insertTable',
|
|
||||||
'codeBlock',
|
|
||||||
'divider',
|
|
||||||
'|',
|
|
||||||
'undo',
|
|
||||||
'redo',
|
|
||||||
'|',
|
|
||||||
'fullScreen',
|
|
||||||
];
|
|
@ -57,6 +57,7 @@ const { themeConfig } = storeToRefs(stores);
|
|||||||
// 导出语言国际化
|
// 导出语言国际化
|
||||||
// https://vue-i18n.intlify.dev/guide/essentials/fallback.html#explicit-fallback-with-one-locale
|
// https://vue-i18n.intlify.dev/guide/essentials/fallback.html#explicit-fallback-with-one-locale
|
||||||
export const i18n = createI18n({
|
export const i18n = createI18n({
|
||||||
|
legacy: false,
|
||||||
silentTranslationWarn: true,
|
silentTranslationWarn: true,
|
||||||
missingWarn: false,
|
missingWarn: false,
|
||||||
silentFallbackWarn: true,
|
silentFallbackWarn: true,
|
||||||
|
@ -71,7 +71,8 @@ export default {
|
|||||||
personal: 'personal',
|
personal: 'personal',
|
||||||
tools: 'tools',
|
tools: 'tools',
|
||||||
layoutLinkView: 'LinkView',
|
layoutLinkView: 'LinkView',
|
||||||
layoutIfameView: 'IfameView',
|
layoutIframeViewOne: 'IframeViewOne',
|
||||||
|
layoutIframeViewTwo: 'IframeViewTwo',
|
||||||
},
|
},
|
||||||
staticRoutes: {
|
staticRoutes: {
|
||||||
signIn: 'signIn',
|
signIn: 'signIn',
|
||||||
@ -139,6 +140,7 @@ export default {
|
|||||||
twoColumnsMenuBar: 'Column menu background',
|
twoColumnsMenuBar: 'Column menu background',
|
||||||
twoColumnsMenuBarColor: 'Default font color bar menu',
|
twoColumnsMenuBarColor: 'Default font color bar menu',
|
||||||
twoIsColumnsMenuBarColorGradual: 'Column gradient',
|
twoIsColumnsMenuBarColorGradual: 'Column gradient',
|
||||||
|
twoIsColumnsMenuHoverPreload: 'Column Menu Hover Preload',
|
||||||
threeTitle: 'Interface settings',
|
threeTitle: 'Interface settings',
|
||||||
threeIsCollapse: 'Menu horizontal collapse',
|
threeIsCollapse: 'Menu horizontal collapse',
|
||||||
threeIsUniqueOpened: 'Menu accordion',
|
threeIsUniqueOpened: 'Menu accordion',
|
||||||
|
@ -71,7 +71,8 @@ export default {
|
|||||||
personal: '个人中心',
|
personal: '个人中心',
|
||||||
tools: '工具类集合',
|
tools: '工具类集合',
|
||||||
layoutLinkView: '外链',
|
layoutLinkView: '外链',
|
||||||
layoutIfameView: '内嵌 iframe',
|
layoutIframeViewOne: '内嵌 iframe1',
|
||||||
|
layoutIframeViewTwo: '内嵌 iframe2',
|
||||||
},
|
},
|
||||||
staticRoutes: {
|
staticRoutes: {
|
||||||
signIn: '登录',
|
signIn: '登录',
|
||||||
@ -139,6 +140,7 @@ export default {
|
|||||||
twoColumnsMenuBar: '分栏菜单背景',
|
twoColumnsMenuBar: '分栏菜单背景',
|
||||||
twoColumnsMenuBarColor: '分栏菜单默认字体颜色',
|
twoColumnsMenuBarColor: '分栏菜单默认字体颜色',
|
||||||
twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变',
|
twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变',
|
||||||
|
twoIsColumnsMenuHoverPreload: '分栏菜单鼠标悬停预加载',
|
||||||
threeTitle: '界面设置',
|
threeTitle: '界面设置',
|
||||||
threeIsCollapse: '菜单水平折叠',
|
threeIsCollapse: '菜单水平折叠',
|
||||||
threeIsUniqueOpened: '菜单手风琴',
|
threeIsUniqueOpened: '菜单手风琴',
|
||||||
|
@ -71,7 +71,8 @@ export default {
|
|||||||
personal: '個人中心',
|
personal: '個人中心',
|
||||||
tools: '工具類集合',
|
tools: '工具類集合',
|
||||||
layoutLinkView: '外鏈',
|
layoutLinkView: '外鏈',
|
||||||
layoutIfameView: '内嵌 iframe',
|
layoutIframeViewOne: '内嵌 iframe1',
|
||||||
|
layoutIframeViewTwo: '内嵌 iframe2',
|
||||||
},
|
},
|
||||||
staticRoutes: {
|
staticRoutes: {
|
||||||
signIn: '登入',
|
signIn: '登入',
|
||||||
@ -139,6 +140,7 @@ export default {
|
|||||||
twoColumnsMenuBar: '分欄選單背景',
|
twoColumnsMenuBar: '分欄選單背景',
|
||||||
twoColumnsMenuBarColor: '分欄選單默認字體顏色',
|
twoColumnsMenuBarColor: '分欄選單默認字體顏色',
|
||||||
twoIsColumnsMenuBarColorGradual: '分欄選單背景漸變',
|
twoIsColumnsMenuBarColorGradual: '分欄選單背景漸變',
|
||||||
|
twoIsColumnsMenuHoverPreload: '分欄選單滑鼠懸停預加載',
|
||||||
threeTitle: '介面設定',
|
threeTitle: '介面設定',
|
||||||
threeIsCollapse: '選單水准折疊',
|
threeIsCollapse: '選單水准折疊',
|
||||||
threeIsUniqueOpened: '選單手風琴',
|
threeIsUniqueOpened: '選單手風琴',
|
||||||
|
@ -10,20 +10,22 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, computed, watch, getCurrentInstance, onBeforeMount, defineComponent } from 'vue';
|
import { defineAsyncComponent, toRefs, reactive, computed, watch, onBeforeMount, defineComponent, ref } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import pinia from '/@/stores/index';
|
import pinia from '/@/stores/index';
|
||||||
import { useRoutesList } from '/@/stores/routesList';
|
import { useRoutesList } from '/@/stores/routesList';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||||
import Logo from '/@/layout/logo/index.vue';
|
import mittBus from '/@/utils/mitt';
|
||||||
import Vertical from '/@/layout/navMenu/vertical.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutAside',
|
name: 'layoutAside',
|
||||||
components: { Logo, Vertical },
|
components: {
|
||||||
|
Logo: defineAsyncComponent(() => import('/@/layout/logo/index.vue')),
|
||||||
|
Vertical: defineAsyncComponent(() => import('/@/layout/navMenu/vertical.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const layoutAsideScrollbarRef = ref();
|
||||||
const stores = useRoutesList();
|
const stores = useRoutesList();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||||
@ -105,14 +107,13 @@ export default defineComponent({
|
|||||||
const onAsideEnterLeave = (bool: Boolean) => {
|
const onAsideEnterLeave = (bool: Boolean) => {
|
||||||
let { layout } = themeConfig.value;
|
let { layout } = themeConfig.value;
|
||||||
if (layout !== 'columns') return false;
|
if (layout !== 'columns') return false;
|
||||||
if (!bool) proxy.mittBus.emit('restoreDefault');
|
if (!bool) mittBus.emit('restoreDefault');
|
||||||
stores.setColumnsMenuHover(bool);
|
stores.setColumnsMenuHover(bool);
|
||||||
};
|
};
|
||||||
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||||
watch(themeConfig.value, (val) => {
|
watch(themeConfig.value, (val) => {
|
||||||
if (val.isShowLogoChange !== val.isShowLogo) {
|
if (val.isShowLogoChange !== val.isShowLogo) {
|
||||||
if (!proxy.$refs.layoutAsideScrollbarRef) return false;
|
if (layoutAsideScrollbarRef.value) layoutAsideScrollbarRef.value.update();
|
||||||
proxy.$refs.layoutAsideScrollbarRef.update();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 监听vuex值的变化,动态赋值给菜单中
|
// 监听vuex值的变化,动态赋值给菜单中
|
||||||
@ -131,27 +132,28 @@ export default defineComponent({
|
|||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
initMenuFixed(document.body.clientWidth);
|
initMenuFixed(document.body.clientWidth);
|
||||||
setFilterRoutes();
|
setFilterRoutes();
|
||||||
// 此界面不需要取消监听(proxy.mittBus.off('setSendColumnsChildren))
|
// 此界面不需要取消监听(mittBus.off('setSendColumnsChildren))
|
||||||
// 因为切换布局时有的监听需要使用,取消了监听,某些操作将不生效
|
// 因为切换布局时有的监听需要使用,取消了监听,某些操作将不生效
|
||||||
proxy.mittBus.on('setSendColumnsChildren', (res: any) => {
|
mittBus.on('setSendColumnsChildren', (res: any) => {
|
||||||
state.menuList = res.children;
|
state.menuList = res.children;
|
||||||
});
|
});
|
||||||
proxy.mittBus.on('setSendClassicChildren', (res: any) => {
|
mittBus.on('setSendClassicChildren', (res: any) => {
|
||||||
let { layout, isClassicSplitMenu } = themeConfig.value;
|
let { layout, isClassicSplitMenu } = themeConfig.value;
|
||||||
if (layout === 'classic' && isClassicSplitMenu) {
|
if (layout === 'classic' && isClassicSplitMenu) {
|
||||||
state.menuList = [];
|
state.menuList = [];
|
||||||
state.menuList = res.children;
|
state.menuList = res.children;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
proxy.mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
||||||
setFilterRoutes();
|
setFilterRoutes();
|
||||||
});
|
});
|
||||||
proxy.mittBus.on('layoutMobileResize', (res: any) => {
|
mittBus.on('layoutMobileResize', (res: any) => {
|
||||||
initMenuFixed(res.clientWidth);
|
initMenuFixed(res.clientWidth);
|
||||||
closeLayoutAsideMobileMode();
|
closeLayoutAsideMobileMode();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
layoutAsideScrollbarRef,
|
||||||
setCollapseStyle,
|
setCollapseStyle,
|
||||||
setShowLogo,
|
setShowLogo,
|
||||||
isTagsViewCurrenFull,
|
isTagsViewCurrenFull,
|
||||||
|
@ -45,12 +45,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { reactive, toRefs, ref, onMounted, nextTick, getCurrentInstance, watch, onUnmounted, defineComponent } from 'vue';
|
import { reactive, toRefs, ref, onMounted, nextTick, watch, onUnmounted, defineComponent } from 'vue';
|
||||||
import { useRoute, useRouter, onBeforeRouteUpdate, RouteRecordRaw } from 'vue-router';
|
import { useRoute, useRouter, onBeforeRouteUpdate, RouteRecordRaw } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import pinia from '/@/stores/index';
|
import pinia from '/@/stores/index';
|
||||||
import { useRoutesList } from '/@/stores/routesList';
|
import { useRoutesList } from '/@/stores/routesList';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
|
import mittBus from '/@/utils/mitt';
|
||||||
|
|
||||||
// 定义接口来定义对象的类型
|
// 定义接口来定义对象的类型
|
||||||
interface ColumnsAsideState {
|
interface ColumnsAsideState {
|
||||||
@ -68,7 +69,6 @@ export default defineComponent({
|
|||||||
setup() {
|
setup() {
|
||||||
const columnsAsideOffsetTopRefs: any = ref([]);
|
const columnsAsideOffsetTopRefs: any = ref([]);
|
||||||
const columnsAsideActiveRef = ref();
|
const columnsAsideActiveRef = ref();
|
||||||
const { proxy } = <any>getCurrentInstance();
|
|
||||||
const stores = useRoutesList();
|
const stores = useRoutesList();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { routesList, isColumnsMenuHover, isColumnsNavHover } = storeToRefs(stores);
|
const { routesList, isColumnsMenuHover, isColumnsNavHover } = storeToRefs(stores);
|
||||||
@ -98,11 +98,12 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 鼠标移入时,显示当前的子级菜单
|
// 鼠标移入时,显示当前的子级菜单
|
||||||
const onColumnsAsideMenuMouseenter = (v: RouteRecordRaw, k: number) => {
|
const onColumnsAsideMenuMouseenter = (v: RouteRecordRaw, k: number) => {
|
||||||
|
if (!themeConfig.value.isColumnsMenuHoverPreload) return false;
|
||||||
let { path } = v;
|
let { path } = v;
|
||||||
state.liOldPath = path;
|
state.liOldPath = path;
|
||||||
state.liOldIndex = k;
|
state.liOldIndex = k;
|
||||||
state.liHoverIndex = k;
|
state.liHoverIndex = k;
|
||||||
proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(path));
|
mittBus.emit('setSendColumnsChildren', setSendChildren(path));
|
||||||
stores.setColumnsMenuHover(false);
|
stores.setColumnsMenuHover(false);
|
||||||
stores.setColumnsNavHover(true);
|
stores.setColumnsNavHover(true);
|
||||||
};
|
};
|
||||||
@ -111,7 +112,7 @@ export default defineComponent({
|
|||||||
await stores.setColumnsNavHover(false);
|
await stores.setColumnsNavHover(false);
|
||||||
// 添加延时器,防止拿到的 store.state.routesList 值不是最新的
|
// 添加延时器,防止拿到的 store.state.routesList 值不是最新的
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!isColumnsMenuHover && !isColumnsNavHover) proxy.mittBus.emit('restoreDefault');
|
if (!isColumnsMenuHover && !isColumnsNavHover) mittBus.emit('restoreDefault');
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
// 设置高亮动态位置
|
// 设置高亮动态位置
|
||||||
@ -126,7 +127,7 @@ export default defineComponent({
|
|||||||
const resData: any = setSendChildren(route.path);
|
const resData: any = setSendChildren(route.path);
|
||||||
if (Object.keys(resData).length <= 0) return false;
|
if (Object.keys(resData).length <= 0) return false;
|
||||||
onColumnsAsideDown(resData.item[0].k);
|
onColumnsAsideDown(resData.item[0].k);
|
||||||
proxy.mittBus.emit('setSendColumnsChildren', resData);
|
mittBus.emit('setSendColumnsChildren', resData);
|
||||||
};
|
};
|
||||||
// 传送当前子级数据到菜单中
|
// 传送当前子级数据到菜单中
|
||||||
const setSendChildren = (path: string) => {
|
const setSendChildren = (path: string) => {
|
||||||
@ -171,11 +172,11 @@ export default defineComponent({
|
|||||||
val.themeConfig.themeConfig.columnsAsideStyle === 'columnsRound' ? (state.difference = 3) : (state.difference = 0);
|
val.themeConfig.themeConfig.columnsAsideStyle === 'columnsRound' ? (state.difference = 3) : (state.difference = 0);
|
||||||
if (!val.routesList.isColumnsMenuHover && !val.routesList.isColumnsNavHover) {
|
if (!val.routesList.isColumnsMenuHover && !val.routesList.isColumnsNavHover) {
|
||||||
state.liHoverIndex = null;
|
state.liHoverIndex = null;
|
||||||
proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(route.path));
|
mittBus.emit('setSendColumnsChildren', setSendChildren(route.path));
|
||||||
} else {
|
} else {
|
||||||
state.liHoverIndex = state.liOldIndex;
|
state.liHoverIndex = state.liOldIndex;
|
||||||
if (!state.liOldPath) return false;
|
if (!state.liOldPath) return false;
|
||||||
proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(state.liOldPath));
|
mittBus.emit('setSendColumnsChildren', setSendChildren(state.liOldPath));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -186,19 +187,19 @@ export default defineComponent({
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setFilterRoutes();
|
setFilterRoutes();
|
||||||
// 销毁变量,防止鼠标再次移入时,保留了上次的记录
|
// 销毁变量,防止鼠标再次移入时,保留了上次的记录
|
||||||
proxy.mittBus.on('restoreDefault', () => {
|
mittBus.on('restoreDefault', () => {
|
||||||
state.liOldIndex = null;
|
state.liOldIndex = null;
|
||||||
state.liOldPath = null;
|
state.liOldPath = null;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// 页面卸载时
|
// 页面卸载时
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
proxy.mittBus.off('restoreDefault', () => {});
|
mittBus.off('restoreDefault', () => {});
|
||||||
});
|
});
|
||||||
// 路由更新时
|
// 路由更新时
|
||||||
onBeforeRouteUpdate((to) => {
|
onBeforeRouteUpdate((to) => {
|
||||||
setColumnsMenuHighlight(to.path);
|
setColumnsMenuHighlight(to.path);
|
||||||
proxy.mittBus.emit('setSendColumnsChildren', setSendChildren(to.path));
|
mittBus.emit('setSendColumnsChildren', setSendChildren(to.path));
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
themeConfig,
|
themeConfig,
|
||||||
@ -221,6 +222,16 @@ export default defineComponent({
|
|||||||
background: var(--next-bg-columnsMenuBar);
|
background: var(--next-bg-columnsMenuBar);
|
||||||
ul {
|
ul {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
.layout-columns-active {
|
||||||
|
color: var(--next-bg-columnsMenuBarColor) !important;
|
||||||
|
transition: 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
.layout-columns-hover {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
a {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
li {
|
li {
|
||||||
color: var(--next-bg-columnsMenuBarColor);
|
color: var(--next-bg-columnsMenuBarColor);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -230,6 +241,9 @@ export default defineComponent({
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
&:hover {
|
||||||
|
@extend .layout-columns-hover;
|
||||||
|
}
|
||||||
.columns-vertical {
|
.columns-vertical {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
.columns-vertical-title {
|
.columns-vertical-title {
|
||||||
@ -257,16 +271,6 @@ export default defineComponent({
|
|||||||
color: var(--next-bg-columnsMenuBarColor);
|
color: var(--next-bg-columnsMenuBarColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.layout-columns-active {
|
|
||||||
color: var(--next-bg-columnsMenuBarColor) !important;
|
|
||||||
transition: 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
.layout-columns-hover {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
a {
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.columns-round {
|
.columns-round {
|
||||||
background: var(--el-color-primary);
|
background: var(--el-color-primary);
|
||||||
color: var(--el-color-white);
|
color: var(--el-color-white);
|
||||||
|
@ -1,32 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-header class="layout-header" :height="setHeaderHeight" v-show="!isTagsViewCurrenFull">
|
<el-header class="layout-header" v-show="!isTagsViewCurrenFull">
|
||||||
<NavBarsIndex />
|
<NavBarsIndex />
|
||||||
</el-header>
|
</el-header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||||
import NavBarsIndex from '/@/layout/navBars/index.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutHeader',
|
name: 'layoutHeader',
|
||||||
components: { NavBarsIndex },
|
components: {
|
||||||
|
NavBarsIndex: defineAsyncComponent(() => import('/@/layout/navBars/index.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||||
const storesThemeConfig = useThemeConfig();
|
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
|
||||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||||
// 设置 header 的高度
|
|
||||||
const setHeaderHeight = computed(() => {
|
|
||||||
let { isTagsview, layout } = themeConfig.value;
|
|
||||||
if (isTagsview && layout !== 'classic') return '84px';
|
|
||||||
else return '50px';
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
setHeaderHeight,
|
|
||||||
isTagsViewCurrenFull,
|
isTagsViewCurrenFull,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,100 +1,58 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-main class="layout-main">
|
<el-main class="layout-main" :style="isFixedHeader ? `height: calc(100% - ${setMainHeight})` : `minHeight: calc(100% - ${setMainHeight})`">
|
||||||
<el-scrollbar
|
<el-scrollbar ref="layoutMainScrollbarRef" class="layout-main-scroll" wrap-class="layout-main-scroll" view-class="layout-main-scroll">
|
||||||
ref="layoutScrollbarRef"
|
<LayoutParentView />
|
||||||
:class="{
|
<LayoutFooter v-if="isFooter" />
|
||||||
'layout-scrollbar':
|
|
||||||
(!isClassicOrTransverse && !currentRouteMeta.isLink && !currentRouteMeta.isIframe) ||
|
|
||||||
(!isClassicOrTransverse && currentRouteMeta.isLink && !currentRouteMeta.isIframe),
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<LayoutParentView
|
|
||||||
:style="{
|
|
||||||
padding: !isClassicOrTransverse || (currentRouteMeta.isLink && currentRouteMeta.isIframe) ? '0' : '15px',
|
|
||||||
transition: 'padding 0.3s ease-in-out',
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<Footer v-if="themeConfig.isFooter" />
|
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
<el-backtop target=".layout-backtop .el-scrollbar__wrap" />
|
||||||
</el-main>
|
</el-main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, toRefs, reactive, getCurrentInstance, watch, onMounted, computed } from 'vue';
|
import { defineAsyncComponent, defineComponent, onMounted, computed, ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import { NextLoading } from '/@/utils/loading';
|
import { NextLoading } from '/@/utils/loading';
|
||||||
import LayoutParentView from '/@/layout/routerView/parent.vue';
|
|
||||||
import Footer from '/@/layout/footer/index.vue';
|
|
||||||
|
|
||||||
// 定义接口来定义对象的类型
|
|
||||||
interface MainState {
|
|
||||||
headerHeight: string | number;
|
|
||||||
currentRouteMeta: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutMain',
|
name: 'layoutMain',
|
||||||
components: { LayoutParentView, Footer },
|
components: {
|
||||||
|
LayoutParentView: defineAsyncComponent(() => import('/@/layout/routerView/parent.vue')),
|
||||||
|
LayoutFooter: defineAsyncComponent(() => import('/@/layout/footer/index.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const layoutMainScrollbarRef = ref('');
|
||||||
|
const route = useRoute();
|
||||||
|
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const route = useRoute();
|
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||||
const state = reactive<MainState>({
|
// 设置 footer 显示/隐藏
|
||||||
headerHeight: '',
|
const isFooter = computed(() => {
|
||||||
currentRouteMeta: {},
|
return themeConfig.value.isFooter && !route.meta.isIframe;
|
||||||
});
|
});
|
||||||
// 判断布局
|
// 设置 header 固定
|
||||||
const isClassicOrTransverse = computed(() => {
|
const isFixedHeader = computed(() => {
|
||||||
const { layout } = themeConfig.value;
|
return themeConfig.value.isFixedHeader;
|
||||||
return layout === 'classic' || layout === 'transverse';
|
});
|
||||||
|
// 设置主内容区的高度
|
||||||
|
const setMainHeight = computed(() => {
|
||||||
|
if (isTagsViewCurrenFull.value) return '0px';
|
||||||
|
const { isTagsview, layout } = themeConfig.value;
|
||||||
|
if (isTagsview && layout !== 'classic') return '85px';
|
||||||
|
else return '51px';
|
||||||
});
|
});
|
||||||
// 设置 main 的高度
|
|
||||||
const initHeaderHeight = () => {
|
|
||||||
const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe;
|
|
||||||
let { isTagsview } = themeConfig.value;
|
|
||||||
if (isTagsview) return (state.headerHeight = bool ? `86px` : `115px`);
|
|
||||||
else return (state.headerHeight = `80px`);
|
|
||||||
};
|
|
||||||
// 初始化获取当前路由 meta,用于设置 iframes padding
|
|
||||||
const initGetMeta = () => {
|
|
||||||
state.currentRouteMeta = route.meta;
|
|
||||||
};
|
|
||||||
// 页面加载前
|
// 页面加载前
|
||||||
onMounted(async () => {
|
onMounted(() => {
|
||||||
await initGetMeta();
|
NextLoading.done(600);
|
||||||
initHeaderHeight();
|
|
||||||
NextLoading.done();
|
|
||||||
});
|
});
|
||||||
// 监听路由变化
|
|
||||||
watch(
|
|
||||||
() => route.path,
|
|
||||||
() => {
|
|
||||||
state.currentRouteMeta = route.meta;
|
|
||||||
const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe;
|
|
||||||
state.headerHeight = bool ? `86px` : `115px`;
|
|
||||||
proxy.$refs.layoutScrollbarRef.update();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
|
||||||
watch(
|
|
||||||
themeConfig,
|
|
||||||
(val) => {
|
|
||||||
state.currentRouteMeta = route.meta;
|
|
||||||
const bool = state.currentRouteMeta.isLink && state.currentRouteMeta.isIframe;
|
|
||||||
state.headerHeight = val.isTagsview ? (bool ? `86px` : `115px`) : '51px';
|
|
||||||
proxy.$refs?.layoutScrollbarRef?.update();
|
|
||||||
},
|
|
||||||
{
|
|
||||||
deep: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
themeConfig,
|
layoutMainScrollbarRef,
|
||||||
isClassicOrTransverse,
|
isFooter,
|
||||||
...toRefs(state),
|
isFixedHeader,
|
||||||
|
setMainHeight,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-footer mt15" v-show="isDelayFooter">
|
<div class="layout-footer pb15">
|
||||||
<div class="layout-footer-warp">
|
<div class="layout-footer-warp">
|
||||||
<div>vue-next-admin,Made by lyt with ❤️</div>
|
<div>vue-next-admin,Made by lyt with ❤️</div>
|
||||||
<div class="mt5">深圳市 xxx 公司版权所有</div>
|
<div class="mt5">深圳市 xxx 公司版权所有</div>
|
||||||
@ -8,28 +8,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { onBeforeRouteUpdate } from 'vue-router';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutFooter',
|
name: 'layoutFooter',
|
||||||
setup() {
|
|
||||||
const state = reactive({
|
|
||||||
isDelayFooter: true,
|
|
||||||
});
|
|
||||||
// 路由改变时,等主界面动画加载完毕再显示 footer
|
|
||||||
onBeforeRouteUpdate(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
state.isDelayFooter = false;
|
|
||||||
setTimeout(() => {
|
|
||||||
state.isDelayFooter = true;
|
|
||||||
}, 800);
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -41,7 +23,7 @@ export default defineComponent({
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
color: var(--el-text-color-secondary);
|
color: var(--el-text-color-secondary);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
animation: error-num 1s ease-in-out;
|
animation: error-num 0.3s ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onBeforeMount, onUnmounted, getCurrentInstance, defineComponent, defineAsyncComponent } from 'vue';
|
import { onBeforeMount, onUnmounted, defineComponent, defineAsyncComponent } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import { Local } from '/@/utils/storage';
|
import { Local } from '/@/utils/storage';
|
||||||
|
import mittBus from '/@/utils/mitt';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layout',
|
name: 'layout',
|
||||||
@ -17,7 +18,6 @@ export default defineComponent({
|
|||||||
columns: defineAsyncComponent(() => import('/@/layout/main/columns.vue')),
|
columns: defineAsyncComponent(() => import('/@/layout/main/columns.vue')),
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
// 窗口大小改变时(适配移动端)
|
// 窗口大小改变时(适配移动端)
|
||||||
@ -26,12 +26,12 @@ export default defineComponent({
|
|||||||
const clientWidth = document.body.clientWidth;
|
const clientWidth = document.body.clientWidth;
|
||||||
if (clientWidth < 1000) {
|
if (clientWidth < 1000) {
|
||||||
themeConfig.value.isCollapse = false;
|
themeConfig.value.isCollapse = false;
|
||||||
proxy.mittBus.emit('layoutMobileResize', {
|
mittBus.emit('layoutMobileResize', {
|
||||||
layout: 'defaults',
|
layout: 'defaults',
|
||||||
clientWidth,
|
clientWidth,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
proxy.mittBus.emit('layoutMobileResize', {
|
mittBus.emit('layoutMobileResize', {
|
||||||
layout: Local.get('oldLayout') ? Local.get('oldLayout') : themeConfig.value.layout,
|
layout: Local.get('oldLayout') ? Local.get('oldLayout') : themeConfig.value.layout,
|
||||||
clientWidth,
|
clientWidth,
|
||||||
});
|
});
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { nextTick, onMounted, reactive, toRefs, ref, onUnmounted, getCurrentInstance, defineComponent } from 'vue';
|
import { nextTick, onMounted, reactive, toRefs, ref, onUnmounted, defineComponent } from 'vue';
|
||||||
import { formatDate } from '/@/utils/formatTime';
|
import { formatDate } from '/@/utils/formatTime';
|
||||||
import { Local } from '/@/utils/storage';
|
import { Local } from '/@/utils/storage';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@ -88,7 +88,7 @@ interface LockScreenState {
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutLockScreen',
|
name: 'layoutLockScreen',
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const layoutLockScreenDateRef = ref();
|
||||||
const layoutLockScreenInputRef = ref();
|
const layoutLockScreenInputRef = ref();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
@ -150,7 +150,7 @@ export default defineComponent({
|
|||||||
// 获取要拖拽的初始元素
|
// 获取要拖拽的初始元素
|
||||||
const initGetElement = () => {
|
const initGetElement = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
state.querySelectorEl = proxy.$refs.layoutLockScreenDateRef;
|
state.querySelectorEl = layoutLockScreenDateRef.value;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 时间初始化
|
// 时间初始化
|
||||||
@ -204,6 +204,7 @@ export default defineComponent({
|
|||||||
window.clearInterval(state.isShowLockScreenIntervalTime);
|
window.clearInterval(state.isShowLockScreenIntervalTime);
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
layoutLockScreenDateRef,
|
||||||
layoutLockScreenInputRef,
|
layoutLockScreenInputRef,
|
||||||
onDown,
|
onDown,
|
||||||
onMove,
|
onMove,
|
||||||
|
@ -1,34 +1,76 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="layout-container flex-center">
|
<el-container class="layout-container flex-center">
|
||||||
<Header />
|
<LayoutHeader />
|
||||||
<el-container class="layout-mian-height-50">
|
<el-container class="layout-mian-height-50">
|
||||||
<Aside />
|
<LayoutAside />
|
||||||
<div class="flex-center layout-backtop">
|
<div class="flex-center layout-backtop">
|
||||||
<TagsView v-if="themeConfig.isTagsview" />
|
<LayoutTagsView v-if="isTagsview" />
|
||||||
<Main />
|
<LayoutMain ref="layoutMainRef" />
|
||||||
</div>
|
</div>
|
||||||
</el-container>
|
</el-container>
|
||||||
<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
|
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineAsyncComponent, defineComponent, computed, ref, watch, nextTick, onMounted } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import Aside from '/@/layout/component/aside.vue';
|
|
||||||
import Header from '/@/layout/component/header.vue';
|
|
||||||
import Main from '/@/layout/component/main.vue';
|
|
||||||
import TagsView from '/@/layout/navBars/tagsView/tagsView.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutClassic',
|
name: 'layoutClassic',
|
||||||
components: { Aside, Header, Main, TagsView },
|
components: {
|
||||||
|
LayoutAside: defineAsyncComponent(() => import('/@/layout/component/aside.vue')),
|
||||||
|
LayoutHeader: defineAsyncComponent(() => import('/@/layout/component/header.vue')),
|
||||||
|
LayoutMain: defineAsyncComponent(() => import('/@/layout/component/main.vue')),
|
||||||
|
LayoutTagsView: defineAsyncComponent(() => import('/@/layout/navBars/tagsView/tagsView.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
const layoutMainRef = ref<any>('');
|
||||||
|
const route = useRoute();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
return {
|
// 判断是否显示 tasgview
|
||||||
|
const isTagsview = computed(() => {
|
||||||
|
return themeConfig.value.isTagsview;
|
||||||
|
});
|
||||||
|
// 重置滚动条高度,更新子级 scrollbar
|
||||||
|
const updateScrollbar = () => {
|
||||||
|
layoutMainRef.value.layoutMainScrollbarRef.update();
|
||||||
|
};
|
||||||
|
// 重置滚动条高度,由于组件是异步引入的
|
||||||
|
const initScrollBarHeight = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
updateScrollbar();
|
||||||
|
layoutMainRef.value.layoutMainScrollbarRef.wrap$.scrollTop = 0;
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 监听路由的变化,切换界面时,滚动条置顶
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
() => {
|
||||||
|
initScrollBarHeight();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||||
|
watch(
|
||||||
themeConfig,
|
themeConfig,
|
||||||
|
() => {
|
||||||
|
updateScrollbar();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 页面加载时
|
||||||
|
onMounted(() => {
|
||||||
|
initScrollBarHeight();
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
layoutMainRef,
|
||||||
|
isTagsview,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,40 +1,77 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="layout-container">
|
<el-container class="layout-container">
|
||||||
<ColumnsAside />
|
<ColumnsAside />
|
||||||
<div class="layout-columns-warp">
|
<el-container class="layout-columns-warp layout-container-view h100">
|
||||||
<Aside />
|
<LayoutAside />
|
||||||
<el-container class="flex-center layout-backtop" :class="{ 'layout-backtop': !isFixedHeader }">
|
<el-scrollbar ref="layoutScrollbarRef" class="layout-backtop">
|
||||||
<Header v-if="isFixedHeader" />
|
<LayoutHeader />
|
||||||
<el-scrollbar :class="{ 'layout-backtop': isFixedHeader }">
|
<LayoutMain ref="layoutMainRef" />
|
||||||
<Header v-if="!isFixedHeader" />
|
</el-scrollbar>
|
||||||
<Main />
|
</el-container>
|
||||||
</el-scrollbar>
|
|
||||||
</el-container>
|
|
||||||
</div>
|
|
||||||
<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
|
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { defineAsyncComponent, watch, defineComponent, onMounted, nextTick, ref } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import Aside from '/@/layout/component/aside.vue';
|
|
||||||
import Header from '/@/layout/component/header.vue';
|
|
||||||
import Main from '/@/layout/component/main.vue';
|
|
||||||
import ColumnsAside from '/@/layout/component/columnsAside.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutColumns',
|
name: 'layoutColumns',
|
||||||
components: { Aside, Header, Main, ColumnsAside },
|
components: {
|
||||||
|
LayoutAside: defineAsyncComponent(() => import('/@/layout/component/aside.vue')),
|
||||||
|
LayoutHeader: defineAsyncComponent(() => import('/@/layout/component/header.vue')),
|
||||||
|
LayoutMain: defineAsyncComponent(() => import('/@/layout/component/main.vue')),
|
||||||
|
ColumnsAside: defineAsyncComponent(() => import('/@/layout/component/columnsAside.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
|
const layoutScrollbarRef = ref<any>('');
|
||||||
|
const layoutMainRef = ref<any>('');
|
||||||
|
const route = useRoute();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const isFixedHeader = computed(() => {
|
// 重置滚动条高度
|
||||||
return themeConfig.value.isFixedHeader;
|
const updateScrollbar = () => {
|
||||||
|
// 更新父级 scrollbar
|
||||||
|
layoutScrollbarRef.value.update();
|
||||||
|
// 更新子级 scrollbar
|
||||||
|
layoutMainRef.value.layoutMainScrollbarRef.update();
|
||||||
|
};
|
||||||
|
// 重置滚动条高度,由于组件是异步引入的
|
||||||
|
const initScrollBarHeight = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
updateScrollbar();
|
||||||
|
layoutScrollbarRef.value.wrap$.scrollTop = 0;
|
||||||
|
layoutMainRef.value.layoutMainScrollbarRef.wrap$.scrollTop = 0;
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 监听路由的变化,切换界面时,滚动条置顶
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
() => {
|
||||||
|
initScrollBarHeight();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||||
|
watch(
|
||||||
|
themeConfig,
|
||||||
|
() => {
|
||||||
|
updateScrollbar();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 页面加载时
|
||||||
|
onMounted(() => {
|
||||||
|
initScrollBarHeight();
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
isFixedHeader,
|
layoutScrollbarRef,
|
||||||
|
layoutMainRef,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,46 +1,77 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="layout-container">
|
<el-container class="layout-container">
|
||||||
<Aside />
|
<LayoutAside />
|
||||||
<el-container class="flex-center" :class="{ 'layout-backtop': !isFixedHeader }">
|
<el-container class="layout-container-view h100">
|
||||||
<Header v-if="isFixedHeader" />
|
<el-scrollbar ref="layoutScrollbarRef" class="layout-backtop">
|
||||||
<el-scrollbar ref="layoutDefaultsScrollbarRef" :class="{ 'layout-backtop': isFixedHeader }">
|
<LayoutHeader />
|
||||||
<Header v-if="!isFixedHeader" />
|
<LayoutMain ref="layoutMainRef" />
|
||||||
<Main />
|
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-container>
|
</el-container>
|
||||||
<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
|
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, getCurrentInstance, watch, defineComponent } from 'vue';
|
import { defineAsyncComponent, watch, defineComponent, onMounted, nextTick, ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import Aside from '/@/layout/component/aside.vue';
|
import { NextLoading } from '/@/utils/loading';
|
||||||
import Header from '/@/layout/component/header.vue';
|
|
||||||
import Main from '/@/layout/component/main.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutDefaults',
|
name: 'layoutDefaults',
|
||||||
components: { Aside, Header, Main },
|
components: {
|
||||||
|
LayoutAside: defineAsyncComponent(() => import('/@/layout/component/aside.vue')),
|
||||||
|
LayoutHeader: defineAsyncComponent(() => import('/@/layout/component/header.vue')),
|
||||||
|
LayoutMain: defineAsyncComponent(() => import('/@/layout/component/main.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const layoutScrollbarRef = ref<any>('');
|
||||||
|
const layoutMainRef = ref<any>('');
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const isFixedHeader = computed(() => {
|
// 重置滚动条高度
|
||||||
return themeConfig.value.isFixedHeader;
|
const updateScrollbar = () => {
|
||||||
});
|
// 更新父级 scrollbar
|
||||||
// 监听路由的变化
|
layoutScrollbarRef.value.update();
|
||||||
|
// 更新子级 scrollbar
|
||||||
|
layoutMainRef.value.layoutMainScrollbarRef.update();
|
||||||
|
};
|
||||||
|
// 重置滚动条高度,由于组件是异步引入的
|
||||||
|
const initScrollBarHeight = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
updateScrollbar();
|
||||||
|
layoutScrollbarRef.value.wrap$.scrollTop = 0;
|
||||||
|
layoutMainRef.value.layoutMainScrollbarRef.wrap$.scrollTop = 0;
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 监听路由的变化,切换界面时,滚动条置顶
|
||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.path,
|
||||||
() => {
|
() => {
|
||||||
proxy.$refs.layoutDefaultsScrollbarRef.wrap$.scrollTop = 0;
|
initScrollBarHeight();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||||
|
watch(
|
||||||
|
themeConfig,
|
||||||
|
() => {
|
||||||
|
updateScrollbar();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 页面加载时
|
||||||
|
onMounted(() => {
|
||||||
|
initScrollBarHeight();
|
||||||
|
NextLoading.done(600);
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
isFixedHeader,
|
layoutScrollbarRef,
|
||||||
|
layoutMainRef,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,17 +1,64 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="layout-container flex-center layout-backtop">
|
<el-container class="layout-container flex-center layout-backtop">
|
||||||
<Header />
|
<LayoutHeader />
|
||||||
<Main />
|
<LayoutMain ref="layoutMainRef" />
|
||||||
<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
|
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Header from '/@/layout/component/header.vue';
|
import { defineAsyncComponent, defineComponent, ref, watch, nextTick, onMounted } from 'vue';
|
||||||
import Main from '/@/layout/component/main.vue';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
|
|
||||||
export default {
|
export default defineComponent({
|
||||||
name: 'layoutTransverse',
|
name: 'layoutTransverse',
|
||||||
components: { Header, Main },
|
components: {
|
||||||
};
|
LayoutHeader: defineAsyncComponent(() => import('/@/layout/component/header.vue')),
|
||||||
|
LayoutMain: defineAsyncComponent(() => import('/@/layout/component/main.vue')),
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const layoutMainRef = ref<any>('');
|
||||||
|
const storesThemeConfig = useThemeConfig();
|
||||||
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
|
const route = useRoute();
|
||||||
|
// 重置滚动条高度,更新子级 scrollbar
|
||||||
|
const updateScrollbar = () => {
|
||||||
|
layoutMainRef.value.layoutMainScrollbarRef.update();
|
||||||
|
};
|
||||||
|
// 重置滚动条高度,由于组件是异步引入的
|
||||||
|
const initScrollBarHeight = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
updateScrollbar();
|
||||||
|
layoutMainRef.value.layoutMainScrollbarRef.wrap$.scrollTop = 0;
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 监听路由的变化,切换界面时,滚动条置顶
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
() => {
|
||||||
|
initScrollBarHeight();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
|
||||||
|
watch(
|
||||||
|
themeConfig,
|
||||||
|
() => {
|
||||||
|
updateScrollbar();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 页面加载时
|
||||||
|
onMounted(() => {
|
||||||
|
initScrollBarHeight();
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
layoutMainRef,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,15 +8,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, reactive, toRefs, onMounted, onUnmounted, getCurrentInstance, defineComponent } from 'vue';
|
import { defineAsyncComponent, computed, reactive, toRefs, onMounted, onUnmounted, defineComponent } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useRoutesList } from '/@/stores/routesList';
|
import { useRoutesList } from '/@/stores/routesList';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import Breadcrumb from '/@/layout/navBars/breadcrumb/breadcrumb.vue';
|
import mittBus from '/@/utils/mitt';
|
||||||
import User from '/@/layout/navBars/breadcrumb/user.vue';
|
|
||||||
import Logo from '/@/layout/logo/index.vue';
|
|
||||||
import Horizontal from '/@/layout/navMenu/horizontal.vue';
|
|
||||||
|
|
||||||
// 定义接口来定义对象的类型
|
// 定义接口来定义对象的类型
|
||||||
interface IndexState {
|
interface IndexState {
|
||||||
@ -25,9 +22,13 @@ interface IndexState {
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutBreadcrumbIndex',
|
name: 'layoutBreadcrumbIndex',
|
||||||
components: { Breadcrumb, User, Logo, Horizontal },
|
components: {
|
||||||
|
Breadcrumb: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/breadcrumb.vue')),
|
||||||
|
User: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/user.vue')),
|
||||||
|
Logo: defineAsyncComponent(() => import('/@/layout/logo/index.vue')),
|
||||||
|
Horizontal: defineAsyncComponent(() => import('/@/layout/navMenu/horizontal.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
|
||||||
const stores = useRoutesList();
|
const stores = useRoutesList();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
@ -52,7 +53,7 @@ export default defineComponent({
|
|||||||
if (layout === 'classic' && isClassicSplitMenu) {
|
if (layout === 'classic' && isClassicSplitMenu) {
|
||||||
state.menuList = delClassicChildren(filterRoutesFun(routesList.value));
|
state.menuList = delClassicChildren(filterRoutesFun(routesList.value));
|
||||||
const resData = setSendClassicChildren(route.path);
|
const resData = setSendClassicChildren(route.path);
|
||||||
proxy.mittBus.emit('setSendClassicChildren', resData);
|
mittBus.emit('setSendClassicChildren', resData);
|
||||||
} else {
|
} else {
|
||||||
state.menuList = filterRoutesFun(routesList.value);
|
state.menuList = filterRoutesFun(routesList.value);
|
||||||
}
|
}
|
||||||
@ -91,13 +92,13 @@ export default defineComponent({
|
|||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setFilterRoutes();
|
setFilterRoutes();
|
||||||
proxy.mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
||||||
setFilterRoutes();
|
setFilterRoutes();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// 页面卸载时
|
// 页面卸载时
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
proxy.mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {});
|
mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {});
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
setIsShowLogo,
|
setIsShowLogo,
|
||||||
|
@ -1,26 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-search-dialog">
|
<div class="layout-search-dialog">
|
||||||
<el-dialog v-model="isShowSearch" width="300px" destroy-on-close :modal="false" fullscreen :show-close="false">
|
<el-dialog v-model="isShowSearch" destroy-on-close :show-close="false">
|
||||||
<el-autocomplete
|
<template #footer>
|
||||||
v-model="menuQuery"
|
<el-autocomplete
|
||||||
:fetch-suggestions="menuSearch"
|
v-model="menuQuery"
|
||||||
:placeholder="$t('message.user.searchPlaceholder')"
|
:fetch-suggestions="menuSearch"
|
||||||
ref="layoutMenuAutocompleteRef"
|
:placeholder="$t('message.user.searchPlaceholder')"
|
||||||
@select="onHandleSelect"
|
ref="layoutMenuAutocompleteRef"
|
||||||
@blur="onSearchBlur"
|
@select="onHandleSelect"
|
||||||
>
|
:fit-input-width="true"
|
||||||
<template #prefix>
|
>
|
||||||
<el-icon class="el-input__icon">
|
<template #prefix>
|
||||||
<ele-Search />
|
<el-icon class="el-input__icon">
|
||||||
</el-icon>
|
<ele-Search />
|
||||||
</template>
|
</el-icon>
|
||||||
<template #default="{ item }">
|
</template>
|
||||||
<div>
|
<template #default="{ item }">
|
||||||
<SvgIcon :name="item.meta.icon" class="mr5" />
|
<div>
|
||||||
{{ $t(item.meta.title) }}
|
<SvgIcon :name="item.meta.icon" class="mr5" />
|
||||||
</div>
|
{{ $t(item.meta.title) }}
|
||||||
</template>
|
</div>
|
||||||
</el-autocomplete>
|
</template>
|
||||||
|
</el-autocomplete>
|
||||||
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -103,17 +105,12 @@ export default defineComponent({
|
|||||||
else router.push(path);
|
else router.push(path);
|
||||||
closeSearch();
|
closeSearch();
|
||||||
};
|
};
|
||||||
// input 失去焦点时
|
|
||||||
const onSearchBlur = () => {
|
|
||||||
closeSearch();
|
|
||||||
};
|
|
||||||
return {
|
return {
|
||||||
layoutMenuAutocompleteRef,
|
layoutMenuAutocompleteRef,
|
||||||
openSearch,
|
openSearch,
|
||||||
closeSearch,
|
closeSearch,
|
||||||
menuSearch,
|
menuSearch,
|
||||||
onHandleSelect,
|
onHandleSelect,
|
||||||
onSearchBlur,
|
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -122,15 +119,23 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.layout-search-dialog {
|
.layout-search-dialog {
|
||||||
|
position: relative;
|
||||||
:deep(.el-dialog) {
|
:deep(.el-dialog) {
|
||||||
box-shadow: unset !important;
|
.el-dialog__header,
|
||||||
border-radius: 0 !important;
|
.el-dialog__body {
|
||||||
background: rgba(0, 0, 0, 0.5);
|
display: none;
|
||||||
|
}
|
||||||
|
.el-dialog__footer {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
top: -53vh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
:deep(.el-autocomplete) {
|
:deep(.el-autocomplete) {
|
||||||
width: 560px;
|
width: 560px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100px;
|
top: 150px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,17 @@
|
|||||||
></el-switch>
|
></el-switch>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layout-breadcrumb-seting-bar-flex mt14" :style="{ opacity: getThemeConfig.layout !== 'columns' ? 0.5 : 1 }">
|
||||||
|
<div class="layout-breadcrumb-seting-bar-flex-label">{{ $t('message.layout.twoIsColumnsMenuHoverPreload') }}</div>
|
||||||
|
<div class="layout-breadcrumb-seting-bar-flex-value">
|
||||||
|
<el-switch
|
||||||
|
v-model="getThemeConfig.isColumnsMenuHoverPreload"
|
||||||
|
size="small"
|
||||||
|
@change="onColumnsMenuHoverPreloadChange"
|
||||||
|
:disabled="getThemeConfig.layout !== 'columns'"
|
||||||
|
></el-switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 界面设置 -->
|
<!-- 界面设置 -->
|
||||||
<el-divider content-position="left">{{ $t('message.layout.threeTitle') }}</el-divider>
|
<el-divider content-position="left">{{ $t('message.layout.threeTitle') }}</el-divider>
|
||||||
@ -408,8 +419,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { nextTick, onUnmounted, onMounted, getCurrentInstance, defineComponent, computed, reactive, toRefs } from 'vue';
|
import { nextTick, onUnmounted, onMounted, defineComponent, computed, reactive, toRefs } from 'vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import { getLightColor, getDarkColor } from '/@/utils/theme';
|
import { getLightColor, getDarkColor } from '/@/utils/theme';
|
||||||
@ -418,11 +430,12 @@ import { Local } from '/@/utils/storage';
|
|||||||
import Watermark from '/@/utils/wartermark';
|
import Watermark from '/@/utils/wartermark';
|
||||||
import commonFunction from '/@/utils/commonFunction';
|
import commonFunction from '/@/utils/commonFunction';
|
||||||
import other from '/@/utils/other';
|
import other from '/@/utils/other';
|
||||||
|
import mittBus from '/@/utils/mitt';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutBreadcrumbSeting',
|
name: 'layoutBreadcrumbSeting',
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const { locale } = useI18n();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const { copyText } = commonFunction();
|
const { copyText } = commonFunction();
|
||||||
@ -479,6 +492,11 @@ export default defineComponent({
|
|||||||
setLocalThemeConfig();
|
setLocalThemeConfig();
|
||||||
}, 200);
|
}, 200);
|
||||||
};
|
};
|
||||||
|
// 2、分栏设置 ->
|
||||||
|
const onColumnsMenuHoverPreloadChange = () => {
|
||||||
|
mittBus.emit('setHoverPreload');
|
||||||
|
setLocalThemeConfig();
|
||||||
|
};
|
||||||
// 3、界面设置 --> 菜单水平折叠
|
// 3、界面设置 --> 菜单水平折叠
|
||||||
const onThemeConfigChange = () => {
|
const onThemeConfigChange = () => {
|
||||||
setDispatchThemeConfig();
|
setDispatchThemeConfig();
|
||||||
@ -492,7 +510,7 @@ export default defineComponent({
|
|||||||
const onClassicSplitMenuChange = () => {
|
const onClassicSplitMenuChange = () => {
|
||||||
getThemeConfig.value.isBreadcrumb = false;
|
getThemeConfig.value.isBreadcrumb = false;
|
||||||
setLocalThemeConfig();
|
setLocalThemeConfig();
|
||||||
proxy.mittBus.emit('getBreadcrumbIndexSetFilterRoutes');
|
mittBus.emit('getBreadcrumbIndexSetFilterRoutes');
|
||||||
};
|
};
|
||||||
// 4、界面显示 --> 侧边栏 Logo
|
// 4、界面显示 --> 侧边栏 Logo
|
||||||
const onIsShowLogoChange = () => {
|
const onIsShowLogoChange = () => {
|
||||||
@ -508,12 +526,12 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 4、界面显示 --> 开启 TagsView 拖拽
|
// 4、界面显示 --> 开启 TagsView 拖拽
|
||||||
const onSortableTagsViewChange = () => {
|
const onSortableTagsViewChange = () => {
|
||||||
proxy.mittBus.emit('openOrCloseSortable');
|
mittBus.emit('openOrCloseSortable');
|
||||||
setLocalThemeConfig();
|
setLocalThemeConfig();
|
||||||
};
|
};
|
||||||
// 4、界面显示 --> 开启 TagsView 共用
|
// 4、界面显示 --> 开启 TagsView 共用
|
||||||
const onShareTagsViewChange = () => {
|
const onShareTagsViewChange = () => {
|
||||||
proxy.mittBus.emit('openShareTagsView');
|
mittBus.emit('openShareTagsView');
|
||||||
setLocalThemeConfig();
|
setLocalThemeConfig();
|
||||||
};
|
};
|
||||||
// 4、界面显示 --> 灰色模式/色弱模式
|
// 4、界面显示 --> 灰色模式/色弱模式
|
||||||
@ -565,7 +583,7 @@ export default defineComponent({
|
|||||||
onBgColorPickerChange('columnsMenuBar');
|
onBgColorPickerChange('columnsMenuBar');
|
||||||
onBgColorPickerChange('columnsMenuBarColor');
|
onBgColorPickerChange('columnsMenuBarColor');
|
||||||
};
|
};
|
||||||
// 关闭弹窗时,初始化变量。变量用于处理 proxy.$refs.layoutScrollbarRef.update()
|
// 关闭弹窗时,初始化变量。变量用于处理 layoutScrollbarRef.value.update() 更新滚动条高度
|
||||||
const onDrawerClose = () => {
|
const onDrawerClose = () => {
|
||||||
getThemeConfig.value.isFixedHeaderChange = false;
|
getThemeConfig.value.isFixedHeaderChange = false;
|
||||||
getThemeConfig.value.isShowLogoChange = false;
|
getThemeConfig.value.isShowLogoChange = false;
|
||||||
@ -618,7 +636,7 @@ export default defineComponent({
|
|||||||
if (!Local.get('frequency')) initLayoutChangeFun();
|
if (!Local.get('frequency')) initLayoutChangeFun();
|
||||||
Local.set('frequency', 1);
|
Local.set('frequency', 1);
|
||||||
// 监听窗口大小改变,非默认布局,设置成默认布局(适配移动端)
|
// 监听窗口大小改变,非默认布局,设置成默认布局(适配移动端)
|
||||||
proxy.mittBus.on('layoutMobileResize', (res: any) => {
|
mittBus.on('layoutMobileResize', (res: any) => {
|
||||||
getThemeConfig.value.layout = res.layout;
|
getThemeConfig.value.layout = res.layout;
|
||||||
getThemeConfig.value.isDrawer = false;
|
getThemeConfig.value.isDrawer = false;
|
||||||
initLayoutChangeFun();
|
initLayoutChangeFun();
|
||||||
@ -636,14 +654,14 @@ export default defineComponent({
|
|||||||
// 开启水印
|
// 开启水印
|
||||||
onWartermarkChange();
|
onWartermarkChange();
|
||||||
// 语言国际化
|
// 语言国际化
|
||||||
if (Local.get('themeConfig')) proxy.$i18n.locale = Local.get('themeConfig').globalI18n;
|
if (Local.get('themeConfig')) locale.value = Local.get('themeConfig').globalI18n;
|
||||||
// 初始化菜单样式等
|
// 初始化菜单样式等
|
||||||
initSetStyle();
|
initSetStyle();
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
proxy.mittBus.off('layoutMobileResize', () => {});
|
mittBus.off('layoutMobileResize', () => {});
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
openDrawer,
|
openDrawer,
|
||||||
@ -652,6 +670,7 @@ export default defineComponent({
|
|||||||
onTopBarGradualChange,
|
onTopBarGradualChange,
|
||||||
onMenuBarGradualChange,
|
onMenuBarGradualChange,
|
||||||
onColumnsMenuBarGradualChange,
|
onColumnsMenuBarGradualChange,
|
||||||
|
onColumnsMenuHoverPreloadChange,
|
||||||
onThemeConfigChange,
|
onThemeConfigChange,
|
||||||
onIsFixedHeaderChange,
|
onIsFixedHeaderChange,
|
||||||
onIsShowLogoChange,
|
onIsShowLogoChange,
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ref, getCurrentInstance, computed, reactive, toRefs, onMounted, defineComponent } from 'vue';
|
import { defineAsyncComponent, ref, computed, reactive, toRefs, onMounted, defineComponent } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
import screenfull from 'screenfull';
|
import screenfull from 'screenfull';
|
||||||
@ -86,16 +86,17 @@ import { storeToRefs } from 'pinia';
|
|||||||
import { useUserInfo } from '/@/stores/userInfo';
|
import { useUserInfo } from '/@/stores/userInfo';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import other from '/@/utils/other';
|
import other from '/@/utils/other';
|
||||||
|
import mittBus from '/@/utils/mitt';
|
||||||
import { Session, Local } from '/@/utils/storage';
|
import { Session, Local } from '/@/utils/storage';
|
||||||
import UserNews from '/@/layout/navBars/breadcrumb/userNews.vue';
|
|
||||||
import Search from '/@/layout/navBars/breadcrumb/search.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutBreadcrumbUser',
|
name: 'layoutBreadcrumbUser',
|
||||||
components: { UserNews, Search },
|
components: {
|
||||||
|
UserNews: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/userNews.vue')),
|
||||||
|
Search: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/search.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { t } = useI18n();
|
const { locale, t } = useI18n();
|
||||||
const { proxy } = <any>getCurrentInstance();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const stores = useUserInfo();
|
const stores = useUserInfo();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
@ -130,7 +131,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 布局配置 icon 点击时
|
// 布局配置 icon 点击时
|
||||||
const onLayoutSetingClick = () => {
|
const onLayoutSetingClick = () => {
|
||||||
proxy.mittBus.emit('openSetingsDrawer');
|
mittBus.emit('openSetingsDrawer');
|
||||||
};
|
};
|
||||||
// 下拉菜单点击时
|
// 下拉菜单点击时
|
||||||
const onHandleCommandClick = (path: string) => {
|
const onHandleCommandClick = (path: string) => {
|
||||||
@ -181,7 +182,7 @@ export default defineComponent({
|
|||||||
Local.remove('themeConfig');
|
Local.remove('themeConfig');
|
||||||
themeConfig.value.globalComponentSize = size;
|
themeConfig.value.globalComponentSize = size;
|
||||||
Local.set('themeConfig', themeConfig.value);
|
Local.set('themeConfig', themeConfig.value);
|
||||||
initComponentSize();
|
initI18nOrSize('globalComponentSize', 'disabledSize');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
};
|
};
|
||||||
// 语言切换
|
// 语言切换
|
||||||
@ -189,50 +190,19 @@ export default defineComponent({
|
|||||||
Local.remove('themeConfig');
|
Local.remove('themeConfig');
|
||||||
themeConfig.value.globalI18n = lang;
|
themeConfig.value.globalI18n = lang;
|
||||||
Local.set('themeConfig', themeConfig.value);
|
Local.set('themeConfig', themeConfig.value);
|
||||||
proxy.$i18n.locale = lang;
|
locale.value = lang;
|
||||||
initI18n();
|
|
||||||
other.useTitle();
|
other.useTitle();
|
||||||
|
initI18nOrSize('globalI18n', 'disabledI18n');
|
||||||
};
|
};
|
||||||
// 设置 element plus 组件的国际化
|
// 初始化组件大小/i18n
|
||||||
const setI18nConfig = (locale: string) => {
|
const initI18nOrSize = (value: string, attr: string) => {
|
||||||
proxy.mittBus.emit('getI18nConfig', proxy.$i18n.messages[locale]);
|
(<any>state)[attr] = Local.get('themeConfig')[value];
|
||||||
};
|
|
||||||
// 初始化言语国际化
|
|
||||||
const initI18n = () => {
|
|
||||||
switch (Local.get('themeConfig').globalI18n) {
|
|
||||||
case 'zh-cn':
|
|
||||||
state.disabledI18n = 'zh-cn';
|
|
||||||
setI18nConfig('zh-cn');
|
|
||||||
break;
|
|
||||||
case 'en':
|
|
||||||
state.disabledI18n = 'en';
|
|
||||||
setI18nConfig('en');
|
|
||||||
break;
|
|
||||||
case 'zh-tw':
|
|
||||||
state.disabledI18n = 'zh-tw';
|
|
||||||
setI18nConfig('zh-tw');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 初始化全局组件大小
|
|
||||||
const initComponentSize = () => {
|
|
||||||
switch (Local.get('themeConfig').globalComponentSize) {
|
|
||||||
case 'large':
|
|
||||||
state.disabledSize = 'large';
|
|
||||||
break;
|
|
||||||
case 'default':
|
|
||||||
state.disabledSize = 'default';
|
|
||||||
break;
|
|
||||||
case 'small':
|
|
||||||
state.disabledSize = 'small';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (Local.get('themeConfig')) {
|
if (Local.get('themeConfig')) {
|
||||||
initI18n();
|
initI18nOrSize('globalComponentSize', 'disabledSize');
|
||||||
initComponentSize();
|
initI18nOrSize('globalI18n', 'disabledI18n');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
@ -6,15 +6,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { defineAsyncComponent, computed, defineComponent } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import BreadcrumbIndex from '/@/layout/navBars/breadcrumb/index.vue';
|
|
||||||
import TagsView from '/@/layout/navBars/tagsView/tagsView.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutNavBars',
|
name: 'layoutNavBars',
|
||||||
components: { BreadcrumbIndex, TagsView },
|
components: {
|
||||||
|
BreadcrumbIndex: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/index.vue')),
|
||||||
|
TagsView: defineAsyncComponent(() => import('/@/layout/navBars/tagsView/tagsView.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
:data-url="v.url"
|
:data-url="v.url"
|
||||||
:class="{ 'is-active': isActive(v) }"
|
:class="{ 'is-active': isActive(v) }"
|
||||||
@contextmenu.prevent="onContextmenu(v, $event)"
|
@contextmenu.prevent="onContextmenu(v, $event)"
|
||||||
|
@mousedown="onMousedownMenu(v, $event)"
|
||||||
@click="onTagsClick(v, k)"
|
@click="onTagsClick(v, k)"
|
||||||
:ref="
|
:ref="
|
||||||
(el) => {
|
(el) => {
|
||||||
@ -47,6 +48,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
|
defineAsyncComponent,
|
||||||
toRefs,
|
toRefs,
|
||||||
reactive,
|
reactive,
|
||||||
onMounted,
|
onMounted,
|
||||||
@ -56,7 +58,6 @@ import {
|
|||||||
onBeforeUpdate,
|
onBeforeUpdate,
|
||||||
onBeforeMount,
|
onBeforeMount,
|
||||||
onUnmounted,
|
onUnmounted,
|
||||||
getCurrentInstance,
|
|
||||||
watch,
|
watch,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
@ -71,7 +72,7 @@ import { useKeepALiveNames } from '/@/stores/keepAliveNames';
|
|||||||
import { Session } from '/@/utils/storage';
|
import { Session } from '/@/utils/storage';
|
||||||
import { isObjectValueEqual } from '/@/utils/arrayOperation';
|
import { isObjectValueEqual } from '/@/utils/arrayOperation';
|
||||||
import other from '/@/utils/other';
|
import other from '/@/utils/other';
|
||||||
import Contextmenu from '/@/layout/navBars/tagsView/contextmenu.vue';
|
import mittBus from '/@/utils/mitt';
|
||||||
|
|
||||||
// 定义接口来定义对象的类型
|
// 定义接口来定义对象的类型
|
||||||
interface TagsViewState {
|
interface TagsViewState {
|
||||||
@ -104,9 +105,10 @@ interface CurrentContextmenu {
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutTagsView',
|
name: 'layoutTagsView',
|
||||||
components: { Contextmenu },
|
components: {
|
||||||
|
Contextmenu: defineAsyncComponent(() => import('/@/layout/navBars/tagsView/contextmenu.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
|
||||||
const tagsRefs = ref<any[]>([]);
|
const tagsRefs = ref<any[]>([]);
|
||||||
const scrollbarRef = ref();
|
const scrollbarRef = ref();
|
||||||
const contextmenuRef = ref();
|
const contextmenuRef = ref();
|
||||||
@ -237,13 +239,21 @@ export default defineComponent({
|
|||||||
// 动态路由(xxx/:id/:name"):参数不同,开启多个 tagsview
|
// 动态路由(xxx/:id/:name"):参数不同,开启多个 tagsview
|
||||||
if (!getThemeConfig.value.isShareTagsView) await solveAddTagsView(path, to);
|
if (!getThemeConfig.value.isShareTagsView) await solveAddTagsView(path, to);
|
||||||
else await singleAddTagsView(path, to);
|
else await singleAddTagsView(path, to);
|
||||||
if (state.tagsViewList.some((v: any) => v.path === to.meta.isDynamicPath)) return false;
|
if (state.tagsViewList.some((v: any) => v.path === to.meta.isDynamicPath)) {
|
||||||
|
// 防止首次进入界面时(登录进入) tagsViewList 不存浏览器中
|
||||||
|
addBrowserSetSession(state.tagsViewList);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
item = state.tagsViewRoutesList.find((v: any) => v.path === to.meta.isDynamicPath);
|
item = state.tagsViewRoutesList.find((v: any) => v.path === to.meta.isDynamicPath);
|
||||||
} else {
|
} else {
|
||||||
// 普通路由:参数不同,开启多个 tagsview
|
// 普通路由:参数不同,开启多个 tagsview
|
||||||
if (!getThemeConfig.value.isShareTagsView) await solveAddTagsView(path, to);
|
if (!getThemeConfig.value.isShareTagsView) await solveAddTagsView(path, to);
|
||||||
else await singleAddTagsView(path, to);
|
else await singleAddTagsView(path, to);
|
||||||
if (state.tagsViewList.some((v: any) => v.path === path)) return false;
|
if (state.tagsViewList.some((v: any) => v.path === path)) {
|
||||||
|
// 防止首次进入界面时(登录进入) tagsViewList 不存浏览器中
|
||||||
|
addBrowserSetSession(state.tagsViewList);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
item = state.tagsViewRoutesList.find((v: any) => v.path === path);
|
item = state.tagsViewRoutesList.find((v: any) => v.path === path);
|
||||||
}
|
}
|
||||||
if (!item) return false;
|
if (!item) return false;
|
||||||
@ -258,12 +268,20 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 2、刷新当前 tagsView:
|
// 2、刷新当前 tagsView:
|
||||||
const refreshCurrentTagsView = async (fullPath: string) => {
|
const refreshCurrentTagsView = async (fullPath: string) => {
|
||||||
const item = state.tagsViewList.find((v: any) => (getThemeConfig.value.isShareTagsView ? v.path === fullPath : v.url === fullPath));
|
const decodeURIPath = decodeURI(fullPath);
|
||||||
if (item != null) {
|
let item: any = {};
|
||||||
await storesKeepALiveNames.delCachedView(item);
|
state.tagsViewList.forEach((v: any) => {
|
||||||
proxy.mittBus.emit('onTagsViewRefreshRouterView', fullPath);
|
v.transUrl = transUrlParams(v);
|
||||||
if (item.meta.isKeepAlive) storesKeepALiveNames.addCachedView(item);
|
if (v.transUrl) {
|
||||||
}
|
if (v.transUrl === transUrlParams(v)) item = v;
|
||||||
|
} else {
|
||||||
|
if (v.path === decodeURIPath) item = v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!item) return false;
|
||||||
|
await storesKeepALiveNames.delCachedView(item);
|
||||||
|
mittBus.emit('onTagsViewRefreshRouterView', fullPath);
|
||||||
|
if (item.meta.isKeepAlive) storesKeepALiveNames.addCachedView(item);
|
||||||
};
|
};
|
||||||
// 3、关闭当前 tagsView:如果是设置了固定的(isAffix),不可以关闭
|
// 3、关闭当前 tagsView:如果是设置了固定的(isAffix),不可以关闭
|
||||||
const closeCurrentTagsView = (path: string) => {
|
const closeCurrentTagsView = (path: string) => {
|
||||||
@ -396,11 +414,31 @@ export default defineComponent({
|
|||||||
state.dropdown.y = clientY;
|
state.dropdown.y = clientY;
|
||||||
contextmenuRef.value.openContextmenu(v);
|
contextmenuRef.value.openContextmenu(v);
|
||||||
};
|
};
|
||||||
|
// 鼠标按下时,判断是鼠标中键就关闭当前 tasgview
|
||||||
|
const onMousedownMenu = (v: any, e: any) => {
|
||||||
|
if (!v.meta.isAffix && e.which === 2) {
|
||||||
|
const item = Object.assign({}, { contextMenuClickId: 1, ...v });
|
||||||
|
onCurrentContextmenuClick(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
// 当前的 tagsView 项点击时
|
// 当前的 tagsView 项点击时
|
||||||
const onTagsClick = (v: any, k: number) => {
|
const onTagsClick = (v: any, k: number) => {
|
||||||
state.tagsRefsIndex = k;
|
state.tagsRefsIndex = k;
|
||||||
router.push(v);
|
router.push(v);
|
||||||
};
|
};
|
||||||
|
// 处理 url,地址栏链接有参数时,tagsview 右键菜单刷新功能失效问题
|
||||||
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I5K3YO
|
||||||
|
const transUrlParams = (v: any) => {
|
||||||
|
let params = v.query && Object.keys(v.query).length > 0 ? v.query : v.params;
|
||||||
|
if (!params) return '';
|
||||||
|
let path = '';
|
||||||
|
for (let [key, value] of Object.entries(params)) {
|
||||||
|
if (v.meta.isDynamic) path += `/${value}`;
|
||||||
|
else path += `&${key}=${value}`;
|
||||||
|
}
|
||||||
|
// 判断是否是动态路由(xxx/:id/:name")isDynamic
|
||||||
|
return v.meta.isDynamic ? `${v.path.split(':')[0]}${path.replace(/^\//, '')}` : `${v.path}${path.replace(/^&/, '?')}`;
|
||||||
|
};
|
||||||
// 处理 tagsView 高亮(多标签详情时使用,单标签详情未使用)
|
// 处理 tagsView 高亮(多标签详情时使用,单标签详情未使用)
|
||||||
const setTagsViewHighlight = (v: any) => {
|
const setTagsViewHighlight = (v: any) => {
|
||||||
let params = v.query && Object.keys(v.query).length > 0 ? v.query : v.params;
|
let params = v.query && Object.keys(v.query).length > 0 ? v.query : v.params;
|
||||||
@ -412,13 +450,9 @@ export default defineComponent({
|
|||||||
// 判断是否是动态路由(xxx/:id/:name")
|
// 判断是否是动态路由(xxx/:id/:name")
|
||||||
return `${v.meta.isDynamic ? v.meta.isDynamicPath : v.path}-${path}`;
|
return `${v.meta.isDynamic ? v.meta.isDynamicPath : v.path}-${path}`;
|
||||||
};
|
};
|
||||||
// 更新滚动条显示
|
|
||||||
const updateScrollbar = () => {
|
|
||||||
proxy.$refs.scrollbarRef.update();
|
|
||||||
};
|
|
||||||
// 鼠标滚轮滚动
|
// 鼠标滚轮滚动
|
||||||
const onHandleScroll = (e: any) => {
|
const onHandleScroll = (e: any) => {
|
||||||
proxy.$refs.scrollbarRef.$refs.wrap$.scrollLeft += e.wheelDelta / 4;
|
scrollbarRef.value.$refs.wrap$.scrollLeft += e.wheelDelta / 4;
|
||||||
};
|
};
|
||||||
// tagsView 横向滚动
|
// tagsView 横向滚动
|
||||||
const tagsViewmoveToCurrentTag = () => {
|
const tagsViewmoveToCurrentTag = () => {
|
||||||
@ -435,7 +469,7 @@ export default defineComponent({
|
|||||||
// 最后 li
|
// 最后 li
|
||||||
let liLast: any = tagsRefs.value[tagsRefs.value.length - 1];
|
let liLast: any = tagsRefs.value[tagsRefs.value.length - 1];
|
||||||
// 当前滚动条的值
|
// 当前滚动条的值
|
||||||
let scrollRefs = proxy.$refs.scrollbarRef.$refs.wrap$;
|
let scrollRefs = scrollbarRef.value.$refs.wrap$;
|
||||||
// 当前滚动条滚动宽度
|
// 当前滚动条滚动宽度
|
||||||
let scrollS = scrollRefs.scrollWidth;
|
let scrollS = scrollRefs.scrollWidth;
|
||||||
// 当前滚动条偏移宽度
|
// 当前滚动条偏移宽度
|
||||||
@ -469,7 +503,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 更新滚动条,防止不出现
|
// 更新滚动条,防止不出现
|
||||||
updateScrollbar();
|
scrollbarRef.value.update();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 获取 tagsView 的下标:用于处理 tagsView 点击时的横向滚动
|
// 获取 tagsView 的下标:用于处理 tagsView 点击时的横向滚动
|
||||||
@ -520,15 +554,15 @@ export default defineComponent({
|
|||||||
// 拖动问题,https://gitee.com/lyt-top/vue-next-admin/issues/I3ZRRI
|
// 拖动问题,https://gitee.com/lyt-top/vue-next-admin/issues/I3ZRRI
|
||||||
window.addEventListener('resize', onSortableResize);
|
window.addEventListener('resize', onSortableResize);
|
||||||
// 监听非本页面调用 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
|
// 监听非本页面调用 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
|
||||||
proxy.mittBus.on('onCurrentContextmenuClick', (data: CurrentContextmenu) => {
|
mittBus.on('onCurrentContextmenuClick', (data: CurrentContextmenu) => {
|
||||||
onCurrentContextmenuClick(data);
|
onCurrentContextmenuClick(data);
|
||||||
});
|
});
|
||||||
// 监听布局配置界面开启/关闭拖拽
|
// 监听布局配置界面开启/关闭拖拽
|
||||||
proxy.mittBus.on('openOrCloseSortable', () => {
|
mittBus.on('openOrCloseSortable', () => {
|
||||||
initSortable();
|
initSortable();
|
||||||
});
|
});
|
||||||
// 监听布局配置开启 TagsView 共用,为了演示还原默认值
|
// 监听布局配置开启 TagsView 共用,为了演示还原默认值
|
||||||
proxy.mittBus.on('openShareTagsView', () => {
|
mittBus.on('openShareTagsView', () => {
|
||||||
if (getThemeConfig.value.isShareTagsView) {
|
if (getThemeConfig.value.isShareTagsView) {
|
||||||
router.push('/home');
|
router.push('/home');
|
||||||
state.tagsViewList = [];
|
state.tagsViewList = [];
|
||||||
@ -544,11 +578,11 @@ export default defineComponent({
|
|||||||
// 页面卸载时
|
// 页面卸载时
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
// 取消非本页面调用监听
|
// 取消非本页面调用监听
|
||||||
proxy.mittBus.off('onCurrentContextmenuClick', () => {});
|
mittBus.off('onCurrentContextmenuClick', () => {});
|
||||||
// 取消监听布局配置界面开启/关闭拖拽
|
// 取消监听布局配置界面开启/关闭拖拽
|
||||||
proxy.mittBus.off('openOrCloseSortable', () => {});
|
mittBus.off('openOrCloseSortable', () => {});
|
||||||
// 取消监听布局配置开启 TagsView 共用
|
// 取消监听布局配置开启 TagsView 共用
|
||||||
proxy.mittBus.off('openShareTagsView', () => {});
|
mittBus.off('openShareTagsView', () => {});
|
||||||
// 取消窗口 resize 监听
|
// 取消窗口 resize 监听
|
||||||
window.removeEventListener('resize', onSortableResize);
|
window.removeEventListener('resize', onSortableResize);
|
||||||
});
|
});
|
||||||
@ -583,6 +617,7 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
isActive,
|
isActive,
|
||||||
onContextmenu,
|
onContextmenu,
|
||||||
|
onMousedownMenu,
|
||||||
onTagsClick,
|
onTagsClick,
|
||||||
tagsRefs,
|
tagsRefs,
|
||||||
contextmenuRef,
|
contextmenuRef,
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
{{ $t(val.meta.title) }}
|
{{ $t(val.meta.title) }}
|
||||||
</template>
|
</template>
|
||||||
<template #title v-else>
|
<template #title v-else>
|
||||||
<a :href="val.meta.isLink" target="_blank" rel="opener" class="w100">
|
<a class="w100" @click.prevent="onALinkClick(val)">
|
||||||
<SvgIcon :name="val.meta.icon" />
|
<SvgIcon :name="val.meta.icon" />
|
||||||
{{ $t(val.meta.title) }}
|
{{ $t(val.meta.title) }}
|
||||||
</a>
|
</a>
|
||||||
@ -31,16 +31,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, computed, defineComponent, getCurrentInstance, onMounted, nextTick, onBeforeMount } from 'vue';
|
import { defineAsyncComponent, toRefs, reactive, computed, defineComponent, onMounted, nextTick, onBeforeMount, ref } from 'vue';
|
||||||
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
|
import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useRoutesList } from '/@/stores/routesList';
|
import { useRoutesList } from '/@/stores/routesList';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import SubItem from '/@/layout/navMenu/subItem.vue';
|
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||||
|
import mittBus from '/@/utils/mitt';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'navMenuHorizontal',
|
name: 'navMenuHorizontal',
|
||||||
components: { SubItem },
|
components: {
|
||||||
|
SubItem: defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue')),
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
menuList: {
|
menuList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@ -48,12 +51,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const elMenuHorizontalScrollRef = ref();
|
||||||
const stores = useRoutesList();
|
const stores = useRoutesList();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { routesList } = storeToRefs(stores);
|
const { routesList } = storeToRefs(stores);
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
defaultActive: null,
|
defaultActive: null,
|
||||||
});
|
});
|
||||||
@ -64,14 +68,14 @@ export default defineComponent({
|
|||||||
// 设置横向滚动条可以鼠标滚轮滚动
|
// 设置横向滚动条可以鼠标滚轮滚动
|
||||||
const onElMenuHorizontalScroll = (e: any) => {
|
const onElMenuHorizontalScroll = (e: any) => {
|
||||||
const eventDelta = e.wheelDelta || -e.deltaY * 40;
|
const eventDelta = e.wheelDelta || -e.deltaY * 40;
|
||||||
proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft = proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft + eventDelta / 4;
|
elMenuHorizontalScrollRef.value.$refs.wrap$.scrollLeft = elMenuHorizontalScrollRef.value.$refs.wrap$.scrollLeft + eventDelta / 4;
|
||||||
};
|
};
|
||||||
// 初始化数据,页面刷新时,滚动条滚动到对应位置
|
// 初始化数据,页面刷新时,滚动条滚动到对应位置
|
||||||
const initElMenuOffsetLeft = () => {
|
const initElMenuOffsetLeft = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
let els: any = document.querySelector('.el-menu.el-menu--horizontal li.is-active');
|
let els: any = document.querySelector('.el-menu.el-menu--horizontal li.is-active');
|
||||||
if (!els) return false;
|
if (!els) return false;
|
||||||
proxy.$refs.elMenuHorizontalScrollRef.$refs.wrap$.scrollLeft = els.offsetLeft;
|
elMenuHorizontalScrollRef.value.$refs.wrap$.scrollLeft = els.offsetLeft;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 路由过滤递归函数
|
// 路由过滤递归函数
|
||||||
@ -109,6 +113,13 @@ export default defineComponent({
|
|||||||
else state.defaultActive = path;
|
else state.defaultActive = path;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// 打开外部链接
|
||||||
|
const onALinkClick = (val: any) => {
|
||||||
|
const { origin, pathname } = window.location;
|
||||||
|
router.push(val.path);
|
||||||
|
if (verifyUrl(val.meta.isLink)) window.open(val.meta.isLink);
|
||||||
|
else window.open(`${origin}${pathname}#${val.meta.isLink}`);
|
||||||
|
};
|
||||||
// 页面加载前
|
// 页面加载前
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
setCurrentRouterHighlight(route);
|
setCurrentRouterHighlight(route);
|
||||||
@ -124,12 +135,14 @@ export default defineComponent({
|
|||||||
// 修复经典布局开启切割菜单时,点击tagsView后左侧导航菜单数据不变的问题
|
// 修复经典布局开启切割菜单时,点击tagsView后左侧导航菜单数据不变的问题
|
||||||
let { layout, isClassicSplitMenu } = themeConfig.value;
|
let { layout, isClassicSplitMenu } = themeConfig.value;
|
||||||
if (layout === 'classic' && isClassicSplitMenu) {
|
if (layout === 'classic' && isClassicSplitMenu) {
|
||||||
proxy.mittBus.emit('setSendClassicChildren', setSendClassicChildren(to.path));
|
mittBus.emit('setSendClassicChildren', setSendClassicChildren(to.path));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
elMenuHorizontalScrollRef,
|
||||||
menuLists,
|
menuLists,
|
||||||
onElMenuHorizontalScroll,
|
onElMenuHorizontalScroll,
|
||||||
|
onALinkClick,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<span>{{ $t(val.meta.title) }}</span>
|
<span>{{ $t(val.meta.title) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a :href="val.meta.isLink" target="_blank" rel="opener" class="w100">
|
<a class="w100" @click.prevent="onALinkClick(val)">
|
||||||
<SvgIcon :name="val.meta.icon" />
|
<SvgIcon :name="val.meta.icon" />
|
||||||
{{ $t(val.meta.title) }}
|
{{ $t(val.meta.title) }}
|
||||||
</a>
|
</a>
|
||||||
@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'navMenuSubItem',
|
name: 'navMenuSubItem',
|
||||||
@ -36,12 +38,21 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
const router = useRouter();
|
||||||
// 获取父级菜单数据
|
// 获取父级菜单数据
|
||||||
const chils = computed(() => {
|
const chils = computed(() => {
|
||||||
return <any>props.chil;
|
return <any>props.chil;
|
||||||
});
|
});
|
||||||
|
// 打开外部链接
|
||||||
|
const onALinkClick = (val: any) => {
|
||||||
|
const { origin, pathname } = window.location;
|
||||||
|
router.push(val.path);
|
||||||
|
if (verifyUrl(val.meta.isLink)) window.open(val.meta.isLink);
|
||||||
|
else window.open(`${origin}${pathname}#${val.meta.isLink}`);
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
chils,
|
chils,
|
||||||
|
onALinkClick,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<span>{{ $t(val.meta.title) }}</span>
|
<span>{{ $t(val.meta.title) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #title v-else>
|
<template #title v-else>
|
||||||
<a :href="val.meta.isLink" target="_blank" rel="opener" class="w100">{{ $t(val.meta.title) }}</a>
|
<a class="w100" @click.prevent="onALinkClick(val)">{{ $t(val.meta.title) }}</a>
|
||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</template>
|
</template>
|
||||||
@ -31,15 +31,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, computed, defineComponent, onMounted, watch } from 'vue';
|
import { defineAsyncComponent, toRefs, reactive, computed, defineComponent, onMounted, watch } from 'vue';
|
||||||
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
|
import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import SubItem from '/@/layout/navMenu/subItem.vue';
|
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'navMenuVertical',
|
name: 'navMenuVertical',
|
||||||
components: { SubItem },
|
components: {
|
||||||
|
SubItem: defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue')),
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
menuList: {
|
menuList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@ -50,6 +52,7 @@ export default defineComponent({
|
|||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
// 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
|
// 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
|
||||||
defaultActive: route.meta.isDynamic ? route.meta.isDynamicPath : route.path,
|
defaultActive: route.meta.isDynamic ? route.meta.isDynamicPath : route.path,
|
||||||
@ -70,6 +73,13 @@ export default defineComponent({
|
|||||||
if (pathSplit.length >= 4 && meta.isHide) return pathSplit.splice(0, 3).join('/');
|
if (pathSplit.length >= 4 && meta.isHide) return pathSplit.splice(0, 3).join('/');
|
||||||
else return path;
|
else return path;
|
||||||
};
|
};
|
||||||
|
// 打开外部链接
|
||||||
|
const onALinkClick = (val: any) => {
|
||||||
|
const { origin, pathname } = window.location;
|
||||||
|
router.push(val.path);
|
||||||
|
if (verifyUrl(val.meta.isLink)) window.open(val.meta.isLink);
|
||||||
|
else window.open(`${origin}${pathname}#${val.meta.isLink}`);
|
||||||
|
};
|
||||||
// 设置菜单的收起/展开
|
// 设置菜单的收起/展开
|
||||||
watch(
|
watch(
|
||||||
themeConfig.value,
|
themeConfig.value,
|
||||||
@ -94,6 +104,7 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
menuLists,
|
menuLists,
|
||||||
getThemeConfig,
|
getThemeConfig,
|
||||||
|
onALinkClick,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,65 +1,89 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-view-bg-white flex mt1" :style="{ height: `calc(100vh - ${setIframeHeight}`, border: 'none' }" v-loading="iframeLoading">
|
<div class="layout-padding layout-padding-unset layout-iframe">
|
||||||
<iframe :src="iframeUrl" frameborder="0" height="100%" width="100%" ref="iframeDom" v-show="!iframeLoading"></iframe>
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
|
<div class="w100" v-for="v in setIframeList" :key="v.path" v-loading="v.meta.loading" element-loading-background="white">
|
||||||
|
<transition-group :name="name" mode="out-in">
|
||||||
|
<iframe
|
||||||
|
:src="v.meta.isLink"
|
||||||
|
:key="v.path"
|
||||||
|
frameborder="0"
|
||||||
|
height="100%"
|
||||||
|
width="100%"
|
||||||
|
style="position: absolute"
|
||||||
|
:data-url="v.path"
|
||||||
|
v-show="getRoutePath === v.path"
|
||||||
|
ref="iframeRef"
|
||||||
|
/>
|
||||||
|
</transition-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, toRefs, onMounted, nextTick, watch, computed } from 'vue';
|
import { defineComponent, computed, watch, ref, nextTick } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutIfameView',
|
name: 'layoutIframeView',
|
||||||
setup() {
|
props: {
|
||||||
const storesThemeConfig = useThemeConfig();
|
refreshKey: {
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
type: String,
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
default: () => '',
|
||||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: () => 'slide-right',
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const iframeRef = ref();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const state = reactive({
|
// 处理 list 列表,当打开时,才进行加载
|
||||||
iframeDom: null as HTMLIFrameElement | null,
|
const setIframeList = computed(() => {
|
||||||
iframeLoading: true,
|
return (<any>props.list).filter((v: any) => v.meta.isIframeOpen);
|
||||||
iframeUrl: '',
|
|
||||||
});
|
});
|
||||||
// 初始化页面加载 loading
|
// 获取 iframe 当前路由 path
|
||||||
const initIframeLoad = () => {
|
const getRoutePath = computed(() => {
|
||||||
state.iframeUrl = <any>route.meta.isLink;
|
return route.path;
|
||||||
nextTick(() => {
|
|
||||||
state.iframeLoading = true;
|
|
||||||
const iframe = state.iframeDom;
|
|
||||||
if (!iframe) return false;
|
|
||||||
iframe.onload = () => {
|
|
||||||
state.iframeLoading = false;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// 设置 iframe 的高度
|
|
||||||
const setIframeHeight = computed(() => {
|
|
||||||
let { isTagsview } = themeConfig.value;
|
|
||||||
if (isTagsViewCurrenFull.value) {
|
|
||||||
return `1px`;
|
|
||||||
} else {
|
|
||||||
if (isTagsview) return `86px`;
|
|
||||||
else return `51px`;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// 页面加载时
|
// 监听路由变化,初始化 iframe 数据,防止多个 iframe 时,切换不生效
|
||||||
onMounted(() => {
|
|
||||||
initIframeLoad();
|
|
||||||
});
|
|
||||||
// 监听路由变化,多个 iframe 时使用
|
|
||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.fullPath,
|
||||||
() => {
|
(val) => {
|
||||||
initIframeLoad();
|
const item: any = props.list.find((v: any) => v.path === val);
|
||||||
|
if (item && !item.meta.isIframeOpen) item.meta.isIframeOpen = true;
|
||||||
|
nextTick(() => {
|
||||||
|
if (!iframeRef.value) return false;
|
||||||
|
iframeRef.value.forEach((v: any) => {
|
||||||
|
if (v.dataset.url === val) {
|
||||||
|
v.onload = () => {
|
||||||
|
if (item && item.meta.isIframeOpen && item.meta.loading) item.meta.loading = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 监听 iframe refreshKey 变化,用于 tagsview 右键菜单刷新
|
||||||
|
watch(
|
||||||
|
() => props.refreshKey,
|
||||||
|
() => {},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
setIframeHeight,
|
iframeRef,
|
||||||
...toRefs(state),
|
setIframeList,
|
||||||
|
getRoutePath,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-view-bg-white flex layout-view-link" :style="{ height: `calc(100vh - ${setLinkHeight}` }">
|
<div class="layout-padding layout-link-container">
|
||||||
<a :href="currentRouteMeta.isLink" target="_blank" rel="opener" class="flex-margin">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
{{ $t(currentRouteMeta.title) }}:{{ currentRouteMeta.isLink }}
|
<div class="layout-link-warp">
|
||||||
</a>
|
<i class="layout-link-icon iconfont icon-xingqiu"></i>
|
||||||
|
<div class="layout-link-msg">页面 "{{ $t(currentRouteMeta.title) }}" 已在新窗口中打开</div>
|
||||||
|
<el-button class="mt30" round size="default" @click="onGotoFullPage">
|
||||||
|
<i class="iconfont icon-lianjie"></i>
|
||||||
|
<span>立即前往体验</span>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, toRefs, reactive, computed, watch } from 'vue';
|
import { defineComponent, toRefs, reactive, watch } from 'vue';
|
||||||
import { useRoute, RouteMeta } from 'vue-router';
|
import { useRoute, RouteMeta } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { verifyUrl } from '/@/utils/toolsValidate';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
|
|
||||||
// 定义接口来定义对象的类型
|
// 定义接口来定义对象的类型
|
||||||
interface LinkViewState {
|
interface LinkViewState {
|
||||||
@ -27,8 +33,6 @@ interface LinkViewRouteMeta extends RouteMeta {
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutLinkView',
|
name: 'layoutLinkView',
|
||||||
setup() {
|
setup() {
|
||||||
const storesThemeConfig = useThemeConfig();
|
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const state = reactive<LinkViewState>({
|
const state = reactive<LinkViewState>({
|
||||||
currentRouteMeta: {
|
currentRouteMeta: {
|
||||||
@ -36,12 +40,12 @@ export default defineComponent({
|
|||||||
title: '',
|
title: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// 设置 link 的高度
|
// 立即前往
|
||||||
const setLinkHeight = computed(() => {
|
const onGotoFullPage = () => {
|
||||||
let { isTagsview } = themeConfig.value;
|
const { origin, pathname } = window.location;
|
||||||
if (isTagsview) return `115px`;
|
if (verifyUrl(state.currentRouteMeta.isLink)) window.open(state.currentRouteMeta.isLink);
|
||||||
else return `80px`;
|
else window.open(`${origin}${pathname}#${state.currentRouteMeta.isLink}`);
|
||||||
});
|
};
|
||||||
// 监听路由的变化,设置内容
|
// 监听路由的变化,设置内容
|
||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.path,
|
||||||
@ -53,9 +57,57 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
setLinkHeight,
|
onGotoFullPage,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.layout-link-container {
|
||||||
|
.layout-link-warp {
|
||||||
|
margin: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
i.layout-link-icon {
|
||||||
|
position: relative;
|
||||||
|
font-size: 100px;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 50px;
|
||||||
|
top: 0;
|
||||||
|
width: 15px;
|
||||||
|
height: 100px;
|
||||||
|
background: linear-gradient(
|
||||||
|
rgba(255, 255, 255, 0.01),
|
||||||
|
rgba(255, 255, 255, 0.01),
|
||||||
|
rgba(255, 255, 255, 0.01),
|
||||||
|
rgba(255, 255, 255, 0.05),
|
||||||
|
rgba(255, 255, 255, 0.05),
|
||||||
|
rgba(255, 255, 255, 0.05),
|
||||||
|
rgba(235, 255, 255, 0.5),
|
||||||
|
rgba(255, 255, 255, 0.05),
|
||||||
|
rgba(255, 255, 255, 0.05),
|
||||||
|
rgba(255, 255, 255, 0.05),
|
||||||
|
rgba(255, 255, 255, 0.01),
|
||||||
|
rgba(255, 255, 255, 0.01),
|
||||||
|
rgba(255, 255, 255, 0.01)
|
||||||
|
);
|
||||||
|
transform: rotate(-15deg);
|
||||||
|
animation: toRight 5s linear infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.layout-link-msg {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--next-bg-topBarColor);
|
||||||
|
opacity: 0.7;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,41 +1,52 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h100">
|
<div class="layout-parent">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<transition :name="setTransitionName" mode="out-in">
|
<transition :name="setTransitionName" mode="out-in">
|
||||||
<keep-alive :include="getKeepAliveNames">
|
<keep-alive :include="getKeepAliveNames">
|
||||||
<component :is="Component" :key="refreshRouterViewKey" class="w100" />
|
<component :is="Component" :key="refreshRouterViewKey" class="w100" v-show="!isIframePage" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
<transition :name="setTransitionName" mode="out-in">
|
||||||
|
<Iframes class="w100" v-show="isIframePage" :refreshKey="iframeRefreshKey" :name="setTransitionName" :list="iframeList" />
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, toRefs, reactive, getCurrentInstance, onBeforeMount, onUnmounted, nextTick, watch, onMounted } from 'vue';
|
import { defineAsyncComponent, computed, defineComponent, toRefs, reactive, onBeforeMount, onUnmounted, nextTick, watch, onMounted } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useKeepALiveNames } from '/@/stores/keepAliveNames';
|
import { useKeepALiveNames } from '/@/stores/keepAliveNames';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import { Session } from '/@/utils/storage';
|
import { Session } from '/@/utils/storage';
|
||||||
|
import mittBus from '/@/utils/mitt';
|
||||||
|
|
||||||
// 定义接口来定义对象的类型
|
// 定义接口来定义对象的类型
|
||||||
interface ParentViewState {
|
interface ParentViewState {
|
||||||
refreshRouterViewKey: null | string;
|
refreshRouterViewKey: string;
|
||||||
|
iframeRefreshKey: string;
|
||||||
keepAliveNameList: string[];
|
keepAliveNameList: string[];
|
||||||
|
iframeList: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'layoutParentView',
|
name: 'layoutParentView',
|
||||||
|
components: {
|
||||||
|
Iframes: defineAsyncComponent(() => import('/@/layout/routerView/iframes.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const storesKeepAliveNames = useKeepALiveNames();
|
const storesKeepAliveNames = useKeepALiveNames();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { keepAliveNames, cachedViews } = storeToRefs(storesKeepAliveNames);
|
const { keepAliveNames, cachedViews } = storeToRefs(storesKeepAliveNames);
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const state = reactive<ParentViewState>({
|
const state = reactive<ParentViewState>({
|
||||||
refreshRouterViewKey: null,
|
refreshRouterViewKey: '', // 非 iframe tagsview 右键菜单刷新时
|
||||||
|
iframeRefreshKey: '', // iframe tagsview 右键菜单刷新时
|
||||||
keepAliveNameList: [],
|
keepAliveNameList: [],
|
||||||
|
iframeList: [],
|
||||||
});
|
});
|
||||||
// 设置主界面切换动画
|
// 设置主界面切换动画
|
||||||
const setTransitionName = computed(() => {
|
const setTransitionName = computed(() => {
|
||||||
@ -45,20 +56,37 @@ export default defineComponent({
|
|||||||
const getKeepAliveNames = computed(() => {
|
const getKeepAliveNames = computed(() => {
|
||||||
return themeConfig.value.isTagsview ? cachedViews.value : state.keepAliveNameList;
|
return themeConfig.value.isTagsview ? cachedViews.value : state.keepAliveNameList;
|
||||||
});
|
});
|
||||||
|
// 设置 iframe 显示/隐藏
|
||||||
|
const isIframePage = computed(() => {
|
||||||
|
return route.meta.isIframe;
|
||||||
|
});
|
||||||
|
// 获取 iframe 组件列表(未进行渲染)
|
||||||
|
const getIframeListRoutes = async () => {
|
||||||
|
router.getRoutes().forEach((v: any) => {
|
||||||
|
if (v.meta.isIframe) {
|
||||||
|
v.meta.isIframeOpen = false;
|
||||||
|
v.meta.loading = true;
|
||||||
|
state.iframeList.push({ ...v });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
// 页面加载前,处理缓存,页面刷新时路由缓存处理
|
// 页面加载前,处理缓存,页面刷新时路由缓存处理
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
state.keepAliveNameList = keepAliveNames.value;
|
state.keepAliveNameList = keepAliveNames.value;
|
||||||
proxy.mittBus.on('onTagsViewRefreshRouterView', (fullPath: string) => {
|
mittBus.on('onTagsViewRefreshRouterView', (fullPath: string) => {
|
||||||
state.keepAliveNameList = keepAliveNames.value.filter((name: string) => route.name !== name);
|
state.keepAliveNameList = keepAliveNames.value.filter((name: string) => route.name !== name);
|
||||||
state.refreshRouterViewKey = null;
|
state.refreshRouterViewKey = '';
|
||||||
|
state.iframeRefreshKey = '';
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
state.refreshRouterViewKey = fullPath;
|
state.refreshRouterViewKey = fullPath;
|
||||||
|
state.iframeRefreshKey = fullPath;
|
||||||
state.keepAliveNameList = keepAliveNames.value;
|
state.keepAliveNameList = keepAliveNames.value;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
getIframeListRoutes();
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I58U75
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I58U75
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I59RXK
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I59RXK
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@ -69,18 +97,24 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
// 页面卸载时
|
// 页面卸载时
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
proxy.mittBus.off('onTagsViewRefreshRouterView', () => {});
|
mittBus.off('onTagsViewRefreshRouterView', () => {});
|
||||||
});
|
});
|
||||||
// 监听路由变化,防止 tagsView 多标签时,切换动画消失
|
// 监听路由变化,防止 tagsView 多标签时,切换动画消失
|
||||||
|
// https://toscode.gitee.com/lyt-top/vue-next-admin/pulls/38/files
|
||||||
watch(
|
watch(
|
||||||
() => route.fullPath,
|
() => route.fullPath,
|
||||||
() => {
|
() => {
|
||||||
state.refreshRouterViewKey = decodeURI(route.fullPath);
|
state.refreshRouterViewKey = decodeURI(route.fullPath);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
route,
|
||||||
setTransitionName,
|
setTransitionName,
|
||||||
getKeepAliveNames,
|
getKeepAliveNames,
|
||||||
|
isIframePage,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,6 @@ import other from '/@/utils/other';
|
|||||||
import ElementPlus from 'element-plus';
|
import ElementPlus from 'element-plus';
|
||||||
import 'element-plus/dist/index.css';
|
import 'element-plus/dist/index.css';
|
||||||
import '/@/theme/index.scss';
|
import '/@/theme/index.scss';
|
||||||
import mitt from 'mitt';
|
|
||||||
import VueGridLayout from 'vue-grid-layout';
|
import VueGridLayout from 'vue-grid-layout';
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
@ -18,5 +17,3 @@ directive(app);
|
|||||||
other.elSvg(app);
|
other.elSvg(app);
|
||||||
|
|
||||||
app.use(pinia).use(router).use(ElementPlus, { i18n: i18n.global.t }).use(i18n).use(VueGridLayout).mount('#app');
|
app.use(pinia).use(router).use(ElementPlus, { i18n: i18n.global.t }).use(i18n).use(VueGridLayout).mount('#app');
|
||||||
|
|
||||||
app.config.globalProperties.mittBus = mitt();
|
|
||||||
|
@ -80,6 +80,8 @@ export function setCacheTagsViewRoutes() {
|
|||||||
*/
|
*/
|
||||||
export function setFilterRouteEnd() {
|
export function setFilterRouteEnd() {
|
||||||
let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
|
let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
|
||||||
|
// notFoundAndNoPower 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
|
||||||
|
// 关联问题 No match found for location with path 'xxx'
|
||||||
filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower];
|
filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower];
|
||||||
return filterRouteEnd;
|
return filterRouteEnd;
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,8 @@ export async function frontEndsResetRoute() {
|
|||||||
*/
|
*/
|
||||||
export function setFilterRouteEnd() {
|
export function setFilterRouteEnd() {
|
||||||
let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
|
let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
|
||||||
|
// notFoundAndNoPower 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
|
||||||
|
// 关联问题 No match found for location with path 'xxx'
|
||||||
filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower];
|
filterRouteEnd[0].children = [...setFilterRoute(filterRouteEnd[0].children), ...notFoundAndNoPower];
|
||||||
return filterRouteEnd;
|
return filterRouteEnd;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { useKeepALiveNames } from '/@/stores/keepAliveNames';
|
|||||||
import { useRoutesList } from '/@/stores/routesList';
|
import { useRoutesList } from '/@/stores/routesList';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import { Session } from '/@/utils/storage';
|
import { Session } from '/@/utils/storage';
|
||||||
import { staticRoutes } from '/@/router/route';
|
import { staticRoutes, notFoundAndNoPower } from '/@/router/route';
|
||||||
import { initFrontEndControlRoutes } from '/@/router/frontEnd';
|
import { initFrontEndControlRoutes } from '/@/router/frontEnd';
|
||||||
import { initBackEndControlRoutes } from '/@/router/backEnd';
|
import { initBackEndControlRoutes } from '/@/router/backEnd';
|
||||||
|
|
||||||
@ -32,7 +32,13 @@ const { isRequestRoutes } = themeConfig.value;
|
|||||||
*/
|
*/
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
routes: staticRoutes,
|
/**
|
||||||
|
* 说明:
|
||||||
|
* 1、notFoundAndNoPower 默认添加 404、401 界面,防止一直提示 No match found for location with path 'xxx'
|
||||||
|
* 2、backEnd.ts(后端控制路由)、frontEnd.ts(前端控制路由) 中也需要加 notFoundAndNoPower 404、401 界面。
|
||||||
|
* 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
|
||||||
|
*/
|
||||||
|
routes: [...notFoundAndNoPower, ...staticRoutes],
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,13 +113,12 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
if (isRequestRoutes) {
|
if (isRequestRoutes) {
|
||||||
// 后端控制路由:路由数据初始化,防止刷新时丢失
|
// 后端控制路由:路由数据初始化,防止刷新时丢失
|
||||||
await initBackEndControlRoutes();
|
await initBackEndControlRoutes();
|
||||||
// 动态添加路由:防止非首页刷新时跳转回首页的问题
|
// 解决刷新时,一直跳 404 页面问题,关联问题 No match found for location with path 'xxx'
|
||||||
// 确保 addRoute() 时动态添加的路由已经被完全加载上去
|
next({ path: to.path });
|
||||||
next({ ...to, replace: true });
|
|
||||||
} else {
|
} else {
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
|
||||||
await initFrontEndControlRoutes();
|
await initFrontEndControlRoutes();
|
||||||
next({ ...to, replace: true });
|
next({ path: to.path });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
|
@ -4,7 +4,7 @@ import { RouteRecordRaw } from 'vue-router';
|
|||||||
* 路由meta对象参数说明
|
* 路由meta对象参数说明
|
||||||
* meta: {
|
* meta: {
|
||||||
* title: 菜单栏及 tagsView 栏、菜单搜索名称(国际化)
|
* title: 菜单栏及 tagsView 栏、菜单搜索名称(国际化)
|
||||||
* isLink: 是否超链接菜单,开启外链条件,`1、isLink: 链接地址不为空`
|
* isLink: 是否超链接菜单,开启外链条件,`1、isLink: 链接地址不为空 2、isIframe:false`
|
||||||
* isHide: 是否隐藏此路由
|
* isHide: 是否隐藏此路由
|
||||||
* isKeepAlive: 是否缓存组件状态
|
* isKeepAlive: 是否缓存组件状态
|
||||||
* isAffix: 是否固定在 tagsView 栏上
|
* isAffix: 是否固定在 tagsView 栏上
|
||||||
@ -1020,6 +1020,11 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
|||||||
roles: ['admin'],
|
roles: ['admin'],
|
||||||
icon: 'ele-ChatLineRound',
|
icon: 'ele-ChatLineRound',
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 打开内置全屏
|
||||||
|
* component 都为 `() => import('/@/layout/routerView/link.vue')`
|
||||||
|
* isLink 链接为内置的路由地址,地址为 staticRoutes 中定义
|
||||||
|
*/
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/visualizing/visualizingLinkDemo1',
|
path: '/visualizing/visualizingLinkDemo1',
|
||||||
@ -1027,7 +1032,7 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import('/@/layout/routerView/link.vue'),
|
component: () => import('/@/layout/routerView/link.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'message.router.visualizingLinkDemo1',
|
title: 'message.router.visualizingLinkDemo1',
|
||||||
isLink: `${import.meta.env.VITE_API_URL}#/visualizingDemo1`,
|
isLink: '/visualizingDemo1',
|
||||||
isHide: false,
|
isHide: false,
|
||||||
isKeepAlive: false,
|
isKeepAlive: false,
|
||||||
isAffix: false,
|
isAffix: false,
|
||||||
@ -1042,7 +1047,7 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import('/@/layout/routerView/link.vue'),
|
component: () => import('/@/layout/routerView/link.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'message.router.visualizingLinkDemo2',
|
title: 'message.router.visualizingLinkDemo2',
|
||||||
isLink: `${import.meta.env.VITE_API_URL}#/visualizingDemo2`,
|
isLink: '/visualizingDemo2',
|
||||||
isHide: false,
|
isHide: false,
|
||||||
isKeepAlive: false,
|
isKeepAlive: false,
|
||||||
isAffix: false,
|
isAffix: false,
|
||||||
@ -1114,14 +1119,29 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/iframes',
|
path: '/iframesOne',
|
||||||
name: 'layoutIfameView',
|
name: 'layoutIframeViewOne',
|
||||||
component: () => import('/@/layout/routerView/iframes.vue'),
|
component: () => import('/@/layout/routerView/iframes.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'message.router.layoutIfameView',
|
title: 'message.router.layoutIframeViewOne',
|
||||||
isLink: 'https://nodejs.org/zh-cn/',
|
isLink: 'https://nodejs.org/zh-cn/',
|
||||||
isHide: false,
|
isHide: false,
|
||||||
isKeepAlive: false,
|
isKeepAlive: true,
|
||||||
|
isAffix: true,
|
||||||
|
isIframe: true,
|
||||||
|
roles: ['admin'],
|
||||||
|
icon: 'iconfont icon-neiqianshujuchucun',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/iframesTwo',
|
||||||
|
name: 'layoutIframeViewTwo',
|
||||||
|
component: () => import('/@/layout/routerView/iframes.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'message.router.layoutIframeViewTwo',
|
||||||
|
isLink: 'https://undraw.co/illustrations',
|
||||||
|
isHide: false,
|
||||||
|
isKeepAlive: true,
|
||||||
isAffix: true,
|
isAffix: true,
|
||||||
isIframe: true,
|
isIframe: true,
|
||||||
roles: ['admin'],
|
roles: ['admin'],
|
||||||
|
@ -52,6 +52,7 @@ export interface ThemeConfigState {
|
|||||||
columnsMenuBar: string;
|
columnsMenuBar: string;
|
||||||
columnsMenuBarColor: string;
|
columnsMenuBarColor: string;
|
||||||
isColumnsMenuBarColorGradual: boolean;
|
isColumnsMenuBarColorGradual: boolean;
|
||||||
|
isColumnsMenuHoverPreload: boolean;
|
||||||
isCollapse: boolean;
|
isCollapse: boolean;
|
||||||
isUniqueOpened: boolean;
|
isUniqueOpened: boolean;
|
||||||
isFixedHeader: boolean;
|
isFixedHeader: boolean;
|
||||||
@ -82,6 +83,7 @@ export interface ThemeConfigState {
|
|||||||
isRequestRoutes: boolean;
|
isRequestRoutes: boolean;
|
||||||
globalTitle: string;
|
globalTitle: string;
|
||||||
globalViceTitle: string;
|
globalViceTitle: string;
|
||||||
|
globalViceTitleMsg: string;
|
||||||
globalI18n: string;
|
globalI18n: string;
|
||||||
globalComponentSize: string;
|
globalComponentSize: string;
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,7 @@ export const useKeepALiveNames = defineStore('keepALiveNames', {
|
|||||||
this.keepAliveNames = data;
|
this.keepAliveNames = data;
|
||||||
},
|
},
|
||||||
async addCachedView(view: any) {
|
async addCachedView(view: any) {
|
||||||
if (this.cachedViews.includes(view.name)) return;
|
if (view.meta.isKeepAlive) this.cachedViews?.push(view.name);
|
||||||
if (view.meta.isKeepAlive) this.cachedViews.push(view.name);
|
|
||||||
},
|
},
|
||||||
async delCachedView(view: any) {
|
async delCachedView(view: any) {
|
||||||
const index = this.cachedViews.indexOf(view.name);
|
const index = this.cachedViews.indexOf(view.name);
|
||||||
|
@ -47,6 +47,8 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||||||
columnsMenuBarColor: '#e6e6e6',
|
columnsMenuBarColor: '#e6e6e6',
|
||||||
// 是否开启分栏菜单背景颜色渐变
|
// 是否开启分栏菜单背景颜色渐变
|
||||||
isColumnsMenuBarColorGradual: false,
|
isColumnsMenuBarColorGradual: false,
|
||||||
|
// 是否开启分栏菜单鼠标悬停预加载(预览菜单)
|
||||||
|
isColumnsMenuHoverPreload: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 界面设置
|
* 界面设置
|
||||||
@ -54,7 +56,7 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||||||
// 是否开启菜单水平折叠效果
|
// 是否开启菜单水平折叠效果
|
||||||
isCollapse: false,
|
isCollapse: false,
|
||||||
// 是否开启菜单手风琴效果
|
// 是否开启菜单手风琴效果
|
||||||
isUniqueOpened: false,
|
isUniqueOpened: true,
|
||||||
// 是否开启固定 Header
|
// 是否开启固定 Header
|
||||||
isFixedHeader: false,
|
isFixedHeader: false,
|
||||||
// 初始化变量,用于更新菜单 el-scrollbar 的高度,请勿删除
|
// 初始化变量,用于更新菜单 el-scrollbar 的高度,请勿删除
|
||||||
@ -88,15 +90,15 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||||||
// 是否开启 TagsView 共用
|
// 是否开启 TagsView 共用
|
||||||
isShareTagsView: false,
|
isShareTagsView: false,
|
||||||
// 是否开启 Footer 底部版权信息
|
// 是否开启 Footer 底部版权信息
|
||||||
isFooter: false,
|
isFooter: true,
|
||||||
// 是否开启灰色模式
|
// 是否开启灰色模式
|
||||||
isGrayscale: false,
|
isGrayscale: false,
|
||||||
// 是否开启色弱模式
|
// 是否开启色弱模式
|
||||||
isInvert: false,
|
isInvert: false,
|
||||||
// 是否开启水印
|
// 是否开启水印
|
||||||
isWartermark: false,
|
isWartermark: true,
|
||||||
// 水印文案
|
// 水印文案
|
||||||
wartermarkText: 'small@小柒',
|
wartermarkText: 'vue-next-admin',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 其它设置
|
* 其它设置
|
||||||
@ -132,6 +134,8 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||||||
globalTitle: 'vue-next-admin',
|
globalTitle: 'vue-next-admin',
|
||||||
// 网站副标题(登录页顶部文字)
|
// 网站副标题(登录页顶部文字)
|
||||||
globalViceTitle: 'vueNextAdmin',
|
globalViceTitle: 'vueNextAdmin',
|
||||||
|
// 网站副标题(登录页顶部文字)
|
||||||
|
globalViceTitleMsg: '专注、免费、开源、维护、解疑',
|
||||||
// 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
|
// 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
|
||||||
globalI18n: 'zh-cn',
|
globalI18n: 'zh-cn',
|
||||||
// 默认全局组件大小,可选值"<large|'default'|small>",默认 'large'
|
// 默认全局组件大小,可选值"<large|'default'|small>",默认 'large'
|
||||||
|
@ -65,7 +65,7 @@ export const useUserInfo = defineStore('userInfo', {
|
|||||||
authBtnList: defaultAuthBtnList,
|
authBtnList: defaultAuthBtnList,
|
||||||
};
|
};
|
||||||
resolve(userInfos);
|
resolve(userInfos);
|
||||||
}, 3000);
|
}, 0);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -46,6 +46,14 @@ body,
|
|||||||
.layout-container {
|
.layout-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
.layout-pd {
|
||||||
|
padding: 15px !important;
|
||||||
|
}
|
||||||
|
.layout-flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
.layout-aside {
|
.layout-aside {
|
||||||
background: var(--next-bg-menuBar);
|
background: var(--next-bg-menuBar);
|
||||||
box-shadow: 2px 0 6px rgb(0 21 41 / 1%);
|
box-shadow: 2px 0 6px rgb(0 21 41 / 1%);
|
||||||
@ -61,24 +69,63 @@ body,
|
|||||||
}
|
}
|
||||||
.layout-header {
|
.layout-header {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
height: auto !important;
|
||||||
}
|
}
|
||||||
.layout-main {
|
.layout-main {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--next-bg-main-color);
|
background-color: var(--next-bg-main-color);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
// 内层 el-scrollbar样式,用于界面高度自适应(main.vue)
|
||||||
|
.layout-main-scroll {
|
||||||
|
@extend .layout-flex;
|
||||||
|
.layout-parent {
|
||||||
|
@extend .layout-flex;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 用于界面高度自适应
|
||||||
|
.layout-padding {
|
||||||
|
@extend .layout-pd;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
@extend .layout-flex;
|
||||||
|
&-auto {
|
||||||
|
height: inherit;
|
||||||
|
@extend .layout-flex;
|
||||||
|
}
|
||||||
|
&-view {
|
||||||
|
background: var(--el-color-white);
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--el-border-color-light, #ebeef5);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 用于界面高度自适应,主视图区 main 的内边距,用于 iframe
|
||||||
|
.layout-padding-unset {
|
||||||
|
padding: 0 !important;
|
||||||
|
&-view {
|
||||||
|
border-radius: 0 !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 用于设置 iframe loading 时的高度(loading 垂直居中显示)
|
||||||
|
.layout-iframe {
|
||||||
|
.el-loading-parent--relative {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.el-scrollbar {
|
.el-scrollbar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
// 此字段多次用到,建议不删除,如需修改,请重写覆盖样式
|
|
||||||
.layout-view-bg-white {
|
|
||||||
background: var(--el-color-white);
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 1px solid var(--el-border-color-light, #ebeef5);
|
|
||||||
}
|
|
||||||
.layout-el-aside-br-color {
|
.layout-el-aside-br-color {
|
||||||
border-right: 1px solid var(--el-border-color-light, #ebeef5);
|
border-right: 1px solid var(--el-border-color-light, #ebeef5);
|
||||||
}
|
}
|
||||||
@ -122,10 +169,6 @@ body,
|
|||||||
z-index: 9999998;
|
z-index: 9999998;
|
||||||
animation: error-img 0.3s;
|
animation: error-img 0.3s;
|
||||||
}
|
}
|
||||||
.layout-scrollbar {
|
|
||||||
@extend .el-scrollbar;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
.layout-mian-height-50 {
|
.layout-mian-height-50 {
|
||||||
height: calc(100vh - 50px);
|
height: calc(100vh - 50px);
|
||||||
}
|
}
|
||||||
|
@ -92,3 +92,56 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 登录页动画
|
||||||
|
------------------------------- */
|
||||||
|
@keyframes loginLeft {
|
||||||
|
0% {
|
||||||
|
left: -100%;
|
||||||
|
}
|
||||||
|
50%,
|
||||||
|
100% {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes loginTop {
|
||||||
|
0% {
|
||||||
|
top: -100%;
|
||||||
|
}
|
||||||
|
50%,
|
||||||
|
100% {
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes loginRight {
|
||||||
|
0% {
|
||||||
|
right: -100%;
|
||||||
|
}
|
||||||
|
50%,
|
||||||
|
100% {
|
||||||
|
right: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes loginBottom {
|
||||||
|
0% {
|
||||||
|
bottom: -100%;
|
||||||
|
}
|
||||||
|
50%,
|
||||||
|
100% {
|
||||||
|
bottom: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左右左 link.vue
|
||||||
|
------------------------------- */
|
||||||
|
@keyframes toRight {
|
||||||
|
0% {
|
||||||
|
left: -5px;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
left: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -233,4 +233,9 @@
|
|||||||
border-color: var(--el-border-color-lighter) !important;
|
border-color: var(--el-border-color-lighter) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loading
|
||||||
|
.el-loading-mask {
|
||||||
|
background-color: var(--next-bg-main) !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,10 @@
|
|||||||
margin-bottom: 18px !important;
|
margin-bottom: 18px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I5K1PM
|
||||||
|
.el-form-item .el-form-item__label .el-icon {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Alert 警告
|
/* Alert 警告
|
||||||
@ -259,17 +263,24 @@
|
|||||||
.el-scrollbar__bar {
|
.el-scrollbar__bar {
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
|
/*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
|
||||||
.el-scrollbar__wrap {
|
.el-scrollbar__wrap {
|
||||||
max-height: 100%; /*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
.el-select-dropdown .el-scrollbar__wrap {
|
.el-select-dropdown .el-scrollbar__wrap {
|
||||||
overflow-x: scroll !important;
|
overflow-x: scroll !important;
|
||||||
}
|
}
|
||||||
|
/*修复Select 选择器高度问题*/
|
||||||
.el-select-dropdown__wrap {
|
.el-select-dropdown__wrap {
|
||||||
max-height: 274px !important; /*修复Select 选择器高度问题*/
|
max-height: 274px !important;
|
||||||
}
|
}
|
||||||
|
/*修复Cascader 级联选择器高度问题*/
|
||||||
.el-cascader-menu__wrap.el-scrollbar__wrap {
|
.el-cascader-menu__wrap.el-scrollbar__wrap {
|
||||||
height: 204px !important; /*修复Cascader 级联选择器高度问题*/
|
height: 204px !important;
|
||||||
|
}
|
||||||
|
/*用于界面高度自适应(main.vue),区分 scrollbar__view,防止其它使用 scrollbar 的地方出现滚动条消失*/
|
||||||
|
.layout-container-view .el-scrollbar__view {
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drawer 抽屉
|
/* Drawer 抽屉
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
}
|
}
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
|
// 响应式表单时,登录页需要重新处理
|
||||||
display: unset !important;
|
display: unset !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,23 @@
|
|||||||
@import './index.scss';
|
@import './index.scss';
|
||||||
|
|
||||||
/* 页面宽度小于992px
|
/* 页面宽度小于1200px
|
||||||
------------------------------- */
|
------------------------------- */
|
||||||
@media screen and (max-width: $lg) {
|
@media screen and (max-width: $lg) and (min-width: $xs) {
|
||||||
.login-container {
|
.login-container {
|
||||||
.login-icon-group {
|
.login-left {
|
||||||
&::before {
|
.login-left-img {
|
||||||
content: '';
|
top: 90% !important;
|
||||||
height: 70% !important;
|
left: 12% !important;
|
||||||
transition: all 0.3s ease;
|
width: 30% !important;
|
||||||
}
|
height: 18% !important;
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
width: 100px !important;
|
|
||||||
height: 200px !important;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
.login-right {
|
||||||
}
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
/* 页面宽度小于992px
|
left: 50%;
|
||||||
------------------------------- */
|
transform: translate(-50%, -50%);
|
||||||
@media screen and (max-width: $md) {
|
}
|
||||||
.login-content {
|
|
||||||
right: unset !important;
|
|
||||||
left: 50% !important;
|
|
||||||
transform: translate(-50%, -50%) translate3d(0, 0, 0) !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,19 +25,34 @@
|
|||||||
------------------------------- */
|
------------------------------- */
|
||||||
@media screen and (max-width: $xs) {
|
@media screen and (max-width: $xs) {
|
||||||
.login-container {
|
.login-container {
|
||||||
.login-icon-group {
|
.login-left {
|
||||||
display: none !important;
|
display: none;
|
||||||
}
|
}
|
||||||
.login-content {
|
.login-right {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
height: 100% !important;
|
.login-right-warp {
|
||||||
padding: 20px 0 !important;
|
width: 100% !important;
|
||||||
border-radius: 0 !important;
|
height: 100% !important;
|
||||||
box-shadow: unset !important;
|
border: none !important;
|
||||||
border: none !important;
|
.login-right-warp-mian {
|
||||||
}
|
.el-form-item {
|
||||||
.el-form-item {
|
display: flex !important;
|
||||||
display: flex !important;
|
}
|
||||||
|
.login-right-warp-main-title {
|
||||||
|
font-size: 20px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.login-right-warp-one {
|
||||||
|
&::after {
|
||||||
|
right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.login-right-warp-two {
|
||||||
|
&::before {
|
||||||
|
bottom: 1px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,9 +61,14 @@
|
|||||||
------------------------------- */
|
------------------------------- */
|
||||||
@media screen and (max-width: $us) {
|
@media screen and (max-width: $us) {
|
||||||
.login-container {
|
.login-container {
|
||||||
.login-content-title {
|
.login-right {
|
||||||
font-size: 18px !important;
|
.login-right-warp {
|
||||||
transition: all 0.3s ease;
|
.login-right-warp-mian {
|
||||||
|
.login-right-warp-main-title {
|
||||||
|
font-size: 18px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* wangeditor富文本编辑器
|
/* wangeditor 富文本编辑器
|
||||||
------------------------------- */
|
------------------------------- */
|
||||||
.editor-container {
|
.editor-container {
|
||||||
z-index: 9999;
|
z-index: 10; // 用于 wangeditor 点击全屏时
|
||||||
.w-e-toolbar {
|
.w-e-toolbar {
|
||||||
border: 1px solid var(--el-border-color-light, #ebeef5) !important;
|
border: 1px solid var(--el-border-color-light, #ebeef5) !important;
|
||||||
border-bottom: 1px solid var(--el-border-color-light, #ebeef5) !important;
|
border-bottom: 1px solid var(--el-border-color-light, #ebeef5) !important;
|
||||||
|
14
src/types/mitt.ts
Normal file
14
src/types/mitt.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// mitt 事件类型定义
|
||||||
|
export type MittType = {
|
||||||
|
openSetingsDrawer?: string; // 打开布局设置弹窗
|
||||||
|
restoreDefault?: string; // 分栏布局,鼠标移入、移出数据显示
|
||||||
|
setSendColumnsChildren?: string; // 分栏布局,鼠标移入、移出菜单数据传入到 navMenu 下的菜单中
|
||||||
|
setSendClassicChildren?: string; // 经典布局,开启切割菜单时,菜单数据传入到 navMenu 下的菜单中
|
||||||
|
getBreadcrumbIndexSetFilterRoutes?: string; // 布局设置弹窗,开启切割菜单时,菜单数据传入到 navMenu 下的菜单中
|
||||||
|
layoutMobileResize?: object; // 浏览器窗口改变时,用于适配移动端界面显示
|
||||||
|
openOrCloseSortable?: string; // 布局设置弹窗,开启 TagsView 拖拽
|
||||||
|
openShareTagsView?: string; // 布局设置弹窗,开启 TagsView 共用
|
||||||
|
onTagsViewRefreshRouterView?: any; // tagsview 刷新界面
|
||||||
|
onCurrentContextmenuClick?: any; // tagsview 右键菜单每项点击时
|
||||||
|
setHoverPreload?: string; // 分栏菜单鼠标悬停预加载
|
||||||
|
};
|
@ -32,11 +32,13 @@ export const NextLoading = {
|
|||||||
window.nextLoading = true;
|
window.nextLoading = true;
|
||||||
},
|
},
|
||||||
// 移除 loading
|
// 移除 loading
|
||||||
done: () => {
|
done: (time: number = 0) => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
window.nextLoading = false;
|
setTimeout(() => {
|
||||||
const el = <HTMLElement>document.querySelector('.loading-next');
|
window.nextLoading = false;
|
||||||
el?.parentNode?.removeChild(el);
|
const el = <HTMLElement>document.querySelector('.loading-next');
|
||||||
|
el?.parentNode?.removeChild(el);
|
||||||
|
}, time);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
9
src/utils/mitt.ts
Normal file
9
src/utils/mitt.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// https://www.npmjs.com/package/mitt
|
||||||
|
import mitt, { Emitter } from 'mitt';
|
||||||
|
import { MittType } from '/@/types/mitt';
|
||||||
|
|
||||||
|
// 类型
|
||||||
|
const emitter: Emitter<MittType> = mitt<MittType>();
|
||||||
|
|
||||||
|
// 导出
|
||||||
|
export default emitter;
|
@ -51,10 +51,10 @@ export function setTagsViewNameI18n(item: any) {
|
|||||||
let tagsViewName: any = '';
|
let tagsViewName: any = '';
|
||||||
const { query, params, meta } = item;
|
const { query, params, meta } = item;
|
||||||
if (query?.tagsViewName || params?.tagsViewName) {
|
if (query?.tagsViewName || params?.tagsViewName) {
|
||||||
if (/\/zh-cn|en|zh-tw\//.test(query?.tagsViewName) || /\/(zh-cn|en|zh-tw)\//.test(params?.tagsViewName)) {
|
if (/\/zh-cn|en|zh-tw\//.test(query?.tagsViewName) || /\/zh-cn|en|zh-tw\//.test(params?.tagsViewName)) {
|
||||||
// 国际化
|
// 国际化
|
||||||
const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName));
|
const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName));
|
||||||
tagsViewName = urlTagsParams[i18n.global.locale];
|
tagsViewName = urlTagsParams[i18n.global.locale.value];
|
||||||
} else {
|
} else {
|
||||||
// 非国际化
|
// 非国际化
|
||||||
tagsViewName = query?.tagsViewName || params?.tagsViewName;
|
tagsViewName = query?.tagsViewName || params?.tagsViewName;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="chart-scrollbar layout-view-bg-white" :style="{ height: `calc(100vh - ${initTagViewHeight}` }">
|
<div class="chart-scrollbar layout-padding">
|
||||||
<div class="chart-warp">
|
<div class="chart-warp layout-padding-auto layout-padding-view">
|
||||||
<div class="chart-warp-top">
|
<div class="chart-warp-top">
|
||||||
<ChartHead />
|
<ChartHead />
|
||||||
</div>
|
</div>
|
||||||
@ -202,12 +202,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, computed, onMounted, getCurrentInstance, watch, nextTick, onActivated, defineComponent } from 'vue';
|
import { toRefs, reactive, onMounted, watch, nextTick, onActivated, defineComponent, ref } from 'vue';
|
||||||
import ChartHead from '/@/views/chart/head.vue';
|
import ChartHead from '/@/views/chart/head.vue';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import 'echarts-wordcloud';
|
import 'echarts-wordcloud';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
||||||
import { skyList, dBtnList, chartData4List } from '/@/views/chart/chart';
|
import { skyList, dBtnList, chartData4List } from '/@/views/chart/chart';
|
||||||
|
|
||||||
@ -215,10 +214,12 @@ export default defineComponent({
|
|||||||
name: 'chartIndex',
|
name: 'chartIndex',
|
||||||
components: { ChartHead },
|
components: { ChartHead },
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const chartsCenterOneRef = ref();
|
||||||
const storesThemeConfig = useThemeConfig();
|
const chartsSevenDaysRef = ref();
|
||||||
|
const chartsWarningRef = ref();
|
||||||
|
const chartsMonitorRef = ref();
|
||||||
|
const chartsInvestmentRef = ref();
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
const storesTagsViewRoutes = useTagsViewRoutes();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
|
||||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
skyList,
|
skyList,
|
||||||
@ -226,19 +227,9 @@ export default defineComponent({
|
|||||||
chartData4List,
|
chartData4List,
|
||||||
myCharts: [],
|
myCharts: [],
|
||||||
});
|
});
|
||||||
// 设置主内容的高度
|
|
||||||
const initTagViewHeight = computed(() => {
|
|
||||||
let { isTagsview } = themeConfig.value;
|
|
||||||
if (isTagsViewCurrenFull.value) {
|
|
||||||
return `30px`;
|
|
||||||
} else {
|
|
||||||
if (isTagsview) return `114px`;
|
|
||||||
else return `80px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 初始化中间图表1
|
// 初始化中间图表1
|
||||||
const initChartsCenterOne = () => {
|
const initChartsCenterOne = () => {
|
||||||
const myChart = echarts.init(proxy.$refs.chartsCenterOneRef);
|
const myChart = echarts.init(chartsCenterOneRef.value);
|
||||||
const option = {
|
const option = {
|
||||||
grid: {
|
grid: {
|
||||||
top: 15,
|
top: 15,
|
||||||
@ -299,7 +290,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 初始化近7天产品追溯扫码统计
|
// 初始化近7天产品追溯扫码统计
|
||||||
const initChartsSevenDays = () => {
|
const initChartsSevenDays = () => {
|
||||||
const myChart = echarts.init(proxy.$refs.chartsSevenDaysRef);
|
const myChart = echarts.init(chartsSevenDaysRef.value);
|
||||||
const option = {
|
const option = {
|
||||||
grid: {
|
grid: {
|
||||||
top: 15,
|
top: 15,
|
||||||
@ -344,7 +335,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 初始化近30天预警总数
|
// 初始化近30天预警总数
|
||||||
const initChartsWarning = () => {
|
const initChartsWarning = () => {
|
||||||
const myChart = echarts.init(proxy.$refs.chartsWarningRef);
|
const myChart = echarts.init(chartsWarningRef.value);
|
||||||
const option = {
|
const option = {
|
||||||
grid: {
|
grid: {
|
||||||
top: 50,
|
top: 50,
|
||||||
@ -379,7 +370,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 初始化当前设备监测
|
// 初始化当前设备监测
|
||||||
const initChartsMonitor = () => {
|
const initChartsMonitor = () => {
|
||||||
const myChart = echarts.init(proxy.$refs.chartsMonitorRef);
|
const myChart = echarts.init(chartsMonitorRef.value);
|
||||||
const option = {
|
const option = {
|
||||||
grid: {
|
grid: {
|
||||||
top: 15,
|
top: 15,
|
||||||
@ -419,7 +410,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 初始化近7天投入品记录
|
// 初始化近7天投入品记录
|
||||||
const initChartsInvestment = () => {
|
const initChartsInvestment = () => {
|
||||||
const myChart = echarts.init(proxy.$refs.chartsInvestmentRef);
|
const myChart = echarts.init(chartsInvestmentRef.value);
|
||||||
const option = {
|
const option = {
|
||||||
grid: {
|
grid: {
|
||||||
top: 15,
|
top: 15,
|
||||||
@ -480,7 +471,11 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
initTagViewHeight,
|
chartsCenterOneRef,
|
||||||
|
chartsSevenDaysRef,
|
||||||
|
chartsWarningRef,
|
||||||
|
chartsMonitorRef,
|
||||||
|
chartsInvestmentRef,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,39 +1,34 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="error layout-view-bg-white" :style="{ height: `calc(100vh - ${initTagViewHeight}` }">
|
<div class="error layout-padding">
|
||||||
<div class="error-flex">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<div class="left">
|
<div class="error-flex">
|
||||||
<div class="left-item">
|
<div class="left">
|
||||||
<div class="left-item-animation left-item-num">401</div>
|
<div class="left-item">
|
||||||
<div class="left-item-animation left-item-title">{{ $t('message.noAccess.accessTitle') }}</div>
|
<div class="left-item-animation left-item-num">401</div>
|
||||||
<div class="left-item-animation left-item-msg">{{ $t('message.noAccess.accessMsg') }}</div>
|
<div class="left-item-animation left-item-title">{{ $t('message.noAccess.accessTitle') }}</div>
|
||||||
<div class="left-item-animation left-item-btn">
|
<div class="left-item-animation left-item-msg">{{ $t('message.noAccess.accessMsg') }}</div>
|
||||||
<el-button type="primary" round @click="onSetAuth">{{ $t('message.noAccess.accessBtn') }}</el-button>
|
<div class="left-item-animation left-item-btn">
|
||||||
|
<el-button type="primary" size="default" round @click="onSetAuth">{{ $t('message.noAccess.accessBtn') }}</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="right">
|
||||||
<div class="right">
|
<img
|
||||||
<img
|
src="https://img-blog.csdnimg.cn/3333f265772a4fa89287993500ecbf96.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
|
||||||
src="https://img-blog.csdnimg.cn/3333f265772a4fa89287993500ecbf96.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
|
||||||
import { Session } from '/@/utils/storage';
|
import { Session } from '/@/utils/storage';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: '401',
|
name: '401',
|
||||||
setup() {
|
setup() {
|
||||||
const storesThemeConfig = useThemeConfig();
|
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
|
||||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
|
||||||
const onSetAuth = () => {
|
const onSetAuth = () => {
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5C3JS
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I5C3JS
|
||||||
// 清除缓存/token等
|
// 清除缓存/token等
|
||||||
@ -41,19 +36,8 @@ export default defineComponent({
|
|||||||
// 使用 reload 时,不需要调用 resetRoute() 重置路由
|
// 使用 reload 时,不需要调用 resetRoute() 重置路由
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
};
|
};
|
||||||
// 设置主内容的高度
|
|
||||||
const initTagViewHeight = computed(() => {
|
|
||||||
let { isTagsview } = themeConfig.value;
|
|
||||||
if (isTagsViewCurrenFull.value) {
|
|
||||||
return `30px`;
|
|
||||||
} else {
|
|
||||||
if (isTagsview) return `114px`;
|
|
||||||
else return `80px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
onSetAuth,
|
onSetAuth,
|
||||||
initTagViewHeight,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -62,8 +46,6 @@ export default defineComponent({
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.error {
|
.error {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: var(--el-color-white);
|
|
||||||
display: flex;
|
|
||||||
.error-flex {
|
.error-flex {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1,56 +1,40 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="error layout-view-bg-white" :style="{ height: `calc(100vh - ${initTagViewHeight}` }">
|
<div class="error layout-padding">
|
||||||
<div class="error-flex">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<div class="left">
|
<div class="error-flex">
|
||||||
<div class="left-item">
|
<div class="left">
|
||||||
<div class="left-item-animation left-item-num">404</div>
|
<div class="left-item">
|
||||||
<div class="left-item-animation left-item-title">{{ $t('message.notFound.foundTitle') }}</div>
|
<div class="left-item-animation left-item-num">404</div>
|
||||||
<div class="left-item-animation left-item-msg">{{ $t('message.notFound.foundMsg') }}</div>
|
<div class="left-item-animation left-item-title">{{ $t('message.notFound.foundTitle') }}</div>
|
||||||
<div class="left-item-animation left-item-btn">
|
<div class="left-item-animation left-item-msg">{{ $t('message.notFound.foundMsg') }}</div>
|
||||||
<el-button type="primary" round @click="onGoHome">{{ $t('message.notFound.foundBtn') }}</el-button>
|
<div class="left-item-animation left-item-btn">
|
||||||
|
<el-button type="primary" size="default" round @click="onGoHome">{{ $t('message.notFound.foundBtn') }}</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="right">
|
||||||
<div class="right">
|
<img
|
||||||
<img
|
src="https://img-blog.csdnimg.cn/9eb1d85a417f4ed1ba7107f149ce3da1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
|
||||||
src="https://img-blog.csdnimg.cn/9eb1d85a417f4ed1ba7107f149ce3da1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbHl0LXRvcA==,size_16,color_FFFFFF,t_70,g_se,x_16"
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, computed } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: '404',
|
name: '404',
|
||||||
setup() {
|
setup() {
|
||||||
const storesThemeConfig = useThemeConfig();
|
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
|
||||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const onGoHome = () => {
|
const onGoHome = () => {
|
||||||
router.push('/');
|
router.push('/');
|
||||||
};
|
};
|
||||||
// 设置主内容的高度
|
|
||||||
const initTagViewHeight = computed(() => {
|
|
||||||
let { isTagsview } = themeConfig.value;
|
|
||||||
if (isTagsViewCurrenFull.value) {
|
|
||||||
return `30px`;
|
|
||||||
} else {
|
|
||||||
if (isTagsview) return `114px`;
|
|
||||||
else return `80px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
onGoHome,
|
onGoHome,
|
||||||
initTagViewHeight,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -59,8 +43,6 @@ export default defineComponent({
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.error {
|
.error {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: var(--el-color-white);
|
|
||||||
display: flex;
|
|
||||||
.error-flex {
|
.error-flex {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card shadow="hover" header="复制剪切演示">
|
<div class="layout-pd">
|
||||||
<el-alert
|
<el-card shadow="hover" header="复制剪切演示">
|
||||||
title="感谢优秀的 `vue-clipboard3`,项目地址:https://github.com/JamieCurnow/vue-clipboard3`"
|
<el-alert
|
||||||
type="success"
|
title="感谢优秀的 `vue-clipboard3`,项目地址:https://github.com/JamieCurnow/vue-clipboard3`"
|
||||||
:closable="false"
|
type="success"
|
||||||
class="mb15"
|
:closable="false"
|
||||||
></el-alert>
|
class="mb15"
|
||||||
<el-input placeholder="请输入内容" v-model="copyVal">
|
></el-alert>
|
||||||
<template #append>
|
<el-input placeholder="请输入内容" v-model="copyVal">
|
||||||
<el-button @click="copyText(copyVal)">复制链接</el-button>
|
<template #append>
|
||||||
</template>
|
<el-button @click="copyText(copyVal)">复制链接</el-button>
|
||||||
</el-input>
|
</template>
|
||||||
<el-input placeholder="先点击上方 `复制链接` 按钮,然后 `Ctrl + V` 进行粘贴! " v-model="shearVal" class="mt15"> </el-input>
|
</el-input>
|
||||||
</el-card>
|
<el-input placeholder="先点击上方 `复制链接` 按钮,然后 `Ctrl + V` 进行粘贴! " v-model="shearVal" class="mt15"> </el-input>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<el-card shadow="hover" header="数字滚动演示">
|
<el-card shadow="hover" header="数字滚动演示">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="感谢优秀的 `countup.js`,项目地址:https://github.com/inorganik/countUp.js"
|
title="感谢优秀的 `countup.js`,项目地址:https://github.com/inorganik/countUp.js"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="croppers-container">
|
<div class="croppers-container layout-pd">
|
||||||
<el-card shadow="hover" header="cropper 图片裁剪">
|
<el-card shadow="hover" header="cropper 图片裁剪">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="感谢优秀的 `cropperjs`,项目地址:https://github.com/fengyuanchen/cropperjs"
|
title="感谢优秀的 `cropperjs`,项目地址:https://github.com/fengyuanchen/cropperjs"
|
||||||
@ -24,16 +24,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ref, toRefs, reactive, defineComponent } from 'vue';
|
import { defineAsyncComponent, ref, toRefs, reactive, defineComponent } from 'vue';
|
||||||
import CropperDialog from '/@/components/cropper/index.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'funCropper',
|
name: 'funCropper',
|
||||||
components: { CropperDialog },
|
components: {
|
||||||
|
CropperDialog: defineAsyncComponent(() => import('/@/components/cropper/index.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const cropperDialogRef = ref();
|
const cropperDialogRef = ref();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
cropperImg: 'https://img1.baidu.com/it/u=2813520958,2218166536&fm=26&fmt=auto&gp=0.jpg',
|
cropperImg: 'https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500',
|
||||||
});
|
});
|
||||||
// 打开裁剪弹窗
|
// 打开裁剪弹窗
|
||||||
const onCropperDialogOpen = () => {
|
const onCropperDialogOpen = () => {
|
||||||
|
@ -1,42 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{ height: `calc(100vh - ${initTagViewHeight}` }">
|
<div class="layout-padding">
|
||||||
<div class="layout-view-bg-white">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<div ref="echartsMap" style="height: 100%"></div>
|
<div ref="echartsMap" style="height: 100%"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, computed, onMounted, defineComponent } from 'vue';
|
import { toRefs, reactive, onMounted, defineComponent } from 'vue';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import 'echarts/extension/bmap/bmap';
|
import 'echarts/extension/bmap/bmap';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
|
||||||
import { echartsMapList, echartsMapData } from './mock';
|
import { echartsMapList, echartsMapData } from './mock';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'funEchartsMap',
|
name: 'funEchartsMap',
|
||||||
setup() {
|
setup() {
|
||||||
const storesThemeConfig = useThemeConfig();
|
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
|
||||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
|
||||||
const state: any = reactive({
|
const state: any = reactive({
|
||||||
echartsMap: null,
|
echartsMap: null,
|
||||||
echartsMapList,
|
echartsMapList,
|
||||||
echartsMapData,
|
echartsMapData,
|
||||||
});
|
});
|
||||||
// 设置主内容的高度
|
|
||||||
const initTagViewHeight = computed(() => {
|
|
||||||
let { isTagsview } = themeConfig.value;
|
|
||||||
if (isTagsViewCurrenFull.value) {
|
|
||||||
return `30px`;
|
|
||||||
} else {
|
|
||||||
if (isTagsview) return `114px`;
|
|
||||||
else return `80px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// echartsMap 将坐标信息和对应物理量的值合在一起
|
// echartsMap 将坐标信息和对应物理量的值合在一起
|
||||||
const convertData = (data: any) => {
|
const convertData = (data: any) => {
|
||||||
let res = [];
|
let res = [];
|
||||||
@ -133,7 +116,6 @@ export default defineComponent({
|
|||||||
initEchartsMap();
|
initEchartsMap();
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
initTagViewHeight,
|
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="grid-layout-container">
|
<div class="grid-layout-container layout-pd">
|
||||||
<el-card shadow="hover" header="vue-grid-layout 拖拽布局演示">
|
<el-card shadow="hover" header="vue-grid-layout 拖拽布局演示">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="感谢优秀的 `vue-grid-layout`,项目地址:https://github.com/jbaysolutions/vue-grid-layout"
|
title="感谢优秀的 `vue-grid-layout`,项目地址:https://github.com/jbaysolutions/vue-grid-layout"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="printRef">
|
<div ref="printRef" class="layout-pd">
|
||||||
<el-card shadow="hover" header="打印演示">
|
<el-card shadow="hover" header="打印演示">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="感谢优秀的 `print-js`,项目地址:https://github.com/crabbly/Print.js。请在打印弹窗 `更多设置` 中开启 `背景图形。`"
|
title="感谢优秀的 `print-js`,项目地址:https://github.com/crabbly/Print.js。请在打印弹窗 `更多设置` 中开启 `背景图形。`"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="qrcode-container">
|
<div class="qrcode-container layout-pd">
|
||||||
<el-card shadow="hover" header="qrcodejs2 二维码生成">
|
<el-card shadow="hover" header="qrcodejs2 二维码生成">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="感谢优秀的 `qrcodejs2`,项目地址:https://github.com/davidshimjs/qrcodejs"
|
title="感谢优秀的 `qrcodejs2`,项目地址:https://github.com/davidshimjs/qrcodejs"
|
||||||
@ -23,19 +23,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, onMounted, getCurrentInstance, defineComponent } from 'vue';
|
import { toRefs, reactive, onMounted, defineComponent, ref } from 'vue';
|
||||||
import QRCode from 'qrcodejs2-fixes';
|
import QRCode from 'qrcodejs2-fixes';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'funQrcode',
|
name: 'funQrcode',
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = getCurrentInstance() as any;
|
const qrcodeRef = ref();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
qrcode: '',
|
qrcode: '',
|
||||||
});
|
});
|
||||||
// 初始化生成二维码
|
// 初始化生成二维码
|
||||||
const initQrcode = () => {
|
const initQrcode = () => {
|
||||||
new QRCode(proxy.$refs.qrcodeRef, {
|
new QRCode(qrcodeRef.value, {
|
||||||
text: `https://lyt-top.gitee.io/vue-next-admin-preview/#/login?t=${new Date().getTime()}`,
|
text: `https://lyt-top.gitee.io/vue-next-admin-preview/#/login?t=${new Date().getTime()}`,
|
||||||
width: 125,
|
width: 125,
|
||||||
height: 125,
|
height: 125,
|
||||||
@ -45,7 +45,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 重新生成
|
// 重新生成
|
||||||
const onInitQrcode = () => {
|
const onInitQrcode = () => {
|
||||||
proxy.$refs.qrcodeRef.innerHTML = '';
|
qrcodeRef.value.innerHTML = '';
|
||||||
initQrcode();
|
initQrcode();
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
@ -53,6 +53,7 @@ export default defineComponent({
|
|||||||
initQrcode();
|
initQrcode();
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
qrcodeRef,
|
||||||
onInitQrcode,
|
onInitQrcode,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="splitpanes-container">
|
<div class="splitpanes-container layout-pd">
|
||||||
<el-card shadow="hover" header="splitpanes 窗格拆分器">
|
<el-card shadow="hover" header="splitpanes 窗格拆分器">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="感谢优秀的 `splitpanes`,项目地址:https://github.com/antoniandre/splitpanes"
|
title="感谢优秀的 `splitpanes`,项目地址:https://github.com/antoniandre/splitpanes"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fun-tagsview">
|
<div class="fun-tagsview layout-pd">
|
||||||
<NoticeBar
|
<NoticeBar
|
||||||
text="已删除非当前页 tagsView 演示,后续有时间可以再加回来!,tagsview 支持多标签(参数不同)、单标签共用(参数不同)"
|
text="已删除非当前页 tagsView 演示,后续有时间可以再加回来!,tagsview 支持多标签(参数不同)、单标签共用(参数不同)"
|
||||||
background="#ecf5ff"
|
background="#ecf5ff"
|
||||||
@ -63,37 +63,38 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getCurrentInstance, reactive, toRefs, defineComponent } from 'vue';
|
import { defineAsyncComponent, reactive, toRefs, defineComponent } from 'vue';
|
||||||
import NoticeBar from '/@/components/noticeBar/index.vue';
|
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import mittBus from '/@/utils/mitt';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'funTagsView',
|
name: 'funTagsView',
|
||||||
components: { NoticeBar },
|
components: {
|
||||||
|
NoticeBar: defineAsyncComponent(() => import('/@/components/noticeBar/index.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = getCurrentInstance() as any;
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const state = reactive({});
|
const state = reactive({});
|
||||||
// 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
|
// 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部 4 当前页全屏
|
||||||
// 1、刷新当前 tagsView
|
// 1、刷新当前 tagsView
|
||||||
const refreshCurrentTagsView = () => {
|
const refreshCurrentTagsView = () => {
|
||||||
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 0, ...route }));
|
mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 0, ...route }));
|
||||||
};
|
};
|
||||||
// 2、关闭当前 tagsView
|
// 2、关闭当前 tagsView
|
||||||
const closeCurrentTagsView = () => {
|
const closeCurrentTagsView = () => {
|
||||||
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
|
mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
|
||||||
};
|
};
|
||||||
// 3、关闭其它 tagsView
|
// 3、关闭其它 tagsView
|
||||||
const closeOtherTagsView = () => {
|
const closeOtherTagsView = () => {
|
||||||
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 2, ...route }));
|
mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 2, ...route }));
|
||||||
};
|
};
|
||||||
// 4、关闭全部 tagsView
|
// 4、关闭全部 tagsView
|
||||||
const closeAllTagsView = () => {
|
const closeAllTagsView = () => {
|
||||||
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 3, ...route }));
|
mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 3, ...route }));
|
||||||
};
|
};
|
||||||
// 5、开启当前页面全屏
|
// 5、开启当前页面全屏
|
||||||
const openCurrenFullscreen = () => {
|
const openCurrenFullscreen = () => {
|
||||||
proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 4, ...route }));
|
mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 4, ...route }));
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
refreshCurrentTagsView,
|
refreshCurrentTagsView,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="editor-container">
|
<div class="editor-container layout-pd">
|
||||||
<el-card shadow="hover" header="wangeditor富文本编辑器">
|
<el-card shadow="hover" header="wangeditor富文本编辑器">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="感谢优秀的 `wangeditor`,项目地址:https://github.com/wangeditor-team/wangEditor"
|
title="感谢优秀的 `wangeditor`,项目地址:https://github.com/wangeditor-team/wangEditor"
|
||||||
@ -7,24 +7,26 @@
|
|||||||
:closable="false"
|
:closable="false"
|
||||||
class="mb15"
|
class="mb15"
|
||||||
></el-alert>
|
></el-alert>
|
||||||
<Editor :is-disable="false" v-model="editorVal" />
|
<Editor v-model="editor.value" :disable="editor.disable" />
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, onMounted, defineComponent } from 'vue';
|
import { defineAsyncComponent, toRefs, reactive, defineComponent } from 'vue';
|
||||||
import Editor from '/@/components/editor/index.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'funWangEditor',
|
name: 'funWangEditor',
|
||||||
components: { Editor },
|
components: {
|
||||||
|
Editor: defineAsyncComponent(() => import('/@/components/editor/index.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
editorVal: '',
|
editor: {
|
||||||
|
value: '<p><span style="color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); font-size: 14px;">胡歌,1982年9月20日出生于上海市徐汇区,中国内地影视男演员、流行乐歌手,</span><a href="https://baike.baidu.com/item/%E6%B0%91%E7%9B%9F/1971441?fromModule=lemma_inlink" target="_blank" style="text-indent: 28px; text-align: start;">民盟</a><span style="color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); font-size: 14px;">盟员</span><span style="color: rgb(51, 102, 204); background-color: rgb(255, 255, 255); font-size: 12px;"><sup> [1]</sup></span><a href="" target="" style="text-indent: 28px; text-align: start;"> </a><span style="color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); font-size: 14px;"> ,毕业于</span><a href="https://baike.baidu.com/item/%E4%B8%8A%E6%B5%B7%E6%88%8F%E5%89%A7%E5%AD%A6%E9%99%A2/1736818?fromModule=lemma_inlink" target="_blank" style="text-indent: 28px; text-align: start;">上海戏剧学院</a><span style="color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); font-size: 14px;">表演系。</span></p>',
|
||||||
|
disable: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
// 页面加载时
|
|
||||||
onMounted(() => {});
|
|
||||||
return {
|
return {
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home-container">
|
<div class="home-container layout-pd">
|
||||||
<el-row :gutter="15" class="home-card-one mb15">
|
<el-row :gutter="15" class="home-card-one mb15">
|
||||||
<el-col
|
<el-col
|
||||||
:xs="24"
|
:xs="24"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="温馨提示:1、此页面无法模拟后端控制路由,因为 `gitee` 上所请求的 `json` 菜单数据线上会出现跨域的情况(json地址:
|
title="温馨提示:1、此页面无法模拟后端控制路由,因为 `gitee` 上所请求的 `json` 菜单数据线上会出现跨域的情况(json地址:
|
||||||
https://gitee.com/lyt-top/vue-next-admin-images/raw/master/menu/adminMenu.json)。2、本地接口请求文件位置:`/src/api/menu/index.ts`。
|
https://gitee.com/lyt-top/vue-next-admin-images/raw/master/menu/adminMenu.json)。2、本地接口请求文件位置:`/src/api/menu/index.ts`。
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<LimitsFrontEndPage />
|
<LimitsFrontEndPage style="padding: 0 !important" />
|
||||||
<!-- 演示1:组件方式 -->
|
<!-- 演示1:组件方式 -->
|
||||||
<el-card shadow="hover" header="演示1:组件方式" class="mt15">
|
<el-card shadow="hover" header="演示1:组件方式" class="mt15">
|
||||||
<el-row class="mb10" style="color: #808080">单个权限验证(:value="xxx"):</el-row>
|
<el-row class="mb10" style="color: #808080">单个权限验证(:value="xxx"):</el-row>
|
||||||
@ -335,17 +335,18 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import LimitsFrontEndPage from '/@/views/limits/frontEnd/page/index.vue';
|
|
||||||
import Auth from '/@/components/auth/auth.vue';
|
|
||||||
import Auths from '/@/components/auth/auths.vue';
|
|
||||||
import AuthAll from '/@/components/auth/authAll.vue';
|
|
||||||
import { auth, auths, authAll } from '/@/utils/authFunction';
|
import { auth, auths, authAll } from '/@/utils/authFunction';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'limitsFrontEndBtn',
|
name: 'limitsFrontEndBtn',
|
||||||
components: { LimitsFrontEndPage, Auth, Auths, AuthAll },
|
components: {
|
||||||
|
LimitsFrontEndPage: defineAsyncComponent(() => import('/@/views/limits/frontEnd/page/index.vue')),
|
||||||
|
Auth: defineAsyncComponent(() => import('/@/components/auth/auth.vue')),
|
||||||
|
Auths: defineAsyncComponent(() => import('/@/components/auth/auths.vue')),
|
||||||
|
AuthAll: defineAsyncComponent(() => import('/@/components/auth/authAll.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
// 单个权限验证
|
// 单个权限验证
|
||||||
const onAuthClick = () => {
|
const onAuthClick = () => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<el-alert
|
<el-alert
|
||||||
title="温馨提示:此权限页面代码及效果只作为演示使用,若出现不可逆转的bug,请尝试 `F5` 刷新页面。若实际项目中非要实现此用户权限切换功能,
|
title="温馨提示:此权限页面代码及效果只作为演示使用,若出现不可逆转的bug,请尝试 `F5` 刷新页面。若实际项目中非要实现此用户权限切换功能,
|
||||||
请在切换方法 `onRadioChange` 最后面添加刷新代码 `window.location.reload()`。 请注意:按钮权限页面中的演示2(指令模式)、演示3(函数模式)
|
请在切换方法 `onRadioChange` 最后面添加刷新代码 `window.location.reload()`。 请注意:按钮权限页面中的演示2(指令模式)、演示3(函数模式)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form size="large" class="login-content-form">
|
<el-form size="large" class="login-content-form">
|
||||||
<el-form-item class="login-animation1">
|
<el-form-item class="login-animation1">
|
||||||
<el-input type="text" :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.userName" clearable autocomplete="off">
|
<el-input text :placeholder="$t('message.account.accountPlaceholder1')" v-model="ruleForm.userName" clearable autocomplete="off">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<el-icon class="el-input__icon"><ele-User /></el-icon>
|
<el-icon class="el-input__icon"><ele-User /></el-icon>
|
||||||
</template>
|
</template>
|
||||||
@ -29,14 +29,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="login-animation3">
|
<el-form-item class="login-animation3">
|
||||||
<el-col :span="15">
|
<el-col :span="15">
|
||||||
<el-input
|
<el-input text maxlength="4" :placeholder="$t('message.account.accountPlaceholder3')" v-model="ruleForm.code" clearable autocomplete="off">
|
||||||
type="text"
|
|
||||||
maxlength="4"
|
|
||||||
:placeholder="$t('message.account.accountPlaceholder3')"
|
|
||||||
v-model="ruleForm.code"
|
|
||||||
clearable
|
|
||||||
autocomplete="off"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<el-icon class="el-input__icon"><ele-Position /></el-icon>
|
<el-icon class="el-input__icon"><ele-Position /></el-icon>
|
||||||
</template>
|
</template>
|
||||||
@ -44,11 +37,11 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1"></el-col>
|
<el-col :span="1"></el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-button class="login-content-code">1234</el-button>
|
<el-button class="login-content-code" v-waves>1234</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="login-animation4">
|
<el-form-item class="login-animation4">
|
||||||
<el-button type="primary" class="login-content-submit" round @click="onSignIn" :loading="loading.signIn">
|
<el-button type="primary" class="login-content-submit" round v-waves @click="onSignIn" :loading="loading.signIn">
|
||||||
<span>{{ $t('message.account.accountBtnText') }}</span>
|
<span>{{ $t('message.account.accountBtnText') }}</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form size="large" class="login-content-form">
|
<el-form size="large" class="login-content-form">
|
||||||
<el-form-item class="login-animation1">
|
<el-form-item class="login-animation1">
|
||||||
<el-input type="text" :placeholder="$t('message.mobile.placeholder1')" v-model="ruleForm.userName" clearable autocomplete="off">
|
<el-input text :placeholder="$t('message.mobile.placeholder1')" v-model="ruleForm.userName" clearable autocomplete="off">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<i class="iconfont icon-dianhua el-input__icon"></i>
|
<i class="iconfont icon-dianhua el-input__icon"></i>
|
||||||
</template>
|
</template>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="login-animation2">
|
<el-form-item class="login-animation2">
|
||||||
<el-col :span="15">
|
<el-col :span="15">
|
||||||
<el-input type="text" maxlength="4" :placeholder="$t('message.mobile.placeholder2')" v-model="ruleForm.code" clearable autocomplete="off">
|
<el-input text maxlength="4" :placeholder="$t('message.mobile.placeholder2')" v-model="ruleForm.code" clearable autocomplete="off">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<el-icon class="el-input__icon"><ele-Position /></el-icon>
|
<el-icon class="el-input__icon"><ele-Position /></el-icon>
|
||||||
</template>
|
</template>
|
||||||
@ -17,11 +17,11 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1"></el-col>
|
<el-col :span="1"></el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-button class="login-content-code">{{ $t('message.mobile.codeText') }}</el-button>
|
<el-button v-waves class="login-content-code">{{ $t('message.mobile.codeText') }}</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="login-animation3">
|
<el-form-item class="login-animation3">
|
||||||
<el-button round type="primary" class="login-content-submit">
|
<el-button round type="primary" v-waves class="login-content-submit">
|
||||||
<span>{{ $t('message.mobile.btnText') }}</span>
|
<span>{{ $t('message.mobile.btnText') }}</span>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-scan-container">
|
<div class="login-scan-container">
|
||||||
<div ref="qrcodeRef"></div>
|
<div ref="qrcodeRef"></div>
|
||||||
<div class="font12 mt20 login-msg">{{ $t('message.scan.text') }}</div>
|
<div class="font12 mt20 login-msg">
|
||||||
|
<i class="iconfont icon-saoyisao mr5"></i>
|
||||||
|
<span>{{ $t('message.scan.text') }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ref, defineComponent, onMounted } from 'vue';
|
import { defineComponent, ref, onMounted, nextTick } from 'vue';
|
||||||
import QRCode from 'qrcodejs2-fixes';
|
import QRCode from 'qrcodejs2-fixes';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -15,20 +18,24 @@ export default defineComponent({
|
|||||||
const qrcodeRef = ref<HTMLElement | null>(null);
|
const qrcodeRef = ref<HTMLElement | null>(null);
|
||||||
// 初始化生成二维码
|
// 初始化生成二维码
|
||||||
const initQrcode = () => {
|
const initQrcode = () => {
|
||||||
(qrcodeRef.value as HTMLElement).innerHTML = '';
|
nextTick(() => {
|
||||||
new QRCode(qrcodeRef.value, {
|
(<HTMLElement>qrcodeRef.value).innerHTML = '';
|
||||||
text: `https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi`,
|
new QRCode(qrcodeRef.value, {
|
||||||
width: 260,
|
text: `https://qm.qq.com/cgi-bin/qm/qr?k=RdUY97Vx0T0vZ_1OOu-X1yFNkWgDwbjC&jump_from=webapi`,
|
||||||
height: 260,
|
width: 260,
|
||||||
colorDark: '#000000',
|
height: 260,
|
||||||
colorLight: '#ffffff',
|
colorDark: '#000000',
|
||||||
|
colorLight: '#ffffff',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initQrcode();
|
initQrcode();
|
||||||
});
|
});
|
||||||
return { qrcodeRef };
|
return {
|
||||||
|
qrcodeRef,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -41,7 +48,7 @@ export default defineComponent({
|
|||||||
animation-fill-mode: forwards;
|
animation-fill-mode: forwards;
|
||||||
}
|
}
|
||||||
.login-scan-container {
|
.login-scan-container {
|
||||||
padding: 20px;
|
padding: 0 20px 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -51,6 +58,9 @@ export default defineComponent({
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
.login-msg {
|
.login-msg {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
color: var(--el-text-color-placeholder);
|
color: var(--el-text-color-placeholder);
|
||||||
@extend .login-scan-animation;
|
@extend .login-scan-animation;
|
||||||
animation-delay: 0.2s;
|
animation-delay: 0.2s;
|
||||||
|
@ -1,29 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login-container">
|
<div class="login-container flex">
|
||||||
<div class="login-icon-group">
|
<div class="login-left">
|
||||||
<div class="login-icon-group-title">
|
<div class="login-left-logo">
|
||||||
<img :src="logoMini" />
|
<img :src="logoMini" />
|
||||||
<div class="login-icon-group-title-text font25">{{ getThemeConfig.globalViceTitle }}</div>
|
<div class="login-left-logo-text">
|
||||||
</div>
|
<span>{{ getThemeConfig.globalViceTitle }}</span>
|
||||||
<img :src="loginIconTwo" class="login-icon-group-icon" />
|
<span class="login-left-logo-text-msg">{{ getThemeConfig.globalViceTitleMsg }}</span>
|
||||||
</div>
|
|
||||||
<div class="login-content">
|
|
||||||
<div class="login-content-main">
|
|
||||||
<h4 class="login-content-title ml15">{{ getThemeConfig.globalTitle }}后台模板</h4>
|
|
||||||
<div v-if="!isScan">
|
|
||||||
<el-tabs v-model="tabsActiveName">
|
|
||||||
<el-tab-pane :label="$t('message.label.one1')" name="account">
|
|
||||||
<Account />
|
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane :label="$t('message.label.two2')" name="mobile">
|
|
||||||
<Mobile />
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
</div>
|
||||||
<Scan v-if="isScan" />
|
</div>
|
||||||
<div class="login-content-main-sacn" @click="isScan = !isScan">
|
<div class="login-left-img">
|
||||||
<i class="iconfont" :class="isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
|
<img :src="loginMain" />
|
||||||
<div class="login-content-main-sacn-delta"></div>
|
</div>
|
||||||
|
<img :src="loginBg" class="login-left-waves" />
|
||||||
|
</div>
|
||||||
|
<div class="login-right flex">
|
||||||
|
<div class="login-right-warp flex-margin">
|
||||||
|
<span class="login-right-warp-one"></span>
|
||||||
|
<span class="login-right-warp-two"></span>
|
||||||
|
<div class="login-right-warp-mian">
|
||||||
|
<div class="login-right-warp-main-title">{{ getThemeConfig.globalTitle }} 欢迎您!</div>
|
||||||
|
<div class="login-right-warp-main-form">
|
||||||
|
<div v-if="!isScan">
|
||||||
|
<el-tabs v-model="tabsActiveName">
|
||||||
|
<el-tab-pane :label="$t('message.label.one1')" name="account">
|
||||||
|
<Account />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane :label="$t('message.label.two2')" name="mobile">
|
||||||
|
<Mobile />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
<Scan v-if="isScan" />
|
||||||
|
<div class="login-content-main-sacn" @click="isScan = !isScan">
|
||||||
|
<i class="iconfont" :class="isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
|
||||||
|
<div class="login-content-main-sacn-delta"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -31,29 +43,25 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, computed, defineComponent, onMounted } from 'vue';
|
import { defineAsyncComponent, defineComponent, onMounted, reactive, toRefs, computed } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||||
import logoMini from '/@/assets/logo-mini.svg';
|
|
||||||
import loginIconTwo from '/@/assets/login-icon-two.svg';
|
|
||||||
import { NextLoading } from '/@/utils/loading';
|
import { NextLoading } from '/@/utils/loading';
|
||||||
import Account from '/@/views/login/component/account.vue';
|
import logoMini from '/@/assets/logo-mini.svg';
|
||||||
import Mobile from '/@/views/login/component/mobile.vue';
|
import loginMain from '/@/assets/login-main.svg';
|
||||||
import Scan from '/@/views/login/component/scan.vue';
|
import loginBg from '/@/assets/login-bg.svg';
|
||||||
|
|
||||||
// 定义接口来定义对象的类型
|
|
||||||
interface LoginState {
|
|
||||||
tabsActiveName: string;
|
|
||||||
isScan: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'loginIndex',
|
name: 'loginIndex',
|
||||||
components: { Account, Mobile, Scan },
|
components: {
|
||||||
|
Account: defineAsyncComponent(() => import('/@/views/login/component/account.vue')),
|
||||||
|
Mobile: defineAsyncComponent(() => import('/@/views/login/component/mobile.vue')),
|
||||||
|
Scan: defineAsyncComponent(() => import('/@/views/login/component/scan.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const storesThemeConfig = useThemeConfig();
|
const storesThemeConfig = useThemeConfig();
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||||
const state = reactive<LoginState>({
|
const state = reactive({
|
||||||
tabsActiveName: 'account',
|
tabsActiveName: 'account',
|
||||||
isScan: false,
|
isScan: false,
|
||||||
});
|
});
|
||||||
@ -67,7 +75,8 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
logoMini,
|
logoMini,
|
||||||
loginIconTwo,
|
loginBg,
|
||||||
|
loginMain,
|
||||||
getThemeConfig,
|
getThemeConfig,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
@ -77,122 +86,176 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.login-container {
|
.login-container {
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
|
||||||
background: var(--el-color-white);
|
background: var(--el-color-white);
|
||||||
.login-icon-group {
|
.login-left {
|
||||||
width: 100%;
|
flex: 1;
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
.login-icon-group-title {
|
background-color: rgba(211, 239, 255, 1);
|
||||||
|
margin-right: 100px;
|
||||||
|
.login-left-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
left: 80px;
|
left: 80px;
|
||||||
display: flex;
|
z-index: 1;
|
||||||
align-items: center;
|
animation: logoAnimation 0.3s ease;
|
||||||
img {
|
img {
|
||||||
width: 30px;
|
width: 52px;
|
||||||
height: 30px;
|
height: 52px;
|
||||||
}
|
}
|
||||||
&-text {
|
.login-left-logo-text {
|
||||||
padding-left: 15px;
|
display: flex;
|
||||||
color: var(--el-color-primary);
|
flex-direction: column;
|
||||||
|
span {
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 28px;
|
||||||
|
color: #26a59a;
|
||||||
|
}
|
||||||
|
.login-left-logo-text-msg {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #32a99e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&::before {
|
.login-left-img {
|
||||||
content: '';
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
top: 50%;
|
||||||
left: 0;
|
left: 50%;
|
||||||
width: 60%;
|
transform: translate(-50%, -50%);
|
||||||
overflow: hidden;
|
width: 100%;
|
||||||
height: 80%;
|
height: 52%;
|
||||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='1200' height='770' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M58.4 47.77C104.6 59.51 135.26 67.37 162.11 78.04C188.97 88.72 226.33 102.69 265.92 123.55C305.51 144.4 366.96 167.09 441.43 121.52C515.9 75.95 546.48 61.01 577.69 46.27C608.9 31.53 625.86 23.69 680.26 12.28C734.65 0.87 837.29 10.7 867.29 21.8C897.29 32.9 935.51 51.9 962.21 95.45C988.9 139.01 972.91 177.36 951.37 221.39C929.83 265.43 883.49 306 890.44 337.33C897.4 368.66 974.73 412.18 974.73 411.47C974.73 412.18 1066.36 457.62 1106.36 491.06C1146.36 524.5 1178.8 563.36 1184.03 579.63C1189.26 595.9 1200.4 622.49 1181.55 676.88C1162.71 731.26 1127.16 764.32 1115.31 778.64C1103.45 792.96 5.34 783.61 4.32 784.63C3.3 785.65 -172.34 2.38 1.13 35.04L58.4 47.77L58.4 47.77Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
img {
|
||||||
background: var(--el-color-primary-light-5);
|
width: 100%;
|
||||||
transition: all 0.3s ease;
|
height: 100%;
|
||||||
|
animation: error-num 0.6s ease;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&::after {
|
.login-left-waves {
|
||||||
content: '';
|
|
||||||
width: 150px;
|
|
||||||
height: 300px;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
|
||||||
top: 0;
|
top: 0;
|
||||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='150' height='300' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M-0.56 -0.28C41.94 36.17 67.73 18.94 93.33 33.96C118.93 48.98 107.58 73.56 101.94 89.76C96.29 105.96 50.09 217.83 47.87 231.18C45.64 244.52 46.02 255.2 64.4 270.05C82.79 284.91 121.99 292.31 111.98 289.81C101.97 287.32 153.96 301.48 151.83 299.9C149.69 298.32 149.98 -1.36 149.71 -1.18C149.98 -1.36 -43.06 -36.74 -0.56 -0.28L-0.56 -0.28Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
right: -100px;
|
||||||
background: var(--el-color-primary-light-5);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
&-icon {
|
|
||||||
width: 60%;
|
|
||||||
height: 70%;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.login-content {
|
.login-right {
|
||||||
width: 500px;
|
width: 700px;
|
||||||
padding: 20px;
|
.login-right-warp {
|
||||||
position: absolute;
|
border: 1px solid var(--el-color-primary-light-3);
|
||||||
right: 200px;
|
border-radius: 3px;
|
||||||
top: 50%;
|
width: 500px;
|
||||||
transform: translateY(-50%) translate3d(0, 0, 0);
|
height: 500px;
|
||||||
background-color: var(--el-color-white);
|
position: relative;
|
||||||
border: 5px solid var(--el-color-primary-light-8);
|
|
||||||
border-radius: 5px;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 1;
|
|
||||||
height: 460px;
|
|
||||||
.login-content-main {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 80%;
|
|
||||||
.login-content-title {
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 22px;
|
|
||||||
text-align: center;
|
|
||||||
letter-spacing: 4px;
|
|
||||||
margin: 15px 0 30px;
|
|
||||||
white-space: nowrap;
|
|
||||||
z-index: 5;
|
|
||||||
position: relative;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.login-content-main-sacn {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: pointer;
|
background-color: var(--el-color-white);
|
||||||
transition: all ease 0.3s;
|
.login-right-warp-one,
|
||||||
color: var(--el-text-color-primary);
|
.login-right-warp-two {
|
||||||
&-delta {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 35px;
|
display: block;
|
||||||
height: 70px;
|
width: inherit;
|
||||||
z-index: 2;
|
height: inherit;
|
||||||
top: 2px;
|
&::before,
|
||||||
right: 21px;
|
&::after {
|
||||||
background: var(--el-color-white);
|
content: '';
|
||||||
transform: rotate(-45deg);
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&:hover {
|
.login-right-warp-one {
|
||||||
opacity: 1;
|
&::before {
|
||||||
transition: all ease 0.3s;
|
filter: hue-rotate(0deg);
|
||||||
color: var(--el-color-primary) !important;
|
top: 0px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--el-color-primary));
|
||||||
|
animation: loginLeft 3s linear infinite;
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
filter: hue-rotate(60deg);
|
||||||
|
top: -100%;
|
||||||
|
right: 2px;
|
||||||
|
width: 3px;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(180deg, transparent, var(--el-color-primary));
|
||||||
|
animation: loginTop 3s linear infinite;
|
||||||
|
animation-delay: 0.7s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i {
|
.login-right-warp-two {
|
||||||
width: 47px;
|
&::before {
|
||||||
height: 50px;
|
filter: hue-rotate(120deg);
|
||||||
display: inline-block;
|
bottom: 2px;
|
||||||
font-size: 48px;
|
right: -100%;
|
||||||
position: absolute;
|
width: 100%;
|
||||||
right: 2px;
|
height: 3px;
|
||||||
top: -1px;
|
background: linear-gradient(270deg, transparent, var(--el-color-primary));
|
||||||
|
animation: loginRight 3s linear infinite;
|
||||||
|
animation-delay: 1.4s;
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
filter: hue-rotate(300deg);
|
||||||
|
bottom: -100%;
|
||||||
|
left: 0px;
|
||||||
|
width: 3px;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(360deg, transparent, var(--el-color-primary));
|
||||||
|
animation: loginBottom 3s linear infinite;
|
||||||
|
animation-delay: 2.1s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.login-right-warp-mian {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
.login-right-warp-main-title {
|
||||||
|
height: 130px;
|
||||||
|
line-height: 130px;
|
||||||
|
font-size: 27px;
|
||||||
|
text-align: center;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
animation: logoAnimation 0.3s ease;
|
||||||
|
animation-delay: 0.3s;
|
||||||
|
}
|
||||||
|
.login-right-warp-main-form {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0 50px 50px;
|
||||||
|
.login-content-main-sacn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all ease 0.3s;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
&-delta {
|
||||||
|
position: absolute;
|
||||||
|
width: 35px;
|
||||||
|
height: 70px;
|
||||||
|
z-index: 2;
|
||||||
|
top: 2px;
|
||||||
|
right: 21px;
|
||||||
|
background: var(--el-color-white);
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
transition: all ease 0.3s;
|
||||||
|
color: var(--el-color-primary) !important;
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
width: 47px;
|
||||||
|
height: 50px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 48px;
|
||||||
|
position: absolute;
|
||||||
|
right: 1px;
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="notice-bar-container">
|
<div class="notice-bar-container layout-pd">
|
||||||
<el-card shadow="hover" header="滚动通知栏:默认">
|
<el-card shadow="hover" header="滚动通知栏:默认">
|
||||||
<NoticeBar
|
<NoticeBar
|
||||||
text="🎉🎉🔥基于vue3.x 、Typescript、vite、Element plus等,适配手机、平板、pc
|
text="🎉🎉🔥基于vue3.x 、Typescript、vite、Element plus等,适配手机、平板、pc
|
||||||
@ -48,12 +48,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, defineComponent } from 'vue';
|
import { defineAsyncComponent, toRefs, reactive, defineComponent } from 'vue';
|
||||||
import NoticeBar from '/@/components/noticeBar/index.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'makeNoticeBar',
|
name: 'makeNoticeBar',
|
||||||
components: { NoticeBar },
|
components: {
|
||||||
|
NoticeBar: defineAsyncComponent(() => import('/@/components/noticeBar/index.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
noticeList: [
|
noticeList: [
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="selector-container">
|
<div class="selector-container layout-pd">
|
||||||
<el-card shadow="hover" header="图标选择器(宽度自动):">
|
<el-card shadow="hover" header="图标选择器(宽度自动):">
|
||||||
<IconSelector @get="onGetIcon" @clear="onClearIcon" v-model="modelIcon" />
|
<IconSelector @get="onGetIcon" @clear="onClearIcon" v-model="modelIcon" />
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -26,12 +26,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, defineComponent } from 'vue';
|
import { defineAsyncComponent, toRefs, reactive, defineComponent } from 'vue';
|
||||||
import IconSelector from '/@/components/iconSelector/index.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'makeSelector',
|
name: 'makeSelector',
|
||||||
components: { IconSelector },
|
components: {
|
||||||
|
IconSelector: defineAsyncComponent(() => import('/@/components/iconSelector/index.vue')),
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
modelIcon: '',
|
modelIcon: '',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="svg-demo-container">
|
<div class="svg-demo-container layout-pd">
|
||||||
<el-card shadow="hover" header="svgIcon:演示(支持本地svg)">
|
<el-card shadow="hover" header="svgIcon:演示(支持本地svg)">
|
||||||
<SvgIcon name="iconfont icon-shuju1" color="red" :size="30" />
|
<SvgIcon name="iconfont icon-shuju1" color="red" :size="30" />
|
||||||
<SvgIcon name="ele-Trophy" color="var(--el-color-primary)" :size="30" />
|
<SvgIcon name="ele-Trophy" color="var(--el-color-primary)" :size="30" />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<el-input v-model="val" placeholder="menu11:请输入内容测试路由缓存"></el-input>
|
<el-input v-model="val" placeholder="menu11:请输入内容测试路由缓存"></el-input>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<el-input v-model="val" placeholder="menu121:请输入内容测试路由缓存"></el-input>
|
<el-input v-model="val" placeholder="menu121:请输入内容测试路由缓存"></el-input>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<el-input v-model="val" placeholder="menu122:请输入内容测试路由缓存"></el-input>
|
<el-input v-model="val" placeholder="menu122:请输入内容测试路由缓存"></el-input>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<el-input v-model="val" placeholder="menu13:请输入内容测试路由缓存"></el-input>
|
<el-input v-model="val" placeholder="menu13:请输入内容测试路由缓存"></el-input>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="layout-pd">
|
||||||
<el-input v-model="val" placeholder="menu2:请输入内容测试路由缓存"></el-input>
|
<el-input v-model="val" placeholder="menu2:请输入内容测试路由缓存"></el-input>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="awesome-container">
|
<div class="awesome-container layout-pd">
|
||||||
<el-card shadow="hover" :header="`fontawesome 字体图标(自动载入):${sheetsIconList.length - 24}个`">
|
<el-card shadow="hover" :header="`fontawesome 字体图标(自动载入):${sheetsIconList.length - 24}个`">
|
||||||
<el-row class="iconfont-row">
|
<el-row class="iconfont-row">
|
||||||
<el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k">
|
<el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="drag-container">
|
<div class="drag-container layout-pd">
|
||||||
<el-card shadow="hover" header="拖动指令效果(v-drag)作用于 Dialog 对话框">
|
<el-card shadow="hover" header="拖动指令效果(v-drag)作用于 Dialog 对话框">
|
||||||
<el-button type="primary" @click="dialogVisible = true" size="default">
|
<el-button type="primary" @click="dialogVisible = true" size="default">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dynamic-form-container">
|
<div class="dynamic-form-container layout-pd">
|
||||||
<el-card shadow="hover" header="动态复杂表单">
|
<el-card shadow="hover" header="动态复杂表单">
|
||||||
<el-form :model="form" ref="formRulesOneRef" size="default" label-width="100px" class="mt35">
|
<el-form :model="form" ref="formRulesOneRef" size="default" label-width="100px" class="mt35">
|
||||||
<el-row :gutter="35">
|
<el-row :gutter="35">
|
||||||
@ -112,7 +112,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, onMounted, getCurrentInstance, defineComponent } from 'vue';
|
import { toRefs, reactive, onMounted, defineComponent, ref } from 'vue';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
import { formData } from './mock';
|
import { formData } from './mock';
|
||||||
|
|
||||||
// 定义接口来定义对象的类型
|
// 定义接口来定义对象的类型
|
||||||
@ -146,7 +147,7 @@ interface DynamicFormState {
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'pagesDynamicForm',
|
name: 'pagesDynamicForm',
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const formRulesOneRef = ref();
|
||||||
const state = reactive<DynamicFormState>({
|
const state = reactive<DynamicFormState>({
|
||||||
formData,
|
formData,
|
||||||
form: {
|
form: {
|
||||||
@ -178,9 +179,9 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 表单验证
|
// 表单验证
|
||||||
const onSubmitForm = () => {
|
const onSubmitForm = () => {
|
||||||
proxy.$refs.formRulesOneRef.validate((valid: boolean) => {
|
formRulesOneRef.value.validate((valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
proxy.$message.success('验证成功');
|
ElMessage.success('验证成功');
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -188,11 +189,12 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
// 重置表单
|
// 重置表单
|
||||||
const onResetForm = () => {
|
const onResetForm = () => {
|
||||||
proxy.$refs.formRulesOneRef.resetFields();
|
formRulesOneRef.value.resetFields();
|
||||||
};
|
};
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {});
|
onMounted(() => {});
|
||||||
return {
|
return {
|
||||||
|
formRulesOneRef,
|
||||||
onAddRow,
|
onAddRow,
|
||||||
onDelRow,
|
onDelRow,
|
||||||
onSubmitForm,
|
onSubmitForm,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="element-container">
|
<div class="element-container layout-pd">
|
||||||
<el-card shadow="hover" :header="`element plus 字体图标(自动载入,增加了 ele- 前缀,使用时:ele-Aim):${sheetsIconList.length}个`">
|
<el-card shadow="hover" :header="`element plus 字体图标(自动载入,增加了 ele- 前缀,使用时:ele-Aim):${sheetsIconList.length}个`">
|
||||||
<el-row class="iconfont-row">
|
<el-row class="iconfont-row">
|
||||||
<el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k">
|
<el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{ height: `calc(100vh - ${initTagViewHeight}` }">
|
<div class="layout-padding">
|
||||||
<div class="layout-view-bg-white">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<div class="w100 h100 flex">
|
<div class="w100 h100 flex">
|
||||||
<div class="flex-margin color-primary">filtering-details 测试界面</div>
|
<div class="flex-margin color-primary">filtering-details 测试界面</div>
|
||||||
</div>
|
</div>
|
||||||
@ -9,31 +9,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'pagesFilteringDetails',
|
name: 'pagesFilteringDetails',
|
||||||
setup() {
|
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
|
||||||
const storesThemeConfig = useThemeConfig();
|
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
|
||||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
|
||||||
// 设置主内容的高度
|
|
||||||
const initTagViewHeight = computed(() => {
|
|
||||||
let { isTagsview } = themeConfig.value;
|
|
||||||
if (isTagsViewCurrenFull.value) {
|
|
||||||
return `30px`;
|
|
||||||
} else {
|
|
||||||
if (isTagsview) return `114px`;
|
|
||||||
else return `80px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
initTagViewHeight,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{ height: `calc(100vh - ${initTagViewHeight}` }">
|
<div class="layout-padding">
|
||||||
<div class="layout-view-bg-white">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<div class="w100 h100 flex">
|
<div class="w100 h100 flex">
|
||||||
<div class="flex-margin color-primary">测试界面</div>
|
<div class="flex-margin color-primary">测试界面</div>
|
||||||
</div>
|
</div>
|
||||||
@ -9,31 +9,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
|
||||||
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'pagesFilteringDetails1',
|
name: 'pagesFilteringDetails1',
|
||||||
setup() {
|
|
||||||
const storesTagsViewRoutes = useTagsViewRoutes();
|
|
||||||
const storesThemeConfig = useThemeConfig();
|
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
|
||||||
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
|
|
||||||
// 设置主内容的高度
|
|
||||||
const initTagViewHeight = computed(() => {
|
|
||||||
let { isTagsview } = themeConfig.value;
|
|
||||||
if (isTagsViewCurrenFull.value) {
|
|
||||||
return `30px`;
|
|
||||||
} else {
|
|
||||||
if (isTagsview) return `114px`;
|
|
||||||
else return `80px`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
initTagViewHeight,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="filtering">
|
<div class="filtering layout-pd">
|
||||||
<el-card
|
<el-card
|
||||||
shadow="hover"
|
shadow="hover"
|
||||||
class="filtering-list br-top-no"
|
class="filtering-list br-top-no"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="form-adapt-container">
|
<div class="form-adapt-container layout-pd">
|
||||||
<el-card shadow="hover" header="表单自适应演示(改变窗口查看效果)">
|
<el-card shadow="hover" header="表单自适应演示(改变窗口查看效果)">
|
||||||
<el-form :model="form" size="default" label-width="100px" class="mt35 mb35">
|
<el-form :model="form" size="default" label-width="100px" class="mt35 mb35">
|
||||||
<el-row :gutter="35">
|
<el-row :gutter="35">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="form-i18n-container">
|
<div class="form-i18n-container layout-pd">
|
||||||
<el-card shadow="hover" header="表单国际化演示(不适用于动态项 form-item)">
|
<el-card shadow="hover" header="表单国际化演示(不适用于动态项 form-item)">
|
||||||
<div style="text-align: center; margin-top: 15px">
|
<div style="text-align: center; margin-top: 15px">
|
||||||
<el-radio-group v-model="radio" size="default" @change="onRadioChange">
|
<el-radio-group v-model="radio" size="default" @change="onRadioChange">
|
||||||
@ -32,12 +32,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, defineComponent, getCurrentInstance } from 'vue';
|
import { toRefs, reactive, defineComponent } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'pagesFormI18n',
|
name: 'pagesFormI18n',
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const { locale } = useI18n();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
radio: 'zh-cn',
|
radio: 'zh-cn',
|
||||||
form: {
|
form: {
|
||||||
@ -48,7 +49,7 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
// 单选框改变时
|
// 单选框改变时
|
||||||
const onRadioChange = () => {
|
const onRadioChange = () => {
|
||||||
proxy.$i18n.locale = state.radio;
|
locale.value = state.radio;
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
onRadioChange,
|
onRadioChange,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="form-rules-container">
|
<div class="form-rules-container layout-pd">
|
||||||
<el-card shadow="hover" header="表单组件1"> <FormRulesOne :data="formRulesOneData" ref="pagesFormRulesOneRef" /></el-card>
|
<el-card shadow="hover" header="表单组件1"> <FormRulesOne :data="formRulesOneData" ref="pagesFormRulesOneRef" /></el-card>
|
||||||
<el-card shadow="hover" header="表单组件2" class="mt15"><FormRulesTwo ref="pagesFormRulesTwoRef" /> </el-card>
|
<el-card shadow="hover" header="表单组件2" class="mt15"><FormRulesTwo ref="pagesFormRulesTwoRef" /> </el-card>
|
||||||
<el-card shadow="hover" header="表单组件3" class="mt15"> <FormRulesThree ref="pagesFormRulesThreeRef" /></el-card>
|
<el-card shadow="hover" header="表单组件3" class="mt15"> <FormRulesThree ref="pagesFormRulesThreeRef" /></el-card>
|
||||||
@ -19,21 +19,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toRefs, reactive, defineComponent, getCurrentInstance } from 'vue';
|
import { defineAsyncComponent, toRefs, reactive, defineComponent, ref } from 'vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import FormRulesOne from '/@/views/pages/formRules/component/formRulesOne.vue';
|
|
||||||
import FormRulesTwo from '/@/views/pages/formRules/component/formRulesTwo.vue';
|
|
||||||
import FormRulesThree from '/@/views/pages/formRules/component/formRulesThree.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'pagesFormRules',
|
name: 'pagesFormRules',
|
||||||
components: {
|
components: {
|
||||||
FormRulesOne,
|
FormRulesOne: defineAsyncComponent(() => import('/@/views/pages/formRules/component/formRulesOne.vue')),
|
||||||
FormRulesTwo,
|
FormRulesTwo: defineAsyncComponent(() => import('/@/views/pages/formRules/component/formRulesTwo.vue')),
|
||||||
FormRulesThree,
|
FormRulesThree: defineAsyncComponent(() => import('/@/views/pages/formRules/component/formRulesThree.vue')),
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { proxy } = <any>getCurrentInstance();
|
const pagesFormRulesOneRef = ref();
|
||||||
|
const pagesFormRulesTwoRef = ref();
|
||||||
|
const pagesFormRulesThreeRef = ref();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
formRulesOneData: {
|
formRulesOneData: {
|
||||||
name: 'lyt',
|
name: 'lyt',
|
||||||
@ -43,25 +42,25 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
// 表单组件验证
|
// 表单组件验证
|
||||||
const formRulesValidate = (pageRef: string, sonRef: string) => {
|
const formRulesValidate = (pageRef: any, sonRef: string) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
proxy.$refs[pageRef].$refs[sonRef].validate((valid: boolean) => {
|
pageRef.value.$refs[sonRef].validate((valid: boolean) => {
|
||||||
if (valid) resolve(valid);
|
if (valid) resolve(valid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 表单组件重置
|
// 表单组件重置
|
||||||
const formRulesResetFields = () => {
|
const formRulesResetFields = () => {
|
||||||
proxy.$refs.pagesFormRulesOneRef.$refs.formRulesOneRef.resetFields();
|
pagesFormRulesOneRef.value.$refs.formRulesOneRef.resetFields();
|
||||||
proxy.$refs.pagesFormRulesTwoRef.$refs.formRulesTwoRef.resetFields();
|
pagesFormRulesTwoRef.value.$refs.formRulesTwoRef.resetFields();
|
||||||
proxy.$refs.pagesFormRulesThreeRef.$refs.formRulesThreeRef.resetFields();
|
pagesFormRulesThreeRef.value.$refs.formRulesThreeRef.resetFields();
|
||||||
};
|
};
|
||||||
// 验证表单
|
// 验证表单
|
||||||
const onSubmitForm = () => {
|
const onSubmitForm = () => {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
formRulesValidate('pagesFormRulesOneRef', 'formRulesOneRef'),
|
formRulesValidate(pagesFormRulesOneRef, 'formRulesOneRef'),
|
||||||
formRulesValidate('pagesFormRulesTwoRef', 'formRulesTwoRef'),
|
formRulesValidate(pagesFormRulesTwoRef, 'formRulesTwoRef'),
|
||||||
formRulesValidate('pagesFormRulesThreeRef', 'formRulesThreeRef'),
|
formRulesValidate(pagesFormRulesThreeRef, 'formRulesThreeRef'),
|
||||||
]).then(() => {
|
]).then(() => {
|
||||||
ElMessage.success('表单全部验证成功');
|
ElMessage.success('表单全部验证成功');
|
||||||
});
|
});
|
||||||
@ -71,6 +70,9 @@ export default defineComponent({
|
|||||||
formRulesResetFields();
|
formRulesResetFields();
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
|
pagesFormRulesOneRef,
|
||||||
|
pagesFormRulesTwoRef,
|
||||||
|
pagesFormRulesThreeRef,
|
||||||
onSubmitForm,
|
onSubmitForm,
|
||||||
onResetForm,
|
onResetForm,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="iconfont-container">
|
<div class="iconfont-container layout-pd">
|
||||||
<el-card shadow="hover" :header="`iconfont 字体图标(自动载入):${sheetsIconList.length}个`">
|
<el-card shadow="hover" :header="`iconfont 字体图标(自动载入):${sheetsIconList.length}个`">
|
||||||
<el-row class="iconfont-row">
|
<el-row class="iconfont-row">
|
||||||
<el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k">
|
<el-col :xs="12" :sm="8" :md="6" :lg="4" :xl="2" v-for="(v, k) in sheetsIconList" :key="k">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="lazy-img-container">
|
<div class="lazy-img-container layout-pd">
|
||||||
<el-card shadow="hover" header="图片懒加载演示(F12 切换到 Network Img下进行图片加载查看)">
|
<el-card shadow="hover" header="图片懒加载演示(F12 切换到 Network Img下进行图片加载查看)">
|
||||||
<div class="flex-warp" v-if="tableData.data.length > 0">
|
<div class="flex-warp" v-if="tableData.data.length > 0">
|
||||||
<el-row :gutter="15">
|
<el-row :gutter="15">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="list-adapt-container">
|
<div class="list-adapt-container layout-pd">
|
||||||
<el-card shadow="hover" header="列表自适应演示(改变窗口查看效果)">
|
<el-card shadow="hover" header="列表自适应演示(改变窗口查看效果)">
|
||||||
<div class="flex-warp" v-if="tableData.data.length > 0">
|
<div class="flex-warp" v-if="tableData.data.length > 0">
|
||||||
<el-row :gutter="15">
|
<el-row :gutter="15">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="preview-container">
|
<div class="preview-container layout-pd">
|
||||||
<el-card shadow="hover" header="element-plus 大图预览">
|
<el-card shadow="hover" header="element-plus 大图预览">
|
||||||
<el-image style="width: 100px; height: 100px; border-radius: 5px" :src="url" :preview-src-list="srcList" title="点击查看大图预览"> </el-image>
|
<el-image style="width: 100px; height: 100px; border-radius: 5px" :src="url" :preview-src-list="srcList" title="点击查看大图预览"> </el-image>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="steps-container">
|
<div class="steps-container layout-pd">
|
||||||
<el-card shadow="hover" header="element-plus 步骤条">
|
<el-card shadow="hover" header="element-plus 步骤条">
|
||||||
<el-steps :active="stepsActive">
|
<el-steps :active="stepsActive">
|
||||||
<el-step title="第一步">
|
<el-step title="第一步">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<SvgIcon name="iconfont icon-0_round_solid" :size="20" />
|
<SvgIcon name="iconfont icon-0_round_solid" :size="40" />
|
||||||
</template>
|
</template>
|
||||||
</el-step>
|
</el-step>
|
||||||
<el-step title="第二步">
|
<el-step title="第二步">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<SvgIcon name="iconfont icon-2_round_solid" :size="20" />
|
<SvgIcon name="iconfont icon-2_round_solid" :size="40" />
|
||||||
</template>
|
</template>
|
||||||
</el-step>
|
</el-step>
|
||||||
<el-step title="第三步">
|
<el-step title="第三步">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<SvgIcon name="iconfont icon-3_round_solid" :size="20" />
|
<SvgIcon name="iconfont icon-3_round_solid" :size="40" />
|
||||||
</template>
|
</template>
|
||||||
</el-step>
|
</el-step>
|
||||||
</el-steps>
|
</el-steps>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user