| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- <script lang="ts" setup>
- import type { SetupContext } from 'vue';
- import type { Recordable } from '@vben/types';
- import type {
- JsonViewerAction,
- JsonViewerProps,
- JsonViewerToggle,
- JsonViewerValue,
- } from './types';
- import { computed, useAttrs } from 'vue';
- // @ts-expect-error - vue-json-viewer does not expose compatible typings for this import path
- import VueJsonViewerImport from 'vue-json-viewer';
- import { $t } from '@vben/locales';
- import { isBoolean } from '@vben-core/shared/utils';
- import JsonBigint from 'json-bigint';
- 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,
- });
- const emit = defineEmits<{
- click: [event: MouseEvent];
- copied: [event: JsonViewerAction];
- keyClick: [key: string];
- toggle: [param: JsonViewerToggle];
- valueClick: [value: JsonViewerValue];
- }>();
- /** CJS/UMD 在 Vite 下解析为 { default: Component },需解包否则会出现 missing template or render */
- const VueJsonViewer =
- (VueJsonViewerImport as { default?: typeof VueJsonViewerImport }).default ??
- VueJsonViewerImport;
- const attrs: SetupContext['attrs'] = useAttrs();
- function handleClick(event: MouseEvent) {
- if (
- event.target instanceof HTMLElement &&
- event.target.classList.contains('jv-item')
- ) {
- const pathNode = event.target.closest('.jv-push');
- if (!pathNode || !pathNode.hasAttribute('path')) {
- return;
- }
- const param: JsonViewerValue = {
- el: event.target,
- path: pathNode.getAttribute('path') || '',
- depth: Number(pathNode.getAttribute('depth')) || 0,
- value: event.target.textContent || undefined,
- };
- param.value = JSON.parse(param.value);
- emit('valueClick', param);
- }
- emit('click', event);
- }
- // 支持显示 bigint 数据,如较长的订单号
- const jsonData = computed<Record<string, any>>(() => {
- if (typeof props.value !== 'string') {
- return props.value || {};
- }
- try {
- return JsonBigint({ storeAsString: true }).parse(props.value);
- } catch (error) {
- console.error('JSON parse error:', error);
- return {};
- }
- });
- 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,
- value: jsonData.value,
- onCopied: (event: JsonViewerAction) => emit('copied', event),
- onKeyclick: (key: string) => emit('keyClick', key),
- onClick: (event: MouseEvent) => handleClick(event),
- copyable: props.copyable ? copyable : false,
- };
- });
- </script>
- <template>
- <VueJsonViewer v-bind="bindProps">
- <template #copy="slotProps">
- <slot name="copy" v-bind="slotProps"></slot>
- </template>
- </VueJsonViewer>
- </template>
- <style lang="scss">
- @use './style.scss';
- </style>
|