소스 검색

feat: JsonEditor

kailong321200875 1 년 전
부모
커밋
c0f4517b87

+ 9 - 0
mock/role/index.ts

@@ -179,6 +179,14 @@ const adminList = [
             meta: {
               title: 'router.richText'
             }
+          },
+          {
+            path: 'json-editor',
+            component: 'views/Components/Editor/JsonEditor',
+            name: 'JsonEditor',
+            meta: {
+              title: 'router.jsonEditor'
+            }
           }
         ]
       },
@@ -588,6 +596,7 @@ const testList: string[] = [
   '/components/table/ref-table',
   '/components/editor-demo',
   '/components/editor-demo/editor',
+  '/components/editor-demo/json-editor',
   '/components/search',
   '/components/descriptions',
   '/components/image-viewer',

+ 1 - 0
package.json

@@ -51,6 +51,7 @@
     "url": "^0.11.1",
     "vue": "3.3.4",
     "vue-i18n": "9.2.2",
+    "vue-json-pretty": "^2.2.4",
     "vue-router": "^4.2.4",
     "vue-types": "^5.1.1"
   },

+ 3 - 1
src/components/Form/src/helper/componentMap.ts

@@ -22,6 +22,7 @@ import {
 } from 'element-plus'
 import { InputPassword } from '@/components/InputPassword'
 import { Editor } from '@/components/Editor'
+import { JsonEditor } from '@/components/JsonEditor'
 import { ComponentName } from '../types'
 
 const componentMap: Recordable<Component, ComponentName> = {
@@ -47,7 +48,8 @@ const componentMap: Recordable<Component, ComponentName> = {
   InputPassword: InputPassword,
   Editor: Editor,
   TreeSelect: ElTreeSelect,
-  Upload: ElUpload
+  Upload: ElUpload,
+  JsonEditor: JsonEditor
 }
 
 export { componentMap }

+ 4 - 1
src/components/Form/src/types/index.ts

@@ -21,6 +21,7 @@ import {
   UploadProps
 } from 'element-plus'
 import { IEditorConfig } from '@wangeditor/editor'
+import { JsonEditorProps } from '@/components/JsonEditor'
 import { CSSProperties } from 'vue'
 
 export interface PlaceholderModel {
@@ -53,7 +54,8 @@ export enum ComponentNameEnum {
   INPUT_PASSWORD = 'InputPassword',
   EDITOR = 'Editor',
   TREE_SELECT = 'TreeSelect',
-  UPLOAD = 'Upload'
+  UPLOAD = 'Upload',
+  JSON_EDITOR = 'JsonEditor'
 }
 
 type CamelCaseComponentName = keyof typeof ComponentNameEnum extends infer K
@@ -620,6 +622,7 @@ export interface FormSchema {
     | InputPasswordComponentProps
     | TreeSelectComponentProps
     | UploadComponentProps
+    | JsonEditorProps
     | any
 
   /**

+ 4 - 0
src/components/JsonEditor/index.ts

@@ -0,0 +1,4 @@
+import JsonEditor from './src/JsonEditor.vue'
+export type { JsonEditorProps } from './src/types'
+
+export { JsonEditor }

+ 98 - 0
src/components/JsonEditor/src/JsonEditor.vue

@@ -0,0 +1,98 @@
+<script setup lang="ts">
+import VueJsonPretty from 'vue-json-pretty'
+import 'vue-json-pretty/lib/styles.css'
+import { propTypes } from '@/utils/propTypes'
+import { computed } from 'vue'
+
+const emits = defineEmits([
+  'update:modelValue',
+  'node-click',
+  'brackets-click',
+  'icon-click',
+  'selected-value'
+])
+
+const props = defineProps({
+  modelValue: {
+    type: Object,
+    default: () => ({})
+  },
+  deep: propTypes.number.def(1),
+  showLength: propTypes.bool.def(true),
+  showLineNumbers: propTypes.bool.def(true),
+  showLineNumber: propTypes.bool.def(true),
+  showIcon: propTypes.bool.def(true),
+  showDoubleQuotes: propTypes.bool.def(true),
+  virtual: propTypes.bool.def(false),
+  height: propTypes.number.def(400),
+  itemHeight: propTypes.number.def(20),
+  rootPath: propTypes.string.def('root'),
+  nodeSelectable: propTypes.func.def(),
+  selectableType: propTypes.oneOf<'multiple' | 'single'>(['multiple', 'single']).def(),
+  showSelectController: propTypes.bool.def(false),
+  selectOnClickNode: propTypes.bool.def(true),
+  highlightSelectedNode: propTypes.bool.def(true),
+  collapsedOnClickBrackets: propTypes.bool.def(true),
+  renderNodeKey: propTypes.func.def(),
+  renderNodeValue: propTypes.func.def(),
+  editable: propTypes.bool.def(true),
+  editableTrigger: propTypes.oneOf<'click' | 'dblclick'>(['click', 'dblclick']).def('click')
+})
+
+const data = computed(() => props.modelValue)
+
+const localModelValue = computed({
+  get: () => data.value,
+  set: (val) => {
+    console.log(val)
+    emits('update:modelValue', val)
+  }
+})
+
+const nodeClick = (node: any) => {
+  emits('node-click', node)
+}
+
+const bracketsClick = (collapsed: boolean) => {
+  emits('brackets-click', collapsed)
+}
+
+const iconClick = (collapsed: boolean) => {
+  emits('icon-click', collapsed)
+}
+
+const selectedChange = (newVal: any, oldVal: any) => {
+  console.log(newVal, oldVal)
+  emits('selected-value', newVal, oldVal)
+}
+</script>
+
+<template>
+  <VueJsonPretty
+    v-model:data="localModelValue"
+    :deep="deep"
+    :show-length="showLength"
+    :show-line-numbers="showLineNumbers"
+    :show-line-number="showLineNumber"
+    :show-icon="showIcon"
+    :show-double-quotes="showDoubleQuotes"
+    :virtual="virtual"
+    :height="height"
+    :item-height="itemHeight"
+    :root-path="rootPath"
+    :node-selectable="nodeSelectable"
+    :selectable-type="selectableType"
+    :show-select-controller="showSelectController"
+    :select-on-click-node="selectOnClickNode"
+    :highlight-selected-node="highlightSelectedNode"
+    :collapsed-on-click-brackets="collapsedOnClickBrackets"
+    :render-node-key="renderNodeKey"
+    :render-node-value="renderNodeValue"
+    :editable="editable"
+    :editable-trigger="editableTrigger"
+    @node-click="nodeClick"
+    @brackets-click="bracketsClick"
+    @icon-click="iconClick"
+    @selected-change="selectedChange"
+  />
+</template>

+ 23 - 0
src/components/JsonEditor/src/types/index.ts

@@ -0,0 +1,23 @@
+export interface JsonEditorProps {
+  value: any
+  deep?: number
+  showLength?: boolean
+  showLineNumbers?: boolean
+  showLineNumber?: boolean
+  showIcon?: boolean
+  showDoubleQuotes?: boolean
+  virtual?: boolean
+  height?: number
+  itemHeight?: number
+  rootPath?: string
+  nodeSelectable?: (...args: any[]) => boolean
+  selectableType?: 'multiple' | 'single'
+  showSelectController?: boolean
+  selectOnClickNode?: boolean
+  highlightSelectedNode?: boolean
+  collapsedOnClickBrackets?: boolean
+  renderNodeKey?: (...args: any[]) => any
+  renderNodeValue?: (...args: any[]) => any
+  editable?: boolean
+  editableTrigger?: 'click' | 'dblclick'
+}

+ 5 - 1
src/locales/en.ts

@@ -147,6 +147,7 @@ export default {
     defaultTable: 'Basic example',
     editor: 'Editor',
     richText: 'Rich text',
+    jsonEditor: 'JSON Editor',
     dialog: 'Dialog',
     imageViewer: 'Image viewer',
     descriptions: 'Descriptions',
@@ -300,6 +301,7 @@ export default {
     verifyReset: 'Verify reset',
     // 富文本编辑器
     richText: 'Rich text',
+    jsonEditor: 'JSON Editor',
     form: 'Form',
     // 远程加载
     remoteLoading: 'Remote loading',
@@ -448,7 +450,9 @@ export default {
   },
   richText: {
     richText: 'Rich text',
-    richTextDes: 'Secondary packaging based on wangeditor'
+    richTextDes: 'Secondary packaging based on wangeditor',
+    jsonEditor: 'JSON Editor',
+    jsonEditorDes: 'Secondary packaging based on vue-json-pretty'
   },
   dialogDemo: {
     dialog: 'Dialog',

+ 6 - 1
src/locales/zh-CN.ts

@@ -147,6 +147,7 @@ export default {
     defaultTable: '基础示例',
     editor: '编辑器',
     richText: '富文本',
+    jsonEditor: 'JSON编辑器',
     dialog: '弹窗',
     imageViewer: '图片预览',
     descriptions: '描述',
@@ -298,6 +299,8 @@ export default {
     verifyReset: '验证重置',
     // 富文本编辑器
     richText: '富文本编辑器',
+    // JSON编辑器
+    jsonEditor: 'JSON编辑器',
     form: '表单',
     // 远程加载
     remoteLoading: '远程加载',
@@ -441,7 +444,9 @@ export default {
   },
   richText: {
     richText: '富文本',
-    richTextDes: '基于 wangeditor 二次封装'
+    richTextDes: '基于 wangeditor 二次封装',
+    jsonEditor: 'JSON编辑器',
+    jsonEditorDes: '基于 vue-json-pretty 二次封装'
   },
   dialogDemo: {
     dialog: '弹窗',

+ 8 - 0
src/router/index.ts

@@ -220,6 +220,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
             meta: {
               title: t('router.richText')
             }
+          },
+          {
+            path: 'json-editor',
+            component: () => import('@/views/Components/Editor/JsonEditor.vue'),
+            name: 'JsonEditor',
+            meta: {
+              title: t('router.jsonEditor')
+            }
           }
         ]
       },

+ 36 - 0
src/views/Components/Editor/JsonEditor.vue

@@ -0,0 +1,36 @@
+<script setup lang="ts">
+import { ContentWrap } from '@/components/ContentWrap'
+import { JsonEditor } from '@/components/JsonEditor'
+import { useI18n } from '@/hooks/web/useI18n'
+import { ref, watch } from 'vue'
+
+const { t } = useI18n()
+
+const defaultData = ref({
+  title: '标题',
+  content: '内容'
+})
+
+watch(
+  () => defaultData.value,
+  (val) => {
+    console.log(val)
+  },
+  {
+    deep: true
+  }
+)
+
+setTimeout(() => {
+  defaultData.value = {
+    title: '异步标题',
+    content: '异步内容'
+  }
+}, 4000)
+</script>
+
+<template>
+  <ContentWrap :title="t('richText.jsonEditor')" :message="t('richText.jsonEditorDes')">
+    <JsonEditor v-model="defaultData" />
+  </ContentWrap>
+</template>

+ 14 - 0
src/views/Components/Form/DefaultForm.vue

@@ -1760,6 +1760,20 @@ const schema = reactive<FormSchema[]>([
         )
       }
     }
+  },
+  {
+    field: 'field85',
+    component: 'Divider',
+    label: t('formDemo.jsonEditor')
+  },
+  {
+    field: 'field86',
+    component: 'JsonEditor',
+    label: t('formDemo.default'),
+    value: {
+      a: 1,
+      b: 2
+    }
   }
 ])
 </script>

+ 8 - 2
vite.config.ts

@@ -31,7 +31,12 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
   return {
     base: env.VITE_BASE_PATH,
     plugins: [
-      Vue(),
+      Vue({
+        script: {
+          // 开启defineModel
+          defineModel: true
+        }
+      }),
       VueJsx(),
       // WindiCSS(),
       progress(),
@@ -145,7 +150,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
         'intro.js',
         'qrcode',
         '@wangeditor/editor',
-        '@wangeditor/editor-for-vue'
+        '@wangeditor/editor-for-vue',
+        'vue-json-pretty'
       ]
     }
   }