mirror of https://github.com/halo-dev/halo-admin
Merge branch 'main' into perf/username-validation
commit
8f79ece3a1
|
@ -78,6 +78,7 @@
|
|||
"transliteration": "^2.3.5",
|
||||
"vue": "^3.2.45",
|
||||
"vue-grid-layout": "3.0.0-beta1",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6",
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
|
|
|
@ -98,6 +98,7 @@ importers:
|
|||
vitest: ^0.25.3
|
||||
vue: ^3.2.45
|
||||
vue-grid-layout: 3.0.0-beta1
|
||||
vue-i18n: ^9.2.2
|
||||
vue-router: ^4.1.6
|
||||
vue-tsc: ^1.0.24
|
||||
vuedraggable: ^4.1.0
|
||||
|
@ -147,6 +148,7 @@ importers:
|
|||
transliteration: 2.3.5
|
||||
vue: 3.2.45
|
||||
vue-grid-layout: 3.0.0-beta1_farzh4kmmmdsqeu7trbjloi3zi
|
||||
vue-i18n: 9.2.2_vue@3.2.45
|
||||
vue-router: 4.1.6_vue@3.2.45
|
||||
vuedraggable: 4.1.0_vue@3.2.45
|
||||
devDependencies:
|
||||
|
@ -2632,6 +2634,44 @@ packages:
|
|||
resolution: {integrity: sha512-sZAW08CkqgvqRjUIaLRjScjObcCzN9D75yekLA21EClYAZIhi4A+GEt2z/WqOCOksTaEPLYmQyhkpXcboc0LhQ==}
|
||||
dev: false
|
||||
|
||||
/@intlify/core-base/9.2.2:
|
||||
resolution: {integrity: sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==}
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
'@intlify/devtools-if': 9.2.2
|
||||
'@intlify/message-compiler': 9.2.2
|
||||
'@intlify/shared': 9.2.2
|
||||
'@intlify/vue-devtools': 9.2.2
|
||||
dev: false
|
||||
|
||||
/@intlify/devtools-if/9.2.2:
|
||||
resolution: {integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==}
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
'@intlify/shared': 9.2.2
|
||||
dev: false
|
||||
|
||||
/@intlify/message-compiler/9.2.2:
|
||||
resolution: {integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==}
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
'@intlify/shared': 9.2.2
|
||||
source-map: 0.6.1
|
||||
dev: false
|
||||
|
||||
/@intlify/shared/9.2.2:
|
||||
resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==}
|
||||
engines: {node: '>= 14'}
|
||||
dev: false
|
||||
|
||||
/@intlify/vue-devtools/9.2.2:
|
||||
resolution: {integrity: sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==}
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
'@intlify/core-base': 9.2.2
|
||||
'@intlify/shared': 9.2.2
|
||||
dev: false
|
||||
|
||||
/@istanbuljs/schema/0.1.3:
|
||||
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -11029,6 +11069,19 @@ packages:
|
|||
- '@interactjs/utils'
|
||||
dev: false
|
||||
|
||||
/vue-i18n/9.2.2_vue@3.2.45:
|
||||
resolution: {integrity: sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==}
|
||||
engines: {node: '>= 14'}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
'@intlify/core-base': 9.2.2
|
||||
'@intlify/shared': 9.2.2
|
||||
'@intlify/vue-devtools': 9.2.2
|
||||
'@vue/devtools-api': 6.4.5
|
||||
vue: 3.2.45
|
||||
dev: false
|
||||
|
||||
/vue-resize/2.0.0-alpha.1_vue@3.2.45:
|
||||
resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==}
|
||||
peerDependencies:
|
||||
|
|
|
@ -36,6 +36,7 @@ const props = withDefaults(
|
|||
|
||||
const emit = defineEmits<{
|
||||
(event: "uploaded", response: SuccessResponse): void;
|
||||
(event: "error", file, response): void;
|
||||
}>();
|
||||
|
||||
const uppy = computed(() => {
|
||||
|
@ -72,6 +73,10 @@ uppy.value.on("upload-success", (_, response: SuccessResponse) => {
|
|||
emit("uploaded", response);
|
||||
});
|
||||
|
||||
uppy.value.on("upload-error", (file, _, response) => {
|
||||
emit("error", file, response);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uppy.value.close({ reason: "unmount" });
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
useRouter,
|
||||
type RouteRecordRaw,
|
||||
} from "vue-router";
|
||||
import { computed, onMounted, onUnmounted, ref } from "vue";
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import axios from "axios";
|
||||
import GlobalSearchModal from "@/components/global-search/GlobalSearchModal.vue";
|
||||
import LoginModal from "@/components/login/LoginModal.vue";
|
||||
|
@ -28,6 +28,8 @@ import { useRoleStore } from "@/stores/role";
|
|||
import { hasPermission } from "@/utils/permission";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
import { useScroll } from "@vueuse/core";
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
@ -189,6 +191,31 @@ const generateMenus = () => {
|
|||
};
|
||||
|
||||
onMounted(generateMenus);
|
||||
|
||||
// store scroll position
|
||||
const navbarScroller = ref();
|
||||
const { y } = useScroll(navbarScroller);
|
||||
|
||||
const useNavbarScrollStore = defineStore("navbar", {
|
||||
state: () => ({
|
||||
y: 0,
|
||||
}),
|
||||
});
|
||||
|
||||
const navbarScrollStore = useNavbarScrollStore();
|
||||
|
||||
watch(
|
||||
() => y.value,
|
||||
() => {
|
||||
navbarScrollStore.y = y.value;
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
y.value = navbarScrollStore.y;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -203,7 +230,7 @@ onMounted(generateMenus);
|
|||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<div ref="navbarScroller" class="flex-1 overflow-y-auto">
|
||||
<div class="px-3">
|
||||
<div
|
||||
class="flex cursor-pointer items-center rounded bg-gray-100 p-2 text-gray-400 transition-all hover:text-gray-900"
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { createI18n } from "vue-i18n";
|
||||
import zh from "./lang/zh";
|
||||
|
||||
const messages = {
|
||||
zh,
|
||||
};
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: "zh",
|
||||
messages,
|
||||
});
|
||||
|
||||
export default i18n;
|
|
@ -0,0 +1,73 @@
|
|||
const zh = {
|
||||
rbac: {
|
||||
"Attachments Management": "附件",
|
||||
"Attachment Manage": "附件管理",
|
||||
"Attachment View": "附件查看",
|
||||
"role-template-view-attachments": "附件查看",
|
||||
|
||||
"Comments Management": "评论",
|
||||
"Comment Manage": "评论管理",
|
||||
"Comment View": "评论查看",
|
||||
"role-template-view-comments": "评论查看",
|
||||
|
||||
"ConfigMaps Management": "配置",
|
||||
"ConfigMap Manage": "配置管理",
|
||||
"ConfigMap View": "配置查看",
|
||||
"role-template-view-configmaps": "配置查看",
|
||||
|
||||
"Menus Management": "菜单",
|
||||
"Menu Manage": "菜单管理",
|
||||
"Menu View": "菜单查看",
|
||||
"role-template-view-menus": "菜单查看",
|
||||
|
||||
"Permissions Management": "权限",
|
||||
"Permissions Manage": "权限管理",
|
||||
"Permissions View": "权限查看",
|
||||
"role-template-view-permissions": "权限查看",
|
||||
"role-template-manage-permissions": "权限管理",
|
||||
|
||||
"Plugins Management": "插件",
|
||||
"Plugin Manage": "插件管理",
|
||||
"Plugin View": "插件查看",
|
||||
"role-template-view-plugins": "插件查看",
|
||||
|
||||
"Posts Management": "文章",
|
||||
"Post Manage": "文章管理",
|
||||
"Post View": "文章查看",
|
||||
"role-template-view-posts": "文章查看",
|
||||
"role-template-manage-snaphosts": "版本管理",
|
||||
"role-template-view-snaphosts": "版本查看",
|
||||
"role-template-manage-tags": "标签管理",
|
||||
"role-template-view-tags": "标签查看",
|
||||
"role-template-manage-categories": "分类管理",
|
||||
"role-template-view-categories": "分类查看",
|
||||
|
||||
"Roles Management": "角色",
|
||||
"Role Manage": "角色管理",
|
||||
"Role View": "角色查看",
|
||||
"role-template-view-roles": "角色查看",
|
||||
|
||||
"Settings Management": "设置表单",
|
||||
"Setting Manage": "设置表单管理",
|
||||
"Setting View": "设置表单查看",
|
||||
"role-template-view-settings": "设置表单查看",
|
||||
|
||||
"SinglePages Management": "页面",
|
||||
"SinglePage Manage": "页面管理",
|
||||
"SinglePage View": "页面查看",
|
||||
"role-template-view-singlepages": "页面查看",
|
||||
|
||||
"Themes Management": "主题",
|
||||
"Theme Manage": "主题管理",
|
||||
"Theme View": "主题查看",
|
||||
"role-template-view-themes": "主题查看",
|
||||
|
||||
"Users Management": "用户",
|
||||
"User manage": "用户管理",
|
||||
"User View": "用户查看",
|
||||
"role-template-view-users": "用户查看",
|
||||
"role-template-change-password": "修改密码",
|
||||
},
|
||||
};
|
||||
|
||||
export default zh;
|
|
@ -20,12 +20,14 @@ import { useThemeStore } from "./stores/theme";
|
|||
import { useSystemStatesStore } from "./stores/system-states";
|
||||
import { useUserStore } from "./stores/user";
|
||||
import { useSystemConfigMapStore } from "./stores/system-configmap";
|
||||
import i18n from "./locales";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
setupComponents(app);
|
||||
|
||||
app.use(createPinia());
|
||||
app.use(i18n);
|
||||
|
||||
function registerModule(pluginModule: PluginModule, core: boolean) {
|
||||
if (pluginModule.components) {
|
||||
|
|
|
@ -347,37 +347,37 @@ function handleClearKeyword() {
|
|||
</template>
|
||||
<template #start>
|
||||
<VEntityField :title="post.post.spec.title" width="27rem">
|
||||
<template #extra>
|
||||
<VSpace class="mt-1 sm:mt-0">
|
||||
<PostTag
|
||||
v-for="(tag, tagIndex) in post.tags"
|
||||
:key="tagIndex"
|
||||
:tag="tag"
|
||||
route
|
||||
></PostTag>
|
||||
</VSpace>
|
||||
</template>
|
||||
<template #description>
|
||||
<VSpace class="flex-wrap !gap-y-1">
|
||||
<p
|
||||
v-if="post.categories.length"
|
||||
class="inline-flex flex-wrap gap-1 text-xs text-gray-500"
|
||||
>
|
||||
分类:<span
|
||||
v-for="(category, categoryIndex) in post.categories"
|
||||
:key="categoryIndex"
|
||||
class="cursor-pointer hover:text-gray-900"
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<VSpace class="flex-wrap !gap-y-1">
|
||||
<p
|
||||
v-if="post.categories.length"
|
||||
class="inline-flex flex-wrap gap-1 text-xs text-gray-500"
|
||||
>
|
||||
{{ category.spec.displayName }}
|
||||
分类:<span
|
||||
v-for="(category, categoryIndex) in post.categories"
|
||||
:key="categoryIndex"
|
||||
class="cursor-pointer hover:text-gray-900"
|
||||
>
|
||||
{{ category.spec.displayName }}
|
||||
</span>
|
||||
</p>
|
||||
<span class="text-xs text-gray-500">
|
||||
访问量 {{ post.stats.visit || 0 }}
|
||||
</span>
|
||||
</p>
|
||||
<span class="text-xs text-gray-500">
|
||||
访问量 {{ post.stats.visit || 0 }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500">
|
||||
评论 {{ post.stats.totalComment || 0 }}
|
||||
</span>
|
||||
</VSpace>
|
||||
<span class="text-xs text-gray-500">
|
||||
评论 {{ post.stats.totalComment || 0 }}
|
||||
</span>
|
||||
</VSpace>
|
||||
<VSpace v-if="post.tags.length" class="flex-wrap">
|
||||
<PostTag
|
||||
v-for="(tag, tagIndex) in post.tags"
|
||||
:key="tagIndex"
|
||||
:tag="tag"
|
||||
route
|
||||
></PostTag>
|
||||
</VSpace>
|
||||
</div>
|
||||
</template>
|
||||
</VEntityField>
|
||||
</template>
|
||||
|
|
|
@ -783,12 +783,6 @@ const hasFilters = computed(() => {
|
|||
>
|
||||
<VStatusDot state="success" animate />
|
||||
</RouterLink>
|
||||
<PostTag
|
||||
v-for="(tag, tagIndex) in post.tags"
|
||||
:key="tagIndex"
|
||||
:tag="tag"
|
||||
route
|
||||
></PostTag>
|
||||
<a
|
||||
v-if="post.post.status?.permalink"
|
||||
target="_blank"
|
||||
|
@ -801,35 +795,45 @@ const hasFilters = computed(() => {
|
|||
</VSpace>
|
||||
</template>
|
||||
<template #description>
|
||||
<VSpace class="flex-wrap !gap-y-1">
|
||||
<p
|
||||
v-if="post.categories.length"
|
||||
class="inline-flex flex-wrap gap-1 text-xs text-gray-500"
|
||||
>
|
||||
分类:<a
|
||||
v-for="(category, categoryIndex) in post.categories"
|
||||
:key="categoryIndex"
|
||||
:href="category.status?.permalink"
|
||||
:title="category.status?.permalink"
|
||||
target="_blank"
|
||||
class="cursor-pointer hover:text-gray-900"
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<VSpace class="flex-wrap !gap-y-1">
|
||||
<p
|
||||
v-if="post.categories.length"
|
||||
class="inline-flex flex-wrap gap-1 text-xs text-gray-500"
|
||||
>
|
||||
{{ category.spec.displayName }}
|
||||
</a>
|
||||
</p>
|
||||
<span class="text-xs text-gray-500">
|
||||
访问量 {{ post.stats.visit || 0 }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500">
|
||||
评论 {{ post.stats.totalComment || 0 }}
|
||||
</span>
|
||||
<span
|
||||
v-if="post.post.spec.pinned"
|
||||
class="text-xs text-gray-500"
|
||||
>
|
||||
已置顶
|
||||
</span>
|
||||
</VSpace>
|
||||
分类:<a
|
||||
v-for="(category, categoryIndex) in post.categories"
|
||||
:key="categoryIndex"
|
||||
:href="category.status?.permalink"
|
||||
:title="category.status?.permalink"
|
||||
target="_blank"
|
||||
class="cursor-pointer hover:text-gray-900"
|
||||
>
|
||||
{{ category.spec.displayName }}
|
||||
</a>
|
||||
</p>
|
||||
<span class="text-xs text-gray-500">
|
||||
访问量 {{ post.stats.visit || 0 }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500">
|
||||
评论 {{ post.stats.totalComment || 0 }}
|
||||
</span>
|
||||
<span
|
||||
v-if="post.post.spec.pinned"
|
||||
class="text-xs text-gray-500"
|
||||
>
|
||||
已置顶
|
||||
</span>
|
||||
</VSpace>
|
||||
<VSpace v-if="post.tags.length" class="flex-wrap">
|
||||
<PostTag
|
||||
v-for="(tag, tagIndex) in post.tags"
|
||||
:key="tagIndex"
|
||||
:tag="tag"
|
||||
route
|
||||
></PostTag>
|
||||
</VSpace>
|
||||
</div>
|
||||
</template>
|
||||
</VEntityField>
|
||||
</template>
|
||||
|
|
|
@ -78,6 +78,7 @@ const handleCopy = () => {
|
|||
- 构建时间:${formatDatetime(info.value?.build?.time)}
|
||||
- Git Commit:${info.value?.git?.commit.id}
|
||||
- Java:${info.value?.java.runtime.name} / ${info.value?.java.runtime.version}
|
||||
- 数据库:${info.value?.database.name} / ${info.value?.database.version}
|
||||
- 操作系统:${info.value?.os.name} / ${info.value?.os.version}
|
||||
`;
|
||||
|
||||
|
@ -85,6 +86,28 @@ const handleCopy = () => {
|
|||
|
||||
Toast.success("复制成功");
|
||||
};
|
||||
|
||||
const handleDownloadLogfile = () => {
|
||||
axios
|
||||
.get(`${import.meta.env.VITE_API_URL}/actuator/logfile`)
|
||||
.then((response) => {
|
||||
const blob = new Blob([response.data]);
|
||||
const downloadElement = document.createElement("a");
|
||||
const href = window.URL.createObjectURL(blob);
|
||||
downloadElement.href = href;
|
||||
downloadElement.download = `halo-log-${formatDatetime(new Date())}.log`;
|
||||
document.body.appendChild(downloadElement);
|
||||
downloadElement.click();
|
||||
document.body.removeChild(downloadElement);
|
||||
window.URL.revokeObjectURL(href);
|
||||
|
||||
Toast.success("下载成功");
|
||||
})
|
||||
.catch((e) => {
|
||||
Toast.error("下载失败");
|
||||
console.log("Failed to download log file.", e);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -225,6 +248,14 @@ const handleCopy = () => {
|
|||
{{ info.java.runtime.name }} / {{ info.java.runtime.version }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">数据库</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
{{ [info.database.name, info.database.version].join(" / ") }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
|
@ -233,6 +264,16 @@ const handleCopy = () => {
|
|||
{{ info.os.name }} {{ info.os.version }} / {{ info.os.arch }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
class="items-center bg-white px-4 py-5 hover:bg-gray-50 sm:grid sm:grid-cols-6 sm:gap-4 sm:px-6"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">运行日志</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
<VButton size="sm" @click="handleDownloadLogfile()">
|
||||
下载
|
||||
</VButton>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,6 +12,12 @@ export interface Info {
|
|||
build?: Build;
|
||||
java: Java;
|
||||
os: Os;
|
||||
database: Database;
|
||||
}
|
||||
|
||||
export interface Database {
|
||||
name: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface Commit {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<script lang="ts" setup>
|
||||
import { VModal, Dialog } from "@halo-dev/components";
|
||||
import { VModal, Dialog, Toast } from "@halo-dev/components";
|
||||
import UppyUpload from "@/components/upload/UppyUpload.vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { Plugin } from "@halo-dev/api-client";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import type { SuccessResponse } from "@uppy/core";
|
||||
import type { SuccessResponse, ErrorResponse } from "@uppy/core";
|
||||
import type { UppyFile } from "@uppy/utils";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -76,6 +77,40 @@ const onUploaded = async (response: SuccessResponse) => {
|
|||
});
|
||||
};
|
||||
|
||||
interface PluginInstallationErrorResponse {
|
||||
detail: string;
|
||||
instance: string;
|
||||
pluginName: string;
|
||||
requestId: string;
|
||||
status: number;
|
||||
timestamp: string;
|
||||
title: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
const PLUGIN_ALREADY_EXISTS_TYPE =
|
||||
"https://halo.run/probs/plugin-alreay-exists";
|
||||
|
||||
const onError = (file: UppyFile<unknown>, response: ErrorResponse) => {
|
||||
const body = response.body as PluginInstallationErrorResponse;
|
||||
if (body.type === PLUGIN_ALREADY_EXISTS_TYPE) {
|
||||
Dialog.info({
|
||||
title: "插件已存在",
|
||||
description: "当前安装的插件已存在,是否升级?",
|
||||
onConfirm: async () => {
|
||||
await apiClient.plugin.upgradePlugin({
|
||||
name: body.pluginName,
|
||||
file: file.data as File,
|
||||
});
|
||||
|
||||
Toast.success("升级成功");
|
||||
|
||||
window.location.reload();
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newValue) => {
|
||||
|
@ -106,6 +141,7 @@ watch(
|
|||
:endpoint="endpoint"
|
||||
auto-proceed
|
||||
@uploaded="onUploaded"
|
||||
@error="onError"
|
||||
/>
|
||||
</VModal>
|
||||
</template>
|
||||
|
|
|
@ -249,7 +249,7 @@ onMounted(() => {
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
<div>
|
||||
{{ group.module }}
|
||||
{{ $t(`rbac.${group.module}`, group.module as string) }}
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
|
@ -300,9 +300,16 @@ onMounted(() => {
|
|||
<div class="flex flex-1 flex-col gap-y-3">
|
||||
<span class="font-medium text-gray-900">
|
||||
{{
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
]
|
||||
$t(
|
||||
`rbac.${
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
]
|
||||
}`,
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
] as string
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
|
@ -319,7 +326,11 @@ onMounted(() => {
|
|||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DEPENDENCIES
|
||||
]
|
||||
).join(", ")
|
||||
)
|
||||
.map((item: string) =>
|
||||
$t(`rbac.${item}`, item as string)
|
||||
)
|
||||
.join(",")
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -156,7 +156,9 @@ const handleResetForm = () => {
|
|||
class="flex flex-col gap-3 bg-white py-5 first:pt-0"
|
||||
>
|
||||
<dt class="text-sm font-medium text-gray-900">
|
||||
<div>{{ group.module }}</div>
|
||||
<div>
|
||||
{{ $t(`rbac.${group.module}`, group.module as string) }}
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
group.roles.length &&
|
||||
|
@ -197,9 +199,16 @@ const handleResetForm = () => {
|
|||
<div class="flex flex-1 flex-col gap-y-3">
|
||||
<span class="font-medium text-gray-900">
|
||||
{{
|
||||
roleTemplate.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
]
|
||||
$t(
|
||||
`rbac.${
|
||||
roleTemplate.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
]
|
||||
}`,
|
||||
roleTemplate.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
] as string
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
|
@ -216,7 +225,11 @@ const handleResetForm = () => {
|
|||
roleTemplate.metadata.annotations?.[
|
||||
rbacAnnotations.DEPENDENCIES
|
||||
]
|
||||
).join(", ")
|
||||
)
|
||||
.map((item: string) =>
|
||||
$t(`rbac.${item}`, item as string)
|
||||
)
|
||||
.join(",")
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -65,6 +65,7 @@ const userStore = useUserStore();
|
|||
const roleStore = useRoleStore();
|
||||
|
||||
const ANONYMOUSUSER_NAME = "anonymousUser";
|
||||
const DELETEDUSER_NAME = "ghost";
|
||||
|
||||
const handleFetchUsers = async (options?: {
|
||||
mute?: boolean;
|
||||
|
@ -85,7 +86,10 @@ const handleFetchUsers = async (options?: {
|
|||
page: users.value.page,
|
||||
size: users.value.size,
|
||||
keyword: keyword.value,
|
||||
fieldSelector: [`name!=${ANONYMOUSUSER_NAME}`],
|
||||
fieldSelector: [
|
||||
`name!=${ANONYMOUSUSER_NAME}`,
|
||||
`name!=${DELETEDUSER_NAME}`,
|
||||
],
|
||||
sort: [selectedSortItem.value?.value].filter(
|
||||
(item) => !!item
|
||||
) as string[],
|
||||
|
|
Loading…
Reference in New Issue