Conflicts:
	src/layout/Header/index.vue
	src/layout/TagsView/index.vue
This commit is contained in:
zouzhibing 2022-10-23 21:50:22 +08:00
commit a5bfac59b0
58 changed files with 544 additions and 911 deletions

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 KiB

View File

@ -0,0 +1,127 @@
<template>
<div class="echarts" ref="echarts"></div>
</template>
<script>
import * as echarts from "echarts";
export default {
data(){
return{
chart:null
}
},
methods:{
initEcharts(){
let option = {
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
center: ['50%', '80%'],
radius: '100%',
min: 0,
max: 1,
z: 5,
splitNumber: 12,
axisLine: {
show: true,
lineStyle: {
width: 6,
color: [
[0.12, "#d92d4d"],
[0.35, "#eb8349"],
[0.63, "#e6e462"],
[0.8, "#74c7da"],
[1, "#67b45a"],
]
}
},
axisTick: {
splitNumber: 13,
show: true,
lineStyle: {
color: "auto",
width: 2,
},
length: 17,
},
splitLine: {
length: 25,
lineStyle: {
color: 'auto',
width: 8
}
},
axisLabel: {
color: '#a0a7b8',
fontSize: 20,
distance: -60,
rotate: 'tangential',
formatter: function (value) {
var value = value.toFixed(2);
if (value == 0.0) {
return "危";
} else if (value == 0.25) {
return "差";
} else if (value == 0.5) {
return "中";
} else if (value == 0.75) {
return "良";
} else if (value == 1.0) {
return "优";
} else {
return "";
}
}
},
title: {
offsetCenter: [0, '-10%'],
fontSize: 20
},
anchor: {
show: true,
showAbove: true,
size: 25,
itemStyle: {
borderWidth: 10
}
},
detail: {
fontSize: 30,
offsetCenter: [0, '-25%'],
valueAnimation: true,
formatter: function (value) {
return Math.round(value * 100);
},
color: 'auto'
},
data: [
{
value: 0.7,
name: 'Grade Rating'
}
]
}
]
};
this.chart = echarts.init(this.$refs.echarts)
this.chart.setOption(option)
}
},
mounted() {
this.initEcharts()
}
}
</script>
<style lang="scss" scoped>
.echarts {
width: 100%;
height: 100%;
}
</style>

View File

@ -1,4 +1,4 @@
import CountTo from './vue-countTo.vue' import CountTo from './index.vue'
export default CountTo export default CountTo
if (typeof window !== 'undefined' && window.Vue) { if (typeof window !== 'undefined' && window.Vue) {
window.Vue.component('count-to', CountTo) window.Vue.component('count-to', CountTo)

View File

@ -1,37 +0,0 @@
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank">create-vue</a>, the
official Vue + Vite starter
</p>
<p>
Install
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
in your IDE for a better DX
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>

View File

@ -193,7 +193,7 @@
} }
} }
::v-deep(.el-drawer__title) { :deep(.el-drawer__title) {
font-weight: bold; font-weight: bold;
color: black; color: black;
} }

View File

@ -13,7 +13,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
padding: 20px; padding: 10px 12px;
box-sizing: border-box; box-sizing: border-box;
.m-container-layout-inner { .m-container-layout-inner {
flex: 1; flex: 1;

View File

@ -1,3 +0,0 @@
<template> </template>
<script lang="ts"></script>

View File

@ -1,154 +0,0 @@
/* eslint-disable promise/prefer-await-to-then */
const methodMap = [
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror',
],
// New WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror',
],
// Old WebKit
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror',
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror',
],
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError',
],
]
const nativeAPI = (() => {
const unprefixedMethods = methodMap[0]
const returnValue = {}
for (const methodList of methodMap) {
const exitFullscreenMethod = methodList?.[1]
if (exitFullscreenMethod in document) {
for (const [index, method] of methodList.entries()) {
returnValue[unprefixedMethods[index]] = method
}
return returnValue
}
}
return false
})()
const eventNameMap = {
change: nativeAPI.fullscreenchange,
error: nativeAPI.fullscreenerror,
}
// eslint-disable-next-line import/no-mutable-exports
let screenfull = {
// eslint-disable-next-line default-param-last
request(element = document.documentElement, options) {
return new Promise((resolve, reject) => {
const onFullScreenEntered = () => {
screenfull.off('change', onFullScreenEntered)
resolve()
}
screenfull.on('change', onFullScreenEntered)
const returnPromise = element[nativeAPI.requestFullscreen](options)
if (returnPromise instanceof Promise) {
returnPromise.then(onFullScreenEntered).catch(reject)
}
})
},
exit() {
return new Promise((resolve, reject) => {
if (!screenfull.isFullscreen) {
resolve()
return
}
const onFullScreenExit = () => {
screenfull.off('change', onFullScreenExit)
resolve()
}
screenfull.on('change', onFullScreenExit)
const returnPromise = document[nativeAPI.exitFullscreen]()
if (returnPromise instanceof Promise) {
returnPromise.then(onFullScreenExit).catch(reject)
}
})
},
toggle(element, options) {
return screenfull.isFullscreen ? screenfull.exit() : screenfull.request(element, options)
},
onchange(callback) {
screenfull.on('change', callback)
},
onerror(callback) {
screenfull.on('error', callback)
},
on(event, callback) {
const eventName = eventNameMap[event]
if (eventName) {
document.addEventListener(eventName, callback, false)
}
},
off(event, callback) {
const eventName = eventNameMap[event]
if (eventName) {
document.removeEventListener(eventName, callback, false)
}
},
raw: nativeAPI,
}
Object.defineProperties(screenfull, {
isFullscreen: {
get: () => Boolean(document[nativeAPI.fullscreenElement]),
},
element: {
enumerable: true,
get: () => document[nativeAPI.fullscreenElement] ?? undefined,
},
isEnabled: {
enumerable: true,
// Coerce to boolean in case of old WebKit.
get: () => Boolean(document[nativeAPI.fullscreenEnabled]),
},
})
if (!nativeAPI) {
screenfull = { isEnabled: false }
}
export default screenfull

View File

