diff --git a/package.json b/package.json index 80f4bff0..0c3e8838 100644 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f0bbb23..9b9faaff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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: diff --git a/src/components/upload/UppyUpload.vue b/src/components/upload/UppyUpload.vue index 756dadb9..8fb1d156 100644 --- a/src/components/upload/UppyUpload.vue +++ b/src/components/upload/UppyUpload.vue @@ -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" }); }); diff --git a/src/layouts/BasicLayout.vue b/src/layouts/BasicLayout.vue index cc2629e7..ff0f4031 100644 --- a/src/layouts/BasicLayout.vue +++ b/src/layouts/BasicLayout.vue @@ -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; + }); +}); diff --git a/src/modules/system/actuator/Actuator.vue b/src/modules/system/actuator/Actuator.vue index 81fbf013..ea40e281 100644 --- a/src/modules/system/actuator/Actuator.vue +++ b/src/modules/system/actuator/Actuator.vue @@ -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); + }); +};