
AI: 增加了AI前端绘制功能,可以根据描述生成客户端页面【授权用户专属】 自动化: 自动化模板采用了function模式,更加方便用户二次开发和自定义改动 自动化: 默认携带ID和CreatedAt排序 自动化: 所有自动化Select模板默认支持select搜索 优化:http交互报错信息增加防止多次弹出错误遮罩机制 ICON: 优化ICON逻辑,防止多次加载svg 布局:增加侧边分栏模式 布局: 顶栏模式样式优化和高亮逻辑调整 优化: 个人配置不再需要手动点击保存,会根据变化自动保存 BUG: 修复了菜单点击设为主页勾选被取消的bug 安全: 更新了jwt版本,修复CVE-2025-30204 导出: 默认支持软删除过滤 代码: 优化了部分代码逻辑 本次更新需要重新执行 npm i --------- Signed-off-by: joohwan <zhouhuan.chen@yunqutech.com > Co-authored-by: huiyifyj <jxfengyijie@gmail.com> Co-authored-by: piexlMax(奇淼 <qimiaojiangjizhao@gmail.com> Co-authored-by: okppop <okppop@protonmail.com> Co-authored-by: joohwan <zhouhuan.chen@yunqutech.com > Co-authored-by: xuedinge <781408517@qq.com>
115 lines
3.4 KiB
Vue
115 lines
3.4 KiB
Vue
<template>
|
|
<div
|
|
class="bg-gray-50 text-slate-700 dark:text-slate-500 dark:bg-slate-800 w-screen h-screen"
|
|
>
|
|
<el-watermark
|
|
v-if="config.show_watermark"
|
|
:font="font"
|
|
:z-index="9999"
|
|
:gap="[180, 150]"
|
|
class="absolute inset-0 pointer-events-none"
|
|
:content="userStore.userInfo.nickName"
|
|
/>
|
|
<gva-header />
|
|
<div class="flex flex-row w-full gva-container pt-16 box-border h-full">
|
|
<gva-aside
|
|
v-if="
|
|
config.side_mode === 'normal' || config.side_mode === 'sidebar' ||
|
|
(device === 'mobile' && config.side_mode == 'head') ||
|
|
(device === 'mobile' && config.side_mode == 'combination')
|
|
"
|
|
/>
|
|
<gva-aside
|
|
v-if="config.side_mode === 'combination' && device !== 'mobile'"
|
|
mode="normal"
|
|
/>
|
|
<div class="flex-1 px-2 w-0 h-full">
|
|
<gva-tabs v-if="config.showTabs" />
|
|
<div
|
|
class="overflow-auto"
|
|
:class="config.showTabs ? 'gva-container2' : 'gva-container pt-1'"
|
|
>
|
|
<router-view v-if="reloadFlag" v-slot="{ Component, route }">
|
|
<div
|
|
id="gva-base-load-dom"
|
|
class="gva-body-h bg-gray-50 dark:bg-slate-800"
|
|
>
|
|
<transition mode="out-in" :name="route.meta.transitionType || config.transition_type">
|
|
<keep-alive :include="routerStore.keepAliveRouters">
|
|
<component :is="Component" :key="route.fullPath" />
|
|
</keep-alive>
|
|
</transition>
|
|
</div>
|
|
</router-view>
|
|
<BottomInfo />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import GvaAside from '@/view/layout/aside/index.vue'
|
|
import GvaHeader from '@/view/layout/header/index.vue'
|
|
import useResponsive from '@/hooks/responsive'
|
|
import GvaTabs from './tabs/index.vue'
|
|
import BottomInfo from '@/components/bottomInfo/bottomInfo.vue'
|
|
import { emitter } from '@/utils/bus.js'
|
|
import { ref, onMounted, nextTick, reactive, watchEffect } from 'vue'
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
import { useRouterStore } from '@/pinia/modules/router'
|
|
import { useUserStore } from '@/pinia/modules/user'
|
|
import { useAppStore } from '@/pinia'
|
|
import { storeToRefs } from 'pinia'
|
|
import '@/style/transition.scss'
|
|
const appStore = useAppStore()
|
|
const { config, isDark, device } = storeToRefs(appStore)
|
|
|
|
defineOptions({
|
|
name: 'GvaLayout'
|
|
})
|
|
|
|
useResponsive(true)
|
|
const font = reactive({
|
|
color: 'rgba(0, 0, 0, .15)'
|
|
})
|
|
|
|
watchEffect(() => {
|
|
font.color = isDark.value ? 'rgba(255,255,255, .15)' : 'rgba(0, 0, 0, .15)'
|
|
})
|
|
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const routerStore = useRouterStore()
|
|
|
|
onMounted(() => {
|
|
// 挂载一些通用的事件
|
|
emitter.on('reload', reload)
|
|
if (userStore.loadingInstance) {
|
|
userStore.loadingInstance.close()
|
|
}
|
|
})
|
|
|
|
const userStore = useUserStore()
|
|
|
|
const reloadFlag = ref(true)
|
|
let reloadTimer = null
|
|
const reload = async () => {
|
|
if (reloadTimer) {
|
|
window.clearTimeout(reloadTimer)
|
|
}
|
|
reloadTimer = window.setTimeout(async () => {
|
|
if (route.meta.keepAlive) {
|
|
reloadFlag.value = false
|
|
await nextTick()
|
|
reloadFlag.value = true
|
|
} else {
|
|
const title = route.meta.title
|
|
router.push({ name: 'Reload', params: { title } })
|
|
}
|
|
}, 400)
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss"></style>
|