@ -1,60 +0,0 @@
<template>
<div class="m-screenful">
<svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" class="full-screen"/>
</div>
</template>
<script lang="ts" setup>
import screenfull from './index'
import { ElMessage } from 'element-plus'
import { onBeforeUnmount, onMounted, ref } from 'vue'
let isFullscreen = ref(false)
const click = () => {
if (!screenfull.isEnabled) {
ElMessage({
message: '你的浏览器不支持',
type: 'warning',
})
return false
}
screenfull.toggle()
}
const change = () => {
isFullscreen.value = screenfull.isFullscreen
}
const init = () => {
if (screenfull.isEnabled) {
screenfull.on('change', change)
}
}
const destroy = () => {
if (screenfull.isEnabled) {
screenfull.off('change', change)
}
}
onMounted(() => {
init()
})
onBeforeUnmount(() => {
destroy()
})
</script>
<style lang="scss" scoped>
.m-screenful {
display: flex;
align-items: center;
padding-right: 0;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
}
.transverseMenu {
.full-screen {
color: white;
}
}
</style>

View File

@ -0,0 +1,30 @@
<template>
<div class="hamburger-container" @click="handleCollapse">
<el-icon class="icon" v-if="isCollapse" ><expand /></el-icon>
<el-icon class="icon" v-else><fold /></el-icon>
</div>
</template>
<script lang="ts" setup>
import {useSettingStore} from "@/store/modules/setting"
import {computed} from "_vue@3.2.40@vue";
const SettingStore = useSettingStore()
const isCollapse = computed(() =>!SettingStore.isCollapse)
const handleCollapse = () => {
SettingStore.setCollapse(isCollapse.value)
}
</script>
<style lang="scss" scoped>
.hamburger-container{
padding: 0px 15px;
height: 100%;
display: flex;
align-items: center;
&:hover {
background: rgba(0, 0, 0, .025)
}
.icon {
font-size: 24px;
cursor: pointer;
}
}
</style>

View File

@ -28,45 +28,45 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue' import { ref } from 'vue'
import type { TabsPaneContext } from 'element-plus' import type { TabsPaneContext } from 'element-plus'
const activeName = ref('first') const activeName = ref('first')
const toGitHub = (link) => { const toGitHub = (link) => {
window.open(link) window.open(link)
} }
const handleClick = (tab: TabsPaneContext, event: Event) => { const handleClick = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event) console.log(tab, event)
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.m-info { .m-info {
display: inline-flex; display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
.item-info-pop {
display: flex;
align-items: center; align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
.item-info-pop {
display: flex;
align-items: center;
}
.bell{
color: black;
}
.item-child {
display: flex;
align-items: center;
font-size: 13px;
}
} }
::v-deep(.el-divider--horizontal){ .bell{
margin-bottom: 10px; color: black;
margin-top: 10px;
} }
.transverseMenu { .item-child {
.bell { display: flex;
color: white; align-items: center;
} font-size: 13px;
} }
}
::v-deep(.el-divider--horizontal){
margin-bottom: 10px;
margin-top: 10px;
}
.transverseMenu {
.bell {
color: white;
}
}
</style> </style>

View File

@ -0,0 +1,26 @@
<template>
<div class="m-screenful">
<svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="toggle" class="full-screen"/>
</div>
</template>
<script lang="ts" setup>
import { useFullscreen } from "@vueuse/core";
const { toggle, isFullscreen } = useFullscreen();
</script>
<style lang="scss" scoped>
.m-screenful {
display: flex;
align-items: center;
padding-right: 0;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
}
.transverseMenu {
.full-screen {
color: white;
}
}
</style>

View File

