feat: JsonEditor
This commit is contained in:
parent
2c99cd20f0
commit
c0f4517b87
|
@ -179,6 +179,14 @@ const adminList = [
|
||||||
meta: {
|
meta: {
|
||||||
title: 'router.richText'
|
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/table/ref-table',
|
||||||
'/components/editor-demo',
|
'/components/editor-demo',
|
||||||
'/components/editor-demo/editor',
|
'/components/editor-demo/editor',
|
||||||
|
'/components/editor-demo/json-editor',
|
||||||
'/components/search',
|
'/components/search',
|
||||||
'/components/descriptions',
|
'/components/descriptions',
|
||||||
'/components/image-viewer',
|
'/components/image-viewer',
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
"url": "^0.11.1",
|
"url": "^0.11.1",
|
||||||
"vue": "3.3.4",
|
"vue": "3.3.4",
|
||||||
"vue-i18n": "9.2.2",
|
"vue-i18n": "9.2.2",
|
||||||
|
"vue-json-pretty": "^2.2.4",
|
||||||
"vue-router": "^4.2.4",
|
"vue-router": "^4.2.4",
|
||||||
"vue-types": "^5.1.1"
|
"vue-types": "^5.1.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
} from 'element-plus'
|
} from 'element-plus'
|
||||||
import { InputPassword } from '@/components/InputPassword'
|
import { InputPassword } from '@/components/InputPassword'
|
||||||
import { Editor } from '@/components/Editor'
|
import { Editor } from '@/components/Editor'
|
||||||
|
import { JsonEditor } from '@/components/JsonEditor'
|
||||||
import { ComponentName } from '../types'
|
import { ComponentName } from '../types'
|
||||||
|
|
||||||
const componentMap: Recordable<Component, ComponentName> = {
|
const componentMap: Recordable<Component, ComponentName> = {
|
||||||
|
@ -47,7 +48,8 @@ const componentMap: Recordable<Component, ComponentName> = {
|
||||||
InputPassword: InputPassword,
|
InputPassword: InputPassword,
|
||||||
Editor: Editor,
|
Editor: Editor,
|
||||||
TreeSelect: ElTreeSelect,
|
TreeSelect: ElTreeSelect,
|
||||||
Upload: ElUpload
|
Upload: ElUpload,
|
||||||
|
JsonEditor: JsonEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
export { componentMap }
|
export { componentMap }
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
UploadProps
|
UploadProps
|
||||||
} from 'element-plus'
|
} from 'element-plus'
|
||||||
import { IEditorConfig } from '@wangeditor/editor'
|
import { IEditorConfig } from '@wangeditor/editor'
|
||||||
|
import { JsonEditorProps } from '@/components/JsonEditor'
|
||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
|
|
||||||
export interface PlaceholderModel {
|
export interface PlaceholderModel {
|
||||||
|
@ -53,7 +54,8 @@ export enum ComponentNameEnum {
|
||||||
INPUT_PASSWORD = 'InputPassword',
|
INPUT_PASSWORD = 'InputPassword',
|
||||||
EDITOR = 'Editor',
|
EDITOR = 'Editor',
|
||||||
TREE_SELECT = 'TreeSelect',
|
TREE_SELECT = 'TreeSelect',
|
||||||
UPLOAD = 'Upload'
|
UPLOAD = 'Upload',
|
||||||
|
JSON_EDITOR = 'JsonEditor'
|
||||||
}
|
}
|
||||||
|
|
||||||
type CamelCaseComponentName = keyof typeof ComponentNameEnum extends infer K
|
type CamelCaseComponentName = keyof typeof ComponentNameEnum extends infer K
|
||||||
|
@ -620,6 +622,7 @@ export interface FormSchema {
|
||||||
| InputPasswordComponentProps
|
| InputPasswordComponentProps
|
||||||
| TreeSelectComponentProps
|
| TreeSelectComponentProps
|
||||||
| UploadComponentProps
|
| UploadComponentProps
|
||||||
|
| JsonEditorProps
|
||||||
| any
|
| any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
import JsonEditor from './src/JsonEditor.vue'
|
||||||
|
export type { JsonEditorProps } from './src/types'
|
||||||
|
|
||||||
|
export { JsonEditor }
|
|
@ -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>
|
|
@ -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'
|
||||||
|
}
|
|
@ -147,6 +147,7 @@ export default {
|
||||||
defaultTable: 'Basic example',
|
defaultTable: 'Basic example',
|
||||||
editor: 'Editor',
|
editor: 'Editor',
|
||||||
richText: 'Rich text',
|
richText: 'Rich text',
|
||||||
|
jsonEditor: 'JSON Editor',
|
||||||
dialog: 'Dialog',
|
dialog: 'Dialog',
|
||||||
imageViewer: 'Image viewer',
|
imageViewer: 'Image viewer',
|
||||||
descriptions: 'Descriptions',
|
descriptions: 'Descriptions',
|
||||||
|
@ -300,6 +301,7 @@ export default {
|
||||||
verifyReset: 'Verify reset',
|
verifyReset: 'Verify reset',
|
||||||
// 富文本编辑器
|
// 富文本编辑器
|
||||||
richText: 'Rich text',
|
richText: 'Rich text',
|
||||||
|
jsonEditor: 'JSON Editor',
|
||||||
form: 'Form',
|
form: 'Form',
|
||||||
// 远程加载
|
// 远程加载
|
||||||
remoteLoading: 'Remote loading',
|
remoteLoading: 'Remote loading',
|
||||||
|
@ -448,7 +450,9 @@ export default {
|
||||||
},
|
},
|
||||||
richText: {
|
richText: {
|
||||||
richText: 'Rich text',
|
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: {
|
dialogDemo: {
|
||||||
dialog: 'Dialog',
|
dialog: 'Dialog',
|
||||||
|
|
|
@ -147,6 +147,7 @@ export default {
|
||||||
defaultTable: '基础示例',
|
defaultTable: '基础示例',
|
||||||
editor: '编辑器',
|
editor: '编辑器',
|
||||||
richText: '富文本',
|
richText: '富文本',
|
||||||
|
jsonEditor: 'JSON编辑器',
|
||||||
dialog: '弹窗',
|
dialog: '弹窗',
|
||||||
imageViewer: '图片预览',
|
imageViewer: '图片预览',
|
||||||
descriptions: '描述',
|
descriptions: '描述',
|
||||||
|
@ -298,6 +299,8 @@ export default {
|
||||||
verifyReset: '验证重置',
|
verifyReset: '验证重置',
|
||||||
// 富文本编辑器
|
// 富文本编辑器
|
||||||
richText: '富文本编辑器',
|
richText: '富文本编辑器',
|
||||||
|
// JSON编辑器
|
||||||
|
jsonEditor: 'JSON编辑器',
|
||||||
form: '表单',
|
form: '表单',
|
||||||
// 远程加载
|
// 远程加载
|
||||||
remoteLoading: '远程加载',
|
remoteLoading: '远程加载',
|
||||||
|
@ -441,7 +444,9 @@ export default {
|
||||||
},
|
},
|
||||||
richText: {
|
richText: {
|
||||||
richText: '富文本',
|
richText: '富文本',
|
||||||
richTextDes: '基于 wangeditor 二次封装'
|
richTextDes: '基于 wangeditor 二次封装',
|
||||||
|
jsonEditor: 'JSON编辑器',
|
||||||
|
jsonEditorDes: '基于 vue-json-pretty 二次封装'
|
||||||
},
|
},
|
||||||
dialogDemo: {
|
dialogDemo: {
|
||||||
dialog: '弹窗',
|
dialog: '弹窗',
|
||||||
|
|
|
@ -220,6 +220,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
|
||||||
meta: {
|
meta: {
|
||||||
title: t('router.richText')
|
title: t('router.richText')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'json-editor',
|
||||||
|
component: () => import('@/views/Components/Editor/JsonEditor.vue'),
|
||||||
|
name: 'JsonEditor',
|
||||||
|
meta: {
|
||||||
|
title: t('router.jsonEditor')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
</script>
|
||||||
|
|
|
@ -31,7 +31,12 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
return {
|
return {
|
||||||
base: env.VITE_BASE_PATH,
|
base: env.VITE_BASE_PATH,
|
||||||
plugins: [
|
plugins: [
|
||||||
Vue(),
|
Vue({
|
||||||
|
script: {
|
||||||
|
// 开启defineModel
|
||||||
|
defineModel: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
VueJsx(),
|
VueJsx(),
|
||||||
// WindiCSS(),
|
// WindiCSS(),
|
||||||
progress(),
|
progress(),
|
||||||
|
@ -145,7 +150,8 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
'intro.js',
|
'intro.js',
|
||||||
'qrcode',
|
'qrcode',
|
||||||
'@wangeditor/editor',
|
'@wangeditor/editor',
|
||||||
'@wangeditor/editor-for-vue'
|
'@wangeditor/editor-for-vue',
|
||||||
|
'vue-json-pretty'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue