merge(sj_1.0.0_beta4): 合并 sa 1.1.4

This commit is contained in:
xlsea 2024-06-07 11:24:30 +08:00
parent 734d5bf97d
commit d239e2f249
32 changed files with 1134 additions and 1368 deletions

View File

@ -14,5 +14,6 @@
"i18n-ally.localesPaths": ["src/locales/langs", "packages/work-flow/src/locales/langs"], "i18n-ally.localesPaths": ["src/locales/langs", "packages/work-flow/src/locales/langs"],
"prettier.enable": false, "prettier.enable": false,
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"unocss.root": ["./"] "unocss.root": ["./"],
"vue.server.hybridMode": true
} }

13
build/plugins/html.ts Normal file
View File

@ -0,0 +1,13 @@
import type { Plugin } from 'vite';
export function setupHtmlPlugin(buildTime: string) {
const plugin: Plugin = {
name: 'html-plugin',
apply: 'build',
transformIndexHtml(html) {
return html.replace('<head>', `<head>\n <meta name="buildTime" content="${buildTime}">`);
}
};
return plugin;
}

View File

@ -6,8 +6,9 @@ import progress from 'vite-plugin-progress';
import { setupElegantRouter } from './router'; import { setupElegantRouter } from './router';
import { setupUnocss } from './unocss'; import { setupUnocss } from './unocss';
import { setupUnplugin } from './unplugin'; import { setupUnplugin } from './unplugin';
import { setupHtmlPlugin } from './html';
export function setupVitePlugins(viteEnv: Env.ImportMeta) { export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) {
const plugins: PluginOption = [ const plugins: PluginOption = [
vue({ vue({
script: { script: {
@ -19,7 +20,8 @@ export function setupVitePlugins(viteEnv: Env.ImportMeta) {
setupElegantRouter(), setupElegantRouter(),
setupUnocss(viteEnv), setupUnocss(viteEnv),
...setupUnplugin(viteEnv), ...setupUnplugin(viteEnv),
progress() progress(),
setupHtmlPlugin(buildTime)
]; ];
return plugins; return plugins;

View File

@ -7,7 +7,7 @@ export default defineConfig(
'vue/multi-word-component-names': [ 'vue/multi-word-component-names': [
'warn', 'warn',
{ {
ignores: ['index', 'App', '[id]', '[url]'] ignores: ['index', 'App', 'Register', '[id]', '[url]']
} }
], ],
'vue/component-name-in-template-casing': [ 'vue/component-name-in-template-casing': [

View File

@ -57,7 +57,7 @@
"@sa/materials": "workspace:*", "@sa/materials": "workspace:*",
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"@sa/workflow": "workspace:*", "@sa/workflow": "workspace:*",
"@vueuse/core": "10.9.0", "@vueuse/core": "10.10.0",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"dayjs": "1.11.11", "dayjs": "1.11.11",
"echarts": "5.5.0", "echarts": "5.5.0",
@ -65,44 +65,45 @@
"naive-ui": "2.38.2", "naive-ui": "2.38.2",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"tailwind-merge": "^2.3.0",
"ts-md5": "1.3.1", "ts-md5": "1.3.1",
"vue": "3.4.27", "vue": "3.4.27",
"vue-codemirror6": "^1.3.0", "vue-codemirror6": "^1.3.0",
"vue-draggable-plus": "0.4.1", "vue-draggable-plus": "0.5.0",
"vue-i18n": "9.13.1", "vue-i18n": "9.13.1",
"vue-router": "4.3.2" "vue-router": "4.3.2"
}, },
"devDependencies": { "devDependencies": {
"@elegant-router/vue": "0.3.7", "@elegant-router/vue": "0.3.7",
"@iconify/json": "2.2.211", "@iconify/json": "2.2.216",
"@sa/scripts": "workspace:*", "@sa/scripts": "workspace:*",
"@sa/uno-preset": "workspace:*", "@sa/uno-preset": "workspace:*",
"@soybeanjs/eslint-config": "1.3.5", "@soybeanjs/eslint-config": "1.3.6",
"@types/lodash-es": "4.17.12", "@types/lodash-es": "4.17.12",
"@types/node": "20.12.12", "@types/node": "20.14.2",
"@types/nprogress": "0.2.3", "@types/nprogress": "0.2.3",
"@unocss/eslint-config": "0.60.2", "@unocss/eslint-config": "0.60.4",
"@unocss/preset-icons": "0.60.2", "@unocss/preset-icons": "0.60.4",
"@unocss/preset-uno": "0.60.2", "@unocss/preset-uno": "0.60.4",
"@unocss/transformer-directives": "0.60.2", "@unocss/transformer-directives": "0.60.4",
"@unocss/transformer-variant-group": "0.60.2", "@unocss/transformer-variant-group": "0.60.4",
"@unocss/vite": "0.60.2", "@unocss/vite": "0.60.4",
"@vitejs/plugin-vue": "5.0.4", "@vitejs/plugin-vue": "5.0.5",
"@vitejs/plugin-vue-jsx": "3.1.0", "@vitejs/plugin-vue-jsx": "4.0.0",
"eslint": "9.3.0", "eslint": "9.4.0",
"eslint-plugin-vue": "9.26.0", "eslint-plugin-vue": "9.26.0",
"lint-staged": "15.2.2", "lint-staged": "15.2.5",
"sass": "1.77.2", "sass": "1.77.4",
"simple-git-hooks": "2.11.1", "simple-git-hooks": "2.11.1",
"tsx": "4.10.5", "tsx": "4.12.0",
"typescript": "5.4.5", "typescript": "5.4.5",
"unplugin-icons": "0.19.0", "unplugin-icons": "0.19.0",
"unplugin-vue-components": "0.27.0", "unplugin-vue-components": "0.27.0",
"vite": "5.2.11", "vite": "5.2.12",
"vite-plugin-progress": "0.0.7", "vite-plugin-progress": "0.0.7",
"vite-plugin-svg-icons": "2.0.1", "vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-devtools": "7.2.0", "vite-plugin-vue-devtools": "7.2.1",
"vue-eslint-parser": "9.4.2", "vue-eslint-parser": "9.4.3",
"vue-tsc": "2.0.19" "vue-tsc": "2.0.19"
}, },
"simple-git-hooks": { "simple-git-hooks": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/axios", "name": "@sa/axios",
"version": "1.1.2", "version": "1.2.0",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },
@ -11,8 +11,8 @@
}, },
"dependencies": { "dependencies": {
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"axios": "1.6.8", "axios": "1.7.2",
"axios-retry": "4.2.0", "axios-retry": "4.4.0",
"qs": "6.12.1" "qs": "6.12.1"
}, },
"devDependencies": { "devDependencies": {

View File

@ -2,4 +2,4 @@
export const REQUEST_ID_KEY = 'X-Request-Id'; export const REQUEST_ID_KEY = 'X-Request-Id';
/** the backend error code key */ /** the backend error code key */
export const BACKEND_ERROR_CODE = 'BACKEND_ERROR'; export const BACKEND_ERROR_CODE = '0';

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/color", "name": "@sa/color",
"version": "1.1.2", "version": "1.2.0",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/hooks", "name": "@sa/hooks",
"version": "1.1.2", "version": "1.2.0",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/materials", "name": "@sa/materials",
"version": "1.1.2", "version": "1.2.0",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/fetch", "name": "@sa/fetch",
"version": "1.1.2", "version": "1.2.0",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/scripts", "name": "@sa/scripts",
"version": "1.1.2", "version": "1.2.0",
"bin": { "bin": {
"sa": "./bin.ts" "sa": "./bin.ts"
}, },
@ -13,7 +13,7 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@soybeanjs/changelog": "0.3.23", "@soybeanjs/changelog": "0.3.24",
"bumpp": "9.4.1", "bumpp": "9.4.1",
"c12": "1.10.0", "c12": "1.10.0",
"cac": "6.7.14", "cac": "6.7.14",

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/uno-preset", "name": "@sa/uno-preset",
"version": "1.1.2", "version": "1.2.0",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/utils", "name": "@sa/utils",
"version": "1.1.2", "version": "1.2.0",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

File diff suppressed because it is too large Load Diff

View File

@ -21,10 +21,10 @@ const columns = defineModel<NaiveUI.TableColumnCheck[]>('columns', {
{{ $t('common.columnSetting') }} {{ $t('common.columnSetting') }}
</NButton> </NButton>
</template> </template>
<VueDraggable v-model="columns"> <VueDraggable v-model="columns" :animation="150" filter=".none_draggable">
<div v-for="item in columns" :key="item.key" class="h-36px flex-y-center rd-4px hover:(bg-primary bg-opacity-20)"> <div v-for="item in columns" :key="item.key" class="h-36px flex-y-center rd-4px hover:(bg-primary bg-opacity-20)">
<icon-mdi-drag class="mr-8px cursor-move text-icon" /> <icon-mdi-drag class="mr-8px h-full cursor-move text-icon" />
<NCheckbox v-model:checked="item.checked"> <NCheckbox v-model:checked="item.checked" class="none_draggable flex-1">
{{ item.title }} {{ item.title }}
</NCheckbox> </NCheckbox>
</div> </div>

View File

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue';
import { createReusableTemplate } from '@vueuse/core';
import type { PopoverPlacement } from 'naive-ui'; import type { PopoverPlacement } from 'naive-ui';
import { twMerge } from 'tailwind-merge';
defineOptions({ defineOptions({
name: 'ButtonIcon', name: 'ButtonIcon',
@ -21,60 +20,29 @@ interface Props {
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
class: 'h-36px text-icon', class: '',
icon: '', icon: '',
tooltipContent: '', tooltipContent: '',
tooltipPlacement: 'bottom', tooltipPlacement: 'bottom',
zIndex: 98 zIndex: 98
}); });
interface ButtonProps { const DEFAULT_CLASS = 'h-[36px] text-icon';
className: string;
}
const [DefineButton, Button] = createReusableTemplate<ButtonProps>();
const cls = computed(() => {
let clsStr = props.class;
if (!clsStr.includes('h-')) {
clsStr += ' h-36px';
}
if (!clsStr.includes('text-')) {
clsStr += ' text-icon';
}
return clsStr;
});
</script> </script>
<template> <template>
<!-- define component start: Button --> <NTooltip :placement="tooltipPlacement" :z-index="zIndex" :disabled="!tooltipContent">
<DefineButton v-slot="{ $slots, className }">
<NButton quaternary :class="className">
<div class="flex-center gap-8px">
<component :is="$slots.default" />
</div>
</NButton>
</DefineButton>
<!-- define component end: Button -->
<NTooltip v-if="tooltipContent" :placement="tooltipPlacement" :z-index="zIndex">
<template #trigger> <template #trigger>
<Button :class-name="cls" v-bind="$attrs"> <NButton quaternary :class="twMerge(DEFAULT_CLASS, props.class)" v-bind="$attrs">
<slot> <div class="flex-center gap-8px">
<SvgIcon :icon="icon" /> <slot>
</slot> <SvgIcon :icon="icon" />
</Button> </slot>
</div>
</NButton>
</template> </template>
{{ tooltipContent }} {{ tooltipContent }}
</NTooltip> </NTooltip>
<Button v-else :class-name="cls" v-bind="$attrs">
<slot>
<SvgIcon :icon="icon" />
</slot>
</Button>
</template> </template>
<style scoped></style> <style scoped></style>

View File

@ -34,9 +34,9 @@ function search() {
} }
function handleClose() { function handleClose() {
visible.value = false;
// handle with setTimeout to prevent user from seeing some operations // handle with setTimeout to prevent user from seeing some operations
setTimeout(() => { setTimeout(() => {
visible.value = false;
resultOptions.value = []; resultOptions.value = [];
keyword.value = ''; keyword.value = '';
}, 200); }, 200);
@ -112,7 +112,7 @@ registerShortcut();
<div class="mt-20px"> <div class="mt-20px">
<NEmpty v-if="resultOptions.length === 0" :description="$t('common.noData')" /> <NEmpty v-if="resultOptions.length === 0" :description="$t('common.noData')" />
<SearchResult v-else v-model:path="activePath" :options="resultOptions" @enter.prevent="handleEnter" /> <SearchResult v-else v-model:path="activePath" :options="resultOptions" @enter="handleEnter" />
</div> </div>
<template #footer> <template #footer>
<SearchFooter v-if="!isMobile" /> <SearchFooter v-if="!isMobile" />

View File

@ -1,7 +1,11 @@
const local: App.I18n.Schema = { const local: App.I18n.Schema = {
system: { system: {
title: 'Snail Job', title: 'Snail Job',
desc: 'A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling.' desc: 'A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling.',
updateTitle: 'System Version Update Notification',
updateContent: 'A new version of the system has been detected. Do you want to refresh the page immediately?',
updateConfirm: 'Refresh immediately',
updateCancel: 'Later'
}, },
common: { common: {
action: 'Action', action: 'Action',

View File

@ -1,7 +1,11 @@
const local: App.I18n.Schema = { const local: App.I18n.Schema = {
system: { system: {
title: 'Snail Job', title: 'Snail Job',
desc: '灵活,可靠和快速的分布式任务重试和分布式任务调度平台' desc: '灵活,可靠和快速的分布式任务重试和分布式任务调度平台',
updateTitle: '系统版本更新通知',
updateContent: '检测到系统有新版本发布,是否立即刷新页面?',
updateConfirm: '立即刷新',
updateCancel: '稍后再说'
}, },
common: { common: {
action: '操作', action: '操作',

View File

@ -1,6 +1,6 @@
import { createApp } from 'vue'; import { createApp } from 'vue';
import './plugins/assets'; import './plugins/assets';
import { setupDayjs, setupIconifyOffline, setupLoading, setupNProgress } from './plugins'; import { setupAppVersionNotification, setupDayjs, setupIconifyOffline, setupLoading, setupNProgress } from './plugins';
import { setupStore } from './store'; import { setupStore } from './store';
import { setupRouter } from './router'; import { setupRouter } from './router';
import { setupI18n } from './locales'; import { setupI18n } from './locales';
@ -23,6 +23,8 @@ async function setupApp() {
setupI18n(app); setupI18n(app);
setupAppVersionNotification();
app.mount('#app'); app.mount('#app');
} }

53
src/plugins/app.ts Normal file
View File

@ -0,0 +1,53 @@
import { h } from 'vue';
import { NButton } from 'naive-ui';
import { $t } from '../locales';
export function setupAppVersionNotification() {
document.addEventListener('visibilitychange', async () => {
const buildTime = await getHtmlBuildTime();
if (buildTime !== BUILD_TIME && document.visibilityState === 'visible') {
const n = window.$notification?.create({
title: $t('system.updateTitle'),
content: $t('system.updateContent'),
action() {
return h('div', { style: { display: 'flex', justifyContent: 'end', gap: '12px', width: '325px' } }, [
h(
NButton,
{
onClick() {
n?.destroy();
}
},
$t('system.updateCancel')
),
h(
NButton,
{
type: 'primary',
onClick() {
location.reload();
}
},
$t('system.updateConfirm')
)
]);
}
});
}
});
}
async function getHtmlBuildTime() {
const baseURL = import.meta.env.VITE_BASE_URL;
const res = await fetch(`${baseURL}index.html`);
const html = await res.text();
const match = html.match(/<meta name="buildTime" content="(.*)">/);
const buildTime = match?.[1] || '';
return buildTime;
}

View File

@ -2,3 +2,4 @@ export * from './loading';
export * from './nprogress'; export * from './nprogress';
export * from './iconify'; export * from './iconify';
export * from './dayjs'; export * from './dayjs';
export * from './app';

View File

@ -48,7 +48,7 @@ export function createRouteGuard(router: Router) {
next({ name: rootRoute }); next({ name: rootRoute });
} }
}, },
// if is is constant route, then it is allowed to access directly // if it is constant route, then it is allowed to access directly
{ {
condition: !needLogin, condition: !needLogin,
callback: () => { callback: () => {
@ -97,6 +97,7 @@ export function createRouteGuard(router: Router) {
* @param to to route * @param to to route
*/ */
async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw | null> { async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw | null> {
const authStore = useAuthStore();
const routeStore = useRouteStore(); const routeStore = useRouteStore();
const notFoundRoute: RouteKey = 'not-found'; const notFoundRoute: RouteKey = 'not-found';
@ -130,6 +131,15 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
// the auth route is initialized // the auth route is initialized
// it is not the "not-found" route, then it is allowed to access // it is not the "not-found" route, then it is allowed to access
if (routeStore.isInitAuthRoute && !isNotFoundRoute) { if (routeStore.isInitAuthRoute && !isNotFoundRoute) {
// update user info
await authStore.updateUserInfo();
const { data, error } = await fetchVersion();
if (!error && data) {
localStg.set('version', data!);
} else {
localStg.remove('version');
}
return null; return null;
} }
// it is captured by the "not-found" route, then check whether the route exists // it is captured by the "not-found" route, then check whether the route exists
@ -165,19 +175,6 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
return location; return location;
} }
if (isLogin) {
if (to.path !== '/pwd-login') {
const authStore = useAuthStore();
await authStore.getInfo();
const { data, error } = await fetchVersion();
if (!error && data) {
localStg.set('version', data!);
} else {
localStg.remove('version');
}
}
}
// initialize the auth route // initialize the auth route
await routeStore.initAuthRoute(); await routeStore.initAuthRoute();

View File

@ -73,6 +73,7 @@ export const request = createFlatRequest<App.Service.Response, RequestInstanceSt
content: $t('request.logoutWithModalMsg'), content: $t('request.logoutWithModalMsg'),
positiveText: $t('common.confirm'), positiveText: $t('common.confirm'),
maskClosable: false, maskClosable: false,
closeOnEsc: false,
onPositiveClick() { onPositiveClick() {
request.state.isLogout = false; request.state.isLogout = false;
logoutAndCleanup(); logoutAndCleanup();

View File

@ -36,19 +36,15 @@ export function showErrorMsg(state: RequestInstanceState, message: string) {
state.errMsgStack = []; state.errMsgStack = [];
} }
const isExist = state.errMsgStack.includes(message); state.errMsgStack.push(message);
if (!isExist) { window.$message?.error(message, {
state.errMsgStack.push(message); onLeave: () => {
state.errMsgStack = state.errMsgStack.filter(msg => msg !== message);
window.$message?.error(message, { setTimeout(() => {
onLeave: () => { state.errMsgStack = [];
state.errMsgStack = state.errMsgStack.filter(msg => msg !== message); }, 5000);
}
setTimeout(() => { });
state.errMsgStack = [];
}, 5000);
}
});
}
} }

View File

@ -125,7 +125,7 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
// update tabs by locale // update tabs by locale
tabStore.updateTabsByLocale(); tabStore.updateTabsByLocale();
// sey dayjs locale // set dayjs locale
setDayjsLocale(locale.value); setDayjsLocale(locale.value);
}); });
}); });

View File

@ -9,7 +9,7 @@ import { localStg } from '@/utils/storage';
import { $t } from '@/locales'; import { $t } from '@/locales';
import { roleTypeRecord } from '@/constants/business'; import { roleTypeRecord } from '@/constants/business';
import { useRouteStore } from '../route'; import { useRouteStore } from '../route';
import { clearAuthStorage, getToken, getUserInfo } from './shared'; import { clearAuthStorage, getToken } from './shared';
export const useAuthStore = defineStore(SetupStoreId.Auth, () => { export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
const route = useRoute(); const route = useRoute();
@ -19,7 +19,17 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
const token = ref(getToken()); const token = ref(getToken());
const userInfo: Api.Auth.UserInfo = reactive(getUserInfo()); const userInfo: Api.Auth.UserInfo = reactive({
id: '',
userId: '',
mode: '',
role: 1,
username: '',
userName: '',
roles: [],
buttons: [],
namespaceIds: []
});
/** is super role in static route */ /** is super role in static route */
const isStaticSuper = computed(() => { const isStaticSuper = computed(() => {
@ -98,22 +108,32 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
localStg.set('userNamespace', userNamespace); localStg.set('userNamespace', userNamespace);
} }
// 2. get user info and update store
const pass = await updateUserInfo();
if (pass) {
token.value = loginToken.token;
return true;
}
return false;
}
async function updateUserInfo() {
const { data: info, error } = await fetchGetUserInfo(); const { data: info, error } = await fetchGetUserInfo();
if (!error) { if (!error) {
info!.userId = info?.id; // update store
info!.userName = info?.username; info!.userName = info?.username;
info!.roles = [roleTypeRecord[info.role]]; info!.roles = [roleTypeRecord[info.role]];
// 2. store user info
localStg.set('userInfo', info); localStg.set('userInfo', info);
// 3. update store
token.value = loginToken.token;
Object.assign(userInfo, info); Object.assign(userInfo, info);
return true; return true;
} }
await resetStore();
return false; return false;
} }
@ -124,21 +144,6 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
localStg.set('namespaceId', namespaceId); localStg.set('namespaceId', namespaceId);
} }
async function getInfo() {
const { data: info, error } = await fetchGetUserInfo();
if (!error) {
info!.userName = info?.username;
info!.roles = [roleTypeRecord[info.role]];
localStg.set('userInfo', info);
Object.assign(userInfo, info);
return true;
}
resetStore();
return false;
}
return { return {
token, token,
userInfo, userInfo,
@ -147,7 +152,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
loginLoading, loginLoading,
resetStore, resetStore,
login, login,
getInfo, updateUserInfo,
setNamespaceId setNamespaceId
}; };
}); });

View File

@ -97,13 +97,19 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
/** Cache routes */ /** Cache routes */
const cacheRoutes = ref<RouteKey[]>([]); const cacheRoutes = ref<RouteKey[]>([]);
/** All cache routes */
const allCacheRoutes = shallowRef<RouteKey[]>([]);
/** /**
* Get cache routes * Get cache routes
* *
* @param routes Vue routes * @param routes Vue routes
*/ */
function getCacheRoutes(routes: RouteRecordRaw[]) { function getCacheRoutes(routes: RouteRecordRaw[]) {
cacheRoutes.value = getCacheRouteNames(routes); const alls = getCacheRouteNames(routes);
cacheRoutes.value = alls;
allCacheRoutes.value = [...alls];
} }
/** /**
@ -130,12 +136,23 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
cacheRoutes.value.splice(index, 1); cacheRoutes.value.splice(index, 1);
} }
/**
* Is cached route
*
* @param routeKey
*/
function isCachedRoute(routeKey: RouteKey) {
return allCacheRoutes.value.includes(routeKey);
}
/** /**
* Re cache routes by route key * Re cache routes by route key
* *
* @param routeKey * @param routeKey
*/ */
async function reCacheRoutesByKey(routeKey: RouteKey) { async function reCacheRoutesByKey(routeKey: RouteKey) {
if (!isCachedRoute(routeKey)) return;
removeCacheRoutes(routeKey); removeCacheRoutes(routeKey);
await appStore.reloadPage(); await appStore.reloadPage();

View File

@ -252,6 +252,10 @@ declare namespace App {
system: { system: {
title: string; title: string;
desc: string; desc: string;
updateTitle: string;
updateContent: string;
updateConfirm: string;
updateCancel: string;
}; };
common: { common: {
action: string; action: string;

View File

@ -27,7 +27,7 @@ declare module 'vue-router' {
/** /**
* Is constant route * Is constant route
* *
* Does not need to login, and the route is defined in the front-end * when it is set to true, there will be no login verification and no permission verification to access the route
*/ */
constant?: boolean | null; constant?: boolean | null;
/** /**
@ -57,7 +57,10 @@ declare module 'vue-router' {
* the route is "user_detail", if it is set to "user_list", the menu "user_list" will be activated * the route is "user_detail", if it is set to "user_list", the menu "user_list" will be activated
*/ */
activeMenu?: import('@elegant-router/types').RouteKey | null; activeMenu?: import('@elegant-router/types').RouteKey | null;
/** By default, the same route path will use one tab, if set to true, it will use multiple tabs */ /**
* By default, the same route path will use one tab, even with different query, if set true, the route with
* different query will use different tabs
*/
multiTab?: boolean | null; multiTab?: boolean | null;
/** If set, the route will be fixed in tabs, and the value is the order of fixed tabs */ /** If set, the route will be fixed in tabs, and the value is the order of fixed tabs */
fixedIndexInTab?: number | null; fixedIndexInTab?: number | null;

View File

@ -25,7 +25,7 @@ export default defineConfig(configEnv => {
} }
} }
}, },
plugins: setupVitePlugins(viteEnv), plugins: setupVitePlugins(viteEnv, buildTime),
define: { define: {
BUILD_TIME: JSON.stringify(buildTime) BUILD_TIME: JSON.stringify(buildTime)
}, },