@ -12,26 +12,21 @@
transverseMenu: mode === 'horizontal', transverseMenu: mode === 'horizontal',
}" }"
> >
<u-menu v-if="mode === 'horizontal'" /> <UMenu v-if="mode === 'horizontal'" />
<div class="left" v-if="mode === 'vertical'"> <div class="left" v-if="mode === 'vertical'">
<div class="hamburger-container"> <CollapseIcon/>
<el-icon class="icon" v-if="isCollapse" @click="handleCollapse"><expand /></el-icon> <Hamburger />
<el-icon class="icon" v-else @click="handleCollapse"><fold /></el-icon>
</div>
<u-hamburger />
</div> </div>
<div class="right"> <div class="right">
<language class="right-item-menu"/> <GlobalComSize class="right-item-menu"/>
<global-com-size class="right-item-menu"/> <HeaderSearch class="right-item-menu"/>
<u-header-search class="right-item-menu"/> <Remind class="right-item-menu"/>
<u-info class="right-item-menu"/> <ScreenFull class="right-item-menu"/>
<u-screen-full class="right-item-menu"/> <Setting class="right-item-menu"/>
<u-setting class="right-item-menu"/>
<el-dropdown @command="commandAction"> <el-dropdown @command="commandAction">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
@ -63,12 +58,12 @@
import Personal from './components/Personal.vue' import Personal from './components/Personal.vue'
import TagViews from '../TagsView/index.vue' import TagViews from '../TagsView/index.vue'
import GlobalComSize from './components/globalComSize.vue' import GlobalComSize from './components/globalComSize.vue'
import Language from './components/Language.vue' import Hamburger from '@/components/Hamburger/index.vue'
import UHamburger from '@/components/u-Hamburger/index.vue' import Setting from './components/Setting.vue'
import USetting from './components/Setting.vue' import ScreenFull from './components/ScreenFull.vue'
import UScreenFull from '@/components/u-screenfull/index.vue' import Remind from './components/Remind'
import UInfo from '@/components/u-info/index.vue' import HeaderSearch from './components/HeaderSearch'
import UHeaderSearch from '@/components/u-headerSearch/index.vue' import CollapseIcon from './components/CollapseIcon'
import UMenu from '../Sidebar/components/Menu.vue' import UMenu from '../Sidebar/components/Menu.vue'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
@ -136,10 +131,7 @@
width: 100%!important; width: 100%!important;
} }
} }
.icon {
font-size: 24px;
cursor: pointer;
}
.header { .header {
height: 50px; height: 50px;
width: 100%; width: 100%;
@ -171,15 +163,7 @@
.zb-no-fixed-header{ .zb-no-fixed-header{
width: 100%!important;; width: 100%!important;;
} }
.hamburger-container{
padding: 0px 15px;
height: 100%;
display: flex;
align-items: center;
&:hover {
background: rgba(0, 0, 0, .025)
}
}
.m-layout-header { .m-layout-header {
width: 100%; width: 100%;
background: white; background: white;

View File

@ -7,19 +7,19 @@
</keep-alive> </keep-alive>
</transition> </transition>
</router-view> </router-view>
<u-theme /> <Theme />
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import UTheme from '@/components/u-theme/index.vue' import Theme from '@/components/Theme/index.vue'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import {useSettingStore} from "@/store/modules/setting" import {useSettingStore} from "@/store/modules/setting"
import {usePermissionStore} from "@/store/modules/permission" import {usePermissionStore} from "@/store/modules/permission"
const SettingStore = useSettingStore() const SettingStore = useSettingStore()
const PermissionStor = usePermissionStore() const PermissionStor = usePermissionStore()
const cacheRoutes = computed(() =>PermissionStor.cacheRoutes) const cacheRoutes = computed(() =>PermissionStor.getCacheRoutes())
const isReload = computed(() => SettingStore.isReload) const isReload = computed(() => SettingStore.isReload)
</script> </script>

View File

@ -1,58 +0,0 @@
<template>
<div ref="bsWrap" class="tags-scroll-wrap">
<div ref="bsContent" class="tags-scroll">
<slot></slot>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import { useElementSize } from '@vueuse/core'
import BScroll from '@better-scroll/core'
import type { Options } from '@better-scroll/core'
interface Props {
/** better-scroll的配置: https://better-scroll.github.io/docs/zh-CN/guide/base-scroll-options.html */
options: Options
}
const props = defineProps<Props>()
const bsWrap = ref<HTMLElement>()
const instance = ref<BScroll>()
const bsContent = ref<HTMLElement>()
function initBetterScroll() {
nextTick(() => {
instance.value = new BScroll(bsWrap.value, props.options)
})
}
// BS
const { width: wrapWidth } = useElementSize(bsWrap)
const { width, height } = useElementSize(bsContent)
watch([() => wrapWidth.value, () => width.value, () => height.value], () => {
if (instance.value) {
instance.value.refresh()
}
})
onMounted(() => {
initBetterScroll()
})
defineExpose({ instance })
</script>
<style scoped>
.tags-scroll-wrap {
width: 100%;
}
.tags-scroll-inner {
/*display: flex;*/
}
.tags-scroll {
display: inline-block;
}
</style>

View File

@ -0,0 +1,59 @@
<template>
<el-dropdown trigger="hover">
<el-button size="small" type="primary">
<span>更多</span>
<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="refresh">刷新当页</el-dropdown-item>
<el-dropdown-item @click="closeCurrentTab">关闭当前</el-dropdown-item>
<el-dropdown-item @click="closeOtherTab">关闭其他</el-dropdown-item>
<el-dropdown-item @click="closeAllTab">关闭所有</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script lang="ts" setup>
import {computed} from "vue";
import {useSettingStore} from "@/store/modules/setting"
import {useTagsViewStore} from "@/store/modules/tagsView"
const SettingStore = useSettingStore()
const TagsViewStore = useTagsViewStore()
const visitedViews = computed(() => TagsViewStore.visitedViews)
const refresh = () => {
SettingStore.setReload()
}
//
const closeCurrentTab = (event)=>{
closeSelectedTag(event,route)
}
//
const closeOtherTab= async ()=>{
const { name } = route
for(let item of visitedViews.value){
if(item.name!==name){
await closeSelectedTag(null,item)
}
}
}
//
const closeAllTab = async ()=>{
let visitedViews = await TagsViewStore.delAllViews()
await TagsViewStore.goHome()
}
</script>
<style lang="scss" scoped>
.more{
background-color: $primaryColor;
color: white;
.tags-view-item{
display: flex;
align-items: center;
}
}
</style>

View File

@ -1,329 +1,166 @@
<template> <template>
<div class="tags-wrap-container"> <div class="tags-wrap-container">
<div class="tags-view" ref="scrollContainer"> <div class="tags-view">
<better-scroll :options="{ scrollX: true, scrollY: false }" ref="bsScroll"> <el-tabs
<div class="tags-scroll-inner"> v-model="activeTabsValue"
<div type="card"
v-for="tag in visitedViews" @tab-click="tabClick"
:ref="setTagRef" @tab-remove="removeTab"
:path="tag.path" >
:data-id="tag.path" <el-tab-pane
:fullPath="tag.fullPath" v-for="item in visitedViews"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" :key="item.path"
:key="tag.path" :path="item.path"
class="item-tag-wrap" :label="item.title"
:class="isActive(tag) ? 'active' : ''" :name="item.path"
@click="routerGo(tag)" :closable="!(item.meta&&item.meta.affix)"
> >
<div class="tags-view-item">{{ tag.title }}</div> <template #label>
<el-icon <el-icon class="tabs-icon" v-if="item.icon">
v-if="!isAffix(tag)" <component :is="item.icon"></component>
@click.prevent.stop="(e) => closeSelectedTag(e, tag)" class="tag-icon"> </el-icon>
<circle-close-filled {{ item.title }}
/></el-icon> </template>
</div> </el-tab-pane>
</div> </el-tabs>
</better-scroll> </div>
<div class="right-btn">
<MoreButton/>
</div> </div>
<el-dropdown trigger="click">
<div class="item-tag-wrap more">
<div class="tags-view-item"> {{ $t("tagsView.more") }} <el-icon class="el-icon--right"><arrow-down /></el-icon></div>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="refresh">{{ $t("tagsView.refresh") }}</el-dropdown-item>
<el-dropdown-item @click="closeCurrentTab"> {{ $t("tagsView.closeCurrent") }}</el-dropdown-item>
<el-dropdown-item @click="closeOtherTab"> {{ $t("tagsView.closeOther") }}</el-dropdown-item>
<el-dropdown-item @click="closeAllTab"> {{ $t("tagsView.closeAll") }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue' import {computed, watch, ref, onMounted} from "vue";
import betterScroll from './betterScroll.vue' import { useRoute, useRouter } from "vue-router";
import { useRoute, useRouter } from 'vue-router' import { TabsPaneContext } from "element-plus";
import MoreButton from './components/MoreButton'
import path from 'path-browserify'
import {useTagsViewStore} from "@/store/modules/tagsView"
import {usePermissionStore} from "@/store/modules/permission"
import {useSettingStore} from "@/store/modules/setting" const route = useRoute()
import {useTagsViewStore} from "@/store/modules/tagsView" const router = useRouter()
import {usePermissionStore} from "@/store/modules/permission" const TagsViewStore = useTagsViewStore()
const PermissionStore = usePermissionStore()
const visitedViews = computed(() => TagsViewStore.visitedViews)
const routes = computed(() => PermissionStore.routes)
import path from 'path-browserify' const addTags = () => {
const route = useRoute() const { name } = route
const router = useRouter() if (name === 'Login') {
const SettingStore = useSettingStore() return
const TagsViewStore = useTagsViewStore()
const PermissionStore = usePermissionStore()
const refresh = () => {
SettingStore.setReload()
} }
if (name) {
const routes = computed(() => PermissionStore.routes) TagsViewStore.addView(route)
const visitedViews = computed(() => TagsViewStore.visitedViews)
const bsScroll = ref<Expose.BetterScroll>()
let obj = new WeakMap()
let affixTags = ref([])
const tags = ref(new Map())
// ref tag
const setTagRef = (el) => {
if (el) {
if (!obj.get(el)) {
tags.value.set(el.dataset['id'], el)
}
obj.set(el, el)
}
} }
return false
const rollPane = ref() }
const scrollContainer = ref() let affixTags = ref([])
function filterAffixTags(routes, basePath = '/') {
function filterAffixTags(routes, basePath = '/') { let tags = []
let tags = [] routes.forEach((route) => {
routes.forEach((route) => { if (route.meta && route.meta.affix) {
if (route.meta && route.meta.affix) { const tagPath = path.resolve(basePath, route.path)
const tagPath = path.resolve(basePath, route.path) tags.push({
tags.push({ fullPath: tagPath,
fullPath: tagPath, path: tagPath,
path: tagPath, name: route.name,
name: route.name, meta: { ...route.meta },
meta: { ...route.meta },
})
}
if (route.children) {
const tempTags = filterAffixTags(route.children, route.path)
if (tempTags.length >= 1) {
tags = [...tags, ...tempTags]
}
}
})
return tags
}
const initTags = () => {
let routesNew = routes.value
let affixTag = (affixTags.value = filterAffixTags(routesNew))
for (const tag of affixTag) {
if (tag.name) {
TagsViewStore.addVisitedView(tag)
}
}
}
const isActive = (rou) => {
return rou.path === route.path
}
const isAffix = (tag) => {
return tag.meta && tag.meta.affix
}
const addTags = () => {
const { name } = route
if (name === 'Login') {
return
}
if (name) {
TagsViewStore.addView(route)
}
return false
}
function toLastView(visitedViews, view) {
const latestView = visitedViews.slice(-1)[0]
if (latestView) {
router.push(latestView.fullPath)
} else {
if (view.name === 'home') {
router.replace({ path: '/redirect' + view.fullPath })
} else {
router.push('/')
}
}
}
const closeSelectedTag = async (event, view) => {
if (tags.value.get(view.path)) {
tags.value.delete(view.path)
}
let { visitedViews } = await TagsViewStore.delView(view)
if (isActive(view)) {
toLastView(visitedViews, view)
}
}
//
const closeCurrentTab = (event)=>{
closeSelectedTag(event,route)
}
//
const closeOtherTab= async ()=>{
const { name } = route
for(let item of visitedViews.value){
if(item.name!==name){
await closeSelectedTag(null,item)
}
}
}
//
const closeAllTab = async ()=>{
let visitedViews = await TagsViewStore.delAllViews()
toLastView(visitedViews,route)
}
const routerGo = (tag) => {
router.push({
path: tag.path,
query: tag.query,
})
}
function handleScrollAction(currentTag) {
const scrollContainerRect = scrollContainer.value.getBoundingClientRect()
let { left: currx, width: currentWidth } = currentTag.getBoundingClientRect()
const clientX = currx + currentWidth / 2
const currentX = clientX - scrollContainerRect.left
const deltaX = currentX - scrollContainerRect.width / 2
if (bsScroll.value) {
const { maxScrollX, x: leftX } = bsScroll.value.instance
const rightX = maxScrollX - leftX
const update = deltaX > 0 ? Math.max(-deltaX, rightX) : Math.min(-deltaX, -leftX)
bsScroll.value?.instance.scrollBy(update, 0, 300)
}
}
function moveToCurrentTag() {
nextTick(() => {
for (const [key, tag] of tags.value) {
let path = tag.attributes.path.value
if (path === route.path) {
let fullPath = tag.attributes.fullPath.value
//
handleScrollAction(tag, tags.value)
if (fullPath !== route.fullPath) {
TagsViewStore.updateVisitedView(route)
}
break
}
}
})
}
onMounted(() => {
initTags()
addTags()
nextTick(() => {
setTimeout(() => {
moveToCurrentTag()
}, 50)
})
watch(route, () => {
addTags()
nextTick(() => {
setTimeout(() => {
moveToCurrentTag()
}, 100)
}) })
}) }
if (route.children) {
router.beforeEach(async (to, from, next) => { const tempTags = filterAffixTags(route.children, route.path)
if ( if (tempTags.length >= 1) {
(from.fullPath === '/error/404' || from.fullPath === '/error/401') && tags = [...tags, ...tempTags]
to.fullPath === '/home'
) {
let whiteList = ['/error/404', '/error/401']
await TagsViewStore.removeView(whiteList)
} }
next() }
})
}) })
</script> return tags
}
const initTags = () => {
let routesNew = routes.value
let affixTag = (affixTags.value = filterAffixTags(routesNew))
for (const tag of affixTag) {
if (tag.name) {
TagsViewStore.addVisitedView(tag)
}
}
}
onMounted(()=>{
initTags()
addTags()
})
watch(route, () => {
addTags()
})
let tabIndex = 2
const activeTabsValue = computed({
get: () => {
return TagsViewStore.activeTabsValue;
},
set: val => {
TagsViewStore.setTabsMenuValue(val);
}
});
function toLastView(activeTabPath) {
let index = visitedViews.value.findIndex(item=>item.path===activeTabPath)
const nextTab = visitedViews.value[index + 1] || visitedViews.value[index - 1];
if (!nextTab) return;
router.push(nextTab.path);
TagsViewStore.addVisitedView(nextTab)
}
// Tab Click
const tabClick = (tabItem: TabsPaneContext) => {
let path = tabItem.props.name as string;
router.push(path);
};
const isActive = (path) => {
return path === route.path
}
const removeTab = async (activeTabPath: string) => {
if (isActive(activeTabPath)) {
toLastView(activeTabPath)
}
await TagsViewStore.delView(activeTabPath)
}
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
.tags-wrap-container { .tags-wrap-container{
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding-left: 10px; padding-left: 10px;
.tags-view { padding-right: 10px;
height: 30px; .right-btn{
background: white; height: 100%;
display: flex; flex-shrink: 0;
align-items: center;
flex: 1;
box-sizing: border-box;
overflow: hidden;
}
.refresh {
//margin-left: 20px;
cursor: pointer;
font-size: 22px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
.refresh-inner {
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 100%;
}
//box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
}
//padding-right: 10px;
} }
.item-tag-wrap { }
position: relative; .tags-view {
display: inline-flex; flex: 1;
align-items: center; overflow: hidden;
padding: 4px 12px; box-sizing: border-box;
font-size: 14px; }
cursor: pointer;
margin-right: 10px; .tags-view{
border: 1px solid #d8dce5; .el-tabs--card :deep(.el-tabs__header){
&.active .tag-icon { box-sizing: border-box;
display: block; height: 40px;
padding: 0 10px;
margin: 0;
}
:deep(.el-tabs){
.el-tabs__nav {
border: none;
} }
&.active { .el-tabs__header .el-tabs__item {
background-color: $primaryColor; border: none;
color: #fff; }
border-color: $primaryColor; .el-tabs__header .el-tabs__item.is-active {
} color: $primaryColor;
} border-bottom:2px solid $primaryColor;
.item-tag-wrap:hover {
border-color: $primaryColor;
}
.tags-scroll-inner {
display: flex;
flex-wrap: nowrap;
}
.tag-icon {
margin-left: 6px;
}
.tags-view-item {
position: relative;
z-index: 2;
white-space: nowrap;
font-size: 12px;
.tags-inner {
display: flex;
align-items: center;
white-space: nowrap;
}
}
.more{
background-color: $primaryColor;
color: white;
.tags-view-item{
display: flex;
align-items: center;
} }
} }
}
</style> </style>

View File

@ -8,7 +8,7 @@
hideSliderLayout: mode === 'horizontal', hideSliderLayout: mode === 'horizontal',
}" }"
> >
<div :style="{ height:`${showTag?80:50}px` }" v-if="SettingStore.themeConfig.fixedHeader"></div> <div :style="{ height:`${showTag?90:50}px` }" v-if="SettingStore.themeConfig.fixedHeader"></div>
<u-header /> <u-header />
<div class="m-container-content" :class="{ 'app-main-hide-tag': !showTag }"> <div class="m-container-content" :class="{ 'app-main-hide-tag': !showTag }">
<u-main /> <u-main />

View File

@ -17,7 +17,7 @@ router.beforeEach(async(to, from, next) => {
if(typeof(to.meta.title) === 'string'){ if(typeof(to.meta.title) === 'string'){
document.title = to.meta.title ||'vue-admin-perfect' document.title = to.meta.title ||'vue-admin-perfect'
} }
const UserStore = useUserStore(); const UserStore = useUserStore();
// 确定用户是否已登录过存在Token // 确定用户是否已登录过存在Token
const hasToken = UserStore.token const hasToken = UserStore.token
if (hasToken) { if (hasToken) {
@ -46,7 +46,6 @@ router.beforeEach(async(to, from, next) => {
next() next()
} else { } else {
next(`/login?redirect=${to.path}`) next(`/login?redirect=${to.path}`)
} }
} }
}) })

View File

@ -1,12 +1,10 @@
import { createRouter, createWebHistory, RouteRecordRaw,createWebHashHistory,Router } from 'vue-router' import { createRouter, createWebHistory, RouteRecordRaw,createWebHashHistory,Router } from 'vue-router'
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
// 扩展继承属性 // 扩展继承属性
interface extendRoute { interface extendRoute {
hidden?:boolean hidden?:boolean
} }
//
// 引入组件
import tableRouter from './modules/table' import tableRouter from './modules/table'
import dataScreenRouter from './modules/dataScreen' import dataScreenRouter from './modules/dataScreen'
import errorRouter from './modules/error' import errorRouter from './modules/error'
@ -21,22 +19,21 @@ import formRouter from './modules/from'
import zipRoutes from './modules/zip' import zipRoutes from './modules/zip'
import clipboardTable from './modules/clipboard' import clipboardTable from './modules/clipboard'
// 异步组件 // 异步组件
export const asyncRoutes = [ export const asyncRoutes = [
dataScreenRouter, ...dataScreenRouter,
chartsRouter, ...chartsRouter,
tableRouter, ...tableRouter,
formRouter, ...formRouter,
chatRouter, ...chatRouter,
othersRouter, ...othersRouter,
nestedRouter, ...nestedRouter,
excelRouter, ...excelRouter,
zipRoutes, ...zipRoutes,
errorRouter, ...errorRouter,
externalLink, ...externalLink,
clipboardTable, ...clipboardTable,
systemRouter, ...systemRouter,
{ {
path: '/:pathMatch(.*)', path: '/:pathMatch(.*)',
redirect: '/error/404' redirect: '/error/404'
@ -82,9 +79,6 @@ export const constantRoutes: Array<RouteRecordRaw&extendRoute> = [
}, },
] ]
const router = createRouter({ const router = createRouter({
// history: createWebHistory(process.env.BASE_URL), // history // history: createWebHistory(process.env.BASE_URL), // history
history: createWebHashHistory(), // hash history: createWebHashHistory(), // hash

View File

@ -2,7 +2,7 @@
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const chartsRouter = { const chartsRouter = [{
path: '/charts', path: '/charts',
component: Layout, component: Layout,
redirect: '/charts/migration', redirect: '/charts/migration',
@ -31,13 +31,13 @@ const chartsRouter = {
name: 'charts-complex', name: 'charts-complex',
meta: { title: '复杂图表', roles:['other'] , icon: 'MenuIcon'} meta: { title: '复杂图表', roles:['other'] , icon: 'MenuIcon'}
}, },
{ // {
path: 'animation', // path: 'animation',
component: () => import('@/views/charts/animation.vue'), // component: () => import('@/views/charts/animation.vue'),
name: 'charts-animation', // name: 'charts-animation',
meta: { title: '动画', roles:['other'],icon: 'MenuIcon' } // meta: { title: '动画', roles:['other'],icon: 'MenuIcon' }
}, // },
] ]
} }]
export default chartsRouter export default chartsRouter

View File

@ -2,7 +2,7 @@
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const chartsRouter = { const chartsRouter = [{
path: '/chat', path: '/chat',
component: Layout, component: Layout,
redirect: '/charts/index', redirect: '/charts/index',
@ -19,6 +19,6 @@ const chartsRouter = {
meta: { title: '聊天框', icon: 'chat-square' } meta: { title: '聊天框', icon: 'chat-square' }
}, },
] ]
} }]
export default chartsRouter export default chartsRouter

View File

@ -1,6 +1,6 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/index.vue'
const clipboardTable = { const clipboardTable = [{
path: '/clipboard', path: '/clipboard',
component: Layout, component: Layout,
redirect: '/clipboard/index', redirect: '/clipboard/index',
@ -19,5 +19,5 @@ const clipboardTable = {
}, },
] ]
} }]
export default clipboardTable export default clipboardTable

View File

@ -1,4 +1,4 @@
const dataScreenRouter= { const dataScreenRouter= [{
path: "/dataScreen", path: "/dataScreen",
name: "dataScreen", name: "dataScreen",
meta: { meta: {
@ -6,7 +6,7 @@ const dataScreenRouter= {
icon:'Histogram' icon:'Histogram'
}, },
component: () => import("@/views/dataScreen/index.vue") component: () => import("@/views/dataScreen/index.vue")
} }]
; ;
export default dataScreenRouter; export default dataScreenRouter;

View File

@ -4,7 +4,7 @@
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const errorRouter = { const errorRouter = [{
path: '/error', path: '/error',
component: Layout, component: Layout,
redirect: '/error/404', redirect: '/error/404',
@ -27,6 +27,6 @@ const errorRouter = {
meta: { title: '401', icon: 'MenuIcon'} meta: { title: '401', icon: 'MenuIcon'}
}, },
] ]
} }]
export default errorRouter export default errorRouter

View File

@ -4,7 +4,7 @@
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const excelRouter = { const excelRouter = [{
path: '/excel', path: '/excel',
component: Layout, component: Layout,
redirect: '/excel/export-excel', redirect: '/excel/export-excel',
@ -39,6 +39,6 @@ const excelRouter = {
meta: { title: '自定义样式导出 Excel', icon: 'MenuIcon' } meta: { title: '自定义样式导出 Excel', icon: 'MenuIcon' }
}, },
] ]
} }]
export default excelRouter export default excelRouter

View File

@ -2,7 +2,7 @@
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const externalLink = { const externalLink = [{
path: '/external-link', path: '/external-link',
component: Layout, component: Layout,
redirect: 'noRedirect', redirect: 'noRedirect',
@ -14,6 +14,6 @@ const externalLink = {
meta: { title: 'Github地址', icon: 'link' } meta: { title: 'Github地址', icon: 'link' }
}, },
] ]
} }]
export default externalLink export default externalLink

View File

@ -3,7 +3,7 @@
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const formRouter = { const formRouter = [{
path: '/form', path: '/form',
component: Layout, component: Layout,
redirect: '/form/validateForm', redirect: '/form/validateForm',
@ -27,6 +27,6 @@ const formRouter = {
meta: { title: '可收缩 Form', keepAlive: true , icon: 'MenuIcon'} meta: { title: '可收缩 Form', keepAlive: true , icon: 'MenuIcon'}
}, },
] ]
} }]
export default formRouter export default formRouter

View File

@ -4,7 +4,7 @@
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const nestedRouter = { const nestedRouter = [{
path: '/nested', path: '/nested',
component: Layout, component: Layout,
redirect: '/form/menu1', redirect: '/form/menu1',
@ -64,6 +64,6 @@ const nestedRouter = {
}, },
] ]
} }]
export default nestedRouter export default nestedRouter

View File

@ -2,7 +2,7 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/index.vue'
const othersRouter = { const othersRouter = [{
path: '/other', path: '/other',
component: Layout, component: Layout,
redirect: '/other/editor', redirect: '/other/editor',
@ -85,6 +85,6 @@ const othersRouter = {
meta: { title: '数字自增长', icon: 'MenuIcon' } meta: { title: '数字自增长', icon: 'MenuIcon' }
} }
] ]
} }]
export default othersRouter export default othersRouter

View File

@ -2,7 +2,7 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/index.vue'
const systemRouter = { const systemRouter = [{
path: '/system', path: '/system',
component: Layout, component: Layout,
redirect: '/system/page', redirect: '/system/page',
@ -37,6 +37,6 @@ const systemRouter = {
meta: { title: '菜单管理', roles: ['other'] , icon: 'MenuIcon'} meta: { title: '菜单管理', roles: ['other'] , icon: 'MenuIcon'}
}, },
] ]
} }]
export default systemRouter export default systemRouter

View File

@ -3,7 +3,7 @@
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const tableRouter = { const tableRouter = [{
path: '/table', path: '/table',
component: Layout, component: Layout,
redirect: '/table/comprehensive', redirect: '/table/comprehensive',
@ -38,6 +38,6 @@ const tableRouter = {
// meta: { title: '虚拟表格', keepAlive: true , icon: 'MenuIcon'} // meta: { title: '虚拟表格', keepAlive: true , icon: 'MenuIcon'}
// }, // },
] ]
} }]
export default tableRouter export default tableRouter

View File

@ -1,6 +1,6 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/index.vue'
const zipRoutes = { const zipRoutes = [{
path: '/zip', path: '/zip',
component: Layout, component: Layout,
isShow:true, isShow:true,
@ -21,7 +21,7 @@ const zipRoutes = {
}, },
] ]
} }]
export default zipRoutes export default zipRoutes

View File

@ -1,5 +1,5 @@
import {defineStore} from 'pinia' import {defineStore} from 'pinia'
import { asyncRoutes, constantRoutes } from '@/router/index' import { asyncRoutes, constantRoutes,routerArray } from '@/router/index'
import {hasPermission,filterAsyncRoutes} from "@/utils/routers" import {hasPermission,filterAsyncRoutes} from "@/utils/routers"
import {filterKeepAlive} from "../../utils/routers"; import {filterKeepAlive} from "../../utils/routers";
export const usePermissionStore = defineStore({ export const usePermissionStore = defineStore({
@ -24,7 +24,6 @@ export const usePermissionStore = defineStore({
// 生成路由 // 生成路由
generateRoutes(roles){ generateRoutes(roles){
return new Promise(resolve => { return new Promise(resolve => {
this.getCacheRoutes()
// 在这判断是否有权限,哪些角色拥有哪些权限 // 在这判断是否有权限,哪些角色拥有哪些权限
let accessedRoutes let accessedRoutes
if (roles&&roles.length&&!roles.includes('admin')) { if (roles&&roles.length&&!roles.includes('admin')) {
@ -45,6 +44,7 @@ export const usePermissionStore = defineStore({
}, },
getCacheRoutes(){ getCacheRoutes(){
this.cacheRoutes = filterKeepAlive(asyncRoutes) this.cacheRoutes = filterKeepAlive(asyncRoutes)
return this.cacheRoutes
} }
}, },

View File

@ -1,11 +1,13 @@
import {defineStore} from 'pinia' import {defineStore} from 'pinia'
import { useRouter } from "vue-router";
const router = useRouter()
export const useTagsViewStore = defineStore({ export const useTagsViewStore = defineStore({
// id: 必须的,在所有 Store 中唯一 // id: 必须的,在所有 Store 中唯一
id:'tagsViewState', id:'tagsViewState',
// state: 返回对象的函数 // state: 返回对象的函数
state: ()=>({ state: ()=>({
activeTabsValue:'/home',
visitedViews:[], visitedViews:[],
cachedViews:[], cachedViews:[],
@ -13,6 +15,9 @@ export const useTagsViewStore = defineStore({
getters: {}, getters: {},
// 可以同步 也可以异步 // 可以同步 也可以异步
actions:{ actions:{
setTabsMenuValue(val){
this.activeTabsValue = val
},
addView(view){ addView(view){
this.addVisitedView(view) this.addVisitedView(view)
}, },
@ -23,7 +28,9 @@ export const useTagsViewStore = defineStore({
}) })
}, },
addVisitedView(view){ addVisitedView(view){
this.setTabsMenuValue(view.path);
if (this.visitedViews.some(v => v.path === view.path)) return if (this.visitedViews.some(v => v.path === view.path)) return
this.visitedViews.push( this.visitedViews.push(
Object.assign({}, view, { Object.assign({}, view, {
title: view.meta.title || 'no-name' title: view.meta.title || 'no-name'
@ -32,11 +39,12 @@ export const useTagsViewStore = defineStore({
if (view.meta.keepAlive) { if (view.meta.keepAlive) {
this.cachedViews.push(view.name) this.cachedViews.push(view.name)
} }
}, },
delView(view){ delView(activeTabPath){
return new Promise(resolve => { return new Promise(resolve => {
this.delVisitedView(view) this.delVisitedView(activeTabPath)
this.delCachedView(view) this.delCachedView(activeTabPath)
resolve({ resolve({
visitedViews: [...this.visitedViews], visitedViews: [...this.visitedViews],
cachedViews: [...this.cachedViews] cachedViews: [...this.cachedViews]
@ -44,13 +52,13 @@ export const useTagsViewStore = defineStore({
}) })
}, },
delVisitedView(view){ delVisitedView(path){
return new Promise(resolve => { return new Promise(resolve => {
this.visitedViews = this.visitedViews.filter(v=>{ this.visitedViews = this.visitedViews.filter(v=>{
return (v.path !== view.path||v.meta.affix) return (v.path !== path||v.meta.affix)
}) })
this.cachedViews = this.cachedViews.filter(v=>{ this.cachedViews = this.cachedViews.filter(v=>{
return (v.path !== view.path||v.meta.affix) return (v.path !== path||v.meta.affix)
}) })
resolve([...this.visitedViews]) resolve([...this.visitedViews])
}) })
@ -74,6 +82,10 @@ export const useTagsViewStore = defineStore({
resolve([...this.visitedViews]) resolve([...this.visitedViews])
}) })
}, },
async goHome() {
router.push('/home');
this.activeTabsValue = '/home';
},
updateVisitedView(view){ updateVisitedView(view){
for (let v of this.visitedViews) { for (let v of this.visitedViews) {
if (v.path === view.path) { if (v.path === view.path) {

View File

@ -1,81 +0,0 @@
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

View File

@ -47,46 +47,5 @@
.breadcrumb-enter-from, .breadcrumb-enter-from,
.breadcrumb-leave-active { .breadcrumb-leave-active {
opacity: 0; opacity: 0;
transform: translateX(30px) skewX(-50deg); transform: translateX(10px) skewX(-10deg);
}
/* 面包屑动画 方案2 */
//.breadcrumb-enter-active,
//.breadcrumb-leave-active {
// transition: all 0.2s ease;
//}
//.breadcrumb-enter-from,
//.breadcrumb-leave-active {
// opacity: 0;
// transform: translateX(10px);
//}
//.breadcrumb-leave-active {
// position: absolute;
// z-index: -1;
//}
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all 0.2s ease;
}
.breadcrumb-enter-from,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(10px);
}
.breadcrumb-leave-active {
position: absolute;
z-index: -1;
}
.fade-transform-leave-active,
.fade-transform-enter-active {
transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1), border 0s;
}
.fade-transform-enter-from {
opacity: 0;
}
.fade-transform-leave-to {
opacity: 0;
} }

View File

@ -34,7 +34,7 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import CountTo from '@/components/u-count-to/vue-countTo.vue' import CountTo from '@/components/CountTo/index.vue'
import { nextTick, onMounted, ref } from 'vue' import { nextTick, onMounted, ref } from 'vue'
const mAnimation = ref<HTMLElement | null>() const mAnimation = ref<HTMLElement | null>()

View File

@ -5,33 +5,33 @@ export const cityIconData = [
value: [88.999903, 43.607078], value: [88.999903, 43.607078],
}, },
{ {
adcode: 150000, // adcode: 150000,
name: '内蒙古自治区', name: '内蒙古自治区',
value: [119.24787, 42.205741], value: [119.24787, 42.205741],
}, },
, ,
{ {
adcode: 150000, // adcode: 150000,
name: '内蒙古自治区', name: '内蒙古自治区',
value: [110.627161, 41.16628], value: [110.627161, 41.16628],
}, },
{ {
adcode: 540000, // adcode: 540000,
name: '西藏自治区', name: '西藏自治区',
value: [89.483714, 30.251951], value: [89.483714, 30.251951],
}, },
{ {
adcode: 630000, // adcode: 630000,
name: '青海省', name: '青海省',
value: [102.064693, 37.084008], value: [102.064693, 37.084008],
}, },
{ {
adcode: 530000, // adcode: 530000,
name: '云南省', name: '云南省',
value: [102.187665, 25.083688], value: [102.187665, 25.083688],
}, },
{ {
adcode: 610000, // adcode: 610000,
name: '陕西省', name: '陕西省',
value: [109.20663, 35.018625], value: [109.20663, 35.018625],
}, },

View File

@ -54,7 +54,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import {onBeforeUnmount, onMounted, ref} from 'vue' import {onBeforeUnmount, onMounted, ref} from 'vue'
import FullScreenContainer from './components/full-screen-container.vue' import FullScreenContainer from './components/full-screen-container.vue'
import CountTo from '@/components/u-count-to/vue-countTo.vue' import CountTo from '@/components/CountTo/index.vue'
import LineCharts from '@/views/charts/components/complex/line/index.vue' import LineCharts from '@/views/charts/components/complex/line/index.vue'
import BarCharts from '@/views/charts/components/complex/bar/index.vue' import BarCharts from '@/views/charts/components/complex/bar/index.vue'
import MigrationCharts from '@/views/charts/components/migration/index.vue' import MigrationCharts from '@/views/charts/components/migration/index.vue'
@ -98,7 +98,8 @@ onBeforeUnmount(()=>{
height: 1080px; height: 1080px;
box-sizing: border-box; box-sizing: border-box;
overflow:hidden; overflow:hidden;
background: url("/static/screen/bg.png") no-repeat center center; //background: url("/static/screen/bg.png") no-repeat center center;
background: #041c4a;
.header{ .header{
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;

View File

@ -57,7 +57,7 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="上传图片" prop="img"> <el-form-item label="上传图片" prop="img">
<u-upload v-model="ruleForm.img" /> <Upload v-model="ruleForm.img" />
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="desc"> <el-form-item label="备注" prop="desc">
<el-input v-model="ruleForm.desc" type="textarea" /> <el-input v-model="ruleForm.desc" type="textarea" />
@ -74,7 +74,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import UUpload from './components/Upload.vue' import Upload from './components/Upload.vue'
const formSize = ref('default') const formSize = ref('default')
const ruleFormRef = ref<FormInstance>() const ruleFormRef = ref<FormInstance>()

View File

@ -149,7 +149,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { User } from '@element-plus/icons-vue' import { User } from '@element-plus/icons-vue'
import { ref } from 'vue' import { ref } from 'vue'
import CountTo from '@/components/u-count-to/vue-countTo.vue' import CountTo from '@/components/CountTo/index.vue'
import BarCharts from '@/views/charts/components/simple/bar.vue' import BarCharts from '@/views/charts/components/simple/bar.vue'
const circleUrl = ref('https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png') const circleUrl = ref('https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png')

View File

@ -1,5 +1,5 @@
$dark_gray: #889aa4; $dark_gray: #889aa4;
::v-deep(input) { :deep(input) {
background: transparent; background: transparent;
border: 0; border: 0;
color: white; color: white;

View File

@ -89,7 +89,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import CountTo from '@/components/u-count-to/vue-countTo.vue' import CountTo from '@/components/CountTo/index.vue'
const example = ref() const example = ref()
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
let options = reactive({ let options = reactive({

View File

@ -13,7 +13,7 @@
label="标题" label="标题"
:rules="[{ required: true, message: '请输入内容', trigger: 'blur' }]" :rules="[{ required: true, message: '请输入内容', trigger: 'blur' }]"
> >
<u-wang-edior v-model="dynamicValidateForm.content" /> <wang-edior v-model="dynamicValidateForm.content" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="submitForm(formRef)">保存</el-button> <el-button type="primary" @click="submitForm(formRef)">保存</el-button>
@ -49,7 +49,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import UWangEdior from '@/components/u-wangEdior/index.vue' import WangEdior from '@/components/WangEdior/index.vue'
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'

View File

@ -7,7 +7,7 @@
<el-button type="primary" @click="print(3)">打印HTML</el-button> <el-button type="primary" @click="print(3)">打印HTML</el-button>
</div> </div>
<div style="margin-top: 20px"> <div style="margin-top: 20px">
<img :src="printImg" style="width: 300px" /> <img :src="logo" style="width: 200px" />
</div> </div>
<div id="tableBox"> <div id="tableBox">
<el-table :data="tableData" style="width: 100%"> <el-table :data="tableData" style="width: 100%">
@ -36,7 +36,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import printJS from 'print-js' import printJS from 'print-js'
import '@/utils/Print' import '@/utils/Print'
import printImg from '@/assets/image/im1.jpeg' import logo from '@/assets/logo.png'
const tableData = [ const tableData = [
{ {
@ -66,7 +66,7 @@
case 1: case 1:
printJS({ printJS({
type: 'image', type: 'image',
printable: [printImg], printable: [logo],
documentTitle: '打印图片', documentTitle: '打印图片',
}) })
break break

View File

@ -1,13 +1,13 @@
<template> <template>
<u-container-layout style="min-height: 300px"> <u-container-layout style="min-height: 300px">
<el-button @contextmenu.prevent="rightClick" style="width: 200px">右键菜单</el-button> <el-button @contextmenu.prevent="rightClick" style="width: 200px">右键菜单</el-button>
<u-right-click-menu :left="clientX" :top="clientY" @ok="operatingRightAction" :data="data" /> <RightClickMenu :left="clientX" :top="clientY" @ok="operatingRightAction" :data="data" />
</u-container-layout> </u-container-layout>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue' import { ref } from 'vue'
import URightClickMenu from '@/components/u-rightClickMenu/index.vue' import RightClickMenu from '@/components/RightClickMenu/index.vue'
const clientX = ref(0) const clientX = ref(0)
const clientY = ref(0) const clientY = ref(0)

View File

@ -25,7 +25,7 @@
<template #header> <template #header>
<span>多图片上传</span> <span>多图片上传</span>
</template> </template>
<u-upload @update="update" v-model="imgs" /> <Upload @update="update" v-model="imgs" />
</el-card> </el-card>
<el-card> <el-card>
@ -58,13 +58,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import UUpload from '@/components/u-upload/index.vue' import Upload from '@/components/Upload/index.vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import TwoPng from '@/assets/image/im1.jpeg' import logo from '@/assets/logo.png'
import { reactive, ref } from 'vue' import { ref } from 'vue'
const imgs = ref([ const imgs = ref([
{ {
url: TwoPng, url: logo,
name: 'female.png', name: 'female.png',
uid: '1651408956803', uid: '1651408956803',
status: 'success', status: 'success',

View File

@ -2,16 +2,15 @@ import { defineConfig,ConfigEnv, UserConfig,loadEnv } from 'vite'
import path from 'path' import path from 'path'
// vite.config.ts中无法使用import.meta.env 所以需要引入 // vite.config.ts中无法使用import.meta.env 所以需要引入
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
// 按需加载
// import AutoImport from 'unplugin-auto-import/vite'
// import Components from 'unplugin-vue-components/vite'
//import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
// 增加 vue文件 script name值 // 增加 vue文件 script name值
import vueSetupExtend from 'vite-plugin-vue-setup-extend' import vueSetupExtend from 'vite-plugin-vue-setup-extend'
// 生产gz文件 // 生产gz文件
import viteCompression from 'vite-plugin-compression' import viteCompression from 'vite-plugin-compression'
// 按需加载
// import AutoImport from 'unplugin-auto-import/vite'
// import Components from 'unplugin-vue-components/vite'
//import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
function resolve (dir) { function resolve (dir) {
return path.join(__dirname, '.', dir) return path.join(__dirname, '.', dir)
@ -19,7 +18,6 @@ function resolve (dir) {
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig(({ mode }: ConfigEnv): UserConfig => { export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
console.log('mode================',mode)
return { return {
plugins: [vue(), plugins: [vue(),
vueSetupExtend(), vueSetupExtend(),