Merge pull request #602 from 2betop/master

Service store 数据不同步问题修复
This commit is contained in:
RickCole 2020-05-19 10:43:22 +08:00 committed by GitHub
commit de31bbf373
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 19 deletions

View File

@ -2,20 +2,15 @@
标签输入框。
- `type` 请设置成 `tag`
- `clearable` 在有值的时候是否显示一个删除图标在右侧。
- `resetValue` 默认为 `""`, 删除后设置此配置项给定的值。
- `optionsTip` 选项提示,默认为 `最近您使用的标签`
- `options` 选项配置,类型为数组,成员格式如下,或者直接为字符串,配置后用户输入内容时会作为选项提示辅助输入
- `label` 文字
- `value`
- `source` 通过 `options` 只能配置静态数据,如果设置了 `source` 则会从接口拉取,实现动态效果。
- `joinValues` 默认为 `true`
- 单选模式:当用户选中某个选项时,选项中的 value 将被作为该表单项的值提交,否则,整个选项对象都会作为该表单项的值提交。
- 多选模式:选中的多个选项的 `value` 会通过 `delimiter` 连接起来,否则直接将以数组的形式提交值。
- `delimiter` 默认为 `,`
- `extractValue` 默认为 `false`, `joinValues`设置为`false`时生效, 开启后将选中的选项 value 的值封装为数组,作为当前表单项的值。
- **还有更多通用配置请参考** [FormItem](./FormItem.md)
- `type` 请设置成 `tag`
- `clearable` 在有值的时候是否显示一个删除图标在右侧。
- `options` 选项配置,类型为数组,成员格式如下,或者直接为字符串,配置后用户输入内容时会作为选项提示辅助输入,可以不指定,当不指定时完全由用户手动输入。
- `label` 文字
- `value`
- `children` 如果需要简单分组,可以考虑把选项包在某个选项的 children 里面。
- `delimiter` 默认为 `,`,当标签在输入中,输入了这个字符时,也能自动创建一个新标签。
- `extractValue` 默认为 `false`, `joinValues`设置为`false`时生效, 开启后将选中的选项 value 的值封装为数组,作为当前表单项的值。
- **还有更多通用配置请参考** [FormItem](./FormItem.md)
```schema:height="200" scope="form-item"
{
@ -25,7 +20,7 @@
}
```
带提示功能
待选项的标签输入。
```schema:height="240" scope="form-item"
{

View File

@ -65,6 +65,7 @@ export default {
label: '标签',
placeholder: '',
clearable: true,
inline: true,
options: [
{
label: '诸葛亮',

View File

@ -1,4 +1,5 @@
.#{$ns}ListMenu {
background: $ListMenu-item-bg;
min-width: px2rem(200px);
border: $ListMenu-borderWidth solid $ListMenu-bordrColor;
border-radius: $ListMenu-borderRadius;
@ -19,7 +20,6 @@
&-item {
display: flex;
min-height: $ListMenu-item-height;
background: $ListMenu-item-bg;
color: $ListMenu-item-color;
line-height: $Form-input-lineHeight;
font-size: $Form-input-fontSize;

View File

@ -1,8 +1,20 @@
.#{$ns}TagControl {
position: relative;
&-input.is-focused {
border-radius: 0;
}
&.is-inline {
display: inline-block;
}
> .#{$ns}TagControl-popover {
box-shadow: none;
padding: 0;
border: none;
width: 100%;
margin-top: $Form-select-popoverGap - $Form-select-outer-borderWidth;
&.#{$ns}PopOver--leftBottomLeftTop {
top: 100% !important;
@ -14,3 +26,15 @@
}
}
}
.#{$ns}TagControl-popover {
&.#{$ns}PopOver--leftBottomLeftTop > .#{$ns}ListMenu {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
&.#{$ns}PopOver--leftTopLeftBottom > .#{$ns}ListMenu {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}

View File

@ -311,6 +311,7 @@ export default class TagControl extends React.PureComponent<
onBlur: this.handleBlur,
disabled
})}
className={cx('TagControl-input')}
result={selectedOptions}
onResultChange={this.handleChange}
itemRender={this.renderItem}

View File

@ -2,14 +2,14 @@ import React from 'react';
import PropTypes from 'prop-types';
import {Renderer, RendererProps} from '../factory';
import {ServiceStore, IServiceStore} from '../store/service';
import {Api, SchemaNode, ApiObject, RendererData} from '../types';
import {Api, SchemaNode, ApiObject, RendererData, Action} from '../types';
import {filter, evalExpression} from '../utils/tpl';
import cx from 'classnames';
import Scoped, {ScopedContext, IScopedContext} from '../Scoped';
import {observer} from 'mobx-react';
import {isApiOutdated, isEffectiveApi} from '../utils/api';
import {Spinner} from '../components';
import {autobind} from '../utils/helper';
import {autobind, isVisible} from '../utils/helper';
export interface ServiceProps extends RendererProps {
api?: Api;
@ -43,6 +43,7 @@ export default class Service extends React.Component<ServiceProps> {
super(props);
this.handleQuery = this.handleQuery.bind(this);
this.handleAction = this.handleAction.bind(this);
this.reload = this.reload.bind(this);
this.silentReload = this.silentReload.bind(this);
this.initInterval = this.initInterval.bind(this);
@ -182,6 +183,60 @@ export default class Service extends React.Component<ServiceProps> {
this.receive(query);
}
reloadTarget(target: string, data?: any) {
// 会被覆写
}
openFeedback(dialog: any, ctx: any) {
return new Promise(resolve => {
const {store} = this.props;
const parentStore = store.parentStore;
// 暂时自己不支持弹出 dialog
if (parentStore && parentStore.openDialog) {
store.setCurrentAction({
type: 'button',
actionType: 'dialog',
dialog: dialog
});
store.openDialog(ctx, undefined, confirmed => {
resolve(confirmed);
});
}
});
}
handleAction(
e: React.UIEvent<any> | void,
action: Action,
data: object,
throwErrors: boolean = false,
delegate?: IScopedContext
) {
const {onAction, store, env, api} = this.props;
if (api && action.actionType === 'ajax') {
store.setCurrentAction(action);
store
.saveRemote(action.api as string, data, {
successMessage: action.messages && action.messages.success,
errorMessage: action.messages && action.messages.failed
})
.then(async () => {
if (action.feedback && isVisible(action.feedback, store.data)) {
await this.openFeedback(action.feedback, store.data);
}
action.redirect &&
env.jumpTo(filter(action.redirect, store.data), action);
action.reload && this.reloadTarget(action.reload, store.data);
})
.catch(() => {});
} else {
onAction(e, action, data, throwErrors, delegate || this.context);
}
}
renderBody() {
const {render, store, body: schema, classnames: cx} = this.props;
@ -190,7 +245,8 @@ export default class Service extends React.Component<ServiceProps> {
{
render('body', store.schema || schema, {
key: store.schemaKey || 'body',
onQuery: this.handleQuery
onQuery: this.handleQuery,
onAction: this.handleAction
}) as JSX.Element
}
</div>
@ -248,4 +304,9 @@ export class ServiceRenderer extends Service {
const scoped = this.context as IScopedContext;
scoped.unRegisterComponent(this);
}
reloadTarget(target: string, data?: any) {
const scoped = this.context as IScopedContext;
scoped.reload(target, data);
}
}