核心功能开发

This commit is contained in:
AlbertZhang
2020-06-27 15:27:55 +08:00
parent b1d67811bd
commit 615431bcc0
7 changed files with 249 additions and 22 deletions

View File

@@ -1,22 +1,28 @@
<template>
<div id="app">
<json-schema-editor/>
<json-schema-editor :disabled="true" :value="tree" :root="true" style="width:600px"/>
</div>
</template>
<script>
export default {
name: 'App'
name: 'App',
data() {
return {
tree:{
root: {
type: "object",
title: "title",
properties: {
field_1: {
type: "string"
},
},
required: ["field_1"]
}
}
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

View File

@@ -1,10 +1,17 @@
import Vue from 'vue'
import App from './App.vue'
import JsonSchemaEditor from '../packages/json-schema-editor/index'
// import { Row, Col, Input, Icon,Checkbox,Button,Select } from 'ant-design-vue'
Vue.config.productionTip = false
Vue.use(JsonSchemaEditor)
// Vue.use(Row)
// Vue.use(Col)
// Vue.use(Input)
// Vue.use(Icon)
// Vue.use(Checkbox)
// Vue.use(Button)
// Vue.use(Select)
new Vue({
render: h => h(App),
}).$mount('#app')

View File

@@ -1,19 +1,219 @@
<template>
<div class="json-schema-editor">
json-schema-editor
<a-input/>
<a-button type="primary">测试按钮</a-button>
<a-icon type="step-backward" />
<div class="form-recursion">
<a-row class="row" :gutter="10">
<a-col :span="8" class="ant-col-name">
<div :style="{marginLeft:`${20*deep}px`}" class="ant-col-name-c">
<a-button v-if="pickValue.type==='object'" type="link" :icon="hidden?'caret-right':'caret-down'" style="color:rgba(0,0,0,.65)" @click="hidden = !hidden"/>
<span v-else style="width:32px;display:inline-block"></span>
<a-input :disabled="disabled" :value="pickKey" class="ant-col-name-input" @input="onInputName"/>
</div>
<a-checkbox v-if="root" :disabled="!isObject && !isArray" class="ant-col-name-required" @change="onRootCheck"/>
<a-checkbox v-else :disabled="isItem" :checked="checked" class="ant-col-name-required" @change="onCheck"/>
</a-col>
<a-col :span="4">
<a-select v-model="pickValue.type" class="ant-col-type" @change="onChangeType">
<a-select-option :key="t" v-for="t in TYPE">
{{t}}
</a-select-option>
</a-select>
</a-col>
<a-col>
<a-input v-model="pickValue.title" class="ant-col-title" placeholder="标题"/>
</a-col>
<a-col :span="6" class="ant-col-setting">
<a-tooltip>
<span slot="title">设置属性</span>
<a-button type="link" icon="setting" class="setting-icon"/>
</a-tooltip>
<a-tooltip v-if="isObject">
<span slot="title">添加子节点</span>
<a-button type="link" icon="plus" class="plus-icon" @click="addChild"/>
</a-tooltip>
<a-tooltip v-if="!root && !isItem">
<span slot="title">删除节点</span>
<a-button type="link" class="close-icon ant-btn-icon-only" @click="removeNode">
<i aria-label="icon: plus" class="anticon anticon-plus">
<svg viewBox="64 64 896 896" data-icon="plus" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M810.666667 273.493333L750.506667 213.333333 512 451.84 273.493333 213.333333 213.333333 273.493333 451.84 512 213.333333 750.506667 273.493333 810.666667 512 572.16 750.506667 810.666667 810.666667 750.506667 572.16 512z" p-id="1142"></path></svg>
</i>
</a-button>
</a-tooltip>
</a-col>
</a-row>
<template v-if="!hidden&&pickValue.properties && !isArray">
<json-schema-editor v-for="(item,key,index) in pickValue.properties" :value="{[key]:item}" :parent="pickValue" :key="index" :deep="deep+1" class="children"/>
</template>
<template v-if="isArray">
<json-schema-editor :value="{items:pickValue.items}" :deep="deep+1" disabled isItem class="children"/>
</template>
</div>
</template>
<script>
import { Button, Input, Icon } from 'ant-design-vue'
import TYPE from './type/type'
import { Row,Col,Button,Input, Icon,Checkbox,Select,Tooltip } from 'ant-design-vue'
import { clearAttr } from './util'
export default {
name: 'JsonSchemaEditor',
name:'JsonSchemaEditor',
components: {
ARow:Row,ACol:Col,
AButton: Button,
// eslint-disable-next-line vue/no-unused-components
AIcon: Icon,
AInput: Input,
AIcon:Icon
ACheckbox: Checkbox,
ASelect: Select,
ASelectOption:Select.Option,
ATooltip: Tooltip,
},
props:{
value: Object,
disabled: { //name不可编辑根节点name不可编辑,数组元素name不可编辑
type: Boolean,
default: false
},
isItem: { //是否数组元素
type: Boolean,
default: false
},
deep:{ // 节点深度根节点deep=0
type:Number,
default: 0
},
root:{ //是否root节点
type:Boolean,
default:false
},
parent: { //父节点
type: Object,
default: null
}
},
computed: {
pickValue(){
return Object.values(this.value)[0]
},
pickKey(){
return Object.keys(this.value)[0]
},
isObject(){
return this.pickValue.type === 'object'
},
isArray(){
return this.pickValue.type === 'array'
},
checked(){
return this.parent && this.parent.required && this.parent.required.indexOf(this.pickKey) >= 0
}
},
data(){
return {
TYPE,
hidden:false,
countAdd: 1
}
},
mounted(){
console.info(this.value)
},
methods: {
onInputName(event){
clearAttr(this.value)
console.info(event)
},
onInputTitle(event){
this.title = event.target.value
},
onChangeType() {
this.$delete(this.pickValue,'properties')
this.$delete(this.pickValue,'required')
if(this.isArray){
this.$set(this.pickValue,'items',{type:'string'})
}
},
onCheck(e){
this._checked(e.target.checked,this.parent)
},
onRootCheck(e){
const checked = e.target.checked
this._deepCheck(checked,this.pickValue)
},
_deepCheck(checked,node){
if(node.type === 'object'){
checked ? this.$set(node,'required',Object.keys(node.properties)) : this.$delete(node,'required')
Object.keys(node.properties).forEach(key => this._deepCheck(checked,node.properties[key]))
} else if(node.type === 'array'){
checked ? this.$set(node.items,'required',Object.keys(node.items.properties)) : this.$delete(node.items,'required')
Object.keys(node.items.properties).forEach(key => this._deepCheck(checked,node.items.properties[key]))
}
},
_checked(checked,parent){
let required = parent.required
if(checked){
required || this.$set(this.parent,'required',[])
required = this.parent.required
required.indexOf(this.pickKey) === -1 && required.push(this.pickKey)
}else{
const pos = required.indexOf(this.pickKey)
pos >=0 && required.splice(pos,1)
}
},
addChild(){
const name = this._joinName()
const type = 'string'
const node = this.pickValue
node.properties || this.$set(node,'properties',{})
const props = node.properties
this.$set(props,name,{type: type})
console.info(this.value)
},
removeNode(){
const { properties,required } = this.parent
console.info(properties,required)
this.$delete(properties,this.pickKey)
if(required){
const pos = required.indexOf(this.pickKey)
pos >=0 && required.splice(pos,1)
required.length === 0 && this.$delete(this.parent,'required')
}
},
_joinName(){
return `feild_${this.deep}_${this.countAdd++}`
}
}
}
</script>
</script>
<style lang="less" scoped>
.form-recursion{
width:100%;
.row{
display: flex;
margin:12px;
.ant-col-name{
display:flex;
align-items:center;
.ant-col-name-c{
display: flex;
align-items: center;
}
.ant-col-name-required{
margin-left:6px;
}
}
.ant-col-type{
width: 100%;
}
.ant-col-setting{
display: inline-block;
}
.setting-icon{
color:rgba(0,0,0,.45);
}
.plus-icon{
color:#5B8FF9;
}
.close-icon{
color:#E8684A
}
}
}
</style>

View File

@@ -0,0 +1,7 @@
const obj = {
type: 'object',
properties: [ 'properties', 'required' ],
enableChildren: true,
requireChildren: false
}
export { obj }

View File

@@ -0,0 +1,2 @@
const TYPE = ['string', 'number', 'integer','object', 'array', 'boolean']
export default TYPE

View File

@@ -0,0 +1,5 @@
export function clearAttr(obj) {
for(let key in obj){
delete obj[key]
}
}