fix(接口自动化): JSON-SCHEMA 编辑器添加
This commit is contained in:
parent
4b975918e1
commit
0a85155932
|
@ -24,6 +24,8 @@
|
||||||
"html2canvas": "^1.0.0-rc.7",
|
"html2canvas": "^1.0.0-rc.7",
|
||||||
"js-base64": "^3.4.4",
|
"js-base64": "^3.4.4",
|
||||||
"json-bigint": "^1.0.0",
|
"json-bigint": "^1.0.0",
|
||||||
|
"json-schema-faker": "^0.5.0-rcv.32",
|
||||||
|
"json5": "^2.1.3",
|
||||||
"jsoneditor": "^9.1.2",
|
"jsoneditor": "^9.1.2",
|
||||||
"jspdf": "^2.1.1",
|
"jspdf": "^2.1.1",
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
|
@ -41,11 +43,7 @@
|
||||||
"vuedraggable": "^2.23.2",
|
"vuedraggable": "^2.23.2",
|
||||||
"vuex": "^3.1.2",
|
"vuex": "^3.1.2",
|
||||||
"xml-js": "^1.6.11",
|
"xml-js": "^1.6.11",
|
||||||
"yan-progress": "^1.0.3",
|
"yan-progress": "^1.0.3"
|
||||||
"lodash": "^4.17.19",
|
|
||||||
"json-schema-faker": "^0.5.0-rcv.24",
|
|
||||||
"jsonlint": "^1.6.3",
|
|
||||||
"codemirror": "^5.58.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^4.1.0",
|
"@vue/cli-plugin-babel": "^4.1.0",
|
||||||
|
@ -56,10 +54,7 @@
|
||||||
"eslint-plugin-vue": "^5.0.0",
|
"eslint-plugin-vue": "^5.0.0",
|
||||||
"file-writer": "^1.0.2",
|
"file-writer": "^1.0.2",
|
||||||
"vue-template-compiler": "^2.6.10",
|
"vue-template-compiler": "^2.6.10",
|
||||||
"vue2-ace-editor": "0.0.15",
|
"vue2-ace-editor": "0.0.15"
|
||||||
"node-sass": "^4.14.1",
|
|
||||||
"sass-loader": "^9.0.2",
|
|
||||||
"script-loader": "^0.7.2"
|
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"root": true,
|
"root": true,
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||||
<el-tab-pane label="模版" name="apiTemplate">
|
<el-tab-pane label="模版" name="apiTemplate">
|
||||||
<div>
|
<div style="min-height: 400px">
|
||||||
<json-schema-editor :schema.sync="schema" :is-mock="true"></json-schema-editor>
|
<json-schema-editor class="schema" :value.sync="schema" lang="zh_CN" custom/>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="预览" name="preview">
|
<el-tab-pane label="预览" name="preview">
|
||||||
|
@ -18,19 +18,19 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {schemaToJson} from './common';
|
import {schemaToJson} from './common';
|
||||||
|
import json5 from 'json5';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {},
|
components: {},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
schema: {
|
schema:
|
||||||
type: 'object',
|
{
|
||||||
title: 'title',
|
"root": {
|
||||||
properties: {
|
"type": "object",
|
||||||
field_1: {
|
"mock": {"mock": ""},
|
||||||
type: 'string'
|
"properties": {},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
preview: null,
|
preview: null,
|
||||||
|
@ -40,9 +40,7 @@
|
||||||
methods: {
|
methods: {
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if (this.activeName === 'preview') {
|
if (this.activeName === 'preview') {
|
||||||
|
this.preview = schemaToJson(json5.parse(JSON.stringify(this.schema)));
|
||||||
console.log(this.schema)
|
|
||||||
this.preview = schemaToJson(this.schema);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,7 @@ jsf.extend('mock', function () {
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
failOnInvalidTypes: false,
|
failOnInvalidTypes: false,
|
||||||
failOnInvalidFormat: false,
|
failOnInvalidFormat: false
|
||||||
alwaysFakeOptionals: true,
|
|
||||||
useDefaultValue: true
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const schemaToJson = (schema, options = {}) => {
|
export const schemaToJson = (schema, options = {}) => {
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-dialog
|
|
||||||
title="基础设置(数组字段)"
|
|
||||||
width="700px"
|
|
||||||
v-bind="$attrs"
|
|
||||||
v-on="$listeners"
|
|
||||||
@open="onOpen"
|
|
||||||
@close="onClose"
|
|
||||||
>
|
|
||||||
<el-row :gutter="15">
|
|
||||||
<el-form ref="elForm" :model="formData" size="small">
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="最小元素个数" prop="minItems">
|
|
||||||
<el-input-number
|
|
||||||
v-model="formData.minItems"
|
|
||||||
placeholder="请输入"
|
|
||||||
:min="0"
|
|
||||||
:step="1"
|
|
||||||
></el-input-number>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="最大元素个数" prop="maxItems">
|
|
||||||
<el-input-number
|
|
||||||
v-model="formData.maxItems"
|
|
||||||
placeholder="请输入"
|
|
||||||
:max="100000"
|
|
||||||
:step="1"
|
|
||||||
></el-input-number>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-form>
|
|
||||||
</el-row>
|
|
||||||
<div slot="footer">
|
|
||||||
<el-button @click="close">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { getValidFormVal } from '../utils'
|
|
||||||
export default {
|
|
||||||
name: 'ArrayDialog',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: { initData: { type: Object, default: () => ({}) } },
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
formData: {
|
|
||||||
minItems: undefined,
|
|
||||||
maxItems: undefined,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {},
|
|
||||||
methods: {
|
|
||||||
onOpen() {
|
|
||||||
const { minItems, maxItems } = this.initData
|
|
||||||
Object.assign(this.formData, { minItems, maxItems })
|
|
||||||
},
|
|
||||||
onClose() {
|
|
||||||
this.$refs['elForm'].resetFields()
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.$emit('update:visible', false)
|
|
||||||
},
|
|
||||||
handleConfirm() {
|
|
||||||
this.$refs['elForm'].validate((valid) => {
|
|
||||||
if (!valid) return
|
|
||||||
const newData = getValidFormVal(this.formData)
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.initData.editorId}`, {
|
|
||||||
eventType: 'save-setting',
|
|
||||||
...this.initData, // 之前的参数
|
|
||||||
newData, // 设置数据
|
|
||||||
})
|
|
||||||
this.close()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,65 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<el-dialog :title="initData.title" :visible.sync="visible" width="30%">
|
|
||||||
<el-input
|
|
||||||
v-model="data"
|
|
||||||
type="textarea"
|
|
||||||
:rows="3"
|
|
||||||
placeholder="请输入内容"
|
|
||||||
style="margin-bottom: 15px"
|
|
||||||
></el-input>
|
|
||||||
<span slot="footer" class="dialog-footer">
|
|
||||||
<el-button @click="close">取 消</el-button>
|
|
||||||
<el-button type="primary" @click="handleOk">确 定</el-button>
|
|
||||||
</span>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'BasicDialog',
|
|
||||||
props: {
|
|
||||||
visible: { type: Boolean, default: false },
|
|
||||||
initData: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({
|
|
||||||
title: '提示',
|
|
||||||
value: '',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dialogVisible: false,
|
|
||||||
data: '',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
initData: {
|
|
||||||
handler() {
|
|
||||||
this.data = this.initData.value
|
|
||||||
},
|
|
||||||
deep: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {},
|
|
||||||
methods: {
|
|
||||||
close() {
|
|
||||||
this.$emit('update:visible', false)
|
|
||||||
},
|
|
||||||
handleOk() {
|
|
||||||
this.initData.value = this.data
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.initData.editorId}`, {
|
|
||||||
eventType: 'save-showedit',
|
|
||||||
...this.initData,
|
|
||||||
})
|
|
||||||
this.close()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
</style>
|
|
|
@ -1,83 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-dialog
|
|
||||||
title="基础设置(布尔型字段)"
|
|
||||||
width="600px"
|
|
||||||
v-bind="$attrs"
|
|
||||||
v-on="$listeners"
|
|
||||||
@open="onOpen"
|
|
||||||
@close="onClose"
|
|
||||||
>
|
|
||||||
<el-form ref="elForm" :model="formData" size="small" label-width="100px">
|
|
||||||
<el-form-item label="默认值:" prop="default">
|
|
||||||
<el-select
|
|
||||||
v-model="formData.default"
|
|
||||||
placeholder="请下拉选择"
|
|
||||||
clearable
|
|
||||||
:style="{ width: '60%' }"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="(item, index) in defaultOptions"
|
|
||||||
:key="index"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
:disabled="item.disabled"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div slot="footer">
|
|
||||||
<el-button @click="close">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { getValidFormVal } from '../utils'
|
|
||||||
export default {
|
|
||||||
name: 'BooleanDialog',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: { initData: { type: Object, default: () => ({}) } },
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
formData: {
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
defaultOptions: [
|
|
||||||
{
|
|
||||||
label: 'true',
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'false',
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {},
|
|
||||||
methods: {
|
|
||||||
onOpen() {
|
|
||||||
Object.assign(this.formData, { default: this.initData.default })
|
|
||||||
},
|
|
||||||
onClose() {
|
|
||||||
this.$refs['elForm'].resetFields()
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.$emit('update:visible', false)
|
|
||||||
},
|
|
||||||
handleConfirm() {
|
|
||||||
this.$refs['elForm'].validate((valid) => {
|
|
||||||
if (!valid) return
|
|
||||||
const newData = getValidFormVal(this.formData)
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.initData.editorId}`, {
|
|
||||||
eventType: 'save-setting',
|
|
||||||
...this.initData, // 之前的参数
|
|
||||||
newData, // 设置数据
|
|
||||||
})
|
|
||||||
this.close()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,164 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<el-dialog
|
|
||||||
title="基础设置(数值型)"
|
|
||||||
width="700px"
|
|
||||||
v-bind="$attrs"
|
|
||||||
v-on="$listeners"
|
|
||||||
@open="onOpen"
|
|
||||||
@close="onClose"
|
|
||||||
>
|
|
||||||
<el-row :gutter="15">
|
|
||||||
<el-form
|
|
||||||
ref="elForm"
|
|
||||||
:model="formData"
|
|
||||||
:rules="rules"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="默认值:" prop="default">
|
|
||||||
<el-input
|
|
||||||
v-model="formData.default"
|
|
||||||
type="number"
|
|
||||||
placeholder="请输入默认值"
|
|
||||||
:maxlength="15"
|
|
||||||
clearable
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="最小值:" prop="minLength">
|
|
||||||
<el-input-number
|
|
||||||
v-model="formData.minLength"
|
|
||||||
placeholder="请输入"
|
|
||||||
:min="-9007199254740992"
|
|
||||||
:step="1"
|
|
||||||
></el-input-number>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="最大值:" prop="maxLength">
|
|
||||||
<el-input-number
|
|
||||||
v-model="formData.maxLength"
|
|
||||||
placeholder="请输入"
|
|
||||||
:step="1"
|
|
||||||
:max="9007199254740992"
|
|
||||||
></el-input-number>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="3">
|
|
||||||
<div>
|
|
||||||
<label for>枚举</label>
|
|
||||||
<el-checkbox v-model="enableEnum">:</el-checkbox>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="21">
|
|
||||||
<el-form-item label-width="0" prop="enum">
|
|
||||||
<el-input
|
|
||||||
v-model="formData.enum"
|
|
||||||
type="textarea"
|
|
||||||
placeholder="请输入枚举,一行一个"
|
|
||||||
:maxlength="120"
|
|
||||||
:disabled="!enableEnum"
|
|
||||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-col>
|
|
||||||
<el-col v-if="enableEnum" :span="24">
|
|
||||||
<el-form-item label="枚举描述:" prop="enumDesc">
|
|
||||||
<el-input
|
|
||||||
v-model="formData.enumDesc"
|
|
||||||
type="textarea"
|
|
||||||
placeholder="请输入枚举描述"
|
|
||||||
:maxlength="100"
|
|
||||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-form>
|
|
||||||
</el-row>
|
|
||||||
<div slot="footer">
|
|
||||||
<el-button @click="close">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import compact from 'lodash/compact'
|
|
||||||
import {getValidFormVal} from '../utils'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'NumberDialog',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {initData: {type: Object, default: () => ({})}},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
enableEnum: false,
|
|
||||||
formData: {
|
|
||||||
default: undefined,
|
|
||||||
minLength: undefined,
|
|
||||||
maxLength: undefined,
|
|
||||||
enum: undefined,
|
|
||||||
enumDesc: undefined,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
default: [],
|
|
||||||
minLength: [],
|
|
||||||
maxLength: [],
|
|
||||||
innerScope: [],
|
|
||||||
enum: [],
|
|
||||||
enumDesc: [],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onOpen() {
|
|
||||||
const {minLength, maxLength, enumDesc} = this.initData
|
|
||||||
let enumValue = this.initData.enum
|
|
||||||
if (enumValue) {
|
|
||||||
try {
|
|
||||||
enumValue = enumValue.join('\n')
|
|
||||||
this.enableEnum = true
|
|
||||||
} catch (e) {
|
|
||||||
this.$message({text: '枚举数据格式不对,将丢失', type: 'warning'})
|
|
||||||
enumValue = ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object.assign(
|
|
||||||
this.formData,
|
|
||||||
{minLength, maxLength, enumDesc},
|
|
||||||
{default: this.initData.default, enum: enumValue}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onClose() {
|
|
||||||
this.$refs['elForm'].resetFields()
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.$emit('update:visible', false)
|
|
||||||
},
|
|
||||||
handleConfirm() {
|
|
||||||
this.$refs['elForm'].validate((valid) => {
|
|
||||||
if (!valid) return
|
|
||||||
const newData = getValidFormVal(this.formData)
|
|
||||||
if (newData.enum) {
|
|
||||||
newData.enum = compact(newData.enum.split('\n'))
|
|
||||||
}
|
|
||||||
if (newData.default) {
|
|
||||||
newData.default = Number(newData.default)
|
|
||||||
}
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.initData.editorId}`, {
|
|
||||||
eventType: 'save-setting',
|
|
||||||
...this.initData, // 之前的参数
|
|
||||||
newData, // 设置数据
|
|
||||||
})
|
|
||||||
this.close()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,78 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-dialog
|
|
||||||
title="基础设置(对象字段)"
|
|
||||||
width="600px"
|
|
||||||
v-bind="$attrs"
|
|
||||||
v-on="$listeners"
|
|
||||||
@open="onOpen"
|
|
||||||
@close="onClose"
|
|
||||||
>
|
|
||||||
<el-form ref="elForm" :model="formData" size="small" label-width="100px">
|
|
||||||
<el-form-item label-width="0" prop="notEmpty" style="text-align: center">
|
|
||||||
<el-radio-group v-model="formData.notEmpty" size="medium">
|
|
||||||
<el-radio
|
|
||||||
v-for="(item, index) in notEmptyOptions"
|
|
||||||
:key="index"
|
|
||||||
:label="item.value"
|
|
||||||
:disabled="item.disabled"
|
|
||||||
>{{ item.label }}</el-radio
|
|
||||||
>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div slot="footer">
|
|
||||||
<el-button @click="close">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { getValidFormVal } from '../utils'
|
|
||||||
export default {
|
|
||||||
name: 'ObjectDialog',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: { initData: { type: Object, default: () => ({}) } },
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
formData: {
|
|
||||||
notEmpty: false,
|
|
||||||
},
|
|
||||||
notEmptyOptions: [
|
|
||||||
{
|
|
||||||
label: '可为空',
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '不允许为空',
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {},
|
|
||||||
methods: {
|
|
||||||
onOpen() {
|
|
||||||
Object.assign(this.formData, { notEmpty: this.initData.notEmpty })
|
|
||||||
},
|
|
||||||
onClose() {
|
|
||||||
this.$refs['elForm'].resetFields()
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.$emit('update:visible', false)
|
|
||||||
},
|
|
||||||
handleConfirm() {
|
|
||||||
this.$refs['elForm'].validate((valid) => {
|
|
||||||
if (!valid) return
|
|
||||||
const newData = getValidFormVal(this.formData)
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.initData.editorId}`, {
|
|
||||||
eventType: 'save-setting',
|
|
||||||
...this.initData, // 之前的参数
|
|
||||||
newData, // 设置数据
|
|
||||||
})
|
|
||||||
this.close()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,43 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<el-dialog
|
|
||||||
title="RAW源码查看"
|
|
||||||
width="700px"
|
|
||||||
v-bind="$attrs"
|
|
||||||
v-on="$listeners"
|
|
||||||
@open="onOpen"
|
|
||||||
@close="onClose"
|
|
||||||
>
|
|
||||||
<div class="sourcecode">
|
|
||||||
<s-json-editor :value="schema"></s-json-editor>
|
|
||||||
</div>
|
|
||||||
<span slot="footer" class="dialog-footer">
|
|
||||||
<el-button @click="close">关 闭</el-button>
|
|
||||||
</span>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import SJsonEditor from '../json-editor/index'
|
|
||||||
export default {
|
|
||||||
name: 'RawDialog',
|
|
||||||
components: { SJsonEditor },
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
schema: { type: Object, default: () => ({}) },
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
created() {},
|
|
||||||
methods: {
|
|
||||||
onOpen() {},
|
|
||||||
onClose() {},
|
|
||||||
close() {
|
|
||||||
this.$emit('update:visible', false)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
</style>
|
|
|
@ -1,153 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<el-dialog
|
|
||||||
title="基础设置(字符串)"
|
|
||||||
width="700px"
|
|
||||||
v-bind="$attrs"
|
|
||||||
v-on="$listeners"
|
|
||||||
@open="onOpen"
|
|
||||||
@close="onClose"
|
|
||||||
>
|
|
||||||
<el-row :gutter="15">
|
|
||||||
<el-form
|
|
||||||
ref="elForm"
|
|
||||||
:model="formData"
|
|
||||||
:rules="rules"
|
|
||||||
size="small">
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-form-item label="默认值:" prop="default">
|
|
||||||
<el-input
|
|
||||||
v-model="formData.default"
|
|
||||||
placeholder="请输入默认值"
|
|
||||||
:maxlength="200"
|
|
||||||
clearable/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="最小长度:" prop="minLength">
|
|
||||||
<el-input-number
|
|
||||||
v-model="formData.minLength"
|
|
||||||
placeholder="请输入"
|
|
||||||
:step="2"/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="最大长度:" prop="maxLength">
|
|
||||||
<el-input-number
|
|
||||||
v-model="formData.maxLength"
|
|
||||||
placeholder="请输入"
|
|
||||||
:step="2"/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="24">
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="3">
|
|
||||||
<div>
|
|
||||||
<label for>枚举</label>
|
|
||||||
<el-checkbox v-model="enableEnum">:</el-checkbox>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="21">
|
|
||||||
<el-form-item label-width="0" prop="enum">
|
|
||||||
<el-input
|
|
||||||
v-model="formData.enum"
|
|
||||||
type="textarea"
|
|
||||||
placeholder="请输入枚举,一行一个"
|
|
||||||
:maxlength="120"
|
|
||||||
:disabled="!enableEnum"
|
|
||||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-col>
|
|
||||||
<el-col v-if="enableEnum" :span="24">
|
|
||||||
<el-form-item label="枚举描述:" prop="enumDesc">
|
|
||||||
<el-input
|
|
||||||
v-model="formData.enumDesc"
|
|
||||||
type="textarea"
|
|
||||||
placeholder="请输入枚举描述"
|
|
||||||
:maxlength="100"
|
|
||||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-form>
|
|
||||||
</el-row>
|
|
||||||
<div slot="footer">
|
|
||||||
<el-button @click="close">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import compact from 'lodash/compact'
|
|
||||||
import { getValidFormVal } from '../utils'
|
|
||||||
export default {
|
|
||||||
name: 'StringDialog',
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: { initData: { type: Object, default: () => ({}) } },
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
enableEnum: false,
|
|
||||||
formData: {
|
|
||||||
default: undefined,
|
|
||||||
minLength: undefined,
|
|
||||||
maxLength: undefined,
|
|
||||||
enum: undefined,
|
|
||||||
enumDesc: undefined,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
default: [],
|
|
||||||
minLength: [],
|
|
||||||
maxLength: [],
|
|
||||||
innerScope: [],
|
|
||||||
enum: [],
|
|
||||||
enumDesc: [],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onOpen() {
|
|
||||||
const { minLength, maxLength, enumDesc } = this.initData
|
|
||||||
let enumValue = this.initData.enum
|
|
||||||
if (enumValue) {
|
|
||||||
try {
|
|
||||||
enumValue = enumValue.join('\n')
|
|
||||||
this.enableEnum = true
|
|
||||||
} catch (e) {
|
|
||||||
this.$message({ text: '枚举数据格式不对,将丢失', type: 'warning' })
|
|
||||||
enumValue = ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object.assign(
|
|
||||||
this.formData,
|
|
||||||
{ minLength, maxLength, enumDesc },
|
|
||||||
{ default: this.initData.default, enum: enumValue }
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onClose() {
|
|
||||||
this.$refs['elForm'].resetFields()
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.$emit('update:visible', false)
|
|
||||||
},
|
|
||||||
handleConfirm() {
|
|
||||||
this.$refs['elForm'].validate((valid) => {
|
|
||||||
if (!valid) return
|
|
||||||
const newData = getValidFormVal(this.formData)
|
|
||||||
if (newData.enum) {
|
|
||||||
newData.enum = compact(newData.enum.split('\n'))
|
|
||||||
}
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.initData.editorId}`, {
|
|
||||||
eventType: 'save-setting',
|
|
||||||
...this.initData, // 之前的参数
|
|
||||||
newData, // 设置数据
|
|
||||||
})
|
|
||||||
this.close()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,17 +0,0 @@
|
||||||
import BasicDialog from './BasicDialog';
|
|
||||||
import StringDialog from './StringDialog';
|
|
||||||
import NumberDialog from './NumberDialog';
|
|
||||||
import ArrayDialog from './ArrayDialog';
|
|
||||||
import BooleanDialog from './BooleanDialog';
|
|
||||||
import ObjectDialog from './ObjectDialog';
|
|
||||||
import RawDialog from './RawDialog';
|
|
||||||
|
|
||||||
export {
|
|
||||||
BasicDialog,
|
|
||||||
StringDialog,
|
|
||||||
NumberDialog,
|
|
||||||
ArrayDialog,
|
|
||||||
BooleanDialog,
|
|
||||||
ObjectDialog,
|
|
||||||
RawDialog
|
|
||||||
};
|
|
|
@ -1,48 +0,0 @@
|
||||||
/**
|
|
||||||
* @author: giscafer ,https://github.com/giscafer
|
|
||||||
* @date: 2020-05-21 17:21:29
|
|
||||||
* @description: 用一个Vue实例封装事件常用的方法并赋值给全局的变量,以便在任何一个组件都可调用这些方法来实现全局事件管理
|
|
||||||
*
|
|
||||||
* 使用如下:
|
|
||||||
* mounted(){
|
|
||||||
this.$jsEditorEvent.on('change_value',id);
|
|
||||||
this.$jsEditorEvent.emit('change_value',1);
|
|
||||||
...
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Vue from 'vue';
|
|
||||||
|
|
||||||
const eventHub = new Vue({
|
|
||||||
methods: {
|
|
||||||
on(...args) {
|
|
||||||
this.$on.apply(this, args);
|
|
||||||
},
|
|
||||||
emit(...args) {
|
|
||||||
this.$emit.apply(this, args);
|
|
||||||
},
|
|
||||||
off(...args) {
|
|
||||||
this.$off.apply(this, args);
|
|
||||||
},
|
|
||||||
once(...args) {
|
|
||||||
this.$once.apply(this, args);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/* const CustomEventPlugin = V =>
|
|
||||||
Object.defineProperty(V.prototype, '$event', {
|
|
||||||
value: eventHub,
|
|
||||||
writable: true
|
|
||||||
}); */
|
|
||||||
|
|
||||||
const CustomEventPlugin = {
|
|
||||||
install: function(V) {
|
|
||||||
Object.defineProperty(V.prototype, '$jsEditorEvent', {
|
|
||||||
value: eventHub,
|
|
||||||
writable: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CustomEventPlugin;
|
|
|
@ -1,17 +0,0 @@
|
||||||
import JsonSchemaEditor from './json-schema-editor.vue';
|
|
||||||
import CustomEventPlugin from './event';
|
|
||||||
|
|
||||||
const install = function(Vue) {
|
|
||||||
Vue.use(CustomEventPlugin);
|
|
||||||
|
|
||||||
Vue.component(JsonSchemaEditor.name, JsonSchemaEditor);
|
|
||||||
};
|
|
||||||
|
|
||||||
JsonSchemaEditor.install = install;
|
|
||||||
|
|
||||||
/* istanbul ignore if */
|
|
||||||
if (typeof window !== 'undefined' && window.Vue) {
|
|
||||||
install(window.Vue);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default JsonSchemaEditor;
|
|
|
@ -1,8 +0,0 @@
|
||||||
import JsonEditor from './src/json-editor';
|
|
||||||
|
|
||||||
/* istanbul ignore next */
|
|
||||||
JsonEditor.install = function(Vue) {
|
|
||||||
Vue.component(JsonEditor.name, JsonEditor);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default JsonEditor;
|
|
|
@ -1,90 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="json-editor">
|
|
||||||
<textarea ref="textarea" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import CodeMirror from 'codemirror'
|
|
||||||
import 'codemirror/addon/lint/lint.css'
|
|
||||||
import 'codemirror/lib/codemirror.css'
|
|
||||||
import 'codemirror/theme/idea.css'
|
|
||||||
import 'codemirror/theme/rubyblue.css'
|
|
||||||
require('script-loader!jsonlint')
|
|
||||||
import 'codemirror/mode/javascript/javascript'
|
|
||||||
import 'codemirror/addon/lint/lint'
|
|
||||||
import 'codemirror/addon/lint/json-lint'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'SJsonEditor',
|
|
||||||
props: {
|
|
||||||
value: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
readonly: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
theme: {
|
|
||||||
type: String,
|
|
||||||
default: 'idea',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
jsonEditor: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
value(value) {
|
|
||||||
const editorValue = this.jsonEditor.getValue()
|
|
||||||
if (value !== editorValue) {
|
|
||||||
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
theme() {
|
|
||||||
this.jsonEditor.setOption({
|
|
||||||
theme: this.theme,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.jsonEditor = CodeMirror.fromTextArea(this.$refs.textarea, {
|
|
||||||
lineNumbers: true,
|
|
||||||
mode: 'application/json',
|
|
||||||
gutters: ['CodeMirror-lint-markers'],
|
|
||||||
theme: this.theme || 'idea',
|
|
||||||
readonly: this.readonly ? 'nocursor' : false,
|
|
||||||
lint: true,
|
|
||||||
})
|
|
||||||
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
|
|
||||||
this.jsonEditor.on('change', (cm) => {
|
|
||||||
this.$emit('changed', cm.getValue())
|
|
||||||
this.$emit('input', cm.getValue())
|
|
||||||
})
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getValue() {
|
|
||||||
return this.jsonEditor.getValue()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.json-editor {
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.json-editor >>> .CodeMirror {
|
|
||||||
height: auto;
|
|
||||||
min-height: 300px;
|
|
||||||
}
|
|
||||||
.json-editor >>> .CodeMirror-scroll {
|
|
||||||
min-height: 300px;
|
|
||||||
}
|
|
||||||
.json-editor >>> .cm-s-rubyblue span.cm-string {
|
|
||||||
color: #f08047;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,617 +0,0 @@
|
||||||
<template>
|
|
||||||
<div style="min-height: 400px;">
|
|
||||||
<el-button
|
|
||||||
v-if="showRaw"
|
|
||||||
type="primary"
|
|
||||||
size="mini"
|
|
||||||
style="margin-bottom: 10px"
|
|
||||||
@click="handleReqBodyRaw"
|
|
||||||
>RAW查看</el-button
|
|
||||||
>
|
|
||||||
<div class="json-schema-vue-editor">
|
|
||||||
<el-row type="flex" align="middle">
|
|
||||||
<el-col :span="8" class="col-item name-item col-item-name">
|
|
||||||
<el-row type="flex" justify="space-around" align="middle">
|
|
||||||
<el-col :span="2" class="down-style-col">
|
|
||||||
<span
|
|
||||||
v-if="schemaData.type === 'object'"
|
|
||||||
class="down-style"
|
|
||||||
@click="handleClickIcon"
|
|
||||||
>
|
|
||||||
<i v-if="show" class="el-icon-caret-bottom icon-object"></i>
|
|
||||||
<i v-if="!show" class="el-icon-caret-right icon-object"></i>
|
|
||||||
</span>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-input disabled value="root" size="small" />
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="2" style="text-align: center">
|
|
||||||
<el-tooltip placement="top" content="全选">
|
|
||||||
<el-checkbox
|
|
||||||
:checked="checked"
|
|
||||||
:disabled="disabled"
|
|
||||||
@change="changeCheckBox"
|
|
||||||
/>
|
|
||||||
</el-tooltip>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="3" class="col-item col-item-type">
|
|
||||||
<el-select
|
|
||||||
:value="schemaData.type"
|
|
||||||
:disabled="schemaData.disabled && !schemaData.canChangeType"
|
|
||||||
class="type-select-style"
|
|
||||||
size="small"
|
|
||||||
@change="handleChangeType2($event)"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in schemaTypes"
|
|
||||||
:key="item"
|
|
||||||
:value="item"
|
|
||||||
:label="item"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-col>
|
|
||||||
<el-col v-if="isMock" :span="3" class="col-item col-item-mock">
|
|
||||||
<MockSelect
|
|
||||||
:schema="schemaData"
|
|
||||||
@showEdit="handleShowEdit"
|
|
||||||
@change="handleChangeMock"
|
|
||||||
/>
|
|
||||||
</el-col>
|
|
||||||
<el-col
|
|
||||||
v-if="showTitle"
|
|
||||||
:span="isMock ? 4 : 5"
|
|
||||||
class="col-item col-item-mock"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="schemaData.title"
|
|
||||||
placeholder="标题"
|
|
||||||
:disabled="schemaData.disabled"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="
|
|
||||||
handleSchemaUpdateEvent({
|
|
||||||
eventType: 'show-edit',
|
|
||||||
field: 'title',
|
|
||||||
prefix: ['properties'],
|
|
||||||
isRoot: true,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
<el-col
|
|
||||||
v-if="!showTitle && showDefaultValue"
|
|
||||||
:span="isMock ? 4 : 5"
|
|
||||||
class="col-item col-item-mock"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="schemaData.default"
|
|
||||||
placeholder="默认值"
|
|
||||||
size="small"
|
|
||||||
:disabled="
|
|
||||||
schemaData.type === 'object' ||
|
|
||||||
schemaData.type === 'array' ||
|
|
||||||
schemaData.disabled
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="
|
|
||||||
handleSchemaUpdateEvent({
|
|
||||||
eventType: 'show-edit',
|
|
||||||
field: 'default',
|
|
||||||
prefix: ['properties'],
|
|
||||||
isRoot: true,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="isMock ? 4 : 5" class="col-item col-item-desc">
|
|
||||||
<el-input
|
|
||||||
v-model="schemaData.description"
|
|
||||||
placeholder="备注"
|
|
||||||
size="small"
|
|
||||||
:disabled="schemaData.disabled"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="
|
|
||||||
handleSchemaUpdateEvent({
|
|
||||||
eventType: 'show-edit',
|
|
||||||
field: 'description',
|
|
||||||
prefix: ['properties'],
|
|
||||||
isRoot: true,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="2" class="col-item col-item-setting">
|
|
||||||
<span
|
|
||||||
class="adv-set"
|
|
||||||
@click="
|
|
||||||
handleSchemaUpdateEvent({
|
|
||||||
eventType: 'setting',
|
|
||||||
schemaType: schemaData.type,
|
|
||||||
prefix: ['properties'],
|
|
||||||
isRoot: true,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<el-tooltip placement="top" content="高级设置">
|
|
||||||
<i class="el-icon-setting"></i>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
v-if="schemaData.type === 'object'"
|
|
||||||
@click="
|
|
||||||
handleSchemaUpdateEvent({
|
|
||||||
eventType: 'add-field',
|
|
||||||
isChild: false,
|
|
||||||
prefix: ['properties'],
|
|
||||||
})
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<el-tooltip placement="top" content="添加子节点">
|
|
||||||
<i class="el-icon-plus plus"></i>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<schema-json
|
|
||||||
v-if="show"
|
|
||||||
:data="schemaData"
|
|
||||||
:is-mock="isMock"
|
|
||||||
:show-title="showTitle"
|
|
||||||
:show-default-value="showDefaultValue"
|
|
||||||
:editor-id="editorId"
|
|
||||||
/>
|
|
||||||
<!-- RAW弹窗 -->
|
|
||||||
<RawDialog
|
|
||||||
v-if="showRaw"
|
|
||||||
:visible.sync="rawDialogVisible"
|
|
||||||
:schema="schemaData"
|
|
||||||
/>
|
|
||||||
<!-- 高级设置弹窗 -->
|
|
||||||
<BasicDialog
|
|
||||||
:visible.sync="basicDialogVisible"
|
|
||||||
:init-data="basicModalData"
|
|
||||||
/>
|
|
||||||
<StringDialog
|
|
||||||
:visible.sync="settingDialogVisible.string"
|
|
||||||
:init-data="settingModalData"
|
|
||||||
/>
|
|
||||||
<NumberDialog
|
|
||||||
:visible.sync="settingDialogVisible.number"
|
|
||||||
:init-data="settingModalData"
|
|
||||||
/>
|
|
||||||
<NumberDialog
|
|
||||||
:visible.sync="settingDialogVisible.integer"
|
|
||||||
:init-data="settingModalData"
|
|
||||||
/>
|
|
||||||
<ArrayDialog
|
|
||||||
:visible.sync="settingDialogVisible.array"
|
|
||||||
:init-data="settingModalData"
|
|
||||||
/>
|
|
||||||
<BooleanDialog
|
|
||||||
:visible.sync="settingDialogVisible.boolean"
|
|
||||||
:init-data="settingModalData"
|
|
||||||
/>
|
|
||||||
<ObjectDialog
|
|
||||||
:visible.sync="settingDialogVisible.object"
|
|
||||||
:init-data="settingModalData"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import set from 'lodash/set'
|
|
||||||
import get from 'lodash/get'
|
|
||||||
import unset from 'lodash/unset'
|
|
||||||
import cloneDeep from 'lodash/cloneDeep'
|
|
||||||
import SchemaJson from './schema'
|
|
||||||
import MockSelect from './mock'
|
|
||||||
import './jsonschema.scss'
|
|
||||||
import {
|
|
||||||
BasicDialog,
|
|
||||||
StringDialog,
|
|
||||||
NumberDialog,
|
|
||||||
ArrayDialog,
|
|
||||||
BooleanDialog,
|
|
||||||
ObjectDialog,
|
|
||||||
RawDialog,
|
|
||||||
} from './dialog'
|
|
||||||
import {
|
|
||||||
SCHEMA_TYPE,
|
|
||||||
log,
|
|
||||||
JSONPATH_JOIN_CHAR,
|
|
||||||
defaultSchema,
|
|
||||||
uuid,
|
|
||||||
defaultInitSchemaData,
|
|
||||||
handleSchemaRequired,
|
|
||||||
cloneObject,
|
|
||||||
deleteData,
|
|
||||||
} from './utils'
|
|
||||||
export default {
|
|
||||||
name: 'JsonSchemaEditor',
|
|
||||||
components: {
|
|
||||||
MockSelect,
|
|
||||||
SchemaJson,
|
|
||||||
BasicDialog,
|
|
||||||
StringDialog,
|
|
||||||
NumberDialog,
|
|
||||||
ArrayDialog,
|
|
||||||
BooleanDialog,
|
|
||||||
ObjectDialog,
|
|
||||||
RawDialog,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
schema: { type: Object, default: () => {} },
|
|
||||||
isMock: { type: Boolean, default: false },
|
|
||||||
showTitle: { type: Boolean, default: false },
|
|
||||||
showDefaultValue: { type: Boolean, default: false },
|
|
||||||
showRaw: { type: Boolean, default: false },
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
const visibleObj = {}
|
|
||||||
SCHEMA_TYPE.map((type) => {
|
|
||||||
visibleObj[type] = false
|
|
||||||
})
|
|
||||||
const initSchema = this.schema || defaultInitSchemaData
|
|
||||||
return {
|
|
||||||
editorId: uuid(),
|
|
||||||
checked: false,
|
|
||||||
disabled: false,
|
|
||||||
show: true,
|
|
||||||
schemaTypes: SCHEMA_TYPE,
|
|
||||||
schemaData: initSchema,
|
|
||||||
rawDialogVisible: false,
|
|
||||||
basicDialogVisible: false,
|
|
||||||
basicModalData: { title: '', value: '' },
|
|
||||||
settingDialogVisible: visibleObj,
|
|
||||||
settingModalData: {},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
schemaData: {
|
|
||||||
handler(newVal) {
|
|
||||||
log(this, 'watch', newVal)
|
|
||||||
},
|
|
||||||
deep: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
log(this, this.schemaData)
|
|
||||||
this.$jsEditorEvent.on(
|
|
||||||
`schema-update-${this.editorId}`,
|
|
||||||
this.handleSchemaUpdateEvent
|
|
||||||
)
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
this.$jsEditorEvent.off(
|
|
||||||
`schema-update-${this.editorId}`,
|
|
||||||
this.handleSchemaUpdateEvent
|
|
||||||
)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleSchemaUpdateEvent(options) {
|
|
||||||
const { eventType, ...opts } = options
|
|
||||||
switch (eventType) {
|
|
||||||
case 'add-field':
|
|
||||||
this.addFieldAction(opts)
|
|
||||||
break
|
|
||||||
case 'delete-field':
|
|
||||||
this.deleteFieldAction(opts)
|
|
||||||
break
|
|
||||||
case 'update-field-name':
|
|
||||||
this.updateFieldNameAction(opts)
|
|
||||||
break
|
|
||||||
case 'schema-type':
|
|
||||||
this.handleChangeType(opts)
|
|
||||||
break
|
|
||||||
case 'show-edit':
|
|
||||||
this.handleShowEdit(opts)
|
|
||||||
break
|
|
||||||
case 'save-showedit':
|
|
||||||
this.handleSaveShowEdit(opts)
|
|
||||||
break
|
|
||||||
case 'setting':
|
|
||||||
this.handleSettingAction(opts)
|
|
||||||
break
|
|
||||||
case 'save-setting':
|
|
||||||
this.handleSaveSetting(opts)
|
|
||||||
break
|
|
||||||
case 'toggle-required':
|
|
||||||
this.enableRequireAction(opts)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleClickIcon() {
|
|
||||||
this.show = !this.show
|
|
||||||
},
|
|
||||||
changeCheckBox(e) {
|
|
||||||
this.requireAllAction({ required: e, value: this.schemaData })
|
|
||||||
},
|
|
||||||
requireAllAction(opts) {
|
|
||||||
const { value, required } = opts
|
|
||||||
const cloneSchema = cloneObject(value)
|
|
||||||
handleSchemaRequired(cloneSchema, required)
|
|
||||||
this.forceUpdate(cloneSchema)
|
|
||||||
this.handleEmitChange(cloneSchema)
|
|
||||||
},
|
|
||||||
enableRequireAction(opts) {
|
|
||||||
const { prefix, name, required } = opts
|
|
||||||
const prefixCopy = cloneDeep(prefix)
|
|
||||||
prefixCopy.pop()
|
|
||||||
const parentKeys = [...prefixCopy]
|
|
||||||
const parentPrefix = parentKeys.join(JSONPATH_JOIN_CHAR)
|
|
||||||
const cloneSchema = cloneDeep(this.schemaData)
|
|
||||||
let parentData = null
|
|
||||||
if (!parentPrefix) {
|
|
||||||
// 一级属性
|
|
||||||
parentData = cloneSchema
|
|
||||||
} else {
|
|
||||||
parentData = get(cloneSchema, parentPrefix)
|
|
||||||
}
|
|
||||||
const requiredData = [].concat(parentData.required || [])
|
|
||||||
const index = requiredData.indexOf(name)
|
|
||||||
// 取消必填
|
|
||||||
if (!required && index >= 0) {
|
|
||||||
requiredData.splice(index, 1)
|
|
||||||
parentKeys.push('required')
|
|
||||||
if (requiredData.length === 0) {
|
|
||||||
deleteData(cloneSchema, parentKeys)
|
|
||||||
} else {
|
|
||||||
set(cloneSchema, parentKeys, requiredData)
|
|
||||||
}
|
|
||||||
} else if (required && index === -1) {
|
|
||||||
// 必填
|
|
||||||
requiredData.push(name)
|
|
||||||
parentKeys.push('required')
|
|
||||||
set(cloneSchema, parentKeys, requiredData)
|
|
||||||
}
|
|
||||||
this.forceUpdate(cloneSchema)
|
|
||||||
this.handleEmitChange(cloneSchema)
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 处理新增字段
|
|
||||||
* @param isChild 新增子节点
|
|
||||||
* @param action 字段和路径
|
|
||||||
*/
|
|
||||||
addFieldAction(opts) {
|
|
||||||
log(this, opts)
|
|
||||||
const { isChild, name, prefix } = opts
|
|
||||||
let parentPrefix = ''
|
|
||||||
let requirePrefix = []
|
|
||||||
if (isChild) {
|
|
||||||
const tempArr = [].concat(prefix, name)
|
|
||||||
parentPrefix = tempArr.concat('properties').join(JSONPATH_JOIN_CHAR)
|
|
||||||
requirePrefix = [...tempArr]
|
|
||||||
} else {
|
|
||||||
parentPrefix = prefix.join(JSONPATH_JOIN_CHAR)
|
|
||||||
const tempPrefix = [].concat(prefix)
|
|
||||||
tempPrefix.pop()
|
|
||||||
requirePrefix = tempPrefix
|
|
||||||
}
|
|
||||||
log('addFieldAction>>>', parentPrefix, '\n\t')
|
|
||||||
let newPropertiesData = {}
|
|
||||||
const ranName = 'field_' + uuid()
|
|
||||||
const propertiesData = get(this.schemaData, parentPrefix)
|
|
||||||
newPropertiesData = Object.assign({}, propertiesData)
|
|
||||||
newPropertiesData[ranName] = defaultSchema.string
|
|
||||||
const cloneSchema = cloneDeep(this.schemaData)
|
|
||||||
set(cloneSchema, parentPrefix, newPropertiesData)
|
|
||||||
|
|
||||||
// add required
|
|
||||||
let pRequiredData = null
|
|
||||||
if (!requirePrefix.length) {
|
|
||||||
// 一级属性
|
|
||||||
pRequiredData = cloneSchema
|
|
||||||
} else {
|
|
||||||
pRequiredData = get(cloneSchema, requirePrefix)
|
|
||||||
}
|
|
||||||
const requiredData = [].concat(pRequiredData.required || [])
|
|
||||||
requiredData.push(ranName)
|
|
||||||
requirePrefix.push('required')
|
|
||||||
set(cloneSchema, requirePrefix, requiredData)
|
|
||||||
// update schema
|
|
||||||
this.schemaData = cloneSchema
|
|
||||||
this.forceUpdate(cloneSchema)
|
|
||||||
this.handleEmitChange(cloneSchema)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 删除字段
|
|
||||||
deleteFieldAction(opts) {
|
|
||||||
const { name, prefix } = opts
|
|
||||||
const curFieldPath = [].concat(prefix, name).join(JSONPATH_JOIN_CHAR)
|
|
||||||
// console.log(curFieldPath)
|
|
||||||
const cloneSchema = cloneDeep(this.schemaData)
|
|
||||||
unset(cloneSchema, curFieldPath)
|
|
||||||
this.schemaData = cloneSchema
|
|
||||||
this.forceUpdate()
|
|
||||||
this.handleEmitChange(cloneSchema)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 更新字段名称
|
|
||||||
updateFieldNameAction(opts) {
|
|
||||||
log(this, opts)
|
|
||||||
const { value, name, prefix } = opts
|
|
||||||
let requirePrefix = []
|
|
||||||
const prefixCopy = cloneDeep(prefix)
|
|
||||||
prefixCopy.pop()
|
|
||||||
requirePrefix = prefixCopy // 上级 required路径
|
|
||||||
const parentPrefix = prefix.join(JSONPATH_JOIN_CHAR)
|
|
||||||
const curFieldPath = prefix.concat(name).join(JSONPATH_JOIN_CHAR)
|
|
||||||
const cloneSchema = cloneDeep(this.schemaData)
|
|
||||||
const propertiesData = get(cloneSchema, curFieldPath) // 原来的值
|
|
||||||
unset(cloneSchema, curFieldPath) // 移除
|
|
||||||
|
|
||||||
set(cloneSchema, `${parentPrefix}.${value}`, propertiesData) // 添加
|
|
||||||
|
|
||||||
// update required name
|
|
||||||
let pRequiredData = null
|
|
||||||
if (!requirePrefix.length) {
|
|
||||||
// 一级属性
|
|
||||||
pRequiredData = cloneSchema
|
|
||||||
} else {
|
|
||||||
pRequiredData = get(cloneSchema, requirePrefix)
|
|
||||||
}
|
|
||||||
let requiredData = [].concat(pRequiredData.required || [])
|
|
||||||
requiredData = requiredData.map((item) => {
|
|
||||||
if (item === name) return value
|
|
||||||
return item
|
|
||||||
})
|
|
||||||
requirePrefix.push('required')
|
|
||||||
set(cloneSchema, requirePrefix, requiredData)
|
|
||||||
|
|
||||||
this.schemaData = cloneSchema
|
|
||||||
this.forceUpdate()
|
|
||||||
this.handleEmitChange(cloneSchema)
|
|
||||||
},
|
|
||||||
// root
|
|
||||||
handleChangeType2(value) {
|
|
||||||
this.schemaData.type = value
|
|
||||||
const parentDataItem = this.schemaData.description
|
|
||||||
? { description: this.schemaData.description }
|
|
||||||
: {}
|
|
||||||
const newParentDataItem = defaultSchema[value]
|
|
||||||
const newParentData = Object.assign({}, newParentDataItem, parentDataItem)
|
|
||||||
this.schemaData = newParentData
|
|
||||||
this.handleEmitChange(this.schemaData)
|
|
||||||
},
|
|
||||||
// schema 类型变化
|
|
||||||
handleChangeType(opts) {
|
|
||||||
log(this, opts, 2)
|
|
||||||
const { value, name, prefix } = opts
|
|
||||||
const parentPrefix = [].concat(prefix, name)
|
|
||||||
const cloneSchema = cloneDeep(this.schemaData)
|
|
||||||
const parentData = get(cloneSchema, parentPrefix)
|
|
||||||
const newParentDataItem = defaultSchema[value] // 重置当前 schema 为默认值
|
|
||||||
// 保留备注信息
|
|
||||||
const parentDataItem = parentData.description
|
|
||||||
? { description: parentData.description }
|
|
||||||
: {}
|
|
||||||
|
|
||||||
const newParentData = Object.assign({}, newParentDataItem, parentDataItem)
|
|
||||||
set(cloneSchema, parentPrefix, newParentData)
|
|
||||||
this.schemaData = cloneSchema
|
|
||||||
this.forceUpdate()
|
|
||||||
this.handleEmitChange(cloneSchema)
|
|
||||||
},
|
|
||||||
// title & description 编辑
|
|
||||||
handleShowEdit(opts) {
|
|
||||||
const { field, name, prefix, isRoot } = opts
|
|
||||||
log(this, 'handleShowEdit', name, prefix)
|
|
||||||
|
|
||||||
let parentData
|
|
||||||
if (isRoot) {
|
|
||||||
parentData = this.schemaData
|
|
||||||
} else {
|
|
||||||
const parentPrefix = [].concat(prefix, name)
|
|
||||||
parentData = get(this.schemaData, parentPrefix)
|
|
||||||
}
|
|
||||||
// disable 的时候,return事件处理
|
|
||||||
if (
|
|
||||||
(field === 'default' && parentData.type === 'array') ||
|
|
||||||
parentData.type === 'object'
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.basicDialogVisible = true
|
|
||||||
|
|
||||||
Object.assign(this.basicModalData, {
|
|
||||||
title:
|
|
||||||
field === 'title' ? '标题' : field === 'default' ? '默认值' : '描述',
|
|
||||||
value: parentData[field],
|
|
||||||
editorId: this.editorId,
|
|
||||||
...opts,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleSaveShowEdit(opts) {
|
|
||||||
const { value, field, name, prefix, isRoot } = opts
|
|
||||||
// console.log(field, value)
|
|
||||||
let parentPrefix
|
|
||||||
const cloneSchema = cloneDeep(this.schemaData)
|
|
||||||
if (isRoot) {
|
|
||||||
cloneSchema[field] = value
|
|
||||||
} else {
|
|
||||||
parentPrefix = [].concat(prefix, name, field)
|
|
||||||
set(cloneSchema, parentPrefix, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.schemaData = cloneSchema
|
|
||||||
this.forceUpdate()
|
|
||||||
this.handleEmitChange(cloneSchema)
|
|
||||||
},
|
|
||||||
// 高级设置
|
|
||||||
handleSettingAction(opts) {
|
|
||||||
const { schemaType, name, prefix, isRoot } = opts
|
|
||||||
// console.log(schemaType)
|
|
||||||
this.settingDialogVisible[schemaType] = true
|
|
||||||
|
|
||||||
let parentData
|
|
||||||
if (isRoot) {
|
|
||||||
parentData = this.schemaData
|
|
||||||
} else {
|
|
||||||
const parentPrefix = [].concat(prefix, name)
|
|
||||||
parentData = get(this.schemaData, parentPrefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.settingModalData = {
|
|
||||||
schemaType,
|
|
||||||
name,
|
|
||||||
isRoot,
|
|
||||||
prefix,
|
|
||||||
editorId: this.editorId,
|
|
||||||
...parentData,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 高级设置更新 schema
|
|
||||||
handleSaveSetting(opts) {
|
|
||||||
const { name, prefix, newData, isRoot } = opts
|
|
||||||
const cloneSchema = cloneDeep(this.schemaData)
|
|
||||||
if (isRoot) {
|
|
||||||
Object.assign(cloneSchema, { ...newData })
|
|
||||||
} else {
|
|
||||||
const parentPrefix = [].concat(prefix, name)
|
|
||||||
const oldData = get(cloneSchema, parentPrefix)
|
|
||||||
set(cloneSchema, parentPrefix, { ...oldData, ...newData })
|
|
||||||
}
|
|
||||||
this.schemaData = cloneSchema
|
|
||||||
this.forceUpdate()
|
|
||||||
this.handleEmitChange(cloneSchema)
|
|
||||||
},
|
|
||||||
handleChangeMock() {},
|
|
||||||
handleReqBodyRaw() {
|
|
||||||
this.rawDialogVisible = true
|
|
||||||
this.forceUpdate()
|
|
||||||
},
|
|
||||||
// 解决嵌套对象属性无法刷新页面问题
|
|
||||||
forceUpdate(data) {
|
|
||||||
const temp = data || this.schemaData
|
|
||||||
this.schemaData = {}
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.schemaData = temp
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleEmitChange(schema) {
|
|
||||||
// console.log(schema)
|
|
||||||
this.$emit('schema-change', schema)
|
|
||||||
this.$emit('update:schema', schema)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,149 +0,0 @@
|
||||||
.json-schema-vue-editor {
|
|
||||||
cursor: pointer;
|
|
||||||
.el-input--medium {
|
|
||||||
height: 36px;
|
|
||||||
}
|
|
||||||
.el-input.is-disabled {
|
|
||||||
background-color: #f5f7fa;
|
|
||||||
border-color: #dfe4ed;
|
|
||||||
color: #c0c4cc;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.json-schema-vue-editor .option-formStyle {
|
|
||||||
/* padding-left: 25px; */
|
|
||||||
padding-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .required-icon {
|
|
||||||
font-size: 1em;
|
|
||||||
color: red;
|
|
||||||
font-weight: bold;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .object-style {
|
|
||||||
/* border-left: 2px dotted gray; */
|
|
||||||
/* padding-left: 8px; */
|
|
||||||
padding-top: 6px;
|
|
||||||
/* margin-left: 20px; */
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .col-item-type {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .down-style {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .col-item-desc {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .col-item-mock {
|
|
||||||
text-align: center;
|
|
||||||
padding-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .col-item-setting {
|
|
||||||
padding-left: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .plus {
|
|
||||||
color: #2395f1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .close {
|
|
||||||
color: #ff561b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .array-type {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .delete-item {
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .object-style .name-item .ant-input-group-addon {
|
|
||||||
background-color: unset;
|
|
||||||
border: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor
|
|
||||||
.object-style
|
|
||||||
.name-item
|
|
||||||
.ant-input-group
|
|
||||||
> .ant-input:first-child,
|
|
||||||
.ant-input-group-addon:first-child {
|
|
||||||
border-bottom-right-radius: 4px;
|
|
||||||
border-top-right-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .icon-object {
|
|
||||||
color: #0d1b3ea6;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .down-style-col {
|
|
||||||
width: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .wrapper {
|
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .schema-content {
|
|
||||||
margin-left: 20px;
|
|
||||||
} */
|
|
||||||
|
|
||||||
.json-schema-vue-editor .adv-set {
|
|
||||||
padding-right: 8px;
|
|
||||||
color: #00a854;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor .type-select-style {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor-import-modal .ant-tabs-nav .ant-tabs-tab {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor-adv-modal .other-row {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor-adv-modal .other-label {
|
|
||||||
text-align: right;
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor-adv-modal .default-setting {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 400;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
border-left: 3px solid #2395f1;
|
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor-adv-modal .ant-modal-body {
|
|
||||||
min-height: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor-adv-modal .ant-modal-body .ace_editor {
|
|
||||||
min-height: 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-schema-vue-editor-adv-modal-select .format-items-title {
|
|
||||||
color: #999;
|
|
||||||
position: absolute;
|
|
||||||
right: 16px;
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>json-schema-editor-vue demo</title>
|
||||||
|
<script src="./json-schema-editor-vue.umd.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="./json-schema-editor-vue.css">
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
console.log(json-schema-editor-vue)
|
||||||
|
</script>
|
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
284
frontend/src/business/components/common/json-schema/ot/lib/json-schema-editor-vue.umd.min.js
vendored
Normal file
284
frontend/src/business/components/common/json-schema/ot/lib/json-schema-editor-vue.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,25 @@
|
||||||
|
import JsonSchemaEditor from './json-schema-editor/index'
|
||||||
|
const components = [
|
||||||
|
JsonSchemaEditor
|
||||||
|
]
|
||||||
|
|
||||||
|
// 定义 install 方法
|
||||||
|
const install = function (Vue) {
|
||||||
|
if (install.installed) return
|
||||||
|
install.installed = true
|
||||||
|
// 遍历并注册全局组件
|
||||||
|
components.map(component => {
|
||||||
|
Vue.component(component.name, component)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window !== 'undefined' && window.Vue) {
|
||||||
|
install(window.Vue)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// 导出的对象必须具备一个 install 方法
|
||||||
|
install,
|
||||||
|
// 组件列表
|
||||||
|
...components
|
||||||
|
}
|
|
@ -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]
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import JsonSchemaEditor from './main.vue'
|
||||||
|
|
||||||
|
JsonSchemaEditor.install = function (Vue) {
|
||||||
|
Vue.component(JsonSchemaEditor.name, JsonSchemaEditor)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JsonSchemaEditor
|
|
@ -0,0 +1,391 @@
|
||||||
|
<template>
|
||||||
|
<div class="json-schema-editor">
|
||||||
|
<el-row class="row" :gutter="10">
|
||||||
|
<el-col :span="12" class="ant-col-name">
|
||||||
|
<div :style="{marginLeft:`${10*deep}px`}" class="ant-col-name-c">
|
||||||
|
<span v-if="pickValue.type==='object'" :class="hidden? 'el-tree-node__expand-icon el-icon-caret-right':
|
||||||
|
'expanded el-tree-node__expand-icon el-icon-caret-right'" @click="hidden = !hidden"/>
|
||||||
|
<span v-else style="width:10px;display:inline-block"></span>
|
||||||
|
<el-input :disabled="disabled || root" :value="pickKey" @blur="onInputName" size="small"/>
|
||||||
|
</div>
|
||||||
|
<el-tooltip v-if="root" content="全选">
|
||||||
|
<input type="checkbox" :disabled="!isObject && !isArray" class="ant-col-name-required" @change="onRootCheck"/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip v-else content="是否必填">
|
||||||
|
<input type="checkbox" :disabled="isItem" :checked="checked" class="ant-col-name-required" @change="onCheck"/>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-select v-model="pickValue.type" :disabled="disabledType" class="ant-col-type" @change="onChangeType" size="small">
|
||||||
|
<el-option :key="t" :value="t" :label="t" v-for="t in TYPE_NAME"/>
|
||||||
|
</el-select>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<ms-mock :schema="pickValue.mock"/>
|
||||||
|
</el-col>
|
||||||
|
<el-col>
|
||||||
|
<el-input v-model="pickValue.description" class="ant-col-title" :placeholder="local['description']" size="small"/>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4" class="col-item-setting">
|
||||||
|
<el-tooltip class="item" effect="dark" content="高级设置" placement="top">
|
||||||
|
<i class="el-icon-setting" @click="onSetting"/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip v-if="isObject" content="添加子节点" placement="top">
|
||||||
|
<i class="el-icon-plus" @click="addChild" style="margin-left: 10px"/>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip v-if="!root && !isItem" content="删除节点" placement="top">
|
||||||
|
<i class="el-icon-close" @click="removeNode" style="margin-left: 10px"/>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-col>
|
||||||
|
</el-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" :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" :lang="lang" :custom="custom"/>
|
||||||
|
</template>
|
||||||
|
<!-- 高级设置-->
|
||||||
|
<el-dialog :close-on-click-modal="false" :title="local['adv_setting']" :visible.sync="modalVisible" width="60%" :destroy-on-close="true"
|
||||||
|
@close="handleClose">
|
||||||
|
<!--<el-dialog 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>
|
||||||
|
<el-form v-model="advancedValue" class="ant-advanced-search-form">
|
||||||
|
<el-row :gutter="6">
|
||||||
|
<el-col :span="8" v-for="(item,key) in advancedValue" :key="key">
|
||||||
|
<el-form-item>
|
||||||
|
<el-input-number v-model="advancedValue[key]" v-if="advancedAttr[key].type === 'integer'" style="width:100%" :placeholder="key" size="small"/>
|
||||||
|
<el-input-number v-model="advancedValue[key]" v-else-if="advancedAttr[key].type === 'number'" style="width:100%" :placeholder="key" size="small"/>
|
||||||
|
<span v-else-if="advancedAttr[key].type === 'boolean'" style="display:inline-block;width:100%">
|
||||||
|
<el-switch :active-text="local[key]" v-model="advancedValue[key]"/>
|
||||||
|
</span>
|
||||||
|
<el-select v-else-if="advancedAttr[key].type === 'array'" v-model="advancedValue[key]" style="width:100%" size="small">
|
||||||
|
<el-option value="" :label="local['nothing']"></el-option>
|
||||||
|
<el-option :key="t" :value="t" :label="t" v-for="t in advancedAttr[key].enums"/>
|
||||||
|
</el-select>
|
||||||
|
<el-input v-model="advancedValue[key]" v-else style="width:100%" :placeholder="key" size="small"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<!--<h3 v-text="local['add_custom']" v-show="custom">添加自定义属性</h3>
|
||||||
|
<el-form class="ant-advanced-search-form" v-show="custom">
|
||||||
|
<el-row :gutter="6">
|
||||||
|
<el-col :span="8" v-for="item in customProps" :key="item.key">
|
||||||
|
<el-form-item :label="item.key">
|
||||||
|
<el-input v-model="item.value" style="width:calc(100% - 30px)" size="small"/>
|
||||||
|
<el-button icon="close" type="link" @click="customProps.splice(customProps.indexOf(item),1)" size="small"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8" v-show="addProp.key != undefined">
|
||||||
|
<el-form-item>
|
||||||
|
<el-input slot="label" v-model="addProp.key" size="small"/>
|
||||||
|
<el-input v-model="addProp.value" size="small"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item>
|
||||||
|
<el-button icon="check" type="link" @click="confirmAddCustomNode" v-if="customing"/>
|
||||||
|
<el-tooltip content="local['add_custom']" v-else>
|
||||||
|
<el-button icon="el-icon-plus" type="link" @click="addCustomNode"/>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>-->
|
||||||
|
<h3 v-text="local['preview']">预览</h3>
|
||||||
|
<pre style="width:100%">{{completeNodeValue}}</pre>
|
||||||
|
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<ms-dialog-footer
|
||||||
|
@cancel="modalVisible = false"
|
||||||
|
@confirm="handleOk"/>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import {isNull} from './util'
|
||||||
|
import {TYPE_NAME, TYPE} from './type/type'
|
||||||
|
import MsMock from './mock/index'
|
||||||
|
import MsDialogFooter from '../../../../../common/components/MsDialogFooter'
|
||||||
|
import LocalProvider from './LocalProvider'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JsonSchemaEditor',
|
||||||
|
components: {MsMock, MsDialogFooter},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
disabled: { //name不可编辑,根节点name不可编辑,数组元素name不可编辑
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
disabledType: { //禁用类型选择
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
isItem: { //是否数组元素
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
deep: { // 节点深度,根节点deep=0
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
root: { //是否root节点
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
parent: { //父节点
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
custom: { //enable custom properties
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
lang: { // i18n language
|
||||||
|
type: String,
|
||||||
|
default: 'zh_CN'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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
|
||||||
|
},
|
||||||
|
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_NAME,
|
||||||
|
hidden: false,
|
||||||
|
countAdd: 1,
|
||||||
|
modalVisible: false,
|
||||||
|
advancedValue: {},
|
||||||
|
addProp: {},// 自定义属性
|
||||||
|
customProps: [],
|
||||||
|
customing: false,
|
||||||
|
local: LocalProvider(this.lang)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onInputName(e) {
|
||||||
|
const val = e.target.value
|
||||||
|
const p = {};
|
||||||
|
for (let key in this.parent.properties) {
|
||||||
|
if (key != this.pickKey) {
|
||||||
|
p[key] = this.parent.properties[key]
|
||||||
|
} else {
|
||||||
|
p[val] = this.parent.properties[key]
|
||||||
|
delete this.parent.properties[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$set(this.parent, 'properties', p)
|
||||||
|
},
|
||||||
|
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',mock: {mock: ""}})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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' && node.properties) {
|
||||||
|
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' && node.items.type === 'object') {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
required.length === 0 && this.$delete(parent, 'required')
|
||||||
|
},
|
||||||
|
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, mock: {mock: ""}})
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
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++}`
|
||||||
|
},
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleClose() {
|
||||||
|
this.modalVisible = false;
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.json-schema-editor .row {
|
||||||
|
display: flex;
|
||||||
|
margin: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor .row .ant-col-name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor .row .ant-col-name .ant-col-name-c {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor .row .ant-col-name .ant-col-name-required {
|
||||||
|
flex: 0 0 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor .row .ant-col-type {
|
||||||
|
min-width: 100px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor .row .ant-col-setting {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor .row .setting-icon {
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor .row .plus-icon {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor .row .close-icon {
|
||||||
|
color: #888;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
.json-schema-editor-advanced-modal {
|
||||||
|
color: rgba(0, 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, 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 {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-schema-editor-advanced-modal .ant-advanced-search-form .ant-form-item .ant-form-item-control-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-item-setting {
|
||||||
|
padding-top: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -31,10 +31,6 @@
|
||||||
default: () => {
|
default: () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mock: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -42,6 +38,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
if (!this.schema.mock) {
|
||||||
|
this.schema.mock = "";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
},
|
},
|
|
@ -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
|
|
@ -0,0 +1,11 @@
|
||||||
|
const value = {
|
||||||
|
description: null
|
||||||
|
}
|
||||||
|
const attr = {
|
||||||
|
description: {
|
||||||
|
name: '描述',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const wrapper = {value, attr}
|
||||||
|
export default wrapper
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,21 @@
|
||||||
|
const value = {
|
||||||
|
description: null,
|
||||||
|
maxProperties: null,
|
||||||
|
minProperties: null
|
||||||
|
}
|
||||||
|
const attr = {
|
||||||
|
description: {
|
||||||
|
name: '描述',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
maxProperties:{
|
||||||
|
name:'最大元素个数',
|
||||||
|
type:'integer'
|
||||||
|
},
|
||||||
|
minProperties:{
|
||||||
|
name:'最小元素个数',
|
||||||
|
type:'integer'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const wrapper = {value, attr}
|
||||||
|
export default wrapper
|
|
@ -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
|
|
@ -0,0 +1,17 @@
|
||||||
|
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}
|
|
@ -0,0 +1,24 @@
|
||||||
|
export function clearAttr(obj) {
|
||||||
|
for(let key in 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;
|
||||||
|
}
|
|
@ -1,45 +0,0 @@
|
||||||
<template>
|
|
||||||
<el-tooltip placement="top" content="添加兄弟/子节点">
|
|
||||||
<el-dropdown trigger="click">
|
|
||||||
<i class="el-icon-plus plus"></i>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<el-dropdown-item>
|
|
||||||
<span @click="addFieldAction({type:'add-field',isChild:false})">兄弟节点</span>
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item>
|
|
||||||
<span @click="addFieldAction({type:'add-field',isChild:true})">子节点</span>
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'DropPlus',
|
|
||||||
components: {},
|
|
||||||
props: {
|
|
||||||
prefix: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
created() {},
|
|
||||||
mounted() {},
|
|
||||||
methods: {
|
|
||||||
addFieldAction(...args) {
|
|
||||||
this.$emit('add-field', ...args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
</style>
|
|
|
@ -1,224 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="array-type">
|
|
||||||
<el-row type="flex" align="middle">
|
|
||||||
<el-col
|
|
||||||
:span="8"
|
|
||||||
class="col-item name-item col-item-name"
|
|
||||||
:style="tagPaddingLeftStyle"
|
|
||||||
>
|
|
||||||
<el-row type="flex" justify="space-around" align="middle">
|
|
||||||
<el-col :span="2" class="down-style-col">
|
|
||||||
<span
|
|
||||||
v-if="items.type === 'object'"
|
|
||||||
class="down-style"
|
|
||||||
@click="handleClickIcon"
|
|
||||||
>
|
|
||||||
<i v-if="!showIcon" class="el-icon-caret-bottom icon-object"></i>
|
|
||||||
<i v-else class="el-icon-caret-right icon-object"></i>
|
|
||||||
</span>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="20">
|
|
||||||
<el-input disabled value="Items" size="small" />
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="2" style="text-align: center">
|
|
||||||
<el-tooltip placement="top" content="全选">
|
|
||||||
<el-checkbox disabled />
|
|
||||||
</el-tooltip>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="3" class="col-item col-item-type">
|
|
||||||
<el-select
|
|
||||||
:value="items.type"
|
|
||||||
size="small"
|
|
||||||
class="type-select-style"
|
|
||||||
@change="handleChangeType"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in schemaTypes"
|
|
||||||
:key="item"
|
|
||||||
:value="item"
|
|
||||||
:label="item"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col v-if="isMock" :span="3" class="col-item col-item-mock">
|
|
||||||
<MockSelect
|
|
||||||
:schema="items"
|
|
||||||
@showEdit="handleAction({ eventType: 'mock-edit' })"
|
|
||||||
@change="handleChangeMock"
|
|
||||||
/>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col
|
|
||||||
v-if="showTitle"
|
|
||||||
:span="isMock ? 4 : 5"
|
|
||||||
class="col-item col-item-mock"
|
|
||||||
>
|
|
||||||
<el-input v-model="items.title" placeholder="标题" size="small">
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="handleAction({ eventType: 'show-edit', field: 'title' })"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
<el-col
|
|
||||||
v-if="!showTitle && showDefaultValue"
|
|
||||||
:span="isMock ? 4 : 5"
|
|
||||||
class="col-item col-item-mock"
|
|
||||||
>
|
|
||||||
<el-input v-model="items.default" placeholder="默认值" size="small">
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="handleAction({ eventType: 'show-edit', field: 'default' })"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="isMock ? 4 : 5" class="col-item col-item-desc">
|
|
||||||
<el-input v-model="items.description" placeholder="备注" size="small">
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="
|
|
||||||
handleAction({ eventType: 'show-edit', field: 'description' })
|
|
||||||
"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="isMock ? 2 : 3" class="col-item col-item-setting">
|
|
||||||
<span
|
|
||||||
class="adv-set"
|
|
||||||
@click="
|
|
||||||
handleAction({ eventType: 'setting', schemaType: items.type })
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<el-tooltip placement="top" content="高级设置">
|
|
||||||
<i class="el-icon-setting"></i>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span
|
|
||||||
v-if="items.type === 'object'"
|
|
||||||
@click="handleAction({ eventType: 'add-field', isChild: true })"
|
|
||||||
>
|
|
||||||
<el-tooltip placement="top" content="添加子节点">
|
|
||||||
<i class="el-icon-plus plus"></i>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<div class="option-formStyle">
|
|
||||||
<template v-if="items.type === 'array'">
|
|
||||||
<SchemaArray
|
|
||||||
:prefix="prefixArray"
|
|
||||||
:data="items"
|
|
||||||
:is-mock="isMock"
|
|
||||||
:show-title="showTitle"
|
|
||||||
:show-default-value="showDefaultValue"
|
|
||||||
:editor-id="editorId"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template v-if="items.type === 'object' && !showIcon">
|
|
||||||
<SchemaObject
|
|
||||||
:prefix="nameArray"
|
|
||||||
:data="items"
|
|
||||||
:is-mock="isMock"
|
|
||||||
:show-title="showTitle"
|
|
||||||
:show-default-value="showDefaultValue"
|
|
||||||
:editor-id="editorId"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import isUndefined from 'lodash/isUndefined'
|
|
||||||
import MockSelect from '../mock'
|
|
||||||
import SchemaObject from './SchemaObject'
|
|
||||||
import { SCHEMA_TYPE } from '../utils'
|
|
||||||
export default {
|
|
||||||
name: 'SchemaArray',
|
|
||||||
components: { MockSelect, SchemaObject },
|
|
||||||
props: {
|
|
||||||
isMock: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
showTitle: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
showDefaultValue: { type: Boolean, default: false },
|
|
||||||
editorId: {
|
|
||||||
type: String,
|
|
||||||
default: 'editor_id',
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
prefix: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {},
|
|
||||||
},
|
|
||||||
action: {
|
|
||||||
type: Function,
|
|
||||||
default: () => () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
tagPaddingLeftStyle: {},
|
|
||||||
schemaTypes: SCHEMA_TYPE,
|
|
||||||
items: this.data.items,
|
|
||||||
showIcon: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
nameArray() {
|
|
||||||
return [].concat(this.prefixArray, 'properties')
|
|
||||||
},
|
|
||||||
prefixArray() {
|
|
||||||
return [].concat(this.prefix, 'items')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
beforeMount() {
|
|
||||||
const length = this.prefix.filter((name) => name !== 'properties').length
|
|
||||||
this.tagPaddingLeftStyle = {
|
|
||||||
paddingLeft: `${20 * (length + 1)}px`,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
isUndefined() {
|
|
||||||
return isUndefined
|
|
||||||
},
|
|
||||||
handleClickIcon() {
|
|
||||||
this.showIcon = !this.showIcon
|
|
||||||
},
|
|
||||||
handleAction(opts) {
|
|
||||||
const { prefix, name } = this
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.editorId}`, {
|
|
||||||
prefix,
|
|
||||||
name: name || 'items',
|
|
||||||
...opts,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleChangeMock() {},
|
|
||||||
handleChangeType(value) {
|
|
||||||
console.log(value)
|
|
||||||
this.handleAction({ eventType: 'schema-type', value })
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,290 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<el-row type="flex" align="middle">
|
|
||||||
<el-col
|
|
||||||
:span="8"
|
|
||||||
class="col-item name-item col-item-name"
|
|
||||||
:style="tagPaddingLeftStyle"
|
|
||||||
>
|
|
||||||
<el-row type="flex" justify="space-around" align="middle">
|
|
||||||
<el-col :span="2" class="down-style-col">
|
|
||||||
<span
|
|
||||||
v-if="value.type === 'object'"
|
|
||||||
class="down-style"
|
|
||||||
@click="handleClickIcon"
|
|
||||||
>
|
|
||||||
<i v-if="showIcon" class="el-icon-caret-bottom icon-object"></i>
|
|
||||||
<i v-if="!showIcon" class="el-icon-caret-right icon-object"></i>
|
|
||||||
</span>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="20" class="el-input--small">
|
|
||||||
<input
|
|
||||||
size="small"
|
|
||||||
class="el-input el-input__inner"
|
|
||||||
:class="{ 'is-disabled': value.disabled }"
|
|
||||||
:value="name"
|
|
||||||
:disabled="value.disabled"
|
|
||||||
@change="handleNameChange"
|
|
||||||
/>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="2" style="text-align: center">
|
|
||||||
<el-tooltip placement="top" content="是否必须">
|
|
||||||
<el-checkbox
|
|
||||||
:checked="
|
|
||||||
(data.required && data.required.indexOf(name) != -1) || false
|
|
||||||
"
|
|
||||||
@change="handleEnableRequire"
|
|
||||||
></el-checkbox>
|
|
||||||
</el-tooltip>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="3" class="col-item col-item-type">
|
|
||||||
<el-select
|
|
||||||
size="small"
|
|
||||||
:value="value.type"
|
|
||||||
:disabled="value.disabled && !value.canChangeType"
|
|
||||||
class="type-select-style"
|
|
||||||
@change="handleChangeType"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in schemaTypes"
|
|
||||||
:key="item"
|
|
||||||
:value="item"
|
|
||||||
:label="item"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col v-if="isMock" :span="3" class="col-item col-item-mock">
|
|
||||||
<MockSelect
|
|
||||||
:schema="value"
|
|
||||||
@showEdit="handleAction({ eventType: 'mock-edit' })"
|
|
||||||
@change="handleChangeMock"
|
|
||||||
/>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col
|
|
||||||
v-if="showTitle"
|
|
||||||
:span="isMock ? 4 : 5"
|
|
||||||
class="col-item col-item-mock"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="value.title"
|
|
||||||
:disabled="value.disabled"
|
|
||||||
size="small"
|
|
||||||
placeholder="标题"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="handleAction({ eventType: 'show-edit', field: 'title' })"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
<!-- 默认值输入框 -->
|
|
||||||
<el-col
|
|
||||||
v-if="!showTitle && showDefaultValue"
|
|
||||||
:span="isMock ? 4 : 5"
|
|
||||||
class="col-item col-item-mock"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model.trim="value.default"
|
|
||||||
placeholder="默认值"
|
|
||||||
size="small"
|
|
||||||
:disabled="
|
|
||||||
value.type === 'object' || value.type === 'array' || value.disabled
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="handleAction({ eventType: 'show-edit', field: 'default' })"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="isMock ? 4 : 5" class="col-item col-item-desc">
|
|
||||||
<el-input
|
|
||||||
v-model="value.description"
|
|
||||||
:disabled="value.disabled"
|
|
||||||
size="small"
|
|
||||||
placeholder="备注"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
slot="append"
|
|
||||||
class="el-icon-edit"
|
|
||||||
@click="
|
|
||||||
handleAction({ eventType: 'show-edit', field: 'description' })
|
|
||||||
"
|
|
||||||
></i>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="isMock ? 2 : 3" class="col-item col-item-setting">
|
|
||||||
<span
|
|
||||||
class="adv-set"
|
|
||||||
@click="
|
|
||||||
handleAction({ eventType: 'setting', schemaType: value.type })
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<el-tooltip placement="top" content="高级设置">
|
|
||||||
<i class="el-icon-setting"></i>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
class="delete-item"
|
|
||||||
:class="{ hidden: value.disabled }"
|
|
||||||
@click="handleAction({ eventType: 'delete-field' })"
|
|
||||||
>
|
|
||||||
<i class="el-icon-close close"></i>
|
|
||||||
</span>
|
|
||||||
<DropPlus
|
|
||||||
v-if="value.type === 'object'"
|
|
||||||
:prefix="prefix"
|
|
||||||
:name="name"
|
|
||||||
@add-field="handleAction"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
v-if="value.type !== 'object'"
|
|
||||||
@click="handleAction({ eventType: 'add-field', isChild: false })"
|
|
||||||
>
|
|
||||||
<el-tooltip placement="top" content="添加兄弟节点">
|
|
||||||
<i class="el-icon-plus plus"></i>
|
|
||||||
</el-tooltip>
|
|
||||||
</span>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<div class="option-formStyle">
|
|
||||||
<!-- {mapping(prefixArray, value, showEdit, showAdv)} -->
|
|
||||||
<template v-if="value.type === 'array'">
|
|
||||||
<schema-array
|
|
||||||
:prefix="prefixArray"
|
|
||||||
:data="value"
|
|
||||||
:is-mock="isMock"
|
|
||||||
:show-title="showTitle"
|
|
||||||
:show-default-value="showDefaultValue"
|
|
||||||
:editor-id="editorId"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template v-if="value.type === 'object' && showIcon">
|
|
||||||
<schema-object
|
|
||||||
:prefix="nameArray"
|
|
||||||
:data="value"
|
|
||||||
:is-mock="isMock"
|
|
||||||
:show-title="showTitle"
|
|
||||||
:show-default-value="showDefaultValue"
|
|
||||||
:editor-id="editorId"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import isUndefined from 'lodash/isUndefined'
|
|
||||||
import MockSelect from '../mock'
|
|
||||||
import DropPlus from './DropPlus'
|
|
||||||
import SchemaObject from './SchemaObject'
|
|
||||||
import SchemaArray from './SchemaArray'
|
|
||||||
import { SCHEMA_TYPE } from '../utils'
|
|
||||||
export default {
|
|
||||||
name: 'SchemaItem',
|
|
||||||
components: {
|
|
||||||
MockSelect,
|
|
||||||
DropPlus,
|
|
||||||
'schema-array': SchemaArray,
|
|
||||||
'schema-object': SchemaObject,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
isMock: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
showTitle: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
showDefaultValue: { type: Boolean, default: false },
|
|
||||||
editorId: {
|
|
||||||
type: String,
|
|
||||||
default: 'editor_id',
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
prefix: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
showIcon: true,
|
|
||||||
tagPaddingLeftStyle: {},
|
|
||||||
schemaTypes: SCHEMA_TYPE,
|
|
||||||
value: this.data.properties[this.name],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
nameArray() {
|
|
||||||
const prefixArray = [].concat(this.prefix, this.name)
|
|
||||||
return [].concat(prefixArray, 'properties')
|
|
||||||
},
|
|
||||||
prefixArray() {
|
|
||||||
return [].concat(this.prefix, this.name)
|
|
||||||
// return [].concat(this.prefix, 'items')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
beforeMount() {
|
|
||||||
const length = this.prefix.filter((name) => name !== 'properties').length
|
|
||||||
this.tagPaddingLeftStyle = {
|
|
||||||
paddingLeft: `${20 * (length + 1)}px`,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
isUndefined() {
|
|
||||||
return isUndefined
|
|
||||||
},
|
|
||||||
handleClickIcon() {
|
|
||||||
this.showIcon = !this.showIcon
|
|
||||||
},
|
|
||||||
|
|
||||||
handleAction(options) {
|
|
||||||
const { prefix, name } = this
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.editorId}`, {
|
|
||||||
eventType: 'add-field',
|
|
||||||
prefix,
|
|
||||||
name,
|
|
||||||
...options,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
handleNameChange(e) {
|
|
||||||
this.handleAction({
|
|
||||||
eventType: 'update-field-name',
|
|
||||||
value: e.target.value,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleEnableRequire(e) {
|
|
||||||
const { prefix, name } = this
|
|
||||||
this.$jsEditorEvent.emit(`schema-update-${this.editorId}`, {
|
|
||||||
eventType: 'toggle-required',
|
|
||||||
prefix,
|
|
||||||
name,
|
|
||||||
required: e,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleChangeMock() {},
|
|
||||||
handleChangeType(value) {
|
|
||||||
this.handleAction({ eventType: 'schema-type', value })
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,54 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="object-style">
|
|
||||||
<schema-item
|
|
||||||
v-for="(name,index) in propertyKeys"
|
|
||||||
:key="index"
|
|
||||||
:data="data"
|
|
||||||
:name="name"
|
|
||||||
:prefix="prefix"
|
|
||||||
:is-mock="isMock"
|
|
||||||
:show-title="showTitle"
|
|
||||||
:show-default-value="showDefaultValue"
|
|
||||||
:editor-id="editorId"
|
|
||||||
></schema-item>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'SchemaObject',
|
|
||||||
components: { 'schema-item': () => import('./SchemaItem.vue') },
|
|
||||||
props: {
|
|
||||||
prefix: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {}
|
|
||||||
},
|
|
||||||
isMock: { type: Boolean, default: false },
|
|
||||||
showTitle: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
showDefaultValue: { type: Boolean, default: false },
|
|
||||||
editorId: {
|
|
||||||
type: String,
|
|
||||||
default: 'editor_id'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
tagPaddingLeftStyle: {},
|
|
||||||
items: this.data.items
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
propertyKeys() {
|
|
||||||
return Object.keys(this.data.properties)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,65 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="schema-content" v-bind="$attrs">
|
|
||||||
<template v-if="data.type==='array'">
|
|
||||||
<schema-array
|
|
||||||
:prefix="name"
|
|
||||||
:data="data"
|
|
||||||
:is-mock="isMock"
|
|
||||||
:show-title="showTitle"
|
|
||||||
:show-default-value="showDefaultValue"
|
|
||||||
:editor-id="editorId"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template v-if="data.type==='object'">
|
|
||||||
<schema-object
|
|
||||||
:prefix="nameArray"
|
|
||||||
:data="data"
|
|
||||||
:is-mock="isMock"
|
|
||||||
:show-title="showTitle"
|
|
||||||
:show-default-value="showDefaultValue"
|
|
||||||
:editor-id="editorId"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import SchemaObject from './SchemaObject'
|
|
||||||
import SchemaArray from './SchemaArray'
|
|
||||||
export default {
|
|
||||||
name: 'SchemaJson',
|
|
||||||
components: {
|
|
||||||
'schema-array': SchemaArray,
|
|
||||||
'schema-object': SchemaObject
|
|
||||||
},
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isMock: { type: Boolean, default: false },
|
|
||||||
showTitle: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
showDefaultValue: { type: Boolean, default: false },
|
|
||||||
editorId: {
|
|
||||||
type: String,
|
|
||||||
default: 'editor_id'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
name: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
nameArray() {
|
|
||||||
return [].concat(this.name, 'properties')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,200 +0,0 @@
|
||||||
export const JSONPATH_JOIN_CHAR = '.';
|
|
||||||
export const lang = 'zh_CN';
|
|
||||||
export const format = [
|
|
||||||
{name: 'date-time'},
|
|
||||||
{name: 'date'},
|
|
||||||
{name: 'email'},
|
|
||||||
{name: 'hostname'},
|
|
||||||
{name: 'ipv4'},
|
|
||||||
{name: 'ipv6'},
|
|
||||||
{name: 'uri'}
|
|
||||||
];
|
|
||||||
export const SCHEMA_TYPE = [
|
|
||||||
'string',
|
|
||||||
'number',
|
|
||||||
'array',
|
|
||||||
'object',
|
|
||||||
'boolean',
|
|
||||||
'integer'
|
|
||||||
];
|
|
||||||
export const defaultInitSchemaData = {
|
|
||||||
type: 'object',
|
|
||||||
title: 'title',
|
|
||||||
properties: {}
|
|
||||||
};
|
|
||||||
export const defaultSchema = {
|
|
||||||
string: {
|
|
||||||
type: 'string'
|
|
||||||
},
|
|
||||||
number: {
|
|
||||||
type: 'number'
|
|
||||||
},
|
|
||||||
array: {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
type: 'string'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
object: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {}
|
|
||||||
},
|
|
||||||
boolean: {
|
|
||||||
type: 'boolean'
|
|
||||||
},
|
|
||||||
integer: {
|
|
||||||
type: 'integer'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 防抖函数,减少高频触发的函数执行的频率
|
|
||||||
// 请在 constructor 里使用:
|
|
||||||
|
|
||||||
// this.func = debounce(this.func, 400);
|
|
||||||
export const debounce = (func, wait) => {
|
|
||||||
let timeout;
|
|
||||||
return function () {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
timeout = setTimeout(func, wait);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getData = (state, keys) => {
|
|
||||||
let curState = state;
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
|
||||||
curState = curState[keys[i]];
|
|
||||||
}
|
|
||||||
return curState;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setData = function (state, keys, value) {
|
|
||||||
let curState = state;
|
|
||||||
for (let i = 0; i < keys.length - 1; i++) {
|
|
||||||
curState = curState[keys[i]];
|
|
||||||
}
|
|
||||||
curState[keys[keys.length - 1]] = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteData = function (state, keys) {
|
|
||||||
let curState = state;
|
|
||||||
for (let i = 0; i < keys.length - 1; i++) {
|
|
||||||
curState = curState[keys[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
delete curState[keys[keys.length - 1]];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getParentKeys = function (keys) {
|
|
||||||
if (keys.length === 1) return [];
|
|
||||||
const arr = [].concat(keys);
|
|
||||||
arr.splice(keys.length - 1, 1);
|
|
||||||
return arr;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const clearSomeFields = function (keys, data) {
|
|
||||||
const newData = Object.assign({}, data);
|
|
||||||
keys.forEach(key => {
|
|
||||||
delete newData[key];
|
|
||||||
});
|
|
||||||
return newData;
|
|
||||||
};
|
|
||||||
|
|
||||||
function getFieldstitle(data) {
|
|
||||||
const requiredtitle = [];
|
|
||||||
Object.keys(data).map(title => {
|
|
||||||
requiredtitle.push(title);
|
|
||||||
});
|
|
||||||
|
|
||||||
return requiredtitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function handleSchemaRequired(schema, checked) {
|
|
||||||
if (schema.type === 'object') {
|
|
||||||
const requiredtitle = getFieldstitle(schema.properties);
|
|
||||||
|
|
||||||
// schema.required = checked ? [].concat(requiredtitle) : [];
|
|
||||||
if (checked) {
|
|
||||||
schema.required = [].concat(requiredtitle);
|
|
||||||
} else {
|
|
||||||
delete schema.required;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleObject(schema.properties, checked);
|
|
||||||
} else if (schema.type === 'array') {
|
|
||||||
handleSchemaRequired(schema.items, checked);
|
|
||||||
} else {
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleObject(properties, checked) {
|
|
||||||
for (var key in properties) {
|
|
||||||
if (properties[key].type === 'array' || properties[key].type === 'object') {
|
|
||||||
handleSchemaRequired(properties[key], checked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cloneObject(obj) {
|
|
||||||
if (typeof obj === 'object') {
|
|
||||||
if (Array.isArray(obj)) {
|
|
||||||
var newArr = [];
|
|
||||||
obj.forEach(function (item, index) {
|
|
||||||
newArr[index] = cloneObject(item);
|
|
||||||
});
|
|
||||||
return newArr;
|
|
||||||
} else {
|
|
||||||
var newObj = {};
|
|
||||||
for (var key in obj) {
|
|
||||||
newObj[key] = cloneObject(obj[key]);
|
|
||||||
}
|
|
||||||
return newObj;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uuid = () => {
|
|
||||||
return Math.random()
|
|
||||||
.toString(16)
|
|
||||||
.substr(2, 5);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const log = (...args) => {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* val值不为空字符,null,undefined
|
|
||||||
*/
|
|
||||||
export const isNotNil = val => {
|
|
||||||
const arr = [undefined, null, ''];
|
|
||||||
return !arr.includes(val);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* form表单值校验是否为空,有值为空则返回true,值都正确则返回false
|
|
||||||
*/
|
|
||||||
export const isFormValid = obj => {
|
|
||||||
if (typeof obj !== 'object') return true;
|
|
||||||
const keys = Object.keys(obj);
|
|
||||||
return keys.some(key => {
|
|
||||||
return !isNotNil(obj[key]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* 只返回有值得属性新对象
|
|
||||||
* @param {Object} formData 表单对象
|
|
||||||
*/
|
|
||||||
export const getValidFormVal = formData => {
|
|
||||||
const obj = {};
|
|
||||||
const keys = Object.keys(formData);
|
|
||||||
keys.forEach(key => {
|
|
||||||
if (isNotNil(formData[key])) {
|
|
||||||
obj[key] = formData[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
};
|
|
|
@ -19,10 +19,9 @@ import '../common/css/main.css';
|
||||||
import CKEditor from '@ckeditor/ckeditor5-vue';
|
import CKEditor from '@ckeditor/ckeditor5-vue';
|
||||||
import VueFab from 'vue-float-action-button'
|
import VueFab from 'vue-float-action-button'
|
||||||
import {horizontalDrag} from "../common/js/directive";
|
import {horizontalDrag} from "../common/js/directive";
|
||||||
import JsonSchemaEditor from './components/common/json-schema/index';
|
import JsonSchemaEditor from './components/common/json-schema/ot/packages/index';
|
||||||
Vue.use(JsonSchemaEditor);
|
Vue.use(JsonSchemaEditor);
|
||||||
|
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
Vue.use(icon);
|
Vue.use(icon);
|
||||||
Vue.use(ElementUI, {
|
Vue.use(ElementUI, {
|
||||||
|
|
Loading…
Reference in New Issue