From 696c6970a7485608429ac9a5a3494ce554e2ce83 Mon Sep 17 00:00:00 2001 From: bigfengyu Date: Tue, 20 Aug 2019 09:32:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AF=BC=E5=85=A5=E6=97=B6=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=AD=98=E5=9C=A8=20length=20=E4=BC=9A=E4=BA=A7?= =?UTF-8?q?=E7=94=9F=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/editor/Importer.tsx | 35 +- src/components/editor/InterfaceSummary.tsx | 26 +- src/components/editor/PropertyList.tsx | 2 +- src/components/editor/RepositoryEditor.sass | 534 ++++++++++---------- 4 files changed, 319 insertions(+), 278 deletions(-) diff --git a/src/components/editor/Importer.tsx b/src/components/editor/Importer.tsx index 12b7fbc..0b04717 100644 --- a/src/components/editor/Importer.tsx +++ b/src/components/editor/Importer.tsx @@ -3,6 +3,7 @@ import { connect, Link, Mock, _, PropTypes } from '../../family' import { RCodeMirror } from '../utils/' import { addProperty } from '../../actions/property' import { RootState } from 'actions/types' +import JSON5 from 'json5' import { Button } from '@material-ui/core' const mockResult = process.env.NODE_ENV === 'development' @@ -14,6 +15,28 @@ const mockResult = }, }) : () => ({}) + +/** MockJS 的 toJSONSchema 的 bug 会导致有 length 属性的对象被识别成数组 + * 众所周知 MockJS 已经不维护了,所以只能自己想想办法 + * 先递归把 length 替换成其他的名称,生成 schema 后再换回来 + */ +const lengthAlias = '__mockjs_length_*#06#' + +const replaceLength = (obj: any) => { + for (const k in obj) { + if (obj[k] && typeof obj[k] === 'object') { + replaceLength(obj[k]) + } else { + // Do something with obj[k] + if (k === 'length') { + const v = obj[k] + delete obj[k] + obj[lengthAlias] = v + } + } + } +} + function isPrimitiveType(type: string) { return ['number', 'null', 'undefined', 'boolean', 'string'].indexOf(type.toLowerCase()) > -1 } @@ -111,7 +134,7 @@ class Importer extends Component { handleBeautify = (e: any) => { e.preventDefault() if (this.$rcm) { - const result = eval('(' + this.state.result + ')') // eslint-disable-line no-eval + const result = JSON5.parse(this.state.result) const beautified = JSON.stringify(result, null, 2) this.$rcm.cm.setValue(beautified) } @@ -123,6 +146,9 @@ class Importer extends Component { const { auth, repository, mod, itf, scope } = this.props const hasSiblings = siblings instanceof Array && siblings.length > 0 // DONE 2.1 需要与 Mock 的 rule.type 规则统一,首字符小写,好烦!应该忽略大小写! + if (schema.name === lengthAlias) { + schema.name = 'length' + } let type = schema.type[0].toUpperCase() + schema.type.slice(1) let rule = '' if (type === 'Array' && schema.items && schema.items.length > 1) { @@ -205,7 +231,12 @@ class Importer extends Component { // DONE 2.1 因为 setState() 是异步的,导致重复调用 handleAddMemoryProperty() 时最后保留最后一个临时属性 handleSubmit = (e: any) => { e.preventDefault() - let result = eval('(' + this.state.result + ')') // eslint-disable-line no-eval + let result = JSON5.parse(this.state.result) + if (this.state.result.indexOf('length') > -1) { + // 递归查找替换 length 是一个重操作,先进行一次字符串查找,发现存在 length 字符再进行 + replaceLength(result) + } + if (result instanceof Array) { result = { _root_: result } } diff --git a/src/components/editor/InterfaceSummary.tsx b/src/components/editor/InterfaceSummary.tsx index 34def05..163629f 100644 --- a/src/components/editor/InterfaceSummary.tsx +++ b/src/components/editor/InterfaceSummary.tsx @@ -159,20 +159,18 @@ class InterfaceSummary extends Component - {itf.description && ( -
  • - {handleChangeInterface({description: e.target.value})}} - margin="normal" - /> -
  • - )} +
  • + {handleChangeInterface({description: e.target.value})}} + margin="normal" + /> +
  • : <>
  • diff --git a/src/components/editor/PropertyList.tsx b/src/components/editor/PropertyList.tsx index 07ea073..3b3b24f 100644 --- a/src/components/editor/PropertyList.tsx +++ b/src/components/editor/PropertyList.tsx @@ -83,7 +83,7 @@ const PropertyLabel = (props: any) => { const getFormattedValue = (itf: any) => { if ((itf.type === 'Array' || itf.type === 'Object' || itf.type === 'String') && itf.value) { try { - const formatted = JSON5.stringify(JSON5.parse(itf.value), undefined, 2) + const formatted = JSON.stringify(JSON5.parse(itf.value), undefined, 2) return formatted } catch (error) { return itf.value || '' diff --git a/src/components/editor/RepositoryEditor.sass b/src/components/editor/RepositoryEditor.sass index b6df7f1..9c6dbca 100644 --- a/src/components/editor/RepositoryEditor.sass +++ b/src/components/editor/RepositoryEditor.sass @@ -1,426 +1,438 @@ -@import "../../assets/variables.sass"; +@import "../../assets/variables.sass" .RepositoryEditor > .header - position: relative; - padding: 2rem; - background-color: #fafbfc; + position: relative + padding: 2rem + background-color: #fafbfc > .title - font-size: 2rem; - margin-right: 1rem; + font-size: 2rem + margin-right: 1rem .slash - color: #999; + color: #999 > .toolbar - display: inline-block; + display: inline-block a, .fake-link - margin-right: 1rem; + margin-right: 1rem > .desc - margin: 1rem 0 .5rem; - color: #666; + margin: 1rem 0 .5rem + color: #666 > .body - // padding: 0 2rem; + // padding: 0 2rem .RelatedProjects - display: flex; - flex-wrap: wrap; - align-items: stretch; - margin: 1rem 0 -1rem; - color: #888; + display: flex + flex-wrap: wrap + align-items: stretch + margin: 1rem 0 -1rem + color: #888 > .Project - border: 1px solid #E6E6E6; - background: #FFF; - padding: 0 1rem; - margin-bottom: 1rem; - margin-right: 1rem; - line-height: 2.44; + border: 1px solid #E6E6E6 + background: #FFF + padding: 0 1rem + margin-bottom: 1rem + margin-right: 1rem + line-height: 2.44 .title - margin-right: .7rem; + margin-right: .7rem svg - transform: scale(1.2) translateY(-1px); + transform: scale(1.2) translateY(-1px) i - color: #888; - font-style: normal; + color: #888 + font-style: normal margin-left: .5rem .RepositorySearcher.dropdown - position: absolute; - top: 2rem; - right: 2rem; - left: auto; + position: absolute + top: 2rem + right: 2rem + left: auto > .dropdown-input - margin-bottom: 0; - width: 20rem; + margin-bottom: 0 + width: 20rem > .dropdown-menu - position: absolute; - right: 0; - left: auto; - display: block; - min-width: 100%; - max-height: 50rem; - overflow: scroll; + position: absolute + right: 0 + left: auto + display: block + min-width: 100% + max-height: 50rem + overflow: scroll a.dropdown-item &.dropdown-item-module - padding-left: 1.5rem; - color: #333; + padding-left: 1.5rem + color: #333 &.dropdown-item-interface - padding-left: 1.5rem + 2.5rem; - color: #333; + padding-left: 1.5rem + 2.5rem + color: #333 &.dropdown-item-property - padding-left: 1.5rem + 2.5rem + 2.5rem; - color: #666; + padding-left: 1.5rem + 2.5rem + 2.5rem + color: #666 > .label - margin-right: .5rem; - color: #666; + margin-right: .5rem + color: #666 > .dropdown-item-clip - margin-right: .5rem; + margin-right: .5rem .highlight - font-weight: bold; - color: $brand; + font-weight: bold + color: $brand &:active - color: #FFF; + color: #FFF > .label - color: #FFF; + color: #FFF > .dropdown-item-clip .highlight - color: #FFF; + color: #FFF .DuplicatedInterfacesWarning - margin-top: 1rem; + margin-top: 1rem .alert.alert-warning - margin-bottom: .5rem; + margin-bottom: .5rem .title - margin-right: 1rem; + margin-right: 1rem .icon - font-size: 1.4rem; - margin-right: .5rem; + font-size: 1.4rem + margin-right: .5rem .msg - font-weight: bold; - margin-right: 1rem; + font-weight: bold + margin-right: 1rem .itf a - margin-right: 1rem; + margin-right: 1rem .ModuleList - margin: 0; - padding: 0 2rem; - list-style: none; - border-bottom: 1px solid #e1e4e8; - background-color: #fafbfc; + margin: 0 + padding: 0 2rem + list-style: none + border-bottom: 1px solid #e1e4e8 + background-color: #fafbfc > li - position: relative; - display: block; - float: left; - margin-bottom: -1px; - padding: .8rem 1.2rem; - border: 1px solid transparent; - border-width: 3px 1px 0px 1px; - border-radius: .4rem .4rem 0 0; + position: relative + display: block + float: left + margin-bottom: -1px + padding: .8rem 1.2rem + border: 1px solid transparent + border-width: 3px 1px 0px 1px + border-radius: .4rem .4rem 0 0 &.active - // border: 1px solid $border; - border-bottom-color: transparent; - background-color: white; - cursor: default; - border-color: #3f51b5 #e1e4e8 transparent #e1e4e8; + // border: 1px solid $border + border-bottom-color: transparent + background-color: white + cursor: default + border-color: #3f51b5 #e1e4e8 transparent #e1e4e8 &.active:hover - background-color: white; + background-color: white > .Module - position: relative; + position: relative a.name - color: #586069; + color: #586069 .toolbar - // float: right; - display: inline-block; + // float: right + display: inline-block a, .fake-link - margin-left: 0.5rem; - font-size: 1.4rem; - color: #999; + margin-left: 0.5rem + font-size: 1.4rem + color: #999 &:hover - color: $brand; + color: $brand > li:hover > .Module .toolbar - display: inline-block; + display: inline-block > li.active > .Module a.name - color: #333; + color: #333 .toolbar - display: inline-block; - // font-size: 1.4rem; + display: inline-block + // font-size: 1.4rem .InterfaceWrapper - display: flex; - flex-direction: row; - background-color: #FFFFFF; - padding: 2rem; + display: flex + flex-direction: row + background-color: #FFFFFF + padding: 2rem .InterfaceList - width: 23rem; - flex-shrink: 0; + width: 23rem + flex-shrink: 0 .InterfaceEditor - overflow-x: hidden; - padding: 0 1px; - flex-grow: 1; + overflow-x: hidden + padding: 0 1px + flex-grow: 1 .InterfaceList .header - margin-bottom: 1rem; + margin-bottom: 1rem ul.body - margin: 0; - padding: 0; - border: 1px solid rgba(63, 81, 181, 0.5); - border-radius: .4rem; - list-style: none; - max-height: 150vh; - overflow-y: auto; + margin: 0 + padding: 0 + border: 1px solid rgba(63, 81, 181, 0.5) + border-radius: .4rem + list-style: none + max-height: 150vh + overflow-y: auto > li - position: relative; - padding: 1rem 1rem; - border-bottom: 1px solid rgba(63, 81, 181, 0.5); + position: relative + padding: 1rem 1rem + border-bottom: 1px solid rgba(63, 81, 181, 0.5) &:first-child - border-top-left-radius: .3rem; + border-top-left-radius: .3rem &:last-child - border-bottom: 0; - border-bottom-left-radius: .3rem; + border-bottom: 0 + border-bottom-left-radius: .3rem .Interface - position: relative; - padding-right: 4rem; + position: relative + padding-right: 4rem .name - position: relative; - font-size: 1.3rem; - width: 100%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + position: relative + font-size: 1.3rem + width: 100% + overflow: hidden + white-space: nowrap + text-overflow: ellipsis .url - font-size: 1rem; - width: 100%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - color: rgba(0, 0, 0, 0.54); + font-size: 1rem + width: 100% + overflow: hidden + white-space: nowrap + text-overflow: ellipsis + color: rgba(0, 0, 0, 0.54) .toolbar - display: none; - position: absolute; - right: 0; - top: 0; - font-size: 1.4rem; + display: none + position: absolute + right: 0 + top: 0 + font-size: 1.4rem a, .fake-link - margin-left: 0.5rem; - color: #999; + margin-left: 0.5rem + color: #999 &:hover - color: $brand; + color: $brand .locked - font-size: 1.4rem; - color: $warning; + font-size: 1.4rem + color: $warning > li:hover .toolbar - display: block; + display: block > li.active .Interface .name a - color: #333; + color: #333 &:hover - color: #333; + color: #333 .toolbar - display: block; + display: block > li.active - border-left: 2px solid #3f51b5; + border-left: 2px solid #3f51b5 // &::before - // position: absolute; - // top: 0; - // bottom: 0; - // left: 0; - // width: 2px; - // content: ""; - // background-color: #3f51b5; + // position: absolute + // top: 0 + // bottom: 0 + // left: 0 + // width: 2px + // content: "" + // background-color: #3f51b5 .InterfaceEditor - margin-left: 2rem; - position: relative; + margin-left: 2rem + position: relative .InterfaceEditorToolbar - position: absolute; - top: 0; - right: 0; - text-align: center; + position: absolute + top: 0 + right: 0 + text-align: center .btn.edit, .btn.save, .btn.cancel, .locker-success, .locker-warning - display: block; - margin-bottom: 0.5rem; - width: 12rem; + display: block + margin-bottom: 0.5rem + width: 12rem .locker-success - display: inline-block; - padding: 0.5rem 1.5rem; - border-radius: 0.4rem; - color: white; - background-color: $success; + display: inline-block + padding: 0.5rem 1.5rem + border-radius: 0.4rem + color: white + background-color: $success .locker-warning - @extend .locker-success; - background-color: $warning; + @extend .locker-success + background-color: $warning .InterfaceSummary - margin-bottom: 2rem; + margin-bottom: 2rem > .header - margin-bottom: .5rem; + margin-bottom: .5rem > .title - font-size: 1.6rem; - margin-right: 1rem; + font-size: 1.6rem + margin-right: 1rem .slash - color: #999; + color: #999 a.edit, a.delete - margin-right: .5rem; + margin-right: .5rem ul.body - color: #666; - margin: 0; - padding: 0; - list-style: none; + color: #666 + margin: 0 + padding: 0 + list-style: none > li - margin-bottom: .2rem; + margin-bottom: .2rem .label - color: #666; - margin-right: .3rem; + color: #666 + margin-right: .3rem .PropertyList - margin-bottom: 3rem; + margin-bottom: 3rem > .header - margin-bottom: 1rem; + margin-bottom: 1rem > .title - font-size: 1.6rem; - margin-right: 1rem; + font-size: 1.6rem + margin-right: 1rem > .toolbar - float: right; + float: right .checked-button background-color: rgba(63, 81, 181, 0.17) .preview - margin: 0; + margin: 0 input - margin-right: .5rem; + margin-right: .5rem > .body - margin-bottom: 1rem; + margin-bottom: 1rem > .footer > .Previewer - display: flex; - justify-content: space-between; - flex-wrap: wrap; - margin-top: 1rem; + display: flex + justify-content: space-between + flex-wrap: wrap + margin-top: 1rem > .result-template, > .result-mocked - width: 49%; + width: 49% > .header - margin-bottom: .5rem; + margin-bottom: .5rem .title - margin-right: .75rem; + margin-right: .75rem > pre.body - max-height: 90vh; - overflow: auto; + max-height: 90vh + overflow: auto > .result-valid - padding-top: 2.5rem; - text-align: center; - color: #999; + padding-top: 2.5rem + text-align: center + color: #999 .SortableTreeTable .SortableTreeTableHeader, .SortableTreeTableRow .flex-row - display: flex; + display: flex .thtd - border: 1px solid #eceeef; - flex-grow: 1; + border: 1px solid #eceeef + flex-grow: 1 // 垂直居中 - display: flex; - align-items: center; - flex-direction: row; - margin-right: -1px; + display: flex + align-items: center + flex-direction: row + margin-right: -1px .th - @extend .thtd; - padding: .75rem; - font-weight: bold; + @extend .thtd + padding: .75rem + font-weight: bold .td - @extend .thtd; - padding: .5rem .75rem; - margin-bottom: -1px; + @extend .thtd + padding: .5rem .75rem + margin-bottom: -1px .th, .td &.operations - width: 4.5rem; - min-width: 4.5rem; + background: #fff + width: 4.5rem + min-width: 4.5rem &.name - width: 20rem; - flex-grow: 3; + width: 20rem + flex-grow: 3 &.type - width: 7rem; + width: 7rem &.rule - width: 10rem; + width: 10rem &.value - width: 10rem; + width: 10rem &.desc - width: 15rem; + width: 15rem .th .helper - margin-left: .5rem; - color: #999; + margin-left: .5rem + color: #999 &:hover - color: $brand; + color: $brand .td &.operations - padding: .5rem .75rem; - height: auto; - line-height: 1; - justify-content: flex-end; + padding: .5rem .75rem + height: auto + line-height: 1 + justify-content: flex-end a - color: #999; - margin-right: .5rem; + color: #999 + margin-right: .5rem &:last-child - margin-right: 0; + margin-right: 0 &:hover - color: $brand; + color: $brand &.payload - padding: .5rem .75rem; - height: auto; - line-height: 1.5; + padding: .5rem .75rem + height: auto + line-height: 1.5 &.payload.name justify-content: space-between - @for $i from 0 through 42 + position: relative + @for $i from 1 through 42 &.depth-#{$i} - padding-left: $i * 1rem + 0.75rem; + padding-left: $i * 1rem + 0.75rem + &:after + display: block + content: '' + position: absolute + top: 0 + bottom: 0 + left: 0 + width: $i * 1rem + opacity: .5 + border-right: 1px dashed #707070 &.payload.value - max-height: 30vh; - overflow: auto; - hyphens: auto; - overflow-wrap: break-word; + max-height: 30vh + overflow: auto + hyphens: auto + overflow-wrap: break-word span.value-container - white-space: pre; - margin: auto 0; + white-space: pre + margin: auto 0 &.payload.required - padding: 0; + padding: 0 &.payload.desc - word-break: break-word; + word-break: break-word .SortableTreeTable.editable .flex-row .td &.payload - padding: 0; + padding: 0 &.payload.name @for $i from 0 through 10 &.depth-#{$i} - padding-left: $i * 1rem; + padding-left: $i * 1rem &.payload.value - max-height: unset; - overflow-wrap: break-word; + max-height: unset + overflow-wrap: break-word input.editable, select.editable, textarea.editable - margin: 0; - padding: .5rem .75rem; - width: 100%; - height: auto; - border: none; - border-radius: 0; - line-height: 1.5; - outline: none; - box-shadow: none; - background-color: transparent; + margin: 0 + padding: .5rem .75rem + width: 100% + height: auto + border: none + border-radius: 0 + line-height: 1.5 + outline: none + box-shadow: none + background-color: transparent .Importer .CodeMirror - height: 30rem; + height: 30rem textarea.result font-family: Menlo, Monaco, 'Courier New', monospace