feat: new component jsonViewer (#5544)

* 添加新组件JsonViewer用于展示JSON结构数据
This commit is contained in:
Netfan 2025-02-16 22:57:00 +08:00 committed by GitHub
parent f9504cece3
commit 6cba181fad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 356 additions and 4 deletions

View File

@ -35,6 +35,7 @@
"qrcode": "catalog:", "qrcode": "catalog:",
"tippy.js": "catalog:", "tippy.js": "catalog:",
"vue": "catalog:", "vue": "catalog:",
"vue-json-viewer": "catalog:",
"vue-router": "catalog:", "vue-router": "catalog:",
"vue-tippy": "catalog:" "vue-tippy": "catalog:"
}, },

View File

@ -3,6 +3,7 @@ export * from './captcha';
export * from './col-page'; export * from './col-page';
export * from './ellipsis-text'; export * from './ellipsis-text';
export * from './icon-picker'; export * from './icon-picker';
export * from './json-viewer';
export * from './page'; export * from './page';
export * from './resize'; export * from './resize';
export * from './tippy'; export * from './tippy';

View File

@ -0,0 +1,3 @@
export { default as JsonViewer } from './index.vue';
export * from './types';

View File

@ -0,0 +1,77 @@
<script lang="ts" setup>
import type { SetupContext } from 'vue';
import type { Recordable } from '@vben/types';
import type { JsonViewerProps } from './types';
import { computed, useAttrs } from 'vue';
// @ts-ignore
import VueJsonViewer from 'vue-json-viewer';
import { $t } from '@vben/locales';
import { isBoolean, isString } from '@vben-core/shared/utils';
defineOptions({ name: 'JsonViewer' });
const props = withDefaults(defineProps<JsonViewerProps>(), {
expandDepth: 1,
copyable: false,
sort: false,
boxed: false,
theme: 'default-json-theme',
expanded: false,
previewMode: false,
showArrayIndex: true,
showDoubleQuotes: false,
parseString: true,
});
const emit = defineEmits<{
parseError: [error: Error];
}>();
const attrs: SetupContext['attrs'] = useAttrs();
const bindProps = computed<Recordable<any>>(() => {
const copyable = {
copyText: $t('ui.jsonViewer.copy'),
copiedText: $t('ui.jsonViewer.copied'),
timeout: 2000,
...(isBoolean(props.copyable) ? {} : props.copyable),
};
return {
...props,
...attrs,
copyable: props.copyable ? copyable : false,
};
});
const modelValue = defineModel();
const jsonToShow = computed(() => {
if (props.parseString && isString(modelValue.value)) {
try {
return JSON.parse(modelValue.value);
} catch (error) {
emit('parseError', error as Error);
console.error('Error parsing JSON:', error);
return modelValue.value;
}
} else {
return modelValue.value;
}
});
</script>
<template>
<VueJsonViewer :value="jsonToShow" v-bind="bindProps">
<template #copy="slotProps">
<slot name="copy" v-bind="slotProps"></slot>
</template>
</VueJsonViewer>
</template>
<style lang="scss">
@use './style.scss';
</style>

View File

@ -0,0 +1,98 @@
.default-json-theme {
font-family: Consolas, Menlo, Courier, monospace;
font-size: 14px;
color: hsl(var(--foreground));
white-space: nowrap;
background: hsl(var(--background));
&.jv-container.boxed {
border: 1px solid hsl(var(--border));
}
.jv-ellipsis {
display: inline-block;
padding: 0 4px 2px;
font-size: 0.9em;
line-height: 0.9;
color: hsl(var(--secondary-foreground));
vertical-align: 2px;
cursor: pointer;
user-select: none;
background-color: hsl(var(--secondary));
border-radius: 3px;
}
.jv-button {
color: hsl(var(--primary));
}
.jv-key {
color: hsl(var(--heavy-foreground));
}
.jv-item {
&.jv-array {
color: hsl(var(--heavy-foreground));
}
&.jv-boolean {
color: hsl(var(--red-400));
}
&.jv-function {
color: hsl(var(--destructive-foreground));
}
&.jv-number {
color: hsl(var(--info-foreground));
}
&.jv-number-float {
color: hsl(var(--info-foreground));
}
&.jv-number-integer {
color: hsl(var(--info-foreground));
}
&.jv-object {
color: hsl(var(--accent-darker));
}
&.jv-undefined {
color: hsl(var(--secondary-foreground));
}
&.jv-string {
color: hsl(var(--primary));
word-break: break-word;
white-space: normal;
}
}
&.jv-container .jv-code {
padding: 10px;
&.boxed:not(.open) {
padding-bottom: 20px;
margin-bottom: 10px;
}
&.open {
padding-bottom: 10px;
}
.jv-toggle {
&::before {
padding: 0 2px;
border-radius: 2px;
}
&:hover {
&::before {
background: hsl(var(--accent-foreground));
}
}
}
}
}

View File

@ -0,0 +1,24 @@
export interface JsonViewerProps {
/** 展开深度 */
expandDepth?: number;
/** 是否可复制 */
copyable?: boolean;
/** 是否排序 */
sort?: boolean;
/** 显示边框 */
boxed?: boolean;
/** 主题 */
theme?: string;
/** 是否展开 */
expanded?: boolean;
/** 时间格式化函数 */
timeformat?: (time: Date | number | string) => string;
/** 预览模式 */
previewMode?: boolean;
/** 显示数组索引 */
showArrayIndex?: boolean;
/** 显示双引号 */
showDoubleQuotes?: boolean;
/** 解析字符串 */
parseString?: boolean;
}

View File

@ -25,6 +25,10 @@
"placeholder": "Select an icon", "placeholder": "Select an icon",
"search": "Search icon..." "search": "Search icon..."
}, },
"jsonViewer": {
"copy": "Copy",
"copied": "Copied"
},
"fallback": { "fallback": {
"pageNotFound": "Oops! Page Not Found", "pageNotFound": "Oops! Page Not Found",
"pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.", "pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.",

View File

@ -25,6 +25,10 @@
"placeholder": "选择一个图标", "placeholder": "选择一个图标",
"search": "搜索图标..." "search": "搜索图标..."
}, },
"jsonViewer": {
"copy": "复制",
"copied": "已复制"
},
"fallback": { "fallback": {
"pageNotFound": "哎呀!未找到页面", "pageNotFound": "哎呀!未找到页面",
"pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。", "pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。",

View File

@ -255,6 +255,15 @@ const routes: RouteRecordRaw[] = [
title: 'Tippy', title: 'Tippy',
}, },
}, },
{
name: 'JsonViewer',
path: '/examples/json-viewer',
component: () => import('#/views/examples/json-viewer/index.vue'),
meta: {
icon: 'tabler:json',
title: 'JsonViewer',
},
},
], ],
}, },
]; ];

View File

@ -0,0 +1,51 @@
export const json1 = {
additionalInfo: {
author: 'Your Name',
debug: true,
version: '1.3.10',
versionCode: 132,
},
additionalNotes: 'This JSON is used for demonstration purposes',
tools: [
{
description: 'Description of Tool 1',
name: 'Tool 1',
},
{
description: 'Description of Tool 2',
name: 'Tool 2',
},
{
description: 'Description of Tool 3',
name: 'Tool 3',
},
{
description: 'Description of Tool 4',
name: 'Tool 4',
},
],
};
export const json2 = `
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-3.5-turbo-0613",
"system_fingerprint": "fp_44709d6fcb",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello there, how may I assist you today?"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21,
"debug_mode": true
}
}
`;

View File

@ -0,0 +1,26 @@
<script lang="ts" setup>
import { JsonViewer, Page } from '@vben/common-ui';
import { Card } from 'ant-design-vue';
import { json1, json2 } from './data';
</script>
<template>
<Page
title="Json Viewer"
description="一个渲染 JSON 结构数据的组件,支持复制、展开等,简单易用"
>
<Card title="默认配置">
<JsonViewer v-model="json1" />
</Card>
<Card title="可复制、默认展开3层、显示边框" class="mt-4">
<JsonViewer
v-model="json2"
:expand-depth="3"
copyable
:sort="false"
boxed
/>
</Card>
</Page>
</template>

View File

@ -474,6 +474,9 @@ catalogs:
vue-i18n: vue-i18n:
specifier: ^11.1.0 specifier: ^11.1.0
version: 11.1.0 version: 11.1.0
vue-json-viewer:
specifier: ^3.0.4
version: 3.0.4
vue-router: vue-router:
specifier: ^4.5.0 specifier: ^4.5.0
version: 4.5.0 version: 4.5.0
@ -1533,6 +1536,9 @@ importers:
vue: vue:
specifier: ^3.5.13 specifier: ^3.5.13
version: 3.5.13(typescript@5.7.3) version: 3.5.13(typescript@5.7.3)
vue-json-viewer:
specifier: 'catalog:'
version: 3.0.4(vue@3.5.13(typescript@5.7.3))
vue-router: vue-router:
specifier: 'catalog:' specifier: 'catalog:'
version: 4.5.0(vue@3.5.13(typescript@5.7.3)) version: 4.5.0(vue@3.5.13(typescript@5.7.3))
@ -3535,6 +3541,10 @@ packages:
resolution: {integrity: sha512-DvpNSxiMrFqYMaGSRDDnQgO/L0MqNH4KWw9CUx8LRHHIdWp08En9DpmSRNpauUOxKpHAhyJJxx92BHZk9J84EQ==} resolution: {integrity: sha512-DvpNSxiMrFqYMaGSRDDnQgO/L0MqNH4KWw9CUx8LRHHIdWp08En9DpmSRNpauUOxKpHAhyJJxx92BHZk9J84EQ==}
engines: {node: '>= 16'} engines: {node: '>= 16'}
'@intlify/shared@11.1.1':
resolution: {integrity: sha512-2kGiWoXaeV8HZlhU/Nml12oTbhv7j2ufsJ5vQaa0VTjzUmZVdd/nmKFRAOJ/FtjO90Qba5AnZDwsrY7ZND5udA==}
engines: {node: '>= 16'}
'@intlify/unplugin-vue-i18n@6.0.3': '@intlify/unplugin-vue-i18n@6.0.3':
resolution: {integrity: sha512-9ZDjBlhUHtgjRl23TVcgfJttgu8cNepwVhWvOv3mUMRDAhjW0pur1mWKEUKr1I8PNwE4Gvv2IQ1xcl4RL0nG0g==} resolution: {integrity: sha512-9ZDjBlhUHtgjRl23TVcgfJttgu8cNepwVhWvOv3mUMRDAhjW0pur1mWKEUKr1I8PNwE4Gvv2IQ1xcl4RL0nG0g==}
engines: {node: '>= 18'} engines: {node: '>= 18'}
@ -5097,6 +5107,9 @@ packages:
resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
engines: {node: '>=18'} engines: {node: '>=18'}
clipboard@2.0.11:
resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==}
clipboardy@4.0.0: clipboardy@4.0.0:
resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -5589,6 +5602,9 @@ packages:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
delegate@3.2.0:
resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
denque@2.1.0: denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
@ -6451,6 +6467,9 @@ packages:
globjoin@0.1.4: globjoin@0.1.4:
resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==}
good-listener@1.2.2:
resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==}
gopd@1.2.0: gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -8852,6 +8871,9 @@ packages:
seemly@0.3.9: seemly@0.3.9:
resolution: {integrity: sha512-bMLcaEqhIViiPbaumjLN8t1y+JpD/N8SiyYOyp0i0W6RgdyLWboIsUWAbZojF//JyerxPZR5Tgda+x3Pdne75A==} resolution: {integrity: sha512-bMLcaEqhIViiPbaumjLN8t1y+JpD/N8SiyYOyp0i0W6RgdyLWboIsUWAbZojF//JyerxPZR5Tgda+x3Pdne75A==}
select@1.1.2:
resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==}
semver-compare@1.0.0: semver-compare@1.0.0:
resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==}
@ -9381,6 +9403,9 @@ packages:
through@2.3.8: through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
tiny-emitter@2.1.0:
resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
tinybench@2.9.0: tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
@ -9978,6 +10003,11 @@ packages:
peerDependencies: peerDependencies:
vue: ^3.5.13 vue: ^3.5.13
vue-json-viewer@3.0.4:
resolution: {integrity: sha512-pnC080rTub6YjccthVSNQod2z9Sl5IUUq46srXtn6rxwhW8QM4rlYn+CTSLFKXWfw+N3xv77Cioxw7B4XUKIbQ==}
peerDependencies:
vue: ^3.5.13
vue-router@4.5.0: vue-router@4.5.0:
resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==} resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==}
peerDependencies: peerDependencies:
@ -12186,12 +12216,14 @@ snapshots:
'@intlify/shared@11.1.0': {} '@intlify/shared@11.1.0': {}
'@intlify/shared@11.1.1': {}
'@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.19.0(jiti@2.4.2))(rollup@4.34.2)(typescript@5.7.3)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))': '@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.19.0(jiti@2.4.2))(rollup@4.34.2)(typescript@5.7.3)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2)) '@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.2))
'@intlify/bundle-utils': 10.0.0(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3))) '@intlify/bundle-utils': 10.0.0(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))
'@intlify/shared': 11.1.0 '@intlify/shared': 11.1.1
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.0)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.1)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
'@rollup/pluginutils': 5.1.4(rollup@4.34.2) '@rollup/pluginutils': 5.1.4(rollup@4.34.2)
'@typescript-eslint/scope-manager': 8.23.0 '@typescript-eslint/scope-manager': 8.23.0
'@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3) '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3)
@ -12213,11 +12245,11 @@ snapshots:
- supports-color - supports-color
- typescript - typescript
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.0)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))': '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.1)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
dependencies: dependencies:
'@babel/parser': 7.26.7 '@babel/parser': 7.26.7
optionalDependencies: optionalDependencies:
'@intlify/shared': 11.1.0 '@intlify/shared': 11.1.1
'@vue/compiler-dom': 3.5.13 '@vue/compiler-dom': 3.5.13
vue: 3.5.13(typescript@5.7.3) vue: 3.5.13(typescript@5.7.3)
vue-i18n: 11.1.0(vue@3.5.13(typescript@5.7.3)) vue-i18n: 11.1.0(vue@3.5.13(typescript@5.7.3))
@ -14109,6 +14141,12 @@ snapshots:
slice-ansi: 5.0.0 slice-ansi: 5.0.0
string-width: 7.2.0 string-width: 7.2.0
clipboard@2.0.11:
dependencies:
good-listener: 1.2.2
select: 1.1.2
tiny-emitter: 2.1.0
clipboardy@4.0.0: clipboardy@4.0.0:
dependencies: dependencies:
execa: 8.0.1 execa: 8.0.1
@ -14610,6 +14648,8 @@ snapshots:
delayed-stream@1.0.0: {} delayed-stream@1.0.0: {}
delegate@3.2.0: {}
denque@2.1.0: {} denque@2.1.0: {}
depcheck@1.4.7: depcheck@1.4.7:
@ -15675,6 +15715,10 @@ snapshots:
globjoin@0.1.4: {} globjoin@0.1.4: {}
good-listener@1.2.2:
dependencies:
delegate: 3.2.0
gopd@1.2.0: {} gopd@1.2.0: {}
graceful-fs@4.2.10: {} graceful-fs@4.2.10: {}
@ -18142,6 +18186,8 @@ snapshots:
seemly@0.3.9: {} seemly@0.3.9: {}
select@1.1.2: {}
semver-compare@1.0.0: {} semver-compare@1.0.0: {}
semver@5.7.2: {} semver@5.7.2: {}
@ -18789,6 +18835,8 @@ snapshots:
through@2.3.8: {} through@2.3.8: {}
tiny-emitter@2.1.0: {}
tinybench@2.9.0: {} tinybench@2.9.0: {}
tinyexec@0.3.2: {} tinyexec@0.3.2: {}
@ -19493,6 +19541,11 @@ snapshots:
'@vue/devtools-api': 6.6.4 '@vue/devtools-api': 6.6.4
vue: 3.5.13(typescript@5.7.3) vue: 3.5.13(typescript@5.7.3)
vue-json-viewer@3.0.4(vue@3.5.13(typescript@5.7.3)):
dependencies:
clipboard: 2.0.11
vue: 3.5.13(typescript@5.7.3)
vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)): vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)):
dependencies: dependencies:
'@vue/devtools-api': 6.6.4 '@vue/devtools-api': 6.6.4

View File

@ -175,6 +175,7 @@ catalog:
vue: ^3.5.13 vue: ^3.5.13
vue-eslint-parser: ^9.4.3 vue-eslint-parser: ^9.4.3
vue-i18n: ^11.1.0 vue-i18n: ^11.1.0
vue-json-viewer: ^3.0.4
vue-router: ^4.5.0 vue-router: ^4.5.0
vue-tippy: ^6.6.0 vue-tippy: ^6.6.0
vue-tsc: 2.1.10 vue-tsc: 2.1.10