diff --git a/mock/sample.js b/mock/sample.js index 1367a91d..c3469510 100644 --- a/mock/sample.js +++ b/mock/sample.js @@ -6,7 +6,7 @@ module.exports = function(req, res) { if (pathname === 'sample' && (req.method === 'POST' || req.method === 'PUT')) { return store(req, res); } else if (/sample\/(\d+(?:,\d+)*)?$/.test(pathname)) { - if ((req.method === 'POST' || req.method === 'PUT')) { + if (req.method === 'POST' || req.method === 'PUT') { return update(req, res, RegExp.$1); } else if (req.method === 'DELETE') { return del(req, res, RegExp.$1); @@ -18,8 +18,7 @@ module.exports = function(req, res) { } return index(req, res); -} - +}; function index(req, res) { const perPage = parseInt(req.query.perPage, 10); @@ -27,23 +26,23 @@ function index(req, res) { let items = DB.concat(); if (req.query.keywords) { - const keywords = req.query.keywords; - items = items.filter(function(item) { - return ~JSON.stringify(item).indexOf(keywords); - }); + const keywords = req.query.keywords; + items = items.filter(function(item) { + return ~JSON.stringify(item).indexOf(keywords); + }); } if (req.query.engine) { const keywords = req.query.engine; items = items.filter(function(item) { - return ~JSON.stringify(item.engine).indexOf(keywords); + return ~JSON.stringify(item.engine).indexOf(keywords); }); - } + } if (req.query.orderBy) { const field = req.query.orderBy; const direction = req.query.orderDir === 'desc' ? -1 : 1; - items = items.sort(function (a, b) { + items = items.sort(function(a, b) { a = String(a[field]); b = String(b[field]); @@ -57,20 +56,27 @@ function index(req, res) { }); } - return res.json({ - status: 0, - msg: 'ok', - data: { - count: items.length, - rows: perPage ? items.splice((page -1) * perPage, perPage) : items.concat() - } - }); + let response = () => + res.json({ + status: 0, + msg: 'ok', + data: { + count: items.length, + rows: perPage ? items.splice((page - 1) * perPage, perPage) : items.concat() + } + }); + + if (req.query.waitSeconds) { + return setTimeout(response, parseInt(req.query.waitSeconds, 10) * 1000); + } + + return response(); } function store(req, res) { const data = Object.assign({}, req.body); - data.id = DB.length ? (DB[DB.length - 1].id + 1) : 1; + data.id = DB.length ? DB[DB.length - 1].id + 1 : 1; DB.push(data); @@ -83,20 +89,22 @@ function store(req, res) { function update(req, res, id) { const ids = id.split(','); - if (!ids.every(function(id) { - const idx = DB.findIndex(function (item) { - return item.id == id; - }); + if ( + !ids.every(function(id) { + const idx = DB.findIndex(function(item) { + return item.id == id; + }); - if (!~idx) { - return false; - } + if (!~idx) { + return false; + } - const item = Object.assign({}, DB[idx], req.body); - item.id = id; - DB.splice(idx, 1, item); - return true; - })) { + const item = Object.assign({}, DB[idx], req.body); + item.id = id; + DB.splice(idx, 1, item); + return true; + }) + ) { return res.json({ status: 404, msg: '保存失败,数据可能已被删除!' @@ -113,18 +121,20 @@ function del(req, res, id) { const ids = id.split(','); console.log(ids); - if (!ids.every(function(id) { - const idx = DB.findIndex(function (item) { - return item.id == id; - }); + if ( + !ids.every(function(id) { + const idx = DB.findIndex(function(item) { + return item.id == id; + }); - if (!~idx) { - return false; - } + if (!~idx) { + return false; + } - DB.splice(idx, 1); - return true; - })) { + DB.splice(idx, 1); + return true; + }) + ) { return res.json({ status: 404, msg: '保存失败,数据可能已被删除!' @@ -140,20 +150,23 @@ function del(req, res, id) { function bulkUpdate(req, res) { const rowDiff = req.body.rowsDiff; const ids = req.body.ids ? req.body.ids.split(',') : []; - if (!ids.length || !ids.every(function(id, index) { - const idx = DB.findIndex(function (item) { - return item.id == id; - }); + if ( + !ids.length || + !ids.every(function(id, index) { + const idx = DB.findIndex(function(item) { + return item.id == id; + }); - if (!~idx) { - return false; - } + if (!~idx) { + return false; + } - const item = Object.assign({}, DB[idx], rowDiff[index]); - item.id = id; - DB.splice(idx, 1, item); - return true; - })) { + const item = Object.assign({}, DB[idx], rowDiff[index]); + item.id = id; + DB.splice(idx, 1, item); + return true; + }) + ) { return res.json({ status: 404, msg: '保存失败,数据可能已被删除!' @@ -172,20 +185,23 @@ function bulkUpdate2(req, res) { delete data.ids; const ids = req.body.ids ? req.body.ids.split(',') : []; - if (!ids.length || !ids.every(function(id, index) { - const idx = DB.findIndex(function (item) { - return item.id == id; - }); + if ( + !ids.length || + !ids.every(function(id, index) { + const idx = DB.findIndex(function(item) { + return item.id == id; + }); - if (!~idx) { - return false; - } + if (!~idx) { + return false; + } - const item = Object.assign({}, DB[idx], data); - item.id = id; - DB.splice(idx, 1, item); - return true; - })) { + const item = Object.assign({}, DB[idx], data); + item.id = id; + DB.splice(idx, 1, item); + return true; + }) + ) { return res.json({ status: 404, msg: '保存失败,数据可能已被删除!' diff --git a/scss/components/_list.scss b/scss/components/_list.scss index e1a35344..22421c7d 100644 --- a/scss/components/_list.scss +++ b/scss/components/_list.scss @@ -15,7 +15,7 @@ &-actions { display: inline-block; - > * { + >* { margin-right: $Crud-toolbar-gap; } } @@ -23,14 +23,14 @@ &-header { padding: $List-toolbar-paddingY $List-toolbar-paddingX; - > * + .#{$ns}Button, - > * + .#{$ns}ButtonGroup, - > * + .#{$ns}ButtonToolbar { + >*+.#{$ns}Button, + >*+.#{$ns}ButtonGroup, + >*+.#{$ns}ButtonToolbar { margin-left: $Crud-toolbar-gap; } } - &-header + &-toolbar { + &-header+&-toolbar { padding-top: 0; } @@ -85,7 +85,7 @@ .#{$ns}ListItem { @include clearfix(); - & + & { + &+& { border-top: $ListItem-borderWidth solid $ListItem-borderColor; } @@ -134,6 +134,7 @@ position: relative; flex-basis: 0; flex-grow: 1; + max-width: 100%; } &-fieldLabel { @@ -146,7 +147,7 @@ border-color: $ListItem-onChecked-borderColor; color: $ListItem-onChecked-color; - + .#{$ns}ListItem { + +.#{$ns}ListItem { border-color: $ListItem-onChecked-borderColor; } @@ -161,7 +162,7 @@ border-color: $ListItem-onModified-borderColor; color: $ListItem-onModified-color; - + .#{$ns}ListItem { + +.#{$ns}ListItem { border-color: $ListItem-onModified-borderColor; } @@ -173,4 +174,4 @@ &.is-dragging { opacity: $ListItem-onDragging-opacity; } -} +} \ No newline at end of file diff --git a/scss/components/_popover.scss b/scss/components/_popover.scss index a4dc5eb9..e6049943 100644 --- a/scss/components/_popover.scss +++ b/scss/components/_popover.scss @@ -24,6 +24,11 @@ border: $borderWidth solid $borderColor; border-radius: $borderRadius; + &>* { + position: relative; + z-index: 2; + } + &-overlay { position: fixed !important; top: 0; @@ -32,10 +37,5 @@ z-index: 1; bottom: 0; background: transparent; - - & + * { - position: relative; - z-index: 2; - } } -} +} \ No newline at end of file diff --git a/scss/components/form/_date.scss b/scss/components/form/_date.scss index a671ce6d..c329500e 100644 --- a/scss/components/form/_date.scss +++ b/scss/components/form/_date.scss @@ -33,7 +33,7 @@ &.is-disabled { background: $gray200; - > &-input { + >&-input { color: $text--muted-color; } } @@ -78,7 +78,7 @@ } } -.#{$ns}DateControl:not(.is-inline) > .#{$ns}DatePicker { +.#{$ns}DateControl:not(.is-inline)>.#{$ns}DatePicker { display: flex; } @@ -107,6 +107,7 @@ .rdtPicker { margin-top: 0; padding: $gap-md; + background: transparent; border: none; .dow { @@ -233,8 +234,7 @@ font-size: $fontSizeSm; } - @include button-variant( - $Calendar-btn-bg, + @include button-variant($Calendar-btn-bg, $Calendar-btn-border, $Calendar-btn-color, $Calendar-btn-onHover-bg, @@ -242,18 +242,16 @@ $Calendar-btn-onHover-color, $Calendar-btn-onActive-bg, $Calendar-btn-onActive-border, - $Calendar-btn-onActive-color - ); + $Calendar-btn-onActive-color); border-radius: $Calendar-btn-borderRadius; - & + .rdtBtn { + &+.rdtBtn { margin-left: $gap-xs; } &Cancel { - @include button-variant( - $Calendar-btnCancel-bg, + @include button-variant($Calendar-btnCancel-bg, $Calendar-btnCancel-border, $Calendar-btnCancel-color, $Calendar-btnCancel-onHover-bg, @@ -261,8 +259,7 @@ $Calendar-btnCancel-onHover-color, $Calendar-btnCancel-onActive-bg, $Calendar-btnCancel-onActive-border, - $Calendar-btnCancel-onActive-color - ); + $Calendar-btnCancel-onActive-color); } } @@ -308,4 +305,4 @@ display: flex; } } -} +} \ No newline at end of file diff --git a/scss/components/form/_image.scss b/scss/components/form/_image.scss index 97fa0861..5ea82828 100644 --- a/scss/components/form/_image.scss +++ b/scss/components/form/_image.scss @@ -40,16 +40,23 @@ } &-pasteTip { - display: block; + pointer-events: none; + left: 0; + top: 50%; + transform: translateY(-50%); position: absolute; - color: $text--muted-color; - font-size: 12px; - transform: scale(0.8); - transform-origin: 100% 100%; - right: 0; - bottom: 0; - padding: 2px 5px; - background: rgba(255, 255, 255, 0.8); + font-size: $Tooltip--attr-fontSize; + line-height: $Tooltip--attr-lineHeigt; + text-align: left; + white-space: nowrap; + background: $Tooltip--attr-bg; + border: $Tooltip--attr-borderWidth solid $Tooltip--attr-borderColor; + border-radius: $Tooltip--attr-borderRadius; + box-shadow: $Tooltip--attr-boxShadow; + left: 100%; + color: $Tooltip--attr-color; + padding: $Tooltip--attr-paddingY $Tooltip--attr-paddingX; + margin: 30px 0 0 $Tooltip--attr-gap; } &-dropzone:focus &-addBtn { diff --git a/scss/components/form/_input-group.scss b/scss/components/form/_input-group.scss index 151785fe..cf76e47c 100644 --- a/scss/components/form/_input-group.scss +++ b/scss/components/form/_input-group.scss @@ -17,10 +17,8 @@ &-addOn { background: $InputGroup-addOn-bg; - border: $InputGroup-addOn-borderWidth solid - $InputGroup-addOn-borderColor; - line-height: $InputGroup-height - $InputGroup-paddingY * 2 - - $InputGroup-addOn-borderWidth * 2; + border: $InputGroup-addOn-borderWidth solid $InputGroup-addOn-borderColor; + line-height: $InputGroup-height - $InputGroup-paddingY * 2 - $InputGroup-addOn-borderWidth * 2; height: $InputGroup-height; box-sizing: border-box; padding: $InputGroup-paddingY $InputGroup-paddingX; @@ -47,8 +45,7 @@ &-btn { .#{$ns}Button { border-radius: 0; - border: $InputGroup-button-borderWidth solid - $InputGroup-button-borderColor; + border: $InputGroup-button-borderWidth solid $InputGroup-button-borderColor; } &:not(:last-child) .#{$ns}Button { @@ -73,6 +70,7 @@ .#{$ns}TextControl-input { flex-basis: 0; flex-grow: 1; + display: inline-flex; &:not(:first-child) { border-top-left-radius: 0; @@ -90,9 +88,7 @@ @if $InputGroup-select-borderWidth { .#{$ns}Select { background-color: $InputGroup-select-bg; - border: $InputGroup-select-borderWidth - solid - $InputGroup-select-borderColor; + border: $InputGroup-select-borderWidth solid $InputGroup-select-borderColor; @if $InputGroup-select-color !=$Form-select-color { color: $InputGroup-select-color; @@ -137,6 +133,7 @@ } &.is-focused { + .#{$ns}InputGroup-addOn, .#{$ns}TextControl-input, .#{$ns}Select, @@ -156,9 +153,7 @@ } } - @if $InputGroup-select-onFocused-arrowColor - !=$Form-select-caret-iconColor - { + @if $InputGroup-select-onFocused-arrowColor !=$Form-select-caret-iconColor { .#{$ns}Select-arrow { color: $InputGroup-select-onFocused-arrowColor; } @@ -172,4 +167,4 @@ .#{$ns}InputGroup:not(.is-inline) { display: flex; -} +} \ No newline at end of file diff --git a/src/factory.tsx b/src/factory.tsx index a24faa94..129b9cfb 100644 --- a/src/factory.tsx +++ b/src/factory.tsx @@ -505,10 +505,10 @@ class SchemaRenderer extends React.Component { return React.isValidElement(schema.children) ? schema.children : (schema.children as Function)({ - ...rest, - $path: $path, - render: this.renderChild - }); + ...rest, + $path: $path, + render: this.renderChild + }); } else if (typeof schema.component === 'function') { return React.createElement(schema.component as any, { ...rest, @@ -600,7 +600,7 @@ export function HocStoreFactory(renderer: {storeType: string; extendsData?: bool path: this.props.$path, storeType: renderer.storeType, parentId: this.props.store ? this.props.store.id : '' - })); + } as any)); if (renderer.extendsData === false) { store.initData( @@ -656,7 +656,8 @@ export function HocStoreFactory(renderer: {storeType: string; extendsData?: bool store.data, nextProps.store.data, props.scope, - nextProps.dataUpdatedAt !== props.dataUpdatedAt + nextProps.dataUpdatedAt !== props.dataUpdatedAt, + store ) ); @@ -680,7 +681,7 @@ export function HocStoreFactory(renderer: {storeType: string; extendsData?: bool ...store.data }) ); - } else if (nextProps.scope !== props.scope) { + } else if (isObjectShallowModified(props.scope, nextProps.scope)) { store.initData( createObject(nextProps.scope, { ...nextProps.data, diff --git a/src/renderers/Form/Image.tsx b/src/renderers/Form/Image.tsx index 273126c2..d94fdbf5 100644 --- a/src/renderers/Form/Image.tsx +++ b/src/renderers/Form/Image.tsx @@ -938,13 +938,13 @@ export default class ImageControl extends React.Component - - ) : null} - {isFocused ? ( - - 当前状态支持从剪切板中粘贴图片文件。 - + {isFocused ? ( + + 当前状态支持从剪切板中粘贴图片文件。 + + ) : null} + ) : null} {!autoUpload && !hideUploadButton && files.length ? ( diff --git a/src/utils/helper.ts b/src/utils/helper.ts index b0801a81..291f6cff 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -7,6 +7,8 @@ import {Schema, PlainObject, FunctionPropertyNames} from '../types'; import {evalExpression} from './tpl'; import {boundMethod} from 'autobind-decorator'; import qs from 'qs'; +import {IIRendererStore} from '../store'; +import {IFormStore} from '../store/form'; // 方便取值的时候能够把上层的取到,但是获取的时候不会全部把所有的数据获取到。 export function createObject( @@ -53,13 +55,27 @@ export function extendObject(to: any, from?: any) { return obj; } -export function syncDataFromSuper(data: any, superObject: any, prevSuperObject: any, force?: boolean) { +export function syncDataFromSuper( + data: any, + superObject: any, + prevSuperObject: any, + force?: boolean, + store?: IIRendererStore +) { const obj = { ...data }; + let keys = Object.keys(obj); + + // 如果是 form store,则从父级同步 formItem 种东西。 + if (store && store.storeType === 'FormStore') { + keys = uniq((store as IFormStore).items.map(item => item.name)); + force = false; + } + if (superObject || prevSuperObject) { - Object.keys(obj).forEach(key => { + keys.forEach(key => { if ( ((superObject && typeof superObject[key] !== 'undefined') || (prevSuperObject && typeof prevSuperObject[key] !== 'undefined')) && @@ -432,7 +448,7 @@ export function difference any) => void, interval: number = 5000 ) { - let timer: number; + let timer: NodeJS.Timeout; let stoped: boolean = false; return new Promise((resolve, reject) => { diff --git a/src/utils/tpl-builtin.ts b/src/utils/tpl-builtin.ts index c888cba2..0eaeb8ee 100644 --- a/src/utils/tpl-builtin.ts +++ b/src/utils/tpl-builtin.ts @@ -2,7 +2,7 @@ import {reigsterTplEnginer, filter} from './tpl'; import moment from 'moment'; import {PlainObject} from '../types'; import isPlainObject = require('lodash/isPlainObject'); -import {createObject, isObject, setVariable} from './helper'; +import {createObject, isObject, setVariable, qsstringify} from './helper'; const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; @@ -387,9 +387,14 @@ export const tokenize = (str: string, data: object, defaultFilter: string = '| h return str; } - return str.replace(/(\\)?\$(?:([a-z0-9_\.]+|&)|{([^}{]+?)})/gi, (_, escape) => - escape ? _.substring(1) : resolveVariableAndFilter(_, data, defaultFilter) - ); + return str + .replace(/(\\)?\$(?:([a-z0-9_\.]+|&)|{([^}{]+?)})/gi, (_, escape) => + escape ? _.substring(1) : resolveVariableAndFilter(_, data, defaultFilter) + ) + .replace(/\$\$/g, (_, index: number, source: string) => { + const prefix = source[index - 1]; + return prefix === '=' ? encodeURIComponent(JSON.stringify(data)) : qsstringify(data); + }); }; function resolveMapping(value: any, data: PlainObject) {