Merge branch 'vue-i18n' of https://github.com/zouzhibin/vue-admin-perfect into ghpages
This commit is contained in:
commit
ef3894f636
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* @description 方法用来切换元素 进入全屏
|
||||
* @vueuse/core 提供了 useFullscreen 方法,因此项目中采用 useFullscreen,目的是为了减少代码量
|
||||
* 它原理原理实现如下:
|
||||
*/
|
||||
|
||||
import { ElMessage } from "element-plus";
|
||||
import {onMounted} from "vue";
|
||||
|
||||
export const useFullscreen = () => {
|
||||
/**
|
||||
* @description: 是否支持全屏+判断浏览器前缀
|
||||
*/
|
||||
const isFullscreen = ()=> {
|
||||
let prefixName = ""; // 浏览器前缀
|
||||
let fullscreenEnabled = false;
|
||||
// 判断浏览器前缀
|
||||
if (document.fullscreenEnabled) {
|
||||
fullscreenEnabled = document.fullscreenEnabled;
|
||||
// webkit
|
||||
} else if (document.webkitFullscreenEnabled) {
|
||||
fullscreenEnabled = document.webkitFullscreenEnabled;
|
||||
prefixName = "webkit";
|
||||
// moz
|
||||
} else if (document.mozFullScreenEnabled) {
|
||||
fullscreenEnabled = document.mozFullScreenEnabled;
|
||||
prefixName = "moz";
|
||||
// ms
|
||||
} else if (document.msFullscreenEnabled) {
|
||||
fullscreenEnabled = document.msFullscreenEnabled;
|
||||
prefixName = "ms";
|
||||
}
|
||||
return {
|
||||
fullscreenEnabled,
|
||||
prefixName
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description: 检测有没有元素处于全屏状态
|
||||
* @return 布尔值
|
||||
*/
|
||||
const isElementFullScreen = ()=> {
|
||||
const fullscreenElement =
|
||||
document.fullscreenElement ||
|
||||
document.msFullscreenElement ||
|
||||
document.mozFullScreenElement ||
|
||||
document.webkitFullscreenElement;
|
||||
if (fullscreenElement === null) {
|
||||
return false; // 当前没有元素在全屏状态
|
||||
} else {
|
||||
return true; // 有元素在全屏状态
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 将传进来的元素全屏
|
||||
* @param {String} domName 要全屏的dom名称
|
||||
*/
|
||||
const Fullscreen = (target)=> {
|
||||
const targetRef = target || (document == null ? void 0 : document.querySelector("html"));
|
||||
const {prefixName} = isFullscreen()
|
||||
const methodName =
|
||||
prefixName === ""
|
||||
? "requestFullscreen"
|
||||
: `${prefixName}RequestFullScreen`;
|
||||
targetRef[methodName]();
|
||||
}
|
||||
|
||||
// 退出全屏
|
||||
const exitFullscreen =()=> {
|
||||
const {prefixName} = isFullscreen()
|
||||
const methodName =
|
||||
prefixName === ""
|
||||
? "exitFullscreen"
|
||||
: `${prefixName}ExitFullscreen`;
|
||||
document[methodName]();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 浏览器无法进入全屏时触发,可能是技术原因,也可能是用户拒绝:比如全屏请求不是在事件处理函数中调用,会在这里拦截到错误
|
||||
* @param {Function} enterErrorFn 回调
|
||||
*/
|
||||
const screenError = ()=> {
|
||||
const {prefixName} = isFullscreen()
|
||||
const methodName = `on${prefixName}fullscreenerror`;
|
||||
document[methodName] = e => {
|
||||
ElMessage.error('进入全屏失败')
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 监听进入/离开全屏
|
||||
* @param {Function} enter 进入全屏的回调
|
||||
* @param {Function} quit 离开全屏的回调
|
||||
*/
|
||||
const screenChange = (enter, quit)=> {
|
||||
const {fullscreenEnabled,prefixName} = isFullscreen()
|
||||
if (!fullscreenEnabled) return;
|
||||
const methodName = `on${prefixName}fullscreenchange`;
|
||||
document[methodName] = e => {
|
||||
if (isElementFullScreen()) {
|
||||
enter && enter(e); // 进入全屏回调
|
||||
} else {
|
||||
quit && quit(e); // 离开全屏的回调
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
screenError()
|
||||
})
|
||||
|
||||
|
||||
return{
|
||||
isFullscreen,
|
||||
isElementFullScreen,
|
||||
Fullscreen,
|
||||
exitFullscreen,
|
||||
screenChange
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<template>
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
background-color="#304156"
|
||||
text-color="#bfcbd9"
|
||||
:mode="mode"
|
||||
:unique-opened="SettingStore.themeConfig.uniqueOpened"
|
||||
:collapse-transition="false"
|
||||
class="el-menu-vertical-demo"
|
||||
:collapse="isCollapse"
|
||||
>
|
||||
<sub-item
|
||||
v-for="route in permission_routes"
|
||||
:key="route.path"
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
/>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import SubItem from './SubItem.vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import {usePermissionStore} from "@/store/modules/permission"
|
||||
import {useSettingStore} from "@/store/modules/setting"
|
||||
import { computed } from 'vue'
|
||||
|
||||
// 在setup中获取store
|
||||
const route = useRoute()
|
||||
const PermissionStore = usePermissionStore()
|
||||
const SettingStore = useSettingStore()
|
||||
|
||||
// 获取路由
|
||||
const permission_routes = computed(() => PermissionStore.permission_routes)
|
||||
|
||||
const activeMenu = computed(() => {
|
||||
const { meta, path } = route
|
||||
// if set path, the sidebar will highlight the path you set
|
||||
if (meta.activeMenu) {
|
||||
return meta.activeMenu
|
||||
}
|
||||
return path
|
||||
})
|
||||
|
||||
// 是否折叠
|
||||
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||
|
||||
// 横向
|
||||
const mode = computed(() => SettingStore.themeConfig.mode)
|
||||
</script>
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
<template>
|
||||
<template v-if="!item.hidden">
|
||||
<template v-if="!item.alwaysShow && hasOneShowingChild(item.children, item)">
|
||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
||||
<el-menu-item :index="resolvePath(onlyOneChild.path)">
|
||||
<el-icon :size="20">
|
||||
<component :is="onlyOneChild?.meta.icon"></component>
|
||||
</el-icon>
|
||||
<template #title>{{ onlyOneChild.meta && onlyOneChild.meta.title }}</template>
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
</template>
|
||||
<el-sub-menu :index="resolvePath(item.path)" v-else popper-append-to-body>
|
||||
<template #title>
|
||||
<el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>
|
||||
<span>{{ item.meta && item.meta.title }}</span>
|
||||
</template>
|
||||
<sub-item
|
||||
v-for="child in item.children"
|
||||
:key="child.path"
|
||||
:item="child"
|
||||
:base-path="resolvePath(child.path)"
|
||||
/>
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { isExternal } from '@/utils/validate.js'
|
||||
import AppLink from '../../SubMenu/Link.vue'
|
||||
import path from 'path-browserify'
|
||||
import { ref, computed } from 'vue'
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const onlyOneChild = ref(null)
|
||||
const hasOneShowingChild = (children = [], parent) => {
|
||||
const showingChildren = children.filter((item) => {
|
||||
// 过滤掉需要隐藏的菜单
|
||||
if (item.hidden) {
|
||||
return false
|
||||
} else {
|
||||
// 临时设置(如果只有一个显示子项,则将使用)
|
||||
onlyOneChild.value = item
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
// 当只有一个子路由器时,默认情况下会显示该子路由器
|
||||
if (showingChildren.length === 1) {
|
||||
return true
|
||||
}
|
||||
// 如果没有要显示的子路由器,则显示父路由器
|
||||
if (showingChildren.length === 0) {
|
||||
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const resolvePath = (routePath) => {
|
||||
if (isExternal(routePath)) {
|
||||
return routePath
|
||||
}
|
||||
if (isExternal(props.basePath)) {
|
||||
return props.basePath
|
||||
}
|
||||
return path.resolve(props.basePath, routePath)
|
||||
}
|
||||
</script>
|
||||
|
|
@ -26,16 +26,15 @@
|
|||
import Logo from './components/Logo.vue'
|
||||
import SubItem from '../SubMenu/SubItem.vue'
|
||||
import {useSettingStore} from "@/store/modules/setting"
|
||||
import {usePermissionStore} from "@/store/modules/permission"
|
||||
import { computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import {usePermissionStore} from "@/store/modules/permission"
|
||||
|
||||
// 在setup中获取store
|
||||
const route = useRoute()
|
||||
const PermissionStore = usePermissionStore()
|
||||
const SettingStore = useSettingStore()
|
||||
|
||||
|
||||
|
||||
// 是否折叠
|
||||
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||
// 设置
|
||||
|
|
@ -52,10 +51,6 @@ const activeMenu = computed(() => {
|
|||
}
|
||||
return path
|
||||
})
|
||||
|
||||
|
||||
// 横向
|
||||
const mode = computed(() => SettingStore.themeConfig.mode)
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
|||
|
|
@ -24,7 +24,13 @@ const formRouter = [{
|
|||
path: 'advancedForm',
|
||||
component: () => import('@/views/form/advancedForm/index.vue'),
|
||||
name: 'advanced-form',
|
||||
meta: { title: '可收缩 Form', keepAlive: true , icon: 'MenuIcon'}
|
||||
meta: { title: '收缩 Form', keepAlive: true , icon: 'MenuIcon'}
|
||||
},
|
||||
{
|
||||
path: 'appendForm',
|
||||
component: () => import('@/views/form/appendForm/index.vue'),
|
||||
name: 'append-form',
|
||||
meta: { title: '增删 Form', keepAlive: true , icon: 'MenuIcon'}
|
||||
},
|
||||
]
|
||||
}]
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@ const functionPageRouter = [{
|
|||
name: 'function-403',
|
||||
meta: { title: '403 页面', keepAlive: true , icon: 'MenuIcon'}
|
||||
},
|
||||
{
|
||||
path: 'fullscreen',
|
||||
component: () => import('@/views/functionPage/fullscreen/index.vue'),
|
||||
name: 'fullscreen',
|
||||
meta: { title: '元素 全屏', keepAlive: true , icon: 'MenuIcon'}
|
||||
},
|
||||
]
|
||||
}]
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
.advancedForm{
|
||||
padding: 20px;
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
<script lang="ts" setup name="advancedForm">
|
||||
import AdvancedForm from "@/components/SearchForm/advancedForm/index.vue"
|
||||
import {reactive, ref} from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
|
@ -103,7 +103,5 @@ const showRow = (number)=>{
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.advancedForm{
|
||||
padding: 20px;
|
||||
}
|
||||
@import "./index.scss";
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
.app-container-inner{
|
||||
text-align: center;
|
||||
.add{
|
||||
margin: 0 0 30px 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<div class="app-container-inner">
|
||||
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="dynamicValidateForm"
|
||||
label-width="120px"
|
||||
class="demo-dynamic"
|
||||
>
|
||||
<el-row v-for="(domain, index) in dynamicValidateForm.domains" :gutter="20" :key="domain.key">
|
||||
<el-col :span="10">
|
||||
<el-form-item
|
||||
:label="'Domain' + index"
|
||||
:prop="'domains.' + index + '.name'"
|
||||
:rules="{
|
||||
required: true,
|
||||
message: 'domain can not be null',
|
||||
trigger: 'blur',
|
||||
}"
|
||||
>
|
||||
<el-input v-model="domain.name" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-form-item
|
||||
:label="'Domain' + index"
|
||||
:prop="'domains.' + index + '.value'"
|
||||
:rules="{
|
||||
required: true,
|
||||
message: 'domain can not be null',
|
||||
trigger: 'blur',
|
||||
}"
|
||||
>
|
||||
<el-input v-model="domain.value" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button @click.prevent="addDomain()" v-if="index===0">
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-button>
|
||||
<el-button @click.prevent="removeDomain(domain)" v-else>
|
||||
<el-icon ><Minus /></el-icon>
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm(formRef)">Submit</el-button>
|
||||
<el-button @click="resetForm(formRef)">Reset</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="appendForm">
|
||||
import { reactive, ref } from 'vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import {ElMessage} from "element-plus"
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const dynamicValidateForm = reactive<{
|
||||
domains: DomainItem[]
|
||||
}>({
|
||||
domains: [
|
||||
{
|
||||
key: 1,
|
||||
value: '',
|
||||
name:''
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
interface DomainItem {
|
||||
key: number
|
||||
value: string,
|
||||
name:string
|
||||
}
|
||||
|
||||
const removeDomain = (item: DomainItem) => {
|
||||
const index = dynamicValidateForm.domains.indexOf(item)
|
||||
if (index !== -1) {
|
||||
dynamicValidateForm.domains.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
const addDomain = () => {
|
||||
dynamicValidateForm.domains.push({
|
||||
key: Date.now(),
|
||||
value: '',
|
||||
name:''
|
||||
})
|
||||
}
|
||||
|
||||
const submitForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
ElMessage.success(`提交数据: ${JSON.stringify(dynamicValidateForm.domains)}`)
|
||||
console.log('submit!',dynamicValidateForm.domains)
|
||||
} else {
|
||||
console.log('error submit!')
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./index.scss";
|
||||
</style>
|
||||
|
|
@ -71,7 +71,7 @@
|
|||
</u-container-layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
<script lang="ts" setup name="advancedForm">
|
||||
import { reactive, ref } from 'vue'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import Upload from './components/Upload.vue'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
.app-container-inner{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
.header{
|
||||
padding: 20px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #0000001a;
|
||||
.title{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
.fullscreen{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: white;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
||||
.title{
|
||||
padding: 20px;
|
||||
}
|
||||
.inner{
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<div class="app-container-inner">
|
||||
<div class="header">
|
||||
<div class="title">window切换全屏</div>
|
||||
<el-button type="primary" @click="fullWindowScreenAction">{{ isFullscreen?'退出全屏':'点击全屏' }}</el-button>
|
||||
</div>
|
||||
<div class="fullscreen" @click="fullscreenAction" ref="domRef">
|
||||
<div class="title">DOM元素切换全屏</div>
|
||||
<div class="inner">
|
||||
<el-button type="primary">{{ isFullscreen?'退出全屏':'点击全屏' }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref} from "vue";
|
||||
import { useFullscreen } from "@vueuse/core";
|
||||
|
||||
const domRef = ref<HTMLElement>(null);
|
||||
const { enter, toggle:fullWindowScreenAction, exit, isFullscreen } = useFullscreen();
|
||||
|
||||
const { toggle: fullscreenAction } = useFullscreen(domRef);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./index.scss";
|
||||
</style>
|
||||
Loading…
Reference in New Issue