Commit b094eedf by 高源

状态保持优化及页面优化

parent 373f393e
# backend service base url, prod environment
VITE_SERVICE_BASE_URL='http://localhost:80'
VITE_SERVICE_BASE_URL=''
# other backend service base url, prod environment
VITE_OTHER_SERVICE_BASE_URL= `{
......
<!doctype html>
<html lang="zh-cmn-Hans">
<head>
<meta name="buildTime" content="2024-11-15 14:25:42">
<meta name="buildTime" content="2024-12-10 17:34:19">
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>VueDashboard</title>
<script type="module" crossorigin src="/Content/VueDashboardUi/VueDashboard1/assets/index-C21dpL_i.js"></script>
<link rel="stylesheet" crossorigin href="/Content/VueDashboardUi/VueDashboard1/assets/index-obeHIzyq.css">
<script type="module" crossorigin src="/Content/VueDashboardUi/VueDashboard1/assets/index-BMlV-6Dx.js"></script>
<link rel="stylesheet" crossorigin href="/Content/VueDashboardUi/VueDashboard1/assets/index-9k_B1ZU8.css">
</head>
<body>
<div id="app"></div>
......
......@@ -133,7 +133,8 @@ function getSiderCollapsedWidth() {
<GlobalSider />
</template>
<GlobalMenu />
<GlobalContent />
<GlobalContent style="display: none;" />
<div id="extjs-root" style="width: 100%; height: 100%"></div>
<ThemeDrawer />
<template #footer>
<GlobalFooter />
......
......@@ -45,7 +45,7 @@ function resetScroll() {
<KeepAlive :include="routeStore.cacheRoutes">
<component
:is="Component"
v-if="appStore.reloadFlag"
v-show="appStore.reloadFlag"
:key="tabStore.getTabIdByRoute(route)"
:class="{ 'p-16px': showPadding }"
class="flex-grow bg-layout transition-300"
......
......@@ -40,7 +40,7 @@ const { isFullscreen, toggle } = useFullscreen();
<div class="h-full flex-y-center justify-end">
<GlobalSearch />
<FullScreen v-if="!appStore.isMobile" :full="isFullscreen" @click="toggle" />
<LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" @change-lang="appStore.changeLocale" />
<!-- <LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" @change-lang="appStore.changeLocale" /> -->
<ThemeSchemaSwitch
:theme-schema="themeStore.themeScheme"
:is-dark="themeStore.darkMode"
......
......@@ -5,6 +5,9 @@ defineOptions({
name: 'GlobalLogo'
});
const DisplayName = window.uiGlobalConfig.DisplayName;
const Icon = window.uiGlobalConfig.Icon;
interface Props {
/** Whether to show the title */
showTitle?: boolean;
......@@ -17,9 +20,14 @@ withDefaults(defineProps<Props>(), {
<template>
<RouterLink to="/" class="w-full flex-center nowrap-hidden">
<SystemLogo class="text-32px text-primary" />
<!-- <SystemLogo class="text-32px text-primary" />
<h2 v-show="showTitle" class="pl-8px text-16px text-primary font-bold transition duration-300 ease-in-out">
{{ $t('system.title') }}
</h2> -->
<img v-if="Icon" :src="Icon" alt="" style="width: 32px" />
<SystemLogo v-else class="text-32px text-primary" />
<h2 v-show="showTitle" class="pl-8px text-16px text-primary font-bold transition duration-300 ease-in-out">
{{ DisplayName }}
</h2>
</RouterLink>
</template>
......
......@@ -16,7 +16,7 @@ import GlobalLogo from '../../global-logo/index.vue';
defineOptions({
name: 'VerticalMenuMix'
});
const DisplayName = window.uiGlobalConfig.DisplayName;
const route = useRoute();
const appStore = useAppStore();
const themeStore = useThemeStore();
......@@ -125,7 +125,7 @@ const renderIcon = (menuOption: any) => {
:style="{ width: showDrawer ? themeStore.sider.mixChildMenuWidth + 'px' : '0px' }"
>
<header class="flex-y-center justify-between px-12px" :style="{ height: themeStore.header.height + 'px' }">
<h2 class="text-16px text-primary font-bold">{{ $t('system.title') }}</h2>
<h2 class="text-16px text-primary font-bold">{{ DisplayName }}</h2>
<PinToggler
:pin="appStore.mixSiderFixed"
:class="{ 'text-white:88 !hover:text-white': inverted }"
......
......@@ -4,19 +4,21 @@ import { $t } from '@/locales';
import { useThemeStore } from '@/store/modules/theme';
import { themePageAnimationModeOptions, themeScrollModeOptions, themeTabModeOptions } from '@/constants/app';
import { translateOptions } from '@/utils/common';
import { useAuthStore } from '@/store/modules/auth';
import SettingItem from '../components/setting-item.vue';
defineOptions({
name: 'PageFun'
});
const authStore = useAuthStore();
const themeStore = useThemeStore();
themeStore.watermark.text = authStore.userInfo.FullName
const layoutMode = computed(() => themeStore.layout.mode);
const isMixLayoutMode = computed(() => layoutMode.value.includes('mix'));
const isWrapperScrollMode = computed(() => themeStore.layout.scrollMode === 'wrapper');
const DisplayName = window.uiGlobalConfig.DisplayName;
</script>
<template>
......@@ -104,7 +106,7 @@ const isWrapperScrollMode = computed(() => themeStore.layout.scrollMode === 'wra
<SettingItem v-if="themeStore.watermark" key="8" :label="$t('theme.watermark.visible')">
<NSwitch v-model:value="themeStore.watermark.visible" />
</SettingItem>
<SettingItem v-if="themeStore.watermark?.visible" key="8-1" :label="$t('theme.watermark.text')">
<SettingItem v-show="false" key="8-1" :label="$t('theme.watermark.text')">
<NInput
v-model:value="themeStore.watermark.text"
autosize
......
......@@ -8,7 +8,8 @@ export function setupLoading() {
const themeColor = localStg.get('themeColor') || '#646cff';
const { r, g, b } = getRgb(themeColor);
// const DisplayName = '123';
const DisplayName = window.uiGlobalConfig.DisplayName;
const primaryColor = `--primary-color: ${r} ${g} ${b}`;
const loadingClasses = [
......@@ -34,7 +35,7 @@ export function setupLoading() {
${dot}
</div>
</div>
<h2 class="text-28px font-500 text-#646464">${$t('system.title')}</h2>
<h2 class="text-28px font-500 text-#646464">${DisplayName}</h2>
</div>`;
const app = document.getElementById('app');
......
......@@ -5,6 +5,7 @@ import { getRootMenu } from '@/service/api';
import { generatedRoutes } from '../elegant/routes';
import { layouts, views } from '../elegant/imports';
import { transformElegantRoutesToVueRoutes } from '../elegant/transform';
import { truncate } from 'fs/promises';
/**
* custom routes
*
......
declare module 'vue3-sfc-loader' {
import type { Component } from 'vue';
interface Options {
moduleCache?: any;
getFile: (url: string) => Promise<string>;
addStyle: (textContent: string) => void;
log?: (type: string, ...args: any[]) => void;
}
export function loadModule(url: string, options: Options): Promise<Component>;
}
......@@ -18,7 +18,6 @@ declare module 'vue' {
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
IconLocalBanner: typeof import('~icons/local/banner')['default']
IconLocalLogo: typeof import('~icons/local/logo')['default']
IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
......@@ -28,7 +27,6 @@ declare module 'vue' {
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
NButton: typeof import('naive-ui')['NButton']
......@@ -48,8 +46,6 @@ declare module 'vue' {
NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup']
NInputNumber: typeof import('naive-ui')['NInputNumber']
NList: typeof import('naive-ui')['NList']
NListItem: typeof import('naive-ui')['NListItem']
NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
NMenu: typeof import('naive-ui')['NMenu']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
......@@ -62,7 +58,6 @@ declare module 'vue' {
NSwitch: typeof import('naive-ui')['NSwitch']
NTab: typeof import('naive-ui')['NTab']
NTabs: typeof import('naive-ui')['NTabs']
NThing: typeof import('naive-ui')['NThing']
NTooltip: typeof import('naive-ui')['NTooltip']
NWatermark: typeof import('naive-ui')['NWatermark']
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
......
<!-- eslint-disable no-console -->
<!-- eslint-disable @typescript-eslint/no-shadow -->
<script setup lang="ts">
import { onActivated, onMounted, ref } from 'vue';
import { onActivated, onMounted, ref, shallowRef } from 'vue';
import { loadModule } from 'vue3-sfc-loader';
import { getSelectMenu } from '@/service/api';
import NotFound from '@/views/_builtin/404/index.vue'; // 引入 404 组件
import ExtJsComponent from './extJs.vue';
import WebviewComponent from './webview.vue';
interface Props {
url: string;
......@@ -9,13 +14,19 @@ interface Props {
kvid: string;
type: string;
}
// 定义一个响应式变量来存储异步加载的组件
const asyncComponent = shallowRef<any>(null);
const { url, kvid, type } = defineProps<Props>();
const selectTag = ref(''); // 定义响应式变量
const extTag = ref(''); // 定义响应式变量
const hasError = ref(false); // 标志位,用于指示是否发生错误
onMounted(() => {
// console.log('mounted');
const origin = window.location.origin;
origin.split('/').slice(0, 3).join('/');
// loadExternalComponent(`${origin}/codet/testComponent.vue`);
// loadExternalComponent(`localhost:8081//src/views/_builtin/iframe-page/extJs.vue`);
});
onActivated(async () => {
......@@ -24,9 +35,12 @@ onActivated(async () => {
origin.split('/').slice(0, 3).join('/');
// const origin = 'http://localhost:80';
if (type === 'System') {
console.log(url);
if (url.startsWith('App')) {
selectTag.value = `${origin}/extjs6/classic/${url}`;
// selectTag.value = `${origin}/extjs6/classic/${url}`;
extTag.value = url;
} else {
selectTag.value = `${origin}/${url}`;
}
......@@ -40,7 +54,8 @@ onActivated(async () => {
if (selectMenu.Results[0].Handler !== undefined && selectMenu.Results[0].Handler.slice(0, 1) === '/') {
selectTag.value = `${origin}${selectMenu.Results[0].Handler}`;
} else {
selectTag.value = `${origin}/extjs6/classic/${selectMenu.Results[0].Handler}`;
// selectTag.value = `${origin}/extjs6/classic/${selectMenu.Results[0].Handler}`;
extTag.value = selectMenu.Results[0].Handler;
}
} else {
hasError.value = true; // 设置错误标志位
......@@ -49,16 +64,48 @@ onActivated(async () => {
hasError.value = true; // 如果请求失败,也设置错误标志位
}
}
// iframeList.value.push(selectTag.value);
// console.log(iframeList.value)
});
// 定义加载外部组件的函数
const loadExternalComponent = async (url: string) => {
const options = {
moduleCache: {
vue: await import('vue')
},
// eslint-disable-next-line @typescript-eslint/no-shadow
async getFile(url: string) {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to fetch ${url}`);
}
return await res.text();
},
addStyle(textContent: string) {
const style = document.createElement('style');
style.textContent = textContent;
document.head.appendChild(style);
},
log(type: string, ...args: any[]) {
console[type](...args);
}
};
// 使用 loadModule 加载外部组件
loadModule(url, options)
.then(component => {
asyncComponent.value = component;
console.log('Component loaded:', asyncComponent.value);
})
.catch(error => {
console.error('Error loading component:', error);
});
};
</script>
<template>
<div class="h-full">
<iframe v-show="!hasError" id="iframePage" class="size-full" :src="selectTag"></iframe>
<NotFound v-if="hasError" />
<!-- 使用引入的 404 组件 -->
<WebviewComponent v-if="selectTag && !hasError" id="iframePage" class="size-full" :url="selectTag"></WebviewComponent>
<ExtJsComponent v-else-if="extTag && !hasError" :key="extTag" :url="extTag"></ExtJsComponent>
<NotFound v-else />
</div>
</template>
......
<!-- MyComponent.vue -->
<script setup lang="ts">
import { nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue';
// 接收一个名为 url 的 prop
const props = defineProps<{
url: string;
}>();
let extComponent: any = null;
// 控制组件显示状态的变量
const isActive = ref(true);
const extjsContainerId = `extjs-${Math.random().toString(36).substr(2, 9)}`;
function initializeExtComponent() {
extComponent = Ext.create('Ext.panel.Panel', {
renderTo: extjsContainerId,
layout: 'fit',
width: '100%',
height: '100%',
hidden: false,
items: [Ext.create(props.url)]
});
}
function updateExtComponent(newUrl: string) {
if (extComponent) {
// 更新 ExtJS 组件的内容,而不销毁整个组件
// 这里假设您可以通过某种方式更新组件的内容
// 例如,替换面板中的子组件
// 获取当前的子组件
const oldItem = extComponent.items.getAt(0);
// 移除旧的子组件
extComponent.remove(oldItem, true); // 第二个参数为 true,表示销毁组件
// 创建新的子组件
const newItem = Ext.create(newUrl);
// 添加新的子组件到面板
extComponent.add(newItem);
}
}
onMounted(() => {
nextTick(() => {
if (!extComponent) {
initializeExtComponent();
} else {
extComponent.show();
isActive.value = true;
}
});
});
onActivated(() => {
// if (extComponent) {
// extComponent.show();
isActive.value = true;
// }
});
onDeactivated(() => {
// if (extComponent) {
// extComponent.hide();
isActive.value = false;
// }
});
onBeforeUnmount(() => {
if (extComponent) {
extComponent.destroy();
extComponent = null;
}
});
// 监听 props.url 的变化
watch(
() => props.url,
(newUrl, oldUrl) => {
if (newUrl !== oldUrl) {
updateExtComponent(newUrl);
}
}
);
</script>
<template>
<!-- 使用 Teleport 将 extjs-container 渲染到组件外部的 extjs-root 中 -->
<Teleport to="#extjs-root">
<div v-show="isActive" :id="extjsContainerId" style="width: 100%; height: 100%"></div>
</Teleport>
</template>
<style scoped>
/* 您的样式代码 */
</style>
<!-- eslint-disable vue/multi-word-component-names -->
<script setup lang="ts">
import { nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue';
// 接收一个名为 url 的 prop
const props = defineProps<{
url: string;
}>();
// 控制组件显示状态的变量
const isActive = ref(true);
// 生成唯一的容器 ID
const extjsContainerId = `webview-${Math.random().toString(36).substr(2, 9)}`;
// 用来存储创建的 iframe 元素引用
let iframeEl: HTMLIFrameElement | null = null;
function initializeExtComponent() {
const container = document.getElementById(extjsContainerId);
if (!container) return;
// 创建 iframe
iframeEl = document.createElement('iframe');
iframeEl.style.width = '100%';
iframeEl.style.height = '100%';
iframeEl.style.border = 'none';
iframeEl.src = props.url;
container.appendChild(iframeEl);
}
function updateExtComponent(newUrl: string) {
if (iframeEl) {
// 更新 iframe 的地址
iframeEl.src = newUrl;
}
}
onMounted(() => {
nextTick(() => {
// 初次挂载时创建 iframe
if (!iframeEl) {
initializeExtComponent();
} else {
isActive.value = true;
}
});
});
onActivated(() => {
isActive.value = true;
});
onDeactivated(() => {
isActive.value = false;
});
onBeforeUnmount(() => {
// 组件卸载前清理
const container = document.getElementById(extjsContainerId);
if (container && iframeEl) {
container.removeChild(iframeEl);
iframeEl = null;
}
});
// 监听 props.url 的变化,当地址变化时更新 iframe 的 src
watch(
() => props.url,
(newUrl, oldUrl) => {
if (newUrl !== oldUrl) {
updateExtComponent(newUrl);
}
}
);
</script>
<template>
<!-- 使用 Teleport 将容器渲染到组件外部的 extjs-root 中 -->
<Teleport to="#extjs-root">
<div v-show="isActive" :id="extjsContainerId" style="width: 100%; height: 100%"></div>
</Teleport>
</template>
<style scoped>
/* 您的样式代码 */
</style>
......@@ -21,7 +21,8 @@ const props = defineProps<Props>();
const appStore = useAppStore();
const themeStore = useThemeStore();
const DisplayName = window.uiGlobalConfig.DisplayName;
const Icon = window.uiGlobalConfig.Icon;
interface LoginModule {
label: string;
component: Component;
......@@ -56,13 +57,14 @@ const bgColor = computed(() => {
<NCard :bordered="false" class="relative z-4 w-auto rd-12px">
<div class="w-400px lt-sm:w-300px">
<header class="flex-y-center justify-between">
<SystemLogo class="text-64px text-primary lt-sm:text-48px" />
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ $t('system.title') }}</h3>
<img v-if="Icon" :src="Icon" alt="" style="width: 50px;" />
<SystemLogo v-else class="text-64px text-primary lt-sm:text-48px" />
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ DisplayName }}</h3>
<div class="i-flex-col">
<ThemeSchemaSwitch :theme-schema="themeStore.themeScheme" :show-tooltip="false"
class="text-20px lt-sm:text-18px" @switch="themeStore.toggleThemeScheme" />
<LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" :show-tooltip="false"
@change-lang="appStore.changeLocale" />
<!-- <LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" :show-tooltip="false"
@change-lang="appStore.changeLocale" /> -->
</div>
</header>
<main class="pt-24px">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment