mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-11-06 16:05:21 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd462e39e8 | ||
|
|
e8ac89dcd2 |
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="cached-tabs">
|
||||
<el-radio-group :model-value="activeTab" @change="select">
|
||||
<el-radio-button v-for="item in items" :key="item.value" :value="item.value" size="large">
|
||||
{{ item.label }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-card>
|
||||
<slot :active="activeTab" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useCachedTab } from '@/composables/useCachedTab';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
items: { value: string; label: string }[];
|
||||
defaultValue: string;
|
||||
cacheKey?: string;
|
||||
requestedValue?: string;
|
||||
}>(),
|
||||
{ cacheKey: 'default' },
|
||||
);
|
||||
const emit = defineEmits<{ activate: [value: string] }>();
|
||||
const pagePath = useRoute().path;
|
||||
const { activeTab, select } = useCachedTab({
|
||||
key: () => JSON.stringify([pagePath, props.cacheKey]),
|
||||
values: () => props.items.map((item) => item.value),
|
||||
defaultValue: () => props.defaultValue,
|
||||
requestedValue: () => props.requestedValue,
|
||||
onActivate: (value) => emit('activate', value),
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.cached-tabs {
|
||||
--el-card-padding: 0;
|
||||
|
||||
:deep(.el-radio-button__inner) {
|
||||
min-width: 100px;
|
||||
height: 100%;
|
||||
background-color: var(--panel-button-active) !important;
|
||||
box-shadow: none !important;
|
||||
outline: none !important;
|
||||
border: 2px solid transparent !important;
|
||||
}
|
||||
|
||||
:deep(.el-radio-button__original-radio:checked + .el-radio-button__inner) {
|
||||
color: $primary-color;
|
||||
border-color: $primary-color !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -50,7 +50,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { routerToNameWithQuery, routerToPathWithQuery } from '@/utils/router';
|
||||
import { openPage } from '@/utils/router';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { hasPermissionMetaAccess, hasRouteAccess } from '@/utils/rbac';
|
||||
@@ -96,8 +96,8 @@ const handleChange = async (label: string) => {
|
||||
const btn = buttonArray.value.find((btn) => btn.label === label);
|
||||
if (!btn) return;
|
||||
try {
|
||||
if (btn.path) await routerToPathWithQuery(btn.path, { uncached: 'true' });
|
||||
else if (btn.name) await routerToNameWithQuery(btn.name, { uncached: 'true' });
|
||||
if (btn.path) await openPage({ path: btn.path });
|
||||
else if (btn.name) await openPage({ name: btn.name });
|
||||
} finally {
|
||||
syncActiveName();
|
||||
}
|
||||
|
||||
@@ -5,21 +5,36 @@
|
||||
clearable
|
||||
v-model="searchInfo"
|
||||
@clear="search()"
|
||||
suffix-icon="Search"
|
||||
@change="search()"
|
||||
@keydown.enter.stop.prevent="search()"
|
||||
@blur="searchIfChanged()"
|
||||
:disabled="props.disabled"
|
||||
:placeholder="props.placeholder || $t('commons.button.search')"
|
||||
></el-input>
|
||||
>
|
||||
<template #suffix>
|
||||
<button
|
||||
type="button"
|
||||
class="search-submit"
|
||||
:disabled="props.disabled"
|
||||
:aria-label="$t('commons.button.search')"
|
||||
@mousedown.prevent
|
||||
@click="search()"
|
||||
>
|
||||
<el-icon><Search /></el-icon>
|
||||
</button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onActivated, ref, watch } from 'vue';
|
||||
import { Search } from '@element-plus/icons-vue';
|
||||
defineOptions({ name: 'TableSearch' });
|
||||
|
||||
const emit = defineEmits(['search', 'update:searchName']);
|
||||
const searchInfo = ref();
|
||||
let lastSearch: string | number | undefined;
|
||||
const props = defineProps({
|
||||
placeholder: String,
|
||||
disabled: {
|
||||
@@ -37,6 +52,7 @@ watch(
|
||||
(newVal) => {
|
||||
if (searchInfo.value !== newVal) {
|
||||
searchInfo.value = newVal;
|
||||
lastSearch = newVal;
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
@@ -47,7 +63,28 @@ onActivated(() => {
|
||||
});
|
||||
|
||||
const search = () => {
|
||||
if (props.disabled) return;
|
||||
lastSearch = searchInfo.value;
|
||||
emit('update:searchName', searchInfo.value);
|
||||
emit('search');
|
||||
};
|
||||
|
||||
const searchIfChanged = () => {
|
||||
if (searchInfo.value !== lastSearch) search();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.search-submit {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
.search-submit:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -175,6 +175,8 @@ import { useCardColumns } from './useCardColumns';
|
||||
import { useContextMenu } from './useContextMenu';
|
||||
import { useResponsivePagination } from './useResponsivePagination';
|
||||
import { useTableSelection } from './useTableSelection';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { usePaginationCache } from './usePaginationCache';
|
||||
const slots = useSlots();
|
||||
const attrs = useAttrs();
|
||||
const { isMobile, openMenuTabs, currentNode } = useGlobalStore();
|
||||
@@ -187,11 +189,16 @@ type ViewMode = 'table' | 'card';
|
||||
const props = defineProps({
|
||||
header: String,
|
||||
data: { type: Array as PropType<any[]>, default: () => [] },
|
||||
loading: { type: Boolean, default: false },
|
||||
selectionContext: { type: [String, Number, Array, Object, Function], default: undefined },
|
||||
paginationConfig: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
cachePagination: { type: Boolean, default: undefined },
|
||||
refreshOnRestore: { type: Boolean, default: true },
|
||||
cacheId: String,
|
||||
cacheScope: [String, Number],
|
||||
pageSizes: {
|
||||
type: Array as PropType<number[]>,
|
||||
default: () => [5, 10, 20, 50, 100, 200, 500],
|
||||
@@ -217,6 +224,15 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(['search', 'update:selects', 'update:paginationConfig', 'update:viewMode']);
|
||||
usePaginationCache({
|
||||
pagePath: useRoute().path,
|
||||
pagination: () => props.paginationConfig as { currentPage: number; pageSize: number; cacheSizeKey?: string },
|
||||
enabled: () => props.cachePagination,
|
||||
id: () => props.cacheId,
|
||||
scope: () => props.cacheScope,
|
||||
search: () => emit('search'),
|
||||
refreshOnRestore: () => props.refreshOnRestore,
|
||||
});
|
||||
const tableRef = ref();
|
||||
const complexTableRef = ref<HTMLElement>();
|
||||
const tableHeight = ref<number | string>('');
|
||||
@@ -343,10 +359,10 @@ const handleRightClick = (row, column, event) => {
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
() => [props.data, props.loading],
|
||||
() => {
|
||||
const pagination = props.paginationConfig;
|
||||
if (!pagination || !pagination.pageSize) return;
|
||||
if (props.loading || !pagination || !pagination.pageSize) return;
|
||||
const lastPage = Math.max(1, Math.ceil(pagination.total / pagination.pageSize));
|
||||
if (pagination.currentPage > lastPage) {
|
||||
pagination.currentPage = lastPage;
|
||||
@@ -361,7 +377,7 @@ function currentChange() {
|
||||
}
|
||||
|
||||
function sizeChange() {
|
||||
if (props.paginationConfig.cacheSizeKey) {
|
||||
if (props.cachePagination === false && props.paginationConfig.cacheSizeKey) {
|
||||
writePanelCache(
|
||||
'pagination',
|
||||
panelCacheKey(`size:${props.paginationConfig.cacheSizeKey}`),
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
import { nextTick, onActivated, onDeactivated, onScopeDispose, watch } from 'vue';
|
||||
import GlobalStore from '@/store/modules/global';
|
||||
import { panelCacheKey, readPanelCache, writePanelCache } from '@/utils/panel-cache';
|
||||
|
||||
interface Pagination {
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
cacheSizeKey?: string;
|
||||
}
|
||||
interface Options {
|
||||
pagePath: string;
|
||||
pagination: () => Pagination | undefined;
|
||||
enabled: () => boolean | undefined;
|
||||
id: () => string | undefined;
|
||||
scope: () => string | number | undefined;
|
||||
search: () => void;
|
||||
refreshOnRestore?: () => boolean;
|
||||
}
|
||||
|
||||
/** Restore during child setup, before the owning page's onMounted query. */
|
||||
export const usePaginationCache = (options: Options) => {
|
||||
const store = GlobalStore();
|
||||
const defaults = new WeakMap<Pagination, { currentPage: number; pageSize: number }>();
|
||||
let active = true;
|
||||
let restoring = false;
|
||||
let activeKey: string | undefined;
|
||||
let queued = false;
|
||||
let disposed = false;
|
||||
let pending: { key: string; currentPage: number; pageSize: number } | undefined;
|
||||
let writeQueued = false;
|
||||
const flush = () => {
|
||||
if (!pending) return;
|
||||
const { key: target, currentPage, pageSize } = pending;
|
||||
pending = undefined;
|
||||
writePanelCache('pagination', target, { currentPage, pageSize });
|
||||
};
|
||||
const requestSearch = () => {
|
||||
if (queued || !key()) return;
|
||||
queued = true;
|
||||
void nextTick(() => {
|
||||
queued = false;
|
||||
if (active && !disposed && key() && options.refreshOnRestore?.() !== false) options.search();
|
||||
});
|
||||
};
|
||||
const key = () => {
|
||||
const pagination = options.pagination();
|
||||
if (options.enabled() === false || !pagination || !store.cacheUserID) return undefined;
|
||||
return panelCacheKey(
|
||||
JSON.stringify([
|
||||
'table-pagination',
|
||||
options.pagePath,
|
||||
options.id() ?? pagination.cacheSizeKey ?? 'default',
|
||||
options.scope() ?? '',
|
||||
]),
|
||||
);
|
||||
};
|
||||
const positiveInteger = (value: unknown): value is number => Number.isInteger(value) && Number(value) > 0;
|
||||
const restore = () => {
|
||||
flush();
|
||||
activeKey = key();
|
||||
const pagination = options.pagination();
|
||||
if (!activeKey || !pagination) return false;
|
||||
if (!defaults.has(pagination)) {
|
||||
defaults.set(pagination, { currentPage: pagination.currentPage, pageSize: pagination.pageSize });
|
||||
}
|
||||
const initial = defaults.get(pagination)!;
|
||||
const saved = readPanelCache<Partial<Pagination>>('pagination', activeKey);
|
||||
const page = positiveInteger(saved?.currentPage) ? saved.currentPage : initial.currentPage;
|
||||
const size = positiveInteger(saved?.pageSize) ? saved.pageSize : initial.pageSize;
|
||||
const changed = pagination.currentPage !== page || pagination.pageSize !== size;
|
||||
restoring = true;
|
||||
try {
|
||||
pagination.pageSize = size;
|
||||
pagination.currentPage = page;
|
||||
} finally {
|
||||
restoring = false;
|
||||
}
|
||||
return changed;
|
||||
};
|
||||
// The initial restore deliberately does not emit: the parent owns its first query.
|
||||
restore();
|
||||
watch(
|
||||
() => [key(), options.pagination(), store.panelCache.pagination, store.panelCache.duration],
|
||||
() => {
|
||||
if (!active) return;
|
||||
const previousKey = activeKey;
|
||||
const changed = restore();
|
||||
if (activeKey && (changed || previousKey !== activeKey)) requestSearch();
|
||||
},
|
||||
{ flush: 'sync' },
|
||||
);
|
||||
watch(
|
||||
() => [options.pagination()?.currentPage, options.pagination()?.pageSize],
|
||||
([currentPage, pageSize]) => {
|
||||
// Never write old-page state under a newly selected node/account.
|
||||
if (!active || restoring || !activeKey || activeKey !== key()) return;
|
||||
if (!positiveInteger(currentPage) || !positiveInteger(pageSize)) return;
|
||||
pending = { key: activeKey, currentPage, pageSize };
|
||||
if (!writeQueued) {
|
||||
writeQueued = true;
|
||||
queueMicrotask(() => {
|
||||
writeQueued = false;
|
||||
flush();
|
||||
});
|
||||
}
|
||||
},
|
||||
{ flush: 'sync' },
|
||||
);
|
||||
onDeactivated(() => {
|
||||
flush();
|
||||
active = false;
|
||||
});
|
||||
onActivated(() => {
|
||||
if (active) return;
|
||||
active = true;
|
||||
restore();
|
||||
requestSearch();
|
||||
});
|
||||
onScopeDispose(() => {
|
||||
flush();
|
||||
disposed = true;
|
||||
active = false;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
import { nextTick, onActivated, onDeactivated, onMounted, onScopeDispose, readonly, ref, watch } from 'vue';
|
||||
import GlobalStore from '@/store/modules/global';
|
||||
import { panelCacheKey, readPanelCache, writePanelCache } from '@/utils/panel-cache';
|
||||
|
||||
interface CachedTabOptions {
|
||||
key: () => string;
|
||||
values: () => string[];
|
||||
defaultValue: () => string;
|
||||
requestedValue?: () => string | undefined;
|
||||
onActivate: (value: string) => unknown;
|
||||
}
|
||||
|
||||
export const useCachedTab = (options: CachedTabOptions) => {
|
||||
const store = GlobalStore();
|
||||
const activeTab = ref('');
|
||||
let active = true;
|
||||
let mounted = false;
|
||||
let version = 0;
|
||||
let restoredKey: string | undefined;
|
||||
const key = () => panelCacheKey(`inline-tabs:${options.key()}`);
|
||||
const valid = (value: unknown): value is string => typeof value === 'string' && options.values().includes(value);
|
||||
const restore = (useRequested = true) => {
|
||||
const requested = useRequested ? options.requestedValue?.() : undefined;
|
||||
const saved = readPanelCache<string>('tabs', key());
|
||||
restoredKey = key();
|
||||
activeTab.value = valid(requested)
|
||||
? requested
|
||||
: valid(saved)
|
||||
? saved
|
||||
: valid(options.defaultValue())
|
||||
? options.defaultValue()
|
||||
: options.values()[0] || '';
|
||||
};
|
||||
const activate = async () => {
|
||||
const current = ++version;
|
||||
await nextTick();
|
||||
if (current !== version || !active || !mounted || !valid(activeTab.value)) return;
|
||||
options.onActivate(activeTab.value);
|
||||
};
|
||||
const select = (value: string) => {
|
||||
if (!active || !valid(value) || value === activeTab.value) return;
|
||||
activeTab.value = value;
|
||||
writePanelCache('tabs', key(), value);
|
||||
void activate();
|
||||
};
|
||||
watch(
|
||||
[
|
||||
key,
|
||||
() => store.panelCache.tabs,
|
||||
() => store.panelCache.duration,
|
||||
() => JSON.stringify(options.values()),
|
||||
options.defaultValue,
|
||||
() => options.requestedValue?.(),
|
||||
],
|
||||
(values, previous) => {
|
||||
if (!active) return;
|
||||
// Reflecting the selected tab into the URL is not another selection.
|
||||
if (
|
||||
previous.length &&
|
||||
values.slice(0, 5).every((value, index) => value === previous[index]) &&
|
||||
values[5] === activeTab.value
|
||||
)
|
||||
return;
|
||||
// A URL left over from the previous node/account must not override its cache.
|
||||
restore(!previous.length || values[0] === previous[0]);
|
||||
if (mounted) void activate();
|
||||
},
|
||||
{ immediate: true, flush: 'sync' },
|
||||
);
|
||||
onMounted(() => {
|
||||
mounted = true;
|
||||
void activate();
|
||||
});
|
||||
onDeactivated(() => {
|
||||
active = false;
|
||||
version++;
|
||||
});
|
||||
onActivated(() => {
|
||||
if (active) return;
|
||||
active = true;
|
||||
restore(restoredKey === key());
|
||||
void activate();
|
||||
});
|
||||
onScopeDispose(() => {
|
||||
active = false;
|
||||
version++;
|
||||
});
|
||||
return { activeTab: readonly(activeTab), select };
|
||||
};
|
||||
@@ -15,7 +15,7 @@
|
||||
<el-menu
|
||||
v-else
|
||||
:default-active="activeMenu"
|
||||
:router="true"
|
||||
:router="false"
|
||||
:collapse="isCollapse"
|
||||
:collapse-transition="false"
|
||||
:unique-opened="!menuAccordion"
|
||||
|
||||
@@ -62,7 +62,7 @@ import TerminalDock from '@/components/terminal/dock/index.vue';
|
||||
import useResize from './hooks/useResize';
|
||||
import { MenuStore, TabsStore } from '@/store';
|
||||
import { getSystemAvailable } from '@/api/modules/setting';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { openMenu } from '@/utils/router';
|
||||
import { loadMasterProductProFromDB, loadProductProFromDB } from '@/utils/xpack';
|
||||
import { useTheme } from '@/global/use-theme';
|
||||
import TaskList from '@/components/task-list/index.vue';
|
||||
@@ -95,8 +95,6 @@ const openTask = () => {
|
||||
menuStore.setCollapse();
|
||||
}
|
||||
};
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const menuStore = MenuStore();
|
||||
|
||||
const tabsStore = TabsStore();
|
||||
@@ -151,9 +149,7 @@ watch(
|
||||
},
|
||||
);
|
||||
const handleMenuClick = async (path) => {
|
||||
await router.push({ path: path });
|
||||
tabsStore.addTab(route);
|
||||
tabsStore.activeTabPath = route.path;
|
||||
await openMenu(path);
|
||||
};
|
||||
|
||||
const toLogin = () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { panelCacheKey, readPanelCache, writePanelCache, removePanelCache, prunePanelCache } from '@/utils/panel-cache';
|
||||
import { panelCacheKey, writePanelCache, prunePanelCache } from '@/utils/panel-cache';
|
||||
import router from '@/routers/router';
|
||||
import NProgress from '@/config/nprogress';
|
||||
import { useGlobalStore } from '@/composables/useGlobalStore';
|
||||
@@ -11,7 +11,6 @@ import { TerminalDockSessionStore, TerminalSessionStore } from '@/store';
|
||||
|
||||
const axiosCanceler = new AxiosCanceler();
|
||||
|
||||
let isRedirecting = false;
|
||||
const enterpriseLicenseCheckWhiteList = ['EnterpriseLicenseRequired', 'entrance', 'login', 'Expired'];
|
||||
const noLoginWhiteList = ['entrance', 'login', 'file-share', '404', 'Expired'];
|
||||
|
||||
@@ -30,7 +29,7 @@ const clearLoginStatus = () => {
|
||||
TerminalDockSessionStore().closeAll();
|
||||
};
|
||||
|
||||
router.beforeEach(async (to, from) => {
|
||||
router.beforeEach(async (to) => {
|
||||
const { entrance, isEnterprise, isEnterpriseLicenseLoaded, isEnterpriseLicensed, isLogin, isOnRestart } =
|
||||
useGlobalStore();
|
||||
NProgress.start();
|
||||
@@ -103,34 +102,11 @@ router.beforeEach(async (to, from) => {
|
||||
if (to.name === 'Expired') {
|
||||
return true;
|
||||
}
|
||||
const activeMenuKey = panelCacheKey(String(to.meta.activeMenu || ''));
|
||||
// Compatibility for old links: explicit navigation no longer needs to clear a cache.
|
||||
if (to.query.uncached != undefined) {
|
||||
const query = { ...to.query };
|
||||
delete query.uncached;
|
||||
removePanelCache('tabs', activeMenuKey);
|
||||
return { path: to.path, query };
|
||||
}
|
||||
|
||||
const cachedRoute = readPanelCache<string>('tabs', activeMenuKey);
|
||||
if (
|
||||
to.meta.activeMenu &&
|
||||
to.meta.activeMenu != from.meta.activeMenu &&
|
||||
typeof cachedRoute === 'string' &&
|
||||
cachedRoute &&
|
||||
cachedRoute !== to.path &&
|
||||
!isRedirecting
|
||||
) {
|
||||
const cachedRouteInfo = router.resolve(cachedRoute);
|
||||
if (
|
||||
cachedRouteInfo.matched.length > 0 &&
|
||||
cachedRouteInfo.meta.activeMenu === to.meta.activeMenu &&
|
||||
hasRouteAccess(cachedRouteInfo)
|
||||
) {
|
||||
isRedirecting = true;
|
||||
NProgress.done();
|
||||
return cachedRoute;
|
||||
}
|
||||
removePanelCache('tabs', activeMenuKey);
|
||||
return { path: to.path, query, hash: to.hash };
|
||||
}
|
||||
|
||||
if (!hasRouteAccess(to)) {
|
||||
@@ -144,11 +120,10 @@ router.beforeEach(async (to, from) => {
|
||||
router.afterEach((to, _from, failure) => {
|
||||
prunePanelCache();
|
||||
if (failure) {
|
||||
isRedirecting = false;
|
||||
NProgress.done();
|
||||
return;
|
||||
}
|
||||
if (to.meta.activeMenu && !to.meta.ignoreTab && !isRedirecting) {
|
||||
if (to.meta.activeMenu && !to.meta.ignoreTab) {
|
||||
let notMathParam = true;
|
||||
if (to.matched.some((record) => record.path.includes(':'))) {
|
||||
notMathParam = false;
|
||||
@@ -166,7 +141,6 @@ router.afterEach((to, _from, failure) => {
|
||||
}
|
||||
}
|
||||
|
||||
isRedirecting = false;
|
||||
NProgress.done();
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { hasRouteAccess } from '@/utils/rbac';
|
||||
import i18n from '@/lang';
|
||||
import { MsgError } from '@/utils/message';
|
||||
import type { RouteLocationRaw } from 'vue-router';
|
||||
import { panelCacheKey, readPanelCache, removePanelCache } from '@/utils/panel-cache';
|
||||
|
||||
const pushWithAccessCheck = async (to: RouteLocationRaw) => {
|
||||
const resolvedRoute = router.resolve(to);
|
||||
@@ -15,24 +16,53 @@ const pushWithAccessCheck = async (to: RouteLocationRaw) => {
|
||||
tabStoreMiddleWare();
|
||||
};
|
||||
|
||||
/** Explicit navigation always opens the requested page, independent of tab caching. */
|
||||
export const openPage = pushWithAccessCheck;
|
||||
|
||||
/** Only module-menu entry points restore the last visited route within that module. */
|
||||
export const openMenu = async (to: RouteLocationRaw) => {
|
||||
let entry = router.resolve(to);
|
||||
const visited = new Set<string>();
|
||||
// Menu roots often redirect and only their destination declares activeMenu.
|
||||
while (!visited.has(entry.fullPath)) {
|
||||
visited.add(entry.fullPath);
|
||||
const redirect = entry.matched[entry.matched.length - 1]?.redirect;
|
||||
if (!redirect) break;
|
||||
entry = router.resolve(typeof redirect === 'function' ? redirect(entry, router.currentRoute.value) : redirect);
|
||||
}
|
||||
const menu = entry.meta.activeMenu;
|
||||
if (menu) {
|
||||
const key = panelCacheKey(String(menu));
|
||||
const cached = readPanelCache<unknown>('tabs', key);
|
||||
if (typeof cached === 'string') {
|
||||
const destination = router.resolve(cached);
|
||||
if (destination.matched.length && destination.meta.activeMenu === menu && hasRouteAccess(destination)) {
|
||||
return openPage(cached);
|
||||
}
|
||||
}
|
||||
if (cached !== undefined) removePanelCache('tabs', key);
|
||||
}
|
||||
return openPage(to);
|
||||
};
|
||||
|
||||
export const routerToName = async (name: string) => {
|
||||
await pushWithAccessCheck({ name: name });
|
||||
await openPage({ name: name });
|
||||
};
|
||||
|
||||
export const routerToPath = async (path: string) => {
|
||||
await pushWithAccessCheck({ path: path });
|
||||
await openPage({ path: path });
|
||||
};
|
||||
|
||||
export const routerToFileWithPath = async (pathItem: string) => {
|
||||
await pushWithAccessCheck({ name: 'File', query: { path: pathItem, uncached: 'true' } });
|
||||
await openPage({ name: 'File', query: { path: pathItem, uncached: 'true' } });
|
||||
};
|
||||
|
||||
export const routerToNameWithQuery = async (name: string, query: any) => {
|
||||
await pushWithAccessCheck({ name: name, query: query });
|
||||
await openPage({ name: name, query: query });
|
||||
};
|
||||
|
||||
export const routerToPathWithQuery = async (path: string, query: any) => {
|
||||
await pushWithAccessCheck({ path: path, query: query });
|
||||
await openPage({ path: path, query: query });
|
||||
};
|
||||
|
||||
export const jumpToPath = (router: any, path: string) => {
|
||||
@@ -40,7 +70,7 @@ export const jumpToPath = (router: any, path: string) => {
|
||||
};
|
||||
|
||||
export const routerToNameWithParams = async (name: string, params: any) => {
|
||||
await pushWithAccessCheck({ name: name, params: params });
|
||||
await openPage({ name: name, params: params });
|
||||
};
|
||||
|
||||
const tabStoreMiddleWare = () => {
|
||||
|
||||
@@ -139,11 +139,11 @@ export const bindSearchState = (key: () => string | undefined, fields: SearchFie
|
||||
|
||||
interface SearchStateOptions {
|
||||
scope?: () => string | number | undefined;
|
||||
onRevisit: () => unknown;
|
||||
onRevisit?: () => unknown;
|
||||
}
|
||||
|
||||
/** Keep queries across page visits and reload data when a cached page becomes active. */
|
||||
export const useSearchState = (page: string, fields: SearchFields, options: SearchStateOptions) => {
|
||||
export const useSearchState = (page: string, fields: SearchFields, options: SearchStateOptions = {}) => {
|
||||
const { cacheUserID } = storeToRefs(GlobalStore());
|
||||
const binding = bindSearchState(() => {
|
||||
const scope = options.scope?.();
|
||||
@@ -160,6 +160,6 @@ export const useSearchState = (page: string, fields: SearchFields, options: Sear
|
||||
onActivated(async () => {
|
||||
if (!deactivated) return;
|
||||
deactivated = false;
|
||||
if (await binding.resume()) return options.onRevisit();
|
||||
if (await binding.resume()) return options.onRevisit?.();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
v-if="!noApp"
|
||||
v-model:view-mode="viewMode"
|
||||
:data="items"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@search="search"
|
||||
>
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
<TableRefresh @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="items" @search="search()">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="items"
|
||||
@search="search()"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
<ComplexTable
|
||||
:data="connections"
|
||||
row-key="id"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="pagination"
|
||||
:columns="accountColumns"
|
||||
local-key="modelServiceColumn"
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
v-else-if="modelInstalled"
|
||||
:selection-context="() => [searchName]"
|
||||
row-key="id"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
@sort-change="search"
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
:selection-context="() => [searchName, activeTag, includeAppStore, props.filters]"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:view-mode="viewMode"
|
||||
v-model:selects="selects"
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="data"
|
||||
@sort-change="search"
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<ComplexTable
|
||||
:selection-context="() => [searchName]"
|
||||
row-key="id"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
:data="data"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
:data="data"
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<ComplexTable
|
||||
:selection-context="() => [searchName]"
|
||||
row-key="id"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
:data="data"
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<ComplexTable
|
||||
:selection-context="() => [searchName]"
|
||||
row-key="name"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
:data="data"
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
<ComplexTable
|
||||
:selection-context="() => [searchName, searchGroupID]"
|
||||
row-key="id"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:default-sort="
|
||||
paginationConfig.order !== 'null'
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
:selection-context="() => [searchInfo, group]"
|
||||
row-key="id"
|
||||
v-model:selects="selects"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="data"
|
||||
@search="search"
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
<ComplexTable
|
||||
v-if="currentDB"
|
||||
:class="{ mask: maskShow }"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@sort-change="search"
|
||||
@search="search"
|
||||
|
||||
@@ -10,7 +10,13 @@
|
||||
<TableSearch @search="search()" v-model:searchName="searchName" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@sort-change="search"
|
||||
@search="search"
|
||||
:data="data"
|
||||
>
|
||||
<el-table-column show-overflow-tooltip :label="$t('commons.table.name')" prop="name" sortable />
|
||||
<el-table-column :label="$t('database.version')" prop="version" />
|
||||
<el-table-column show-overflow-tooltip :label="$t('database.address')" prop="address" />
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
v-if="currentDB"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:class="{ mask: maskShow }"
|
||||
@sort-change="search"
|
||||
|
||||
@@ -10,7 +10,13 @@
|
||||
<TableSearch @search="search()" v-model:searchName="searchName" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@sort-change="search"
|
||||
@search="search"
|
||||
:data="data"
|
||||
>
|
||||
<el-table-column show-overflow-tooltip :label="$t('commons.table.name')" prop="name" sortable />
|
||||
<el-table-column show-overflow-tooltip :label="$t('database.address')" prop="address" />
|
||||
<el-table-column :label="$t('commons.login.username')" prop="username" />
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
<ComplexTable
|
||||
v-if="currentDB"
|
||||
:class="{ mask: maskShow }"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@sort-change="search"
|
||||
@search="search"
|
||||
|
||||
@@ -10,7 +10,13 @@
|
||||
<TableSearch @search="search()" v-model:searchName="searchName" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@sort-change="search"
|
||||
@search="search"
|
||||
:data="data"
|
||||
>
|
||||
<el-table-column show-overflow-tooltip :label="$t('commons.table.name')" prop="name" sortable />
|
||||
<el-table-column show-overflow-tooltip :label="$t('database.address')" prop="address" />
|
||||
<el-table-column :label="$t('commons.login.username')" prop="username" />
|
||||
|
||||
@@ -10,7 +10,13 @@
|
||||
<TableSearch @search="search()" v-model:searchName="searchName" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@sort-change="search"
|
||||
@search="search"
|
||||
:data="data"
|
||||
>
|
||||
<el-table-column show-overflow-tooltip :label="$t('commons.table.name')" prop="name" sortable />
|
||||
<el-table-column show-overflow-tooltip :label="$t('database.address')" prop="address" />
|
||||
<el-table-column :label="$t('commons.login.password')" prop="password">
|
||||
|
||||
@@ -506,6 +506,7 @@
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
class="file-table"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
:ref="(el) => setTableRef(item.id, el)"
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
<ComplexTable
|
||||
v-model:selects="selects"
|
||||
:data="containerPageRows"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:heightDiff="320"
|
||||
row-key="key"
|
||||
@@ -169,6 +170,7 @@
|
||||
v-model:selects="orphanSelects"
|
||||
v-loading="loading"
|
||||
:data="orphanPageRows"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="orphanPaginationConfig"
|
||||
row-key="policyUUID"
|
||||
max-height="calc(100vh - 220px)"
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
row.interface,
|
||||
])
|
||||
"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
@search="search"
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
<ComplexTable
|
||||
:selection-context="() => [searchName, selectedRuleFilters]"
|
||||
v-model:selects="selects"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="allRows"
|
||||
:heightDiff="320 + noticeHeight"
|
||||
|
||||
@@ -26,7 +26,13 @@
|
||||
</template>
|
||||
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" :heightDiff="400">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="data"
|
||||
@search="search"
|
||||
:heightDiff="400"
|
||||
>
|
||||
<el-table-column min-width="80" :label="$t('logs.loginIP')" prop="address" />
|
||||
<el-table-column min-width="60" :label="$t('ssh.belong')" prop="area" />
|
||||
<el-table-column min-width="60" :label="$t('commons.table.port')" prop="port" />
|
||||
|
||||
@@ -57,7 +57,13 @@
|
||||
<TableRefresh @search="resetAndLoadLogs" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :data="logs" :pagination-config="paginationConfig" @row-click="openDetail" :heightDiff="320">
|
||||
<ComplexTable
|
||||
:data="logs"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@row-click="openDetail"
|
||||
:heightDiff="320"
|
||||
>
|
||||
<el-table-column prop="time" :label="$t('commons.table.date')" width="220" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('logs.priority')" width="120">
|
||||
<template #default="{ row }">
|
||||
|
||||
@@ -21,7 +21,13 @@
|
||||
<TableSetting title="login-log-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" :heightDiff="330">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="data"
|
||||
@search="search"
|
||||
:heightDiff="330"
|
||||
>
|
||||
<el-table-column :label="$t('logs.loginIP')" prop="ip" />
|
||||
<el-table-column v-if="isEnterprise" :label="$t('commons.login.username')" prop="user" />
|
||||
<el-table-column :label="$t('logs.loginAddress')" prop="address" />
|
||||
|
||||
@@ -78,7 +78,13 @@
|
||||
<TableSetting title="operation-log-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" :heightDiff="330">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="data"
|
||||
@search="search"
|
||||
:heightDiff="330"
|
||||
>
|
||||
<el-table-column :label="$t('logs.resource')" prop="group" fix>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.source && row.source.indexOf('-') === -1">
|
||||
|
||||
@@ -16,7 +16,13 @@
|
||||
<TableSetting title="task-log-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" :heightDiff="330">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="data"
|
||||
@search="search"
|
||||
:heightDiff="330"
|
||||
>
|
||||
<el-table-column :label="$t('logs.taskName')" prop="name" min-width="180px">
|
||||
<template #default="{ row }">
|
||||
{{ translateTaskText(row.name) }}
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="data"
|
||||
:height-diff="380"
|
||||
|
||||
@@ -14,7 +14,12 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search()">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="data"
|
||||
@search="search()"
|
||||
>
|
||||
<el-table-column :label="$t('xpack.alert.alertMsg')" prop="message" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ formatMessage(row.alertDetail) }}
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
</el-alert>
|
||||
<ComplexTable
|
||||
class="mt-3"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="allConfigs"
|
||||
:empty-text="$t('commons.msg.noneData')"
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
</template>
|
||||
</el-alert>
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@sort-change="search"
|
||||
@search="search"
|
||||
|
||||
@@ -14,7 +14,13 @@
|
||||
<TableSetting title="backup-account-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@sort-change="search"
|
||||
@search="search"
|
||||
:data="data"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('license.authorizationId')"
|
||||
:min-width="80"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
<ComplexTable
|
||||
:selection-context="() => [searchName]"
|
||||
row-key="id"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
:data="data"
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
:data="data"
|
||||
@@ -114,11 +115,11 @@ const paginationConfig = reactive({
|
||||
order: 'ascending',
|
||||
});
|
||||
const info = ref();
|
||||
useSearchState(
|
||||
'terminal/command/index',
|
||||
{ search: info, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
|
||||
{ onRevisit: () => search() },
|
||||
);
|
||||
useSearchState('terminal/command/index', {
|
||||
search: info,
|
||||
page: toRef(paginationConfig, 'currentPage'),
|
||||
pageSize: toRef(paginationConfig, 'pageSize'),
|
||||
});
|
||||
const group = ref<string>('');
|
||||
const dialogRef = ref();
|
||||
const opRef = ref();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
:data="data"
|
||||
@@ -90,11 +91,11 @@ const paginationConfig = reactive({
|
||||
total: 0,
|
||||
});
|
||||
const info = ref();
|
||||
useSearchState(
|
||||
'terminal/host/index',
|
||||
{ search: info, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
|
||||
{ onRevisit: () => search() },
|
||||
);
|
||||
useSearchState('terminal/host/index', {
|
||||
search: info,
|
||||
page: toRef(paginationConfig, 'currentPage'),
|
||||
pageSize: toRef(paginationConfig, 'pageSize'),
|
||||
});
|
||||
const group = ref<string>('');
|
||||
|
||||
const opRef = ref();
|
||||
|
||||
@@ -1,35 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="router_card">
|
||||
<el-radio-group v-model="activeNames" @change="handleChange">
|
||||
<el-radio-button class="router_card_button" size="large" value="terminal">
|
||||
{{ $t('menu.terminal', 2) }}
|
||||
</el-radio-button>
|
||||
<el-radio-button v-if="isAdmin" class="router_card_button" size="large" value="host">
|
||||
{{ $t('terminal.host', 2) }}
|
||||
</el-radio-button>
|
||||
<el-radio-button class="router_card_button" size="large" value="command">
|
||||
{{ $t('terminal.quickCommand', 2) }}
|
||||
</el-radio-button>
|
||||
<el-radio-button v-if="isAdmin" class="router_card_button" size="large" value="setting">
|
||||
{{ $t('container.setting') }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-card>
|
||||
|
||||
<div v-show="activeNames === 'terminal'">
|
||||
<TerminalTab ref="terminalTabRef" />
|
||||
</div>
|
||||
<div v-if="isAdmin && activeNames === 'host'">
|
||||
<HostTab ref="hostTabRef" />
|
||||
</div>
|
||||
<div v-if="activeNames === 'command'">
|
||||
<CommandTab ref="commandTabRef" />
|
||||
</div>
|
||||
<div v-if="isAdmin && activeNames === 'setting'">
|
||||
<SettingTab ref="settingTabRef" />
|
||||
</div>
|
||||
</div>
|
||||
<CachedTabs
|
||||
:items="tabs"
|
||||
default-value="terminal"
|
||||
cache-key="terminal/main"
|
||||
:requested-value="route.path === '/terminal' && route.query.path ? 'terminal' : undefined"
|
||||
@activate="handleChange"
|
||||
>
|
||||
<template #default="{ active }">
|
||||
<div v-show="active === 'terminal'">
|
||||
<TerminalTab ref="terminalTabRef" />
|
||||
</div>
|
||||
<HostTab v-if="isAdmin && active === 'host'" ref="hostTabRef" />
|
||||
<CommandTab v-if="active === 'command'" ref="commandTabRef" />
|
||||
<SettingTab v-if="isAdmin && active === 'setting'" ref="settingTabRef" />
|
||||
</template>
|
||||
</CachedTabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -37,20 +22,29 @@ import HostTab from '@/views/terminal/host/index.vue';
|
||||
import CommandTab from '@/views/terminal/command/index.vue';
|
||||
import TerminalTab from '@/views/terminal/terminal/index.vue';
|
||||
import SettingTab from '@/views/terminal/setting/index.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import CachedTabs from '@/components/cached-tabs/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import { getTerminalInfo } from '@/api/modules/setting';
|
||||
import { TerminalStore } from '@/store';
|
||||
import { useGlobalStore } from '@/composables/useGlobalStore';
|
||||
|
||||
const terminalStore = TerminalStore();
|
||||
const { isAdmin } = useGlobalStore();
|
||||
const activeNames = ref<string>('terminal');
|
||||
const route = useRoute();
|
||||
const tabs = computed(() => [
|
||||
{ value: 'terminal', label: i18n.global.t('menu.terminal', 2) },
|
||||
...(isAdmin.value ? [{ value: 'host', label: i18n.global.t('terminal.host', 2) }] : []),
|
||||
{ value: 'command', label: i18n.global.t('terminal.quickCommand', 2) },
|
||||
...(isAdmin.value ? [{ value: 'setting', label: i18n.global.t('container.setting') }] : []),
|
||||
]);
|
||||
const hostTabRef = ref();
|
||||
const commandTabRef = ref();
|
||||
const terminalTabRef = ref();
|
||||
const settingTabRef = ref();
|
||||
|
||||
const handleChange = (tab: any) => {
|
||||
const handleChange = (tab: string) => {
|
||||
if (tab === 'host' && isAdmin.value) {
|
||||
hostTabRef.value?.acceptParams();
|
||||
}
|
||||
@@ -85,29 +79,5 @@ const loadTerminalSetting = async () => {
|
||||
|
||||
onMounted(() => {
|
||||
loadTerminalSetting();
|
||||
handleChange('terminal');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.router_card {
|
||||
--el-card-padding: 0;
|
||||
}
|
||||
|
||||
.router_card_button {
|
||||
:deep(.el-radio-button__inner) {
|
||||
min-width: 100px;
|
||||
height: 100%;
|
||||
background-color: var(--panel-button-active) !important;
|
||||
box-shadow: none !important;
|
||||
outline: none !important;
|
||||
border: 2px solid transparent !important;
|
||||
}
|
||||
|
||||
:deep(.el-radio-button__original-radio:checked + .el-radio-button__inner) {
|
||||
color: $primary-color;
|
||||
border-color: $primary-color !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
row-key="id"
|
||||
:class="{ mask: !clamStatus.isRunning }"
|
||||
v-if="!isSettingShow"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:scrollbar-always-on="isMobile"
|
||||
v-model:selects="selects"
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
@sort-change="search"
|
||||
|
||||
@@ -13,7 +13,13 @@
|
||||
<TableSetting title="dotnet-runtime-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="items" @search="search()" :heightDiff="260">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="items"
|
||||
@search="search()"
|
||||
:heightDiff="260"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
|
||||
@@ -13,7 +13,13 @@
|
||||
<TableSetting title="go-runtime-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="items" @search="search()" :heightDiff="260">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="items"
|
||||
@search="search()"
|
||||
:heightDiff="260"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
|
||||
@@ -13,7 +13,13 @@
|
||||
<TableSetting title="java-runtime-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="items" @search="search()" :heightDiff="260">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="items"
|
||||
@search="search()"
|
||||
:heightDiff="260"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
|
||||
@@ -13,7 +13,13 @@
|
||||
<TableSetting title="node-runtime-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="items" @search="search()" :heightDiff="260">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="items"
|
||||
@search="search()"
|
||||
:heightDiff="260"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
|
||||
@@ -21,7 +21,13 @@
|
||||
<TableSetting title="php-runtime-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="items" @search="search()" :heightDiff="260">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="items"
|
||||
@search="search()"
|
||||
:heightDiff="260"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
|
||||
@@ -13,7 +13,13 @@
|
||||
<TableSetting title="python-runtime-refresh" @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :pagination-config="paginationConfig" :data="items" @search="search()" :heightDiff="260">
|
||||
<ComplexTable
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:data="items"
|
||||
@search="search()"
|
||||
:heightDiff="260"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
|
||||
@@ -11,7 +11,13 @@
|
||||
<el-alert :title="$t('ssl.acmeHelper')" type="info" :closable="false" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()" v-loading="loading">
|
||||
<ComplexTable
|
||||
:data="data"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@search="search()"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('website.email')"
|
||||
fix
|
||||
|
||||
@@ -11,7 +11,13 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()" v-loading="loading">
|
||||
<ComplexTable
|
||||
:data="data"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@search="search()"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
show-overflow-tooltip
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()">
|
||||
<ComplexTable
|
||||
:data="data"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@search="search()"
|
||||
>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
fix
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<template #rightToolBar>
|
||||
<TableSearch @search="search()" v-model:searchName="req.domain" />
|
||||
<TableSearch @search="searchByDomain" v-model:searchName="req.domain" />
|
||||
<TableRefresh @search="search()" />
|
||||
<fu-table-column-select
|
||||
:columns="columns"
|
||||
@@ -36,6 +36,7 @@
|
||||
<template #main>
|
||||
<ComplexTable
|
||||
:data="data"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@search="search()"
|
||||
v-model:selects="selects"
|
||||
@@ -434,6 +435,11 @@ const search = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const searchByDomain = () => {
|
||||
paginationConfig.currentPage = 1;
|
||||
search();
|
||||
};
|
||||
|
||||
const updateDesc = (row: Website.SSLDTO, bulr: Function) => {
|
||||
bulr();
|
||||
if (row.description && row.description.length > 128) {
|
||||
|
||||
@@ -15,7 +15,13 @@
|
||||
<TableRefresh @search="search()" />
|
||||
</template>
|
||||
<template #main>
|
||||
<ComplexTable :data="data" :pagination-config="paginationConfig" @search="search()" v-loading="loading">
|
||||
<ComplexTable
|
||||
:data="data"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
@search="search()"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-table-column :label="$t('template.name')" prop="name" min-width="120px" show-overflow-tooltip />
|
||||
<el-table-column :label="$t('template.type')" prop="type" width="150px">
|
||||
<template #default="{ row }">
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
<ComplexTable
|
||||
:selection-context="() => [req.name, req.type, req.websiteGroupId]"
|
||||
row-key="id"
|
||||
:cache-pagination="false"
|
||||
:pagination-config="paginationConfig"
|
||||
:default-sort="tableSort.order ? tableSort : undefined"
|
||||
v-model:view-mode="viewMode"
|
||||
|
||||
Reference in New Issue
Block a user