1.添加国际化支持;2.自定义属性开关

This commit is contained in:
zyqwst
2020-10-12 22:33:58 +08:00
parent a7747bf229
commit 2677bc7c92
30 changed files with 26711 additions and 10716 deletions

View File

@@ -1,15 +1,33 @@
<p align="center">
<img width="60" src="https://github.com/zyqwst/json-schema-editor-vue/blob/master/examples/assets/logo.png">
<img width="60" src="https://gitee.com/hz8866/json-schema-editor-vue/raw/master/examples/assets/logo.png">
</p>
<h1 align="center">
<a href="http://json-schema.sviip.com/" target="_blank">json-schema-editor-vue</a>
</h1>
<p align="center">A json-schema editor of high efficient and easy-to-use, base on Vue</p>
[![Start](https://img.shields.io/github/stars/zyqwst/json-schema-editor-vue?style=social)](https://github.com/zyqwst/json-schema-editor-vue/stargazers)
[![Fork](https://img.shields.io/github/forks/zyqwst/json-schema-editor-vue?style=social)](https://github.com/zyqwst/json-schema-editor-vue/fork)
[![GitHub open issues](https://img.shields.io/github/issues/zyqwst/json-schema-editor-vue.svg)](https://github.com/zyqwst/json-schema-editor-vue/issues?q=is%3Aopen+is%3Aissue)
[![npm download](https://img.shields.io/npm/dt/json-schema-editor-vue.svg?maxAge=30)](https://www.npmjs.com/package/json-schema-editor-vue)
[![npm download per month](https://img.shields.io/npm/dm/json-schema-editor-vue.svg)](https://www.npmjs.com/package/json-schema-editor-vue)
[![npm version](https://img.shields.io/npm/v/json-schema-editor-vue.svg)](https://www.npmjs.com/package/json-schema-editor-vue)
[![MIT License](https://img.shields.io/github/license/zyqwst/json-schema-editor-vue.svg)](https://github.com/zyqwst/json-schema-editor-vue/blob/master/LICENSE)
A json-schema editor of high efficient and easy-to-use, base on Vue
<p align="center">
<img width="100%" src="https://raw.githubusercontent.com/zyqwst/json-schema-editor-vue/master/examples/assets/capture.png">
<img width="100%" src="https://gitee.com/hz8866/json-schema-editor-vue/raw/master/examples/assets/capture.png">
</p>
**支持自定义属性,满足特殊的需求**
<p align="center">
<img width="100%" src="https://gitee.com/hz8866/json-schema-editor-vue/raw/master/examples/assets/custom.png">
</p>
### Example
**Demo** [http://json-schema.sviip.com](http://json-schema.sviip.com)
**[国内Demo](http://json-schema-editor.sviip.com)**
### Usage
```bash
@@ -17,7 +35,7 @@ npm install json-schema-editor-vue
```
```vue
import JsonSchemaEditor from '../packages/index'
import JsonSchemaEditor from 'json-schema-editor-vue'
Vue.use(JsonSchemaEditor)
```
@@ -46,7 +64,18 @@ export default {
}
</script>
```
### json-schema-editor-vue属性说明如下
|属性|说明|类型|是否必须|默认值|
:-|:-|:-|:-|:-
|value|传入一个默认的树节点用来接收编辑后的json schema结果|Object|是||
|disabled|节点名称不可编辑|Boolean||`false`|
|disabledType|节点类型不可选择|Boolean||`false`|
|root|是否是根节点|Boolean||`true`|
|custom|是否允许添加自定义属性|Boolean||`false`|
Don't forget to star if it helped!
如果对您有帮助,别忘记给个星哦
### Links
- [json-schema-editor-visual](https://github.com/YMFE/json-schema-editor-visual)

1
dist/css/chunk-vendors.d2d1eca3.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
dist/css/index.6c3f23db.css vendored Normal file
View File

@@ -0,0 +1 @@
*{padding:0;margin:0;box-sizing:border-box}.title{text-align:center;font-size:40px;font-weight:700;height:100px;line-height:100px}.container{display:flex;padding:20px;width:80vw;min-width:800px;justify-content:center;height:calc(100vh - 150px);margin:auto}.container>pre{font-family:monospace}.container>pre,.schema{height:100%;overflow-y:auto;border:1px solid rgba(0,0,0,.1);border-radius:8px;padding:12px;width:50%}.schema{margin-left:20px;overflow-x:hidden}.json-schema-editor .row[data-v-196eaef8]{display:flex;margin:12px}.json-schema-editor .row .ant-col-name .ant-col-name-c[data-v-196eaef8],.json-schema-editor .row .ant-col-name[data-v-196eaef8]{display:flex;align-items:center}.json-schema-editor .row .ant-col-name .ant-col-name-required[data-v-196eaef8]{flex:0 0 24px;text-align:center}.json-schema-editor .row .ant-col-type[data-v-196eaef8]{width:100%}.json-schema-editor .row .ant-col-setting[data-v-196eaef8]{display:inline-block}.json-schema-editor .row .setting-icon[data-v-196eaef8]{color:rgba(0,0,0,.45);border:none}.json-schema-editor .row .plus-icon[data-v-196eaef8]{border:none}.json-schema-editor .row .close-icon[data-v-196eaef8]{color:#888;border:none}.json-schema-editor-advanced-modal{color:rgba(0,0,0,.65);min-width:600px}.json-schema-editor-advanced-modal pre{font-family:monospace;height:100%;overflow-y:auto;border:1px solid rgba(0,0,0,.1);border-radius:4px;padding:12px;width:50%}.json-schema-editor-advanced-modal h3{display:block;border-left:3px solid #1890ff;padding:0 8px}.json-schema-editor-advanced-modal .ant-advanced-search-form .ant-form-item{display:flex}.json-schema-editor-advanced-modal .ant-advanced-search-form .ant-form-item .ant-form-item-control-wrapper{flex:1}

View File

@@ -1 +0,0 @@
*{padding:0;margin:0;box-sizing:border-box}.title{text-align:center;font-size:40px;font-weight:700;height:100px;line-height:100px}.container{display:flex;padding:20px;width:80vw;min-width:800px;justify-content:center;height:calc(100vh - 100px);margin:auto}pre{font-family:monospace}.schema,pre{height:100%;overflow-y:auto;border:1px solid rgba(0,0,0,.1);border-radius:8px;padding:12px;width:50%}.schema{margin-left:20px;overflow-x:hidden}.json-schema-editor .row[data-v-7590959b]{display:flex;margin:12px}.json-schema-editor .row .ant-col-name .ant-col-name-c[data-v-7590959b],.json-schema-editor .row .ant-col-name[data-v-7590959b]{display:flex;align-items:center}.json-schema-editor .row .ant-col-name .ant-col-name-required[data-v-7590959b]{flex:0 0 24px;text-align:center}.json-schema-editor .row .ant-col-type[data-v-7590959b]{width:100%}.json-schema-editor .row .ant-col-setting[data-v-7590959b]{display:inline-block}.json-schema-editor .row .setting-icon[data-v-7590959b]{color:rgba(0,0,0,.45)}.json-schema-editor .row .plus-icon[data-v-7590959b]{color:#5b8ff9}.json-schema-editor .row .close-icon[data-v-7590959b]{color:#e8684a}

109
dist/index.html vendored
View File

@@ -1 +1,108 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=favicon.ico><title>json-schema-editor-vue</title><link href=css/chunk-vendors.f4ffed8f.css rel=preload as=style><link href=css/index.f23e0edd.css rel=preload as=style><link href=js/chunk-vendors.f9af6da6.js rel=preload as=script><link href=js/index.3da5f4f3.js rel=preload as=script><link href=css/chunk-vendors.f4ffed8f.css rel=stylesheet><link href=css/index.f23e0edd.css rel=stylesheet></head><body><noscript><strong>We're sorry but json-schema-editor-vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=js/chunk-vendors.f9af6da6.js></script><script src=js/index.3da5f4f3.js></script></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=favicon.ico><title>json-schema-editor-vue</title><style>/* GitHub Cornor */
.github-corner :hover .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
@media (max-width: 991px) {
.github-corner >svg {
fill: #fff !important;
color: #008000 !important;
}
.github-corner .github-corner:hover .octo-arm {
animation: none;
}
.github-corner .github-corner .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
}
@-moz-keyframes octocat-wave {
0%, 100% {
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-ms-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
20%, 60% {
-webkit-transform: rotate(-25deg);
-moz-transform: rotate(-25deg);
-ms-transform: rotate(-25deg);
-o-transform: rotate(-25deg);
transform: rotate(-25deg);
}
40%, 80% {
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
-o-transform: rotate(10deg);
transform: rotate(10deg);
}
}
@-webkit-keyframes octocat-wave {
0%, 100% {
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-ms-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
20%, 60% {
-webkit-transform: rotate(-25deg);
-moz-transform: rotate(-25deg);
-ms-transform: rotate(-25deg);
-o-transform: rotate(-25deg);
transform: rotate(-25deg);
}
40%, 80% {
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
-o-transform: rotate(10deg);
transform: rotate(10deg);
}
}
@-o-keyframes octocat-wave {
0%, 100% {
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-ms-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
20%, 60% {
-webkit-transform: rotate(-25deg);
-moz-transform: rotate(-25deg);
-ms-transform: rotate(-25deg);
-o-transform: rotate(-25deg);
transform: rotate(-25deg);
}
40%, 80% {
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
-o-transform: rotate(10deg);
transform: rotate(10deg);
}
}
@keyframes octocat-wave {
0%, 100% {
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-ms-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
20%, 60% {
-webkit-transform: rotate(-25deg);
-moz-transform: rotate(-25deg);
-ms-transform: rotate(-25deg);
-o-transform: rotate(-25deg);
transform: rotate(-25deg);
}
40%, 80% {
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
-o-transform: rotate(10deg);
transform: rotate(10deg);
}
}</style><link href=css/chunk-vendors.d2d1eca3.css rel=preload as=style><link href=css/index.6c3f23db.css rel=preload as=style><link href=js/chunk-vendors.dcf6433b.js rel=preload as=script><link href=js/index.2dfbcc7d.js rel=preload as=script><link href=css/chunk-vendors.d2d1eca3.css rel=stylesheet><link href=css/index.6c3f23db.css rel=stylesheet></head><body><a href=https://github.com/zyqwst/json-schema-editor-vue class=github-corner target=_blank title="Follow me on GitHub" aria-label="Follow me on GitHub"><svg width=80 height=80 viewBox="0 0 250 250" style="fill:#008000; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden=true><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill=currentColor style="transform-origin: 130px 106px;" class=octo-arm></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill=currentColor class=octo-body></path></svg></a><noscript><strong>We're sorry but json-schema-editor-vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><footer style=text-align:center;margin-bottom:16px;><a href="" target=_blank style="color: #999">Github</a><a href="" target=_blank style="color: #999;margin-left:16px;">Gitee</a><span style=margin-left:16px>©Zhangyq</span></footer><script src=js/chunk-vendors.dcf6433b.js></script><script src=js/index.2dfbcc7d.js></script></body></html>

File diff suppressed because one or more lines are too long

1
dist/js/index.2dfbcc7d.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,7 @@
</div>
<div class="container">
<pre>{{tree}}</pre>
<json-schema-editor class="schema" :value="tree"/>
<json-schema-editor class="schema" :value="tree" disabledType lang="zh_CN" custom/>
</div>
</div>
</template>
@@ -17,8 +17,31 @@ export default {
return {
tree:
{
root: {
type: "object"
"root": {
"type": "object",
"title": "条件",
"properties": {
"name": {
"type": "string",
"title": "名称",
"maxLength": 10,
"minLength": 2
},
"appId": {
"type": "integer",
"title": "应用ID"
},
"credate": {
"type": "string",
"title": "创建日期",
"format": "date"
}
},
"required": [
"name",
"appId",
"credate"
]
}
}
}
@@ -44,10 +67,10 @@ export default {
width:80vw;
min-width:800px;
justify-content:center;
height: calc(100vh - 100px);
height: calc(100vh - 150px);
margin:auto;
}
pre {
.container>pre {
font-family: monospace;
height: 100%;
overflow-y: auto;

BIN
examples/assets/custom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

View File

@@ -1,17 +1,11 @@
import Vue from 'vue'
import App from './App.vue'
import JsonSchemaEditor from '../packages/index'
// import { Row, Col, Input, Icon,Checkbox,Button,Select } from 'ant-design-vue'
Vue.config.productionTip = false
import { Modal} from 'ant-design-vue'
Vue.use(Modal)
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')

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2301
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,20 @@
{
"name": "json-schema-editor-vue",
"version": "1.0.1",
"version": "1.2.1",
"author": "zhangyq",
"description": "A json-schema editor of high efficient and easy-to-use, base on Vue",
"keyword": "json schema vue",
"keywords": [
"jsonschema",
"jsonschemavue",
"jsonschemaeditor",
"json",
"jsoneditor"
],
"repository": {
"type": "git",
"url": "git+https://github.com/zyqwst/json-schema-editor-vue"
},
"homepage": "http://json-schema.sviip.com/",
"license": " Apache-2.0 License",
"main": "lib/json-schema-editor-vue.umd.min.js",
"private": false,
@@ -14,7 +25,7 @@
"lib": "vue-cli-service build --target lib --name json-schema-editor-vue --dest lib packages/index.js"
},
"dependencies": {
"ant-design-vue": "^1.6.2",
"ant-design-vue": "^1.6.4",
"core-js": "^3.6.5",
"vue": "^2.6.11"
},

View File

@@ -0,0 +1,90 @@
const langs = {
en_US: {
'title': 'Title',
'import_json': 'Import JSON',
'base_setting': 'Base Setting',
'all_setting': 'Source Code',
'default': 'Default',
'description':'Description',
"adv_setting": "Advanced Settings",
"add_child_node": "Add child node",
'add_sibling_node': 'Add sibling nodes',
'add_node':'Add sibling/child nodes',
'remove_node': 'Remove node',
'child_node': 'Child node',
'sibling_node':'Sibling node',
'ok':'OK',
'cancel':'Cancel',
'minLength':'Min length',
'maxLength': 'Max length',
'pattern':'MUST be a valid regular expression.',
'exclusiveMinimum': 'Value strictly less than',
'exclusiveMaximum': 'Value strictly more than',
'minimum': 'Min',
'maximum': 'Max',
'uniqueItems': 'Unique Items',
'minItems':'MinItems',
'maxItems': 'MaxItems',
'minProperties':'MinProperties',
'maxProperties': 'MaxProperties',
'checked_all': 'Checked All',
'valid_json': 'Not valid json',
'enum': 'Enum',
'enum_msg': 'One value per line',
'enum_desc': 'desc',
'enum_desc_msg': 'enum description',
'required': 'Required',
'mock': 'mock',
'mockLink': 'Help',
'format': 'Format',
'nothing': 'Nothing',
'preview': 'Preview',
'add_custom': 'Add Custom Prop',
},
zh_CN: {
'title': '标题',
'import_json': '导入 json',
'base_setting': '基础设置',
'all_setting': '编辑源码',
'default': '默认值',
'description':'描述',
'adv_setting': '高级设置',
"add_child_node": "添加子节点",
'add_sibling_node': '添加兄弟节点',
'add_node':'添加兄弟/子节点',
'remove_node': '删除节点',
'child_node': '子节点',
'sibling_node':'兄弟节点',
'ok':'确定',
'cancel':'取消',
'minLength':'最小长度',
'maxLength': '最大长度',
'pattern': '用正则表达式约束字符串',
'exclusiveMinimum': '开启后,数据必须大于最小值',
'exclusiveMaximum': '开启后,数据必须小于最大值',
'minimum': '最小值',
'maximum': '最大值',
'uniqueItems': '开启后,每个元素都不相同',
'minItems':'最小元素个数',
'maxItems': '最大元素个数',
'minProperties':'最小元素个数',
'maxProperties': '最大元素个数',
'checked_all': '全选',
'valid_json': '不是合法的json字符串',
'enum': '枚举',
'enum_msg': '每行只能写一个值',
'enum_desc': '备注',
'enum_desc_msg': '备注描述信息',
'required': '是否必须',
'mock': 'mock',
'mockLink': '查看文档',
'format': '格式化',
'nothing': '无',
'preview': '预览',
'add_custom': '添加自定义属性'
}
}
export default (lang) => {
return langs[lang]
}

View File

@@ -8,35 +8,39 @@
<a-input :disabled="disabled || root" :value="pickKey" class="ant-col-name-input" @blur="onInputName"/>
</div>
<a-tooltip v-if="root">
<span slot="title">全选</span>
<span slot="title" v-text="local['checked_all']">全选</span>
<a-checkbox :disabled="!isObject && !isArray" class="ant-col-name-required" @change="onRootCheck"/>
</a-tooltip>
<a-tooltip v-else>
<span slot="title">是否必填</span>
<span slot="title" v-text="local['required']">是否必填</span>
<a-checkbox :disabled="isItem" :checked="checked" class="ant-col-name-required" @change="onCheck"/>
</a-tooltip>
</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">
<a-select v-model="pickValue.type" :disabled="disabledType" class="ant-col-type" @change="onChangeType" :getPopupContainer="
triggerNode => {
return triggerNode.parentNode || document.body;
}"
>
<a-select-option :key="t" v-for="t in TYPE_NAME">
{{t}}
</a-select-option>
</a-select>
</a-col>
<a-col>
<a-input v-model="pickValue.title" class="ant-col-title" placeholder="标题"/>
<a-input v-model="pickValue.title" class="ant-col-title" :placeholder="local['title']"/>
</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"/>
<span slot="title" v-text="local['adv_setting']">高级设置</span>
<a-button type="link" icon="setting" class="setting-icon" @click="onSetting"/>
</a-tooltip>
<a-tooltip v-if="isObject">
<span slot="title">添加子节点</span>
<span slot="title" v-text="local['add_child_node']">添加子节点</span>
<a-button type="link" icon="plus" class="plus-icon" @click="addChild"/>
</a-tooltip>
<a-tooltip v-if="!root && !isItem">
<span slot="title">删除节点</span>
<span slot="title" v-text="local['remove_node']">删除节点</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>
@@ -46,16 +50,76 @@
</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" :root="false" class="children"/>
<json-schema-editor v-for="(item,key,index) in pickValue.properties" :value="{[key]:item}" :parent="pickValue" :key="index" :deep="deep+1" :root="false" class="children" :lang="lang" :custom="custom"/>
</template>
<template v-if="isArray">
<json-schema-editor :value="{items:pickValue.items}" :deep="deep+1" disabled isItem :root="false" class="children"/>
<json-schema-editor :value="{items:pickValue.items}" :deep="deep+1" disabled isItem :root="false" class="children" :lang="lang" :custom="custom"/>
</template>
<a-modal v-model="modalVisible" :title="local['adv_setting']" :maskClosable="false" :okText="local['ok']" :cancelText="local['cancel']" width="800px" @ok="handleOk" dialogClass="json-schema-editor-advanced-modal">
<h3 v-text="local['base_setting']">基础设置</h3>
<a-form v-model="advancedValue" class="ant-advanced-search-form">
<a-row :gutter="6">
<a-col :span="8" v-for="(item,key) in advancedValue" :key="key">
<a-form-item>
<span>{{ local[key] }}</span>
<a-input-number v-model="advancedValue[key]" v-if="advancedAttr[key].type === 'integer'" style="width:100%" :placeholder="key"/>
<a-input-number v-model="advancedValue[key]" v-else-if="advancedAttr[key].type === 'number'" style="width:100%" :placeholder="key"/>
<span v-else-if="advancedAttr[key].type === 'boolean'" style="display:inline-block;width:100%">
<a-switch v-model="advancedValue[key]"/>
</span>
<a-select v-else-if="advancedAttr[key].type === 'array'" v-model="advancedValue[key]" style="width:100%" :getPopupContainer="
triggerNode => {
return triggerNode.parentNode || document.body;
}"
:placeholder="local[key]"
>
<a-select-option value="">{{ local['nothing'] }}</a-select-option>
<a-select-option :key="t" v-for="t in advancedAttr[key].enums">
{{t}}
</a-select-option>
</a-select>
<a-input v-model="advancedValue[key]" v-else style="width:100%" :placeholder="key"/>
</a-form-item>
</a-col>
</a-row>
</a-form>
<h3 v-text="local['add_custom']" v-show="custom">添加自定义属性</h3>
<a-form class="ant-advanced-search-form" v-show="custom">
<a-row :gutter="6">
<a-col :span="8" v-for="item in customProps" :key="item.key">
<a-form-item :label="item.key">
<a-input v-model="item.value" style="width:calc(100% - 30px)"/>
<a-button icon="close" type="link" @click="customProps.splice(customProps.indexOf(item),1)" style="width:30px"></a-button>
</a-form-item>
</a-col>
<a-col :span="8" v-show="addProp.key != undefined">
<a-form-item>
<a-input slot="label" v-model="addProp.key" style="width:100px"/>
<a-input v-model="addProp.value" style="width:100%"/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item>
<a-button icon="check" type="link" @click="confirmAddCustomNode" v-if="customing"></a-button>
<a-tooltip :title="local['add_custom']" v-else>
<a-button icon="plus" type="link" @click="addCustomNode"></a-button>
</a-tooltip>
</a-form-item>
</a-col>
</a-row>
</a-form>
<h3 v-text="local['preview']">预览</h3>
<pre style="width:100%">{{completeNodeValue}}</pre>
</a-modal>
</div>
</template>
<script>
import TYPE from './type/type'
import { Row,Col,Button,Input, Icon,Checkbox,Select,Tooltip } from 'ant-design-vue'
import { isNull } from './util'
import {TYPE_NAME, TYPE} from './type/type'
import { Row,Col,Button,Input,InputNumber, Icon,Checkbox,Select,Tooltip,Modal,Form,Switch} from 'ant-design-vue'
import LocalProvider from './LocalProvider'
export default {
name:'JsonSchemaEditor',
components: {
@@ -63,11 +127,15 @@ export default {
AButton: Button,
// eslint-disable-next-line vue/no-unused-components
AIcon: Icon,
AInput: Input,
AInput: Input,AInputNumber:InputNumber,
ACheckbox: Checkbox,
ASelect: Select,
ASelectOption:Select.Option,
ATooltip: Tooltip,
AModal:Modal,
AForm:Form,
AFormItem: Form.Item,
ASwitch: Switch
},
props:{
value: {
@@ -78,6 +146,10 @@ export default {
type: Boolean,
default: false
},
disabledType: { //禁用类型选择
type: Boolean,
default: false
},
isItem: { //是否数组元素
type: Boolean,
default: false
@@ -93,6 +165,14 @@ export default {
parent: { //父节点
type: Object,
default: null
},
custom: { //enable custom properties
type: Boolean,
default: false
},
lang: { // i18n language
type: String,
default: 'zh_CN'
}
},
computed: {
@@ -110,13 +190,39 @@ export default {
},
checked(){
return this.parent && this.parent.required && this.parent.required.indexOf(this.pickKey) >= 0
},
advanced(){
return TYPE[this.pickValue.type]
},
advancedAttr(){
return TYPE[this.pickValue.type].attr
},
advancedNotEmptyValue(){
const jsonNode = Object.assign({},this.advancedValue);
for(let key in jsonNode){
isNull(jsonNode[key]) && delete jsonNode[key]
}
return jsonNode
},
completeNodeValue(){
const t = {}
for(const item of this.customProps){
t[item.key] = item.value
}
return Object.assign({},this.pickValue,this.advancedNotEmptyValue, t)
}
},
data(){
return {
TYPE,
TYPE_NAME,
hidden:false,
countAdd: 1
countAdd: 1,
modalVisible: false,
advancedValue:{},
addProp:{},// 自定义属性
customProps: [],
customing: false,
local: LocalProvider(this.lang)
}
},
methods: {
@@ -135,6 +241,7 @@ export default {
},
onChangeType() {
this.$delete(this.pickValue,'properties')
this.$delete(this.pickValue,'items')
this.$delete(this.pickValue,'required')
if(this.isArray){
this.$set(this.pickValue,'items',{type:'string'})
@@ -177,6 +284,16 @@ export default {
const props = node.properties
this.$set(props,name,{type: type})
},
addCustomNode(){
this.$set(this.addProp,'key',this._joinName())
this.$set(this.addProp,'value','')
this.customing = true
},
confirmAddCustomNode() {
this.customProps.push(this.addProp)
this.addProp = {}
this.customing = false
},
removeNode(){
const { properties,required } = this.parent
this.$delete(properties,this.pickKey)
@@ -188,6 +305,27 @@ export default {
},
_joinName(){
return `feild_${this.deep}_${this.countAdd++}`
},
onSetting(){
this.modalVisible = true
this.advancedValue = this.advanced.value
for(const k in this.advancedValue) {
if(this.pickValue[k]) this.advancedValue[k] = this.pickValue[k]
}
},
handleOk(){
this.modalVisible = false
for(const key in this.advancedValue){
if(isNull(this.advancedValue[key])){
this.$delete(this.pickValue,key)
}else {
this.$set(this.pickValue,key,this.advancedValue[key])
}
}
for(const item of this.customProps){
this.$set(this.pickValue,item.key,item.value)
}
}
}
}
@@ -217,13 +355,45 @@ export default {
}
.setting-icon{
color:rgba(0,0,0,.45);
border:none
}
.plus-icon{
color:#5B8FF9;
border:none
}
.close-icon{
color:#E8684A
color:#888;
border:none
}
}
}
</style>
<style lang="less">
.json-schema-editor-advanced-modal{
color: rgba(0,0,0,.65);
min-width:600px;
pre {
font-family: monospace;
height: 100%;
overflow-y: auto;
border:1px solid rgba(0,0,0,.1);
border-radius: 4px;
padding: 12px;
width:50%
}
h3{
display: block;
border-left: 3px solid #1890ff;
padding:0 8px;
}
.ant-advanced-search-form {
.ant-form-item {
display: flex;
.ant-form-item-control-wrapper {
flex: 1;
}
}
}
}
</style>

View File

@@ -0,0 +1,26 @@
const value = {
description: null,
minItems:null,
maxItems:null,
uniqueItems:false
}
const attr = {
description: {
name: '描述',
type: 'string'
},
maxItems:{
name: '最大元素个数',
type: 'integer'
},
minItems:{
name: '最小元素个数',
type: 'integer'
},
uniqueItems:{
name:'元素不可重复',
type: 'boolean'
}
}
const wrapper = {value, attr}
export default wrapper

View File

@@ -0,0 +1,11 @@
const value = {
description: null
}
const attr = {
description: {
name: '描述',
type: 'string'
}
}
const wrapper = {value, attr}
export default wrapper

View File

@@ -0,0 +1,31 @@
const value = {
description: null,
maximum: null,
minimum: null,
exclusiveMaximum:null,
exclusiveMinimum:null
}
const attr = {
description: {
name: '描述',
type: 'string',
},
maximum:{
name:'最大值',
type:'integer'
},
minimum:{
name:'最小值',
type:'integer'
},
exclusiveMaximum:{
name:'不包含最大值',
type:'boolean'
},
exclusiveMinimum:{
name:'不包含最小值',
type:'boolean'
}
}
const wrapper = {value, attr}
export default wrapper

View File

@@ -0,0 +1,31 @@
const value = {
description: null,
maximum: null,
minimum: null,
exclusiveMaximum:null,
exclusiveMinimum:null
}
const attr = {
description: {
name: '描述',
type: 'string',
},
maximum:{
name:'最大值',
type:'number'
},
minimum:{
name:'最小值',
type:'number'
},
exclusiveMaximum:{
name:'不包含最大值',
type:'boolean'
},
exclusiveMinimum:{
name:'不包含最小值',
type:'boolean'
}
}
const wrapper = {value, attr}
export default wrapper

View File

@@ -1,7 +1,21 @@
const obj = {
type: 'object',
properties: [ 'properties', 'required' ],
enableChildren: true,
requireChildren: false
const value = {
description: null,
maxProperties: null,
minProperties: null
}
export { obj }
const attr = {
description: {
name: '描述',
type: 'string',
},
maxProperties:{
name:'最大元素个数',
type:'integer'
},
minProperties:{
name:'最小元素个数',
type:'integer'
}
}
const wrapper = {value, attr}
export default wrapper

View File

@@ -0,0 +1,32 @@
const value = {
description: null,
maxLength: null,
minLength: null,
pattern: null,
format:null
}
const attr = {
description: {
name: '描述',
type: 'string',
},
maxLength:{
name:'最大字符数',
type:'integer'
},
minLength:{
name:'最小字符数',
type:'integer'
},
pattern: {
name: '正则表达式',
type:'string'
},
format: {
name:'格式',
type:'array',
enums:['date','date-time','email','hostname','ipv4','ipv6','uri']
}
}
const wrapper = {value, attr}
export default wrapper

View File

@@ -1,2 +1,17 @@
const TYPE = ['string', 'number', 'integer','object', 'array', 'boolean']
export default TYPE
import _object from './object'
import _string from './string'
import _array from './array'
import _boolean from './boolean'
import _integer from './integer'
import _number from './number'
const TYPE_NAME = ['string', 'number', 'integer','object', 'array', 'boolean']
const TYPE = {
'object': _object,
'string': _string,
'array': _array,
'boolean': _boolean,
'integer': _integer,
'number': _number
}
export {TYPE ,TYPE_NAME}

View File

@@ -3,3 +3,22 @@ export function clearAttr(obj) {
delete obj[key]
}
}
/**
* 快速拷贝两个对象的属性值
* @param {*} source
* @param {*} target
*/
export function copyAttr(source, target){
Object.keys(target).forEach(key=>{target[key]=source[key]})
}
export function isNull(ele){
if(typeof ele==='undefined'){
return true;
}else if(ele==null){
return true;
}else if(ele==''){
return true;
}
return false;
}

View File

@@ -6,12 +6,132 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<style>
/* GitHub Cornor */
.github-corner :hover .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
@media (max-width: 991px) {
.github-corner >svg {
fill: #fff !important;
color: #008000 !important;
}
.github-corner .github-corner:hover .octo-arm {
animation: none;
}
.github-corner .github-corner .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
}
@-moz-keyframes octocat-wave {
0%, 100% {
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-ms-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
20%, 60% {
-webkit-transform: rotate(-25deg);
-moz-transform: rotate(-25deg);
-ms-transform: rotate(-25deg);
-o-transform: rotate(-25deg);
transform: rotate(-25deg);
}
40%, 80% {
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
-o-transform: rotate(10deg);
transform: rotate(10deg);
}
}
@-webkit-keyframes octocat-wave {
0%, 100% {
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-ms-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
20%, 60% {
-webkit-transform: rotate(-25deg);
-moz-transform: rotate(-25deg);
-ms-transform: rotate(-25deg);
-o-transform: rotate(-25deg);
transform: rotate(-25deg);
}
40%, 80% {
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
-o-transform: rotate(10deg);
transform: rotate(10deg);
}
}
@-o-keyframes octocat-wave {
0%, 100% {
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-ms-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
20%, 60% {
-webkit-transform: rotate(-25deg);
-moz-transform: rotate(-25deg);
-ms-transform: rotate(-25deg);
-o-transform: rotate(-25deg);
transform: rotate(-25deg);
}
40%, 80% {
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
-o-transform: rotate(10deg);
transform: rotate(10deg);
}
}
@keyframes octocat-wave {
0%, 100% {
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-ms-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
20%, 60% {
-webkit-transform: rotate(-25deg);
-moz-transform: rotate(-25deg);
-ms-transform: rotate(-25deg);
-o-transform: rotate(-25deg);
transform: rotate(-25deg);
}
40%, 80% {
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
-o-transform: rotate(10deg);
transform: rotate(10deg);
}
}
</style>
</head>
<body>
<a href="https://github.com/zyqwst/json-schema-editor-vue" class="github-corner" target="_blank" title="Follow me on GitHub" aria-label="Follow me on GitHub">
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#008000; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>
</svg>
</a>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<footer style="text-align:center;margin-bottom:16px;">
<a href="" target="_blank" style="color: #999">Github</a><a href="" target="_blank" style="color: #999;margin-left:16px;">Gitee</a><span style="margin-left:16px">©Zhangyq</span>
</footer>
</body>
</html>

View File

@@ -8,9 +8,6 @@ module.exports = {
filename: 'index.html'
}
},
// chainWebpack: config => {
// config.module.rule('js').include.add('/packages').end().use('babel').loader('babel-loader')
// },
css: {
loaderOptions: {
less: {