index.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <script lang="ts" setup>
  2. import type { SetupContext } from 'vue';
  3. import type { Recordable } from '@vben/types';
  4. import type {
  5. JsonViewerAction,
  6. JsonViewerProps,
  7. JsonViewerToggle,
  8. JsonViewerValue,
  9. } from './types';
  10. import { computed, useAttrs } from 'vue';
  11. // @ts-expect-error - vue-json-viewer does not expose compatible typings for this import path
  12. import VueJsonViewerImport from 'vue-json-viewer';
  13. import { $t } from '@vben/locales';
  14. import { isBoolean } from '@vben-core/shared/utils';
  15. import JsonBigint from 'json-bigint';
  16. defineOptions({ name: 'JsonViewer' });
  17. const props = withDefaults(defineProps<JsonViewerProps>(), {
  18. expandDepth: 1,
  19. copyable: false,
  20. sort: false,
  21. boxed: false,
  22. theme: 'default-json-theme',
  23. expanded: false,
  24. previewMode: false,
  25. showArrayIndex: true,
  26. showDoubleQuotes: false,
  27. });
  28. const emit = defineEmits<{
  29. click: [event: MouseEvent];
  30. copied: [event: JsonViewerAction];
  31. keyClick: [key: string];
  32. toggle: [param: JsonViewerToggle];
  33. valueClick: [value: JsonViewerValue];
  34. }>();
  35. /** CJS/UMD 在 Vite 下解析为 { default: Component },需解包否则会出现 missing template or render */
  36. const VueJsonViewer =
  37. (VueJsonViewerImport as { default?: typeof VueJsonViewerImport }).default ??
  38. VueJsonViewerImport;
  39. const attrs: SetupContext['attrs'] = useAttrs();
  40. function handleClick(event: MouseEvent) {
  41. if (
  42. event.target instanceof HTMLElement &&
  43. event.target.classList.contains('jv-item')
  44. ) {
  45. const pathNode = event.target.closest('.jv-push');
  46. if (!pathNode || !pathNode.hasAttribute('path')) {
  47. return;
  48. }
  49. const param: JsonViewerValue = {
  50. el: event.target,
  51. path: pathNode.getAttribute('path') || '',
  52. depth: Number(pathNode.getAttribute('depth')) || 0,
  53. value: event.target.textContent || undefined,
  54. };
  55. param.value = JSON.parse(param.value);
  56. emit('valueClick', param);
  57. }
  58. emit('click', event);
  59. }
  60. // 支持显示 bigint 数据,如较长的订单号
  61. const jsonData = computed<Record<string, any>>(() => {
  62. if (typeof props.value !== 'string') {
  63. return props.value || {};
  64. }
  65. try {
  66. return JsonBigint({ storeAsString: true }).parse(props.value);
  67. } catch (error) {
  68. console.error('JSON parse error:', error);
  69. return {};
  70. }
  71. });
  72. const bindProps = computed<Recordable<any>>(() => {
  73. const copyable = {
  74. copyText: $t('ui.jsonViewer.copy'),
  75. copiedText: $t('ui.jsonViewer.copied'),
  76. timeout: 2000,
  77. ...(isBoolean(props.copyable) ? {} : props.copyable),
  78. };
  79. return {
  80. ...props,
  81. ...attrs,
  82. value: jsonData.value,
  83. onCopied: (event: JsonViewerAction) => emit('copied', event),
  84. onKeyclick: (key: string) => emit('keyClick', key),
  85. onClick: (event: MouseEvent) => handleClick(event),
  86. copyable: props.copyable ? copyable : false,
  87. };
  88. });
  89. </script>
  90. <template>
  91. <VueJsonViewer v-bind="bindProps">
  92. <template #copy="slotProps">
  93. <slot name="copy" v-bind="slotProps"></slot>
  94. </template>
  95. </VueJsonViewer>
  96. </template>
  97. <style lang="scss">
  98. @use './style.scss';
  99. </style>