多处调用提取成通用方法

This commit is contained in:
2betop 2019-12-24 12:10:07 +08:00
parent 1b14a40506
commit 44f966e791
5 changed files with 109 additions and 108 deletions

View File

@ -7,7 +7,7 @@ import {filter, evalExpression} from '../utils/tpl';
import cx from 'classnames';
import LazyComponent from '../components/LazyComponent';
import {resizeSensor} from '../utils/resize-sensor';
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
import {resolveVariableAndFilter, isPureVariable} from '../utils/tpl-builtin';
import {isApiOutdated, isEffectiveApi} from '../utils/api';
import {ScopedContext, IScopedContext} from '../Scoped';
@ -51,7 +51,7 @@ export class Chart extends React.Component<ChartProps> {
this.mounted = true;
if (source && /^\$(?:([a-z0-9_.]+)|{.+})$/.test(source)) {
if (source && isPureVariable(source)) {
const ret = resolveVariableAndFilter(source, data, '| raw');
ret && this.renderChart(ret);
} else if (api && initFetch !== false) {
@ -68,10 +68,7 @@ export class Chart extends React.Component<ChartProps> {
if (isApiOutdated(prevProps.api, props.api, prevProps.data, props.data)) {
this.reload();
} else if (
props.source &&
/^\$(?:([a-z0-9_.]+)|{.+})$/.test(props.source)
) {
} else if (props.source && isPureVariable(props.source)) {
const prevRet = prevProps.source
? resolveVariableAndFilter(prevProps.source, prevProps.data, '| raw')
: null;

View File

@ -5,6 +5,7 @@ import {filter} from '../../utils/tpl';
import cx from 'classnames';
import LazyComponent from '../../components/LazyComponent';
import debouce = require('lodash/debounce');
import {isPureVariable} from '../../utils/tpl-builtin';
function loadComponent(): Promise<React.ReactType> {
return new Promise(resolve =>
@ -101,7 +102,7 @@ export class DiffEditor extends React.Component<DiffEditorProps, any> {
this.originalEditor
.getModel()
.setValue(
/^\$(?:([a-z0-9_.]+)|{.+})$/.test(diffValue as string)
isPureVariable(diffValue as string)
? filter(normalizeValue(diffValue || ''), data, '| raw')
: normalizeValue(diffValue)
);
@ -143,7 +144,7 @@ export class DiffEditor extends React.Component<DiffEditorProps, any> {
this.editor.setModel({
original: this.monaco.editor.createModel(
/^\$(?:([a-z0-9_.]+)|{.+})$/.test(diffValue as string)
isPureVariable(diffValue as string)
? filter(normalizeValue(diffValue || ''), data, '| raw')
: normalizeValue(diffValue),
language

View File

@ -2,9 +2,9 @@
* @file SelectRadiosCheckboxes
* ListButtonGroup
*/
import { Api, Schema } from "../../types";
import { isEffectiveApi, isApiOutdated } from "../../utils/api";
import { isAlive } from "mobx-state-tree";
import {Api, Schema} from '../../types';
import {isEffectiveApi, isApiOutdated} from '../../utils/api';
import {isAlive} from 'mobx-state-tree';
import {
anyChanged,
autobind,
@ -13,29 +13,32 @@ import {
spliceTree,
findTreeIndex,
getTree
} from "../../utils/helper";
import { reaction } from "mobx";
} from '../../utils/helper';
import {reaction} from 'mobx';
import {
FormControlProps,
registerFormItem,
FormItemBasicConfig,
detectProps as itemDetectProps
} from "./Item";
import { IFormItemStore } from "../../store/formItem";
} from './Item';
import {IFormItemStore} from '../../store/formItem';
export type OptionsControlComponent = React.ComponentType<FormControlProps>;
import React from "react";
import { resolveVariableAndFilter } from "../../utils/tpl-builtin";
import React from 'react';
import {
resolveVariableAndFilter,
isPureVariable
} from '../../utils/tpl-builtin';
import {
Option,
OptionProps,
normalizeOptions,
optionValueCompare
} from "../../components/Select";
import { filter } from "../../utils/tpl";
import findIndex from "lodash/findIndex";
} from '../../components/Select';
import {filter} from '../../utils/tpl';
import findIndex from 'lodash/findIndex';
export { Option };
export {Option};
export interface OptionsBasicConfig extends FormItemBasicConfig {
autoLoadOptionsFromSource?: boolean;
@ -87,18 +90,18 @@ export interface OptionsProps extends FormControlProps, OptionProps {
}
export const detectProps = itemDetectProps.concat([
"options",
"size",
"buttons",
"columnsCount",
"multiple",
"hideRoot",
"checkAll",
"showIcon",
"showRadio",
"btnDisabled",
"joinValues",
"extractValue"
'options',
'size',
'buttons',
'columnsCount',
'multiple',
'hideRoot',
'checkAll',
'showIcon',
'showRadio',
'btnDisabled',
'joinValues',
'extractValue'
]);
export function registerOptionsControl(config: OptionsConfig) {
@ -107,15 +110,15 @@ export function registerOptionsControl(config: OptionsConfig) {
class FormOptionsItem extends React.Component<OptionsProps, any> {
static displayName = `OptionsControl(${config.type})`;
static defaultProps = {
delimiter: ",",
labelField: "label",
valueField: "value",
delimiter: ',',
labelField: 'label',
valueField: 'value',
joinValues: true,
extractValue: false,
multiple: false,
placeholder: "请选择",
resetValue: "",
deleteConfirmText: "确定要删除?",
placeholder: '请选择',
resetValue: '',
deleteConfirmText: '确定要删除?',
...Control.defaultProps
};
static propsList: any = (Control as any).propsList
@ -155,10 +158,10 @@ export function registerOptionsControl(config: OptionsConfig) {
let loadOptions: boolean = initFetch !== false;
if (/^\$(?:([a-z0-9_.]+)|{.+})$/.test(source as string) && formItem) {
if (isPureVariable(source as string) && formItem) {
formItem.setOptions(
normalizeOptions(
resolveVariableAndFilter(source as string, data, "| raw") || []
resolveVariableAndFilter(source as string, data, '| raw') || []
)
);
loadOptions = false;
@ -170,7 +173,7 @@ export function registerOptionsControl(config: OptionsConfig) {
.getSelectedOptions(value)
.map(
(selectedOption: Option) =>
selectedOption[valueField || "value"]
selectedOption[valueField || 'value']
)
: formItem.getSelectedOptions(value);
setPrinstineValue(
@ -182,7 +185,7 @@ export function registerOptionsControl(config: OptionsConfig) {
config.autoLoadOptionsFromSource !== false &&
(formInited
? this.reload()
: addHook && addHook(this.initOptions, "init"));
: addHook && addHook(this.initOptions, 'init'));
}
componentDidMount() {
@ -225,16 +228,16 @@ export function registerOptionsControl(config: OptionsConfig) {
formItem &&
(prevProps.source !== props.source || prevProps.data !== props.data)
) {
if (/^\$(?:([a-z0-9_.]+)|{.+})$/.test(props.source as string)) {
if (isPureVariable(props.source as string)) {
const prevOptions = resolveVariableAndFilter(
prevProps.source as string,
prevProps.data,
"| raw"
'| raw'
);
const options = resolveVariableAndFilter(
props.source as string,
props.data,
"| raw"
'| raw'
);
prevOptions !== options &&
formItem.setOptions(normalizeOptions(options || []));
@ -260,7 +263,7 @@ export function registerOptionsControl(config: OptionsConfig) {
}
componentWillUnmount() {
this.props.removeHook && this.props.removeHook(this.reload, "init");
this.props.removeHook && this.props.removeHook(this.reload, 'init');
this.reaction && this.reaction();
}
@ -280,7 +283,7 @@ export function registerOptionsControl(config: OptionsConfig) {
if (
extractValue === false &&
(typeof value === "string" || typeof value === "number")
(typeof value === 'string' || typeof value === 'number')
) {
const selectedOptions = formItem.getSelectedOptions(value);
formItem.changeValue(
@ -292,16 +295,16 @@ export function registerOptionsControl(config: OptionsConfig) {
!(
(Array.isArray(value) &&
value.every(
val => typeof val === "string" || typeof val === "number"
val => typeof val === 'string' || typeof val === 'number'
)) ||
typeof value === "string" ||
typeof value === "number"
typeof value === 'string' ||
typeof value === 'number'
)
) {
const selectedOptions = formItem
.getSelectedOptions(value)
.map(
(selectedOption: Option) => selectedOption[valueField || "value"]
(selectedOption: Option) => selectedOption[valueField || 'value']
);
formItem.changeValue(
multiple ? selectedOptions.concat() : selectedOptions[0]
@ -344,9 +347,9 @@ export function registerOptionsControl(config: OptionsConfig) {
let valueArray = formItem.getSelectedOptions(value).concat();
const idx = findIndex(
valueArray,
optionValueCompare(option.value, valueField || "value")
optionValueCompare(option.value, valueField || 'value')
);
let newValue: string | Array<Option> | Option = "";
let newValue: string | Array<Option> | Option = '';
if (multiple) {
if (~idx) {
@ -359,11 +362,11 @@ export function registerOptionsControl(config: OptionsConfig) {
if (joinValues) {
newValue = (newValue as Array<any>)
.map(item => item[valueField || "value"])
.map(item => item[valueField || 'value'])
.join(delimiter);
} else if (extractValue) {
newValue = (newValue as Array<any>).map(
item => item[valueField || "value"]
item => item[valueField || 'value']
);
}
} else {
@ -376,7 +379,7 @@ export function registerOptionsControl(config: OptionsConfig) {
newValue = valueArray[0] || resetValue;
if (joinValues && newValue) {
newValue = (newValue as any)[valueField || "value"];
newValue = (newValue as any)[valueField || 'value'];
}
}
@ -407,25 +410,25 @@ export function registerOptionsControl(config: OptionsConfig) {
? []
: formItem.filteredOptions.concat();
let newValue: string | Array<Option> | Option = "";
let newValue: string | Array<Option> | Option = '';
if (multiple) {
newValue = valueArray;
if (joinValues) {
newValue = (newValue as Array<any>)
.map(item => item[valueField || "value"])
.map(item => item[valueField || 'value'])
.join(delimiter);
} else if (extractValue) {
newValue = (newValue as Array<any>).map(
item => item[valueField || "value"]
item => item[valueField || 'value']
);
}
} else {
newValue = valueArray[0] || resetValue;
if (joinValues && newValue) {
newValue = (newValue as any)[valueField || "value"];
newValue = (newValue as any)[valueField || 'value'];
}
}
@ -435,7 +438,7 @@ export function registerOptionsControl(config: OptionsConfig) {
// 当有 action 触发,如果指定了 reload 目标组件,有可能会来到这里面来
@autobind
reload() {
const { source, formItem, data, onChange } = this.props;
const {source, formItem, data, onChange} = this.props;
if (!formItem || !isEffectiveApi(source, data)) {
return;
@ -447,7 +450,7 @@ export function registerOptionsControl(config: OptionsConfig) {
@autobind
async initOptions(data: any) {
await this.reload();
const { formItem, name } = this.props;
const {formItem, name} = this.props;
if (!formItem) {
return;
}
@ -508,10 +511,10 @@ export function registerOptionsControl(config: OptionsConfig) {
if (!skipForm && (!Array.isArray(addControls) || !addControls.length)) {
addControls = [
{
type: "text",
name: labelField || "label",
type: 'text',
name: labelField || 'label',
label: false,
placeholder: "请输入名称"
placeholder: '请输入名称'
}
];
}
@ -529,10 +532,10 @@ export function registerOptionsControl(config: OptionsConfig) {
? ctx
: await onOpenDialog(
{
type: "dialog",
title: createBtnLabel || `新增${optionLabel || "选项"}`,
type: 'dialog',
title: createBtnLabel || `新增${optionLabel || '选项'}`,
body: {
type: "form",
type: 'form',
api: addApi,
controls: addControls
}
@ -544,11 +547,11 @@ export function registerOptionsControl(config: OptionsConfig) {
if (skipForm && addApi) {
try {
const payload = await env.fetcher(addApi!, result, {
method: "post"
method: 'post'
});
if (!payload.ok) {
env.notify("error", payload.msg || "新增失败,请仔细检查");
env.notify('error', payload.msg || '新增失败,请仔细检查');
result = null;
} else {
result = payload.data || result;
@ -556,7 +559,7 @@ export function registerOptionsControl(config: OptionsConfig) {
} catch (e) {
result = null;
console.error(e);
env.notify("error", e.message);
env.notify('error', e.message);
}
}
@ -566,10 +569,10 @@ export function registerOptionsControl(config: OptionsConfig) {
}
// 没走服务端的。
if (!result.hasOwnProperty(valueField || "value")) {
if (!result.hasOwnProperty(valueField || 'value')) {
result = {
...result,
[valueField || "value"]: result[labelField || "label"]
[valueField || 'value']: result[labelField || 'label']
};
}
@ -581,11 +584,11 @@ export function registerOptionsControl(config: OptionsConfig) {
// 否则直接前端变更 options
let options = model.options.concat();
if (Array.isArray(idx)) {
options = spliceTree(options, idx, 0, { ...result });
options = spliceTree(options, idx, 0, {...result});
} else {
~idx
? options.splice(idx, 0, { ...result })
: options.push({ ...result });
? options.splice(idx, 0, {...result})
: options.push({...result});
}
model.setOptions(options);
}
@ -617,10 +620,10 @@ export function registerOptionsControl(config: OptionsConfig) {
if (!skipForm && (!Array.isArray(editControls) || !editControls.length)) {
editControls = [
{
type: "text",
name: labelField || "label",
type: 'text',
name: labelField || 'label',
label: false,
placeholder: "请输入名称"
placeholder: '请输入名称'
}
];
}
@ -629,10 +632,10 @@ export function registerOptionsControl(config: OptionsConfig) {
? value
: await onOpenDialog(
{
type: "dialog",
title: `编辑${optionLabel || "选项"}`,
type: 'dialog',
title: `编辑${optionLabel || '选项'}`,
body: {
type: "form",
type: 'form',
api: editApi,
controls: editControls
}
@ -647,12 +650,12 @@ export function registerOptionsControl(config: OptionsConfig) {
editApi!,
createObject(data, result),
{
method: "post"
method: 'post'
}
);
if (!payload.ok) {
env.notify("error", payload.msg || "保存失败,请仔细检查");
env.notify('error', payload.msg || '保存失败,请仔细检查');
result = null;
} else {
result = payload.data || result;
@ -660,7 +663,7 @@ export function registerOptionsControl(config: OptionsConfig) {
} catch (e) {
result = null;
console.error(e);
env.notify("error", e.message);
env.notify('error', e.message);
}
}
@ -715,22 +718,22 @@ export function registerOptionsControl(config: OptionsConfig) {
// 通过 deleteApi 删除。
try {
if (!deleteApi) {
throw new Error("请配置 deleteApi");
throw new Error('请配置 deleteApi');
}
const result = await env.fetcher(deleteApi!, ctx, {
method: "delete"
method: 'delete'
});
if (!result.ok) {
env.notify("error", result.msg || "删除失败,请重试");
env.notify('error', result.msg || '删除失败,请重试');
} else if (source) {
this.reload();
} else {
const options = model.options.concat();
const idx = findIndex(
options,
item => item[valueField || "value"] == value[valueField || "value"]
item => item[valueField || 'value'] == value[valueField || 'value']
);
if (~idx) {
@ -740,7 +743,7 @@ export function registerOptionsControl(config: OptionsConfig) {
}
} catch (e) {
console.error(e);
env.notify("error", e.message);
env.notify('error', e.message);
}
}
@ -802,7 +805,7 @@ export function OptionsControl(config: OptionsBasicConfig) {
export function highlight(
text: string,
input?: string,
hlClassName: string = "is-matched"
hlClassName: string = 'is-matched'
) {
if (!input) {
return text;
@ -810,8 +813,8 @@ export function highlight(
text = String(text);
const reg = new RegExp(
input.replace(/([\$\^\*\+\-\?\.\(\)\|\[\]\\])/, "\\$1"),
"i"
input.replace(/([\$\^\*\+\-\?\.\(\)\|\[\]\\])/, '\\$1'),
'i'
);
if (!reg.test(text)) {
return text;

View File

@ -6,7 +6,7 @@ import cx from 'classnames';
import getExprProperties from '../utils/filter-schema';
import {filter, evalExpression} from '../utils/tpl';
import {createObject, mapTree, someTree} from '../utils/helper';
import {resolveVariable} from '../utils/tpl-builtin';
import {resolveVariable, isPureVariable} from '../utils/tpl-builtin';
import {isApiOutdated, isEffectiveApi} from '../utils/api';
import {ScopedContext, IScopedContext} from '../Scoped';
import {Api} from '../types';
@ -55,7 +55,7 @@ export default class Navigation extends React.Component<
props,
(props.source &&
typeof props.source === 'string' &&
/^\$(?:([a-z0-9_.]+)|{.+})$/.test(props.source) &&
isPureVariable(props.source) &&
resolveVariable(props.source, props.data)) ||
props.links
)
@ -65,7 +65,7 @@ export default class Navigation extends React.Component<
componentDidMount() {
const {source} = this.props;
if (source && !/^\$(?:([a-z0-9_.]+)|{.+})$/.test(source)) {
if (source && !isPureVariable(source as string)) {
this.reload();
}
}
@ -73,10 +73,7 @@ export default class Navigation extends React.Component<
componentWillReceiveProps(nextProps: NavigationProps) {
const props = this.props;
if (
nextProps.source &&
/^\$(?:([a-z0-9_.]+)|{.+})$/.test(nextProps.source as string)
) {
if (nextProps.source && isPureVariable(nextProps.source as string)) {
if (nextProps.source !== props.source) {
this.setState({
links: this.syncLinks(nextProps)
@ -108,10 +105,7 @@ export default class Navigation extends React.Component<
componentDidUpdate(prevProps: NavigationProps) {
const props = this.props;
if (
props.source &&
!/^\$(?:([a-z0-9_.]+)|{.+})$/.test(props.source as string)
) {
if (props.source && !isPureVariable(props.source as string)) {
isApiOutdated(
prevProps.source,
props.source,

View File

@ -351,6 +351,9 @@ export const resolveVariable = (path: string, data: any = {}): any => {
}, data);
};
export const isPureVariable = (path: string) =>
/^\$(?:([a-z0-9_.]+)|{[^}{]+})$/.test(path);
export const resolveVariableAndFilter = (
path: string,
data: object = {},
@ -443,9 +446,12 @@ export const tokenize = (
);
};
function resolveMapping(value: any, data: PlainObject, defaultFilter = '| raw') {
return typeof value === 'string' &&
/^\$(?:([a-z0-9_.]+)|{[^}{]+})$/.test(value)
function resolveMapping(
value: any,
data: PlainObject,
defaultFilter = '| raw'
) {
return typeof value === 'string' && isPureVariable(value)
? resolveVariableAndFilter(value, data, defaultFilter)
: typeof value === 'string' && ~value.indexOf('$')
? tokenize(value, data, defaultFilter)