fastlion-amis
Version:
一种MIS页面生成工具
1,230 lines (1,095 loc) • 33.7 kB
text/typescript
import {
types,
getParent,
SnapshotIn,
flow,
getRoot,
hasParent,
isAlive,
getEnv,
Instance
} from 'mobx-state-tree';
import { FormStore, IFormStore } from './form';
import { str2rules, validate as doValidate } from '../utils/validations';
import { Api, Payload, fetchOptions, ApiObject } from '../types';
import { ComboStore, IComboStore, IUniqueGroup } from './combo';
import { evalExpression, filter } from '../utils/tpl';
import { isEffectiveApi } from '../utils/api';
import findIndex from 'lodash/findIndex';
import {
isArrayChildrenModified,
isObject,
createObject,
isObjectShallowModified,
findTree,
findTreeIndex,
spliceTree,
isEmpty,
getTreeAncestors,
filterTree
} from '../utils/helper';
import { flattenTree } from '../utils/helper';
import { IRendererStore } from '.';
import { normalizeOptions, optionValueCompare } from '../components/Select';
import find from 'lodash/find';
import { SimpleMap } from '../utils/SimpleMap';
import memoize from 'lodash/memoize';
import { TranslateFn } from '../locale';
import { StoreNode } from './node';
import { dataMapping } from '../utils/tpl-builtin';
import { getStoreById } from './manager';
import isPlainObject from 'lodash/isPlainObject';
import { IColumn } from './table';
import { isNil } from 'lodash';
import { EventEnum, EventSub } from '../utils/sub';
interface IOption {
value?: string | number | null;
label?: string | null;
children?: IOption[] | null;
disabled?: boolean | null;
visible?: boolean | null;
hidden?: boolean | null;
}
const ErrorDetail = types.model('ErrorDetail', {
msg: '',
tag: '',
rule: ''
});
//select缓存
const SelectCache: any = {}
//并发请求时,一个一个来
const SelectWaitingCache: any = {}
//注册监听,在页面更新时清空缓存
EventSub.on(EventEnum.ClearSelectCache, (instance) => {
if (!instance) return;
delete SelectCache[instance]
})
export const FormItemStore = StoreNode.named('FormItemStore')
.props({
isFocused: false,
type: '',
unique: false,
loading: false,
required: false,
tmpValue: types.frozen(),
emitedValue: types.frozen(),
rules: types.optional(types.frozen(), {}),
messages: types.optional(types.frozen(), {}),
errorData: types.optional(types.array(ErrorDetail), []),
name: types.string,
itemId: '', // 因为 name 可能会重名,所以加个 id 进来,如果有需要用来定位具体某一个
unsetValueOnInvisible: false,
itemsRef: types.optional(types.array(types.string), []),
validated: false,
validating: false,
multiple: false,
delimiter: ',',
valueField: 'value',
labelField: 'label',
joinValues: true,
extractValue: false,
options: types.optional(types.frozen<Array<any>>(), []),
expressionsInOptions: false,
selectFirst: false,
autoFill: types.frozen(),
clearValueOnHidden: false,
validateApi: types.optional(types.frozen(), ''),
selectedOptions: types.optional(types.frozen(), []),
filteredOptions: types.optional(types.frozen(), []),
dialogSchema: types.frozen(),
dialogOpen: false,
dialogData: types.frozen(),
resetValue: types.optional(types.frozen(), ''),
validateOnChange: false,
labelName: ''
})
.views(self => {
function getForm(): any {
const form = self.parentStore;
return form?.storeType === FormStore.name ? form : undefined;
}
function getValue(): any {
return getForm()?.getValueByName(self.name);
}
function getLastOptionValue(): any {
if (self.selectedOptions.length) {
return self.selectedOptions[self.selectedOptions.length - 1].value;
}
return '';
}
function getErrors(): Array<string> {
return self.errorData.map(item => item.msg);
}
return {
get subFormItems(): any {
return self.itemsRef.map(item => getStoreById(item));
},
get form(): any {
return getForm();
},
get value(): any {
return getValue();
},
get prinstine(): any {
return (getForm() as IFormStore)?.getPristineValueByName(self.name);
},
get errors() {
return getErrors();
},
get valid() {
const errors = getErrors();
return !!(!errors || !errors.length);
},
get errClassNames() {
return self.errorData
.map(item => item.rule)
.filter((item, index, arr) => item && arr.indexOf(item) === index)
.map(item => `has-error--${item}`)
.join(' ');
},
get lastSelectValue(): string {
return getLastOptionValue();
},
getSelectedOptions: (
value: any = self.tmpValue,
nodeValueArray?: any[] | undefined
) => {
if (typeof value === 'undefined') {
return [];
}
const valueArray = nodeValueArray
? nodeValueArray
: Array.isArray(value)
? value
: typeof value === 'string'
? value.split(self.delimiter || ',')
: [value];
const selected = valueArray.map(item =>
item && item.hasOwnProperty(self.valueField || 'value')
? item[self.valueField || 'value']
: item
);
const selectedOptions: Array<any> = [];
selected.forEach((item, index) => {
const matched = findTree(
self.filteredOptions,
optionValueCompare(item, self.valueField || 'value')
);
if (matched) {
selectedOptions.push(matched);
} else {
let unMatched = (valueArray && valueArray[index]) || item;
if (
unMatched &&
(typeof unMatched === 'string' || typeof unMatched === 'number')
) {
unMatched = {
[self.valueField || 'value']: item,
[self.labelField || 'label']: item,
__unmatched: true
};
} else if (unMatched && self.extractValue) {
unMatched = {
[self.valueField || 'value']: item,
[self.labelField || 'label']: 'UnKnown',
__unmatched: true
};
}
unMatched && selectedOptions.push(unMatched);
}
});
return selectedOptions;
}
};
})
.actions(self => {
let loadAutoUpdateCancel: Function | null = null;
const form = self.form as IFormStore;
const dialogCallbacks = new SimpleMap<(result?: any) => void>();
function config({
required,
unique,
value,
rules,
messages,
delimiter,
multiple,
valueField,
labelField,
joinValues,
extractValue,
type,
id,
selectFirst,
autoFill,
clearValueOnHidden,
validateApi,
maxLength,
minLength,
validateOnChange,
labelName
}: {
required?: boolean;
unique?: boolean;
value?: any;
rules?: string | { [propName: string]: any };
messages?: { [propName: string]: string };
multiple?: boolean;
delimiter?: string;
valueField?: string;
labelField?: string;
joinValues?: boolean;
extractValue?: boolean;
type?: string;
id?: string;
selectFirst?: boolean;
autoFill?: any;
clearValueOnHidden?: boolean;
validateApi?: boolean;
minLength?: number;
maxLength?: number;
validateOnChange?: boolean;
labelName?: string;
}) {
if (typeof rules === 'string') {
rules = str2rules(rules);
}
typeof type !== 'undefined' && (self.type = type);
typeof labelName !== 'undefined' && (self.labelName = labelName);
typeof id !== 'undefined' && (self.itemId = id);
typeof messages !== 'undefined' && (self.messages = messages);
typeof required !== 'undefined' && (self.required = !!required);
typeof unique !== 'undefined' && (self.unique = !!unique);
typeof multiple !== 'undefined' && (self.multiple = !!multiple);
typeof selectFirst !== 'undefined' && (self.selectFirst = !!selectFirst);
typeof autoFill !== 'undefined' && (self.autoFill = autoFill);
typeof joinValues !== 'undefined' && (self.joinValues = !!joinValues);
typeof extractValue !== 'undefined' &&
(self.extractValue = !!extractValue);
typeof delimiter !== 'undefined' &&
(self.delimiter = (delimiter as string) || ',');
typeof valueField !== 'undefined' &&
(self.valueField = (valueField as string) || 'value');
typeof labelField !== 'undefined' &&
(self.labelField = (labelField as string) || 'label');
typeof clearValueOnHidden !== 'undefined' &&
(self.clearValueOnHidden = !!clearValueOnHidden);
typeof validateApi !== 'undefined' && (self.validateApi = validateApi);
typeof validateOnChange !== 'undefined' &&
(self.validateOnChange = !!validateOnChange);
rules = {
...rules,
isRequired: self.required
};
// todo 这个弄个配置由渲染器自己来决定
// 暂时先这样
if (~['input-text', 'textarea'].indexOf(self.type)) {
if (typeof minLength === 'number') {
rules.minLength = minLength;
}
if (typeof maxLength === 'number') {
rules.maxLength = maxLength;
}
}
if (isObjectShallowModified(rules, self.rules)) {
self.rules = rules;
clearError('builtin');
self.validated = false;
}
}
function focus() {
self.isFocused = true;
}
function blur() {
self.isFocused = false;
}
let validateCancel: Function | null = null;
const validate: (data: Object, hook?: any) => Promise<boolean> = flow(
function* validate(data: Object, hook?: any) {
if (self.validating && !isEffectiveApi(self.validateApi, data)) {
return self.valid;
}
self.validating = true;
clearError();
if (hook) {
yield hook();
}
addError(
doValidate(self.tmpValue, data, self.rules, self.messages, self.__, self.labelName)
);
if (!self.errors.length && isEffectiveApi(self.validateApi, data)) {
if (validateCancel) {
validateCancel();
validateCancel = null;
}
const json: Payload = yield getEnv(self).fetcher(
self.validateApi,
data,
{
cancelExecutor: (executor: Function) =>
(validateCancel = executor)
}
);
validateCancel = null;
if (!json.ok && json.status === 422 && json.errors) {
addError(
String(
json.errors || json.msg || `表单项「${self.name}」校验失败`
)
);
}
}
self.validated = true;
if (self.unique && self.form?.parentStore?.storeType === 'ComboStore') {
const combo = self.form.parentStore as IComboStore;
const group = combo.uniques.get(self.name) as IUniqueGroup;
if (
group.items.some(
item =>
item !== self &&
self.tmpValue !== undefined &&
item.value === self.tmpValue
)
) {
addError(self.__('Form.unique'));
}
}
self.validating = false;
return self.valid;
}
);
function setError(msg: string | Array<string>, tag: string = 'builtin') {
clearError();
addError(msg, tag);
}
function addError(
msg:
| string
| Array<
| string
| {
msg: string;
rule: string;
}
>,
tag: string = 'builtin'
) {
const msgs: Array<
| string
| {
msg: string;
rule: string;
}
> = Array.isArray(msg) ? msg : [msg];
msgs.forEach(item =>
self.errorData.push({
msg: typeof item === 'string' ? item : item.msg,
rule: typeof item !== 'string' ? item.rule : undefined,
tag: tag
})
);
}
function clearError(tag?: string) {
if (tag) {
const filtered = self.errorData.filter(item => item.tag !== tag);
self.errorData.replace(filtered);
} else {
self.errorData.clear();
}
}
function getFirstAvaibleOption(options: Array<any>): any {
if (!Array.isArray(options)) {
return;
}
for (let option of options) {
if (Array.isArray(option.children)) {
const childFirst = getFirstAvaibleOption(option.children);
if (childFirst !== undefined) {
return childFirst;
}
} else if (option[self.valueField || 'value'] && !option.disabled) {
return option;
}
}
}
function setOptions(
options: Array<object>,
onChange?: (value: any, pristine?: boolean) => void,
data?: Object
) {
if (!Array.isArray(options)) {
return;
}
options = filterTree(options, item => item);
const originOptions = self.options.concat();
self.options = options;
syncOptions(originOptions, data);
let selectedOptions;
if (
onChange &&
self.selectFirst &&
self.filteredOptions.length &&
(selectedOptions = self.getSelectedOptions(self.value)) &&
!selectedOptions.filter(item => !item.__unmatched).length
) {
const fistOption = getFirstAvaibleOption(self.filteredOptions);
if (!fistOption) {
return;
}
const list = [fistOption].map((item: any) => {
if (self.extractValue || self.joinValues) {
return item[self.valueField || 'value'];
}
return item;
});
const value =
self.joinValues && self.multiple
? list.join(self.delimiter)
: self.multiple
? list
: list[0];
onChange(value, false);
}
}
let loadCancel: Function | null = null;
const fetchOptions: (
api: Api,
data?: object,
config?: fetchOptions,
setErrorFlag?: boolean,
dataAreaName?: string
) => Promise<Payload | null> = flow(function* getInitData(
api: Api,
data: object,
config?: fetchOptions,
setErrorFlag?: boolean,
dataAreaName?: string
) {
try {
if (loadCancel) {
loadCancel();
loadCancel = null;
self.loading = false;
}
let result: any = null;
const fetchUrl = filter((api as ApiObject)?.url || '', data);
const getFetchResult: any = () => new Promise(async (res) => {
const needCache = dataAreaName !== 'filterParam' && self.type !== 'input-tree'
if (needCache && dataAreaName && SelectCache[dataAreaName]?.[fetchUrl]) {
const cacheData = SelectCache[dataAreaName][fetchUrl];
config?.onSuccess?.(cacheData) // Jay
res(cacheData)
} else {
if (!SelectWaitingCache[fetchUrl]) {
// 查询器里面不缓存
if (dataAreaName && needCache)
SelectWaitingCache[fetchUrl] = []
if (!config?.silent) {
self.loading = true;
}
const json: Payload = await getEnv(self).fetcher(api, data, {
autoAppend: false,
cancelExecutor: (executor: Function) => (loadCancel = executor),
...config
});
if (!json.ok) {
config?.onFailed?.(json) // Jay
setErrorFlag !== false &&
setError(
self.__('Form.loadOptionsFailed', {
reason: json.msg ?? (config && config.errorMessage)
})
);
getEnv(self).notify(
'error',
self.errors.join('') || `${api}:${json.msg}`,
json.msgTimeout !== undefined
? {
closeButton: true,
timeout: json.msgTimeout
}
: undefined
);
res(null)
} else {
dataAreaName && (SelectCache[dataAreaName] = {
...(SelectCache[dataAreaName] || {}),
[fetchUrl]: json
});
if (SelectWaitingCache?.[fetchUrl]) {
SelectWaitingCache?.[fetchUrl]?.map((fn: any) => {
fn?.()
})
delete SelectWaitingCache[fetchUrl];
}
config?.onSuccess?.(json) // Jay
res(json)
}
} else {
SelectWaitingCache[fetchUrl].push(() => {
if (dataAreaName) {
const cacheData = SelectCache[dataAreaName][fetchUrl];
config?.onSuccess?.(cacheData) // Jay
res(cacheData)
}
})
}
}
})
//@ts-ignore 不懂为什么类型写了还是报错 ignore掉
result = yield (getFetchResult() as any)
loadCancel = null;
self.loading = false;
return result;
} catch (e) {
const env = getEnv(self);
if (!isAlive(self) || self.disposed) {
return;
}
self.loading = false;
if (env.isCancel(e)) {
return;
}
console.error(e.stack);
env.notify('error', e.message);
return;
}
} as any);
const loadOptions: (
api: Api,
data?: object,
config?: fetchOptions & {
extendsOptions?: boolean;
},
clearValue?: boolean,
onChange?: (value: any) => void,
setErrorFlag?: boolean,
dataAreaName?: string
) => Promise<Payload | null> = flow(function* getInitData(
api: string,
data: object,
config?: fetchOptions,
clearValue?: any,
onChange?: (
value: any,
submitOnChange?: boolean,
changeImmediately?: boolean
) => void,
setErrorFlag?: boolean,
dataAreaName?: string
) {
let json = yield fetchOptions(api, data, config, setErrorFlag, dataAreaName);
if (!json) {
return;
}
clearError();
self.validated = false; // 拉完数据应该需要再校验一下
let options: Array<IOption> =
json.data?.options ||
json.data?.items ||
json.data?.rows ||
json.data ||
[];
options = normalizeOptions(options as any, undefined, self.valueField);
if (config?.extendsOptions && self.selectedOptions.length > 0) {
self.selectedOptions.forEach((item: any) => {
const exited = findTree(
options as any,
optionValueCompare(item, self.valueField || 'value')
);
if (!exited) {
options.push(item);
}
});
}
setOptions(options, onChange, data);
if (json.data && !isNil((json.data as any).value)) {
onChange && onChange((json.data as any).value, false, true);
} else if (clearValue && !self.selectFirst) {
self.selectedOptions.some((item: any) => item.__unmatched) &&
onChange &&
onChange('', false, true);
}
return json;
});
const loadAutoUpdateData: (
api: Api,
data?: object,
silent?: boolean
) => Promise<any | null> = flow(function* getAutoUpdateData(
api: string,
data: object,
silent: boolean = true
) {
if (loadAutoUpdateCancel) {
loadAutoUpdateCancel();
loadAutoUpdateCancel = null;
}
const json: Payload = yield getEnv(self).fetcher(api, data, {
cancelExecutor: (executor: Function) =>
(loadAutoUpdateCancel = executor)
});
loadAutoUpdateCancel = null;
if (!json) {
return;
}
const result = json.data?.items || json.data?.rows;
// 只处理仅有一个结果的数据
if (result?.length === 1) {
return result[0];
} else if (isPlainObject(json.data)) {
return json.data;
}
if (json.status !== 0) {
!silent && getEnv(self).notify('info', json.msg);
}
return;
});
const tryDeferLoadLeftOptions: (
option: any,
api: Api,
data?: object,
config?: fetchOptions
) => Promise<Payload | null> = flow(function* (
option: any,
api: string,
data: object,
config?: fetchOptions
) {
if (
self.options.length != 1 ||
!Array.isArray(self.options[0].leftOptions)
) {
return;
}
let leftOptions = self.options[0].leftOptions as any;
const indexes = findTreeIndex(leftOptions, item => item === option);
if (!indexes) {
return;
}
setOptions(
[
{
...self.options[0],
leftOptions: spliceTree(leftOptions, indexes, 1, {
...option,
loading: true
})
}
],
undefined,
data
);
let json = yield fetchOptions(
api,
data,
{
...config,
silent: true
},
false
);
if (!json) {
setOptions(
[
{
...self.options[0],
leftOptions: spliceTree(leftOptions, indexes, 1, {
...option,
loading: false,
error: true
})
}
],
undefined,
data
);
return;
}
let options: Array<IOption> =
json.data?.options ||
json.data.items ||
json.data.rows ||
json.data ||
[];
setOptions(
[
{
...self.options[0],
leftOptions: spliceTree(leftOptions, indexes, 1, {
...option,
loading: false,
loaded: true,
children: options
})
}
],
undefined,
data
);
// 插入新的子节点,用于之后BaseSelection.resolveSelected查找
if (Array.isArray(self.options[0].children)) {
const children = self.options[0].children.concat();
flattenTree(self.options[0].leftOptions).forEach(item => {
if (
!findTree(self.options[0].children, node => node.ref === item.value)
) {
children.push({ ref: item.value, defer: true });
}
});
setOptions([{ ...self.options[0], children }], undefined, data);
}
return json;
});
const deferLoadOptions: (
option: any,
api: Api,
data?: object,
config?: fetchOptions
) => Promise<Payload | null> = flow(function* (
option: any,
api: string,
data: object,
config?: fetchOptions
) {
const indexes = findTreeIndex(self.options, item => item === option);
if (!indexes) {
return yield tryDeferLoadLeftOptions(option, api, data, config);
}
setOptions(
spliceTree(self.options, indexes, 1, {
...option,
loading: true
}),
undefined,
data
);
let json = yield fetchOptions(
api,
data,
{
...config,
silent: true
},
false
);
if (!json) {
setOptions(
spliceTree(self.options, indexes, 1, {
...option,
loading: false,
error: true
}),
undefined,
data
);
return;
}
let options: Array<IOption> =
json.data?.options ||
json.data.items ||
json.data.rows ||
json.data ||
[];
setOptions(
spliceTree(self.options, indexes, 1, {
...option,
loading: false,
loaded: true,
children: options
}),
undefined,
data
);
return json;
});
/**
* 根据当前节点路径展开树形组件父节点
*/
const expandTreeOptions: (
nodePathArr: any[],
api: Api,
data?: object,
config?: fetchOptions
) => Promise<Payload | null | void> = flow(function* getInitData(
nodePathArr: any[],
api: string,
data: object,
config?: fetchOptions
) {
// 多选模式下需要记录遍历过的Node,避免发送相同的请求
const traversedNode = new Map();
for (let nodePath of nodePathArr) {
// 根节点已经展开了,不需要加载
if (nodePath.length <= 1) {
continue;
}
// 叶节点不需要展开
for (let level = 0; level < nodePath.length - 1; level++) {
let tree = self.options.concat();
let nodeValue = nodePath[level];
if (traversedNode.has(nodeValue)) {
continue;
}
// 节点value认为是唯一的
let node = findTree(tree, (item, key, treeLevel: number) => {
return (
treeLevel === level + 1 &&
optionValueCompare(nodeValue, self.valueField || 'value')(item)
);
});
// 只处理懒加载节点
if (!node || !node.defer) {
continue;
}
const indexes = findTreeIndex(
tree,
item => item === node
) as number[];
setOptions(
spliceTree(tree, indexes, 1, {
...node,
loading: true
}),
undefined,
node
);
let json = yield fetchOptions(
api,
node,
{ ...config, silent: true },
false
);
if (!json) {
setOptions(
spliceTree(tree, indexes, 1, {
...node,
loading: false,
error: true
}),
undefined,
node
);
}
traversedNode.set(nodeValue, true);
let childrenOptions: Array<IOption> =
json.data?.options ||
json.data.items ||
json.data.rows ||
json.data ||
[];
setOptions(
spliceTree(tree, indexes, 1, {
...node,
loading: false,
loaded: true,
children: childrenOptions
}),
undefined,
node
);
}
}
});
// @issue 强依赖form,需要改造暂且放过。
function syncOptions(originOptions?: Array<any>, data?: Object) {
if (!self.options.length && typeof self.value === 'undefined') {
self.selectedOptions = [];
self.filteredOptions = [];
return;
}
const value = self.tmpValue;
const selected = Array.isArray(value)
? value.map(item =>
item && item.hasOwnProperty(self.valueField || 'value')
? item[self.valueField || 'value']
: item
)
: typeof value === 'string'
? value.split(self.delimiter || ',')
: value === void 0
? []
: [
value && value.hasOwnProperty(self.valueField || 'value')
? value[self.valueField || 'value']
: value
];
if (value && value.hasOwnProperty(self.labelField || 'label')) {
selected[0] = {
[self.labelField || 'label']: value[self.labelField || 'label'],
[self.valueField || 'value']: value[self.valueField || 'value']
};
}
let expressionsInOptions = false;
let filteredOptions = self.options
.filter((item: any) => {
if (
!expressionsInOptions &&
(item.visibleOn || item.hiddenOn || item.disabledOn)
) {
expressionsInOptions = true;
}
return item.visibleOn
? evalExpression(item.visibleOn, data) !== false
: item.hiddenOn
? evalExpression(item.hiddenOn, data) !== true
: item?.visible !== false || item.hidden !== true;
})
.map((item: any, index) => {
const disabled = evalExpression(item.disabledOn, data);
const newItem = item.disabledOn
? self.filteredOptions.length > index &&
self.filteredOptions[index].disabled === disabled
? self.filteredOptions[index]
: {
...item,
disabled: disabled
}
: item;
return newItem;
});
self.expressionsInOptions = expressionsInOptions;
const flattened: Array<any> = flattenTree(filteredOptions);
const selectedOptions: Array<any> = [];
selected.forEach((item, index) => {
let idx = findIndex(
flattened,
optionValueCompare(item, self.valueField || 'value')
);
if (~idx) {
selectedOptions.push(flattened[idx]);
} else {
let unMatched = (value && value[index]) || item;
if (
unMatched &&
(typeof unMatched === 'string' || typeof unMatched === 'number')
) {
unMatched = {
[self.valueField || 'value']: item,
[self.labelField || 'label']: item,
__unmatched: true
};
const orgin: any =
originOptions &&
find(
originOptions,
optionValueCompare(item, self.valueField || 'value')
);
if (orgin) {
unMatched[self.labelField || 'label'] =
orgin[self.labelField || 'label'];
}
} else if (unMatched && self.extractValue) {
unMatched = {
[self.valueField || 'value']: item,
[self.labelField || 'label']: 'UnKnown',
__unmatched: true
};
}
unMatched && selectedOptions.push(unMatched);
}
});
const form = self.form;
let parentStore = form?.parentStore;
if (parentStore?.storeType === ComboStore.name) {
let combo = parentStore as IComboStore;
let group = combo.uniques.get(self.name) as IUniqueGroup;
let options: Array<any> = [];
group &&
group.items.forEach(item => {
if (self !== item) {
options.push(
...item.selectedOptions.map((item: any) => item && item.value)
);
}
});
if (filteredOptions.length) {
filteredOptions = filteredOptions.filter(
option => !~options.indexOf(option.value)
);
}
}
isArrayChildrenModified(self.selectedOptions, selectedOptions) &&
(self.selectedOptions = selectedOptions);
isArrayChildrenModified(self.filteredOptions, filteredOptions) &&
(self.filteredOptions = filteredOptions);
}
function setLoading(value: boolean) {
self.loading = value;
}
let subStore: any;
function getSubStore() {
return subStore;
}
function setSubStore(store: any) {
subStore = store;
}
function reset(keepErrors: boolean = false) {
self.validated = false;
if (subStore && subStore.storeType === 'ComboStore') {
const combo = subStore as IComboStore;
combo.forms.forEach(form => form.reset());
}
!keepErrors && clearError();
}
function openDialog(
schema: any,
data: any,
callback?: (ret?: any) => void
) {
self.dialogSchema = schema;
self.dialogData = data;
self.dialogOpen = true;
callback && dialogCallbacks.set(self.dialogData, callback);
}
function closeDialog(result?: any) {
const callback = dialogCallbacks.get(self.dialogData);
self.dialogOpen = false;
if (callback) {
dialogCallbacks.delete(self.dialogData);
setTimeout(() => callback(result), 200);
}
}
function changeTmpValue(value: any) {
self.tmpValue = value;
}
function changeEmitedValue(value: any) {
self.emitedValue = value;
}
function addSubFormItem(item: IFormItemStore) {
self.itemsRef.push(item.id);
}
function removeSubFormItem(item: IFormItemStore) {
const idx = self.itemsRef.findIndex(a => a === item.id);
if (~idx) {
self.itemsRef.splice(idx, 1);
}
}
return {
focus,
blur,
config,
validate,
setError,
addError,
clearError,
setOptions,
loadOptions,
deferLoadOptions,
expandTreeOptions,
syncOptions,
setLoading,
setSubStore,
getSubStore,
reset,
openDialog,
closeDialog,
changeTmpValue,
changeEmitedValue,
addSubFormItem,
removeSubFormItem,
loadAutoUpdateData
};
});
export type IFormItemStore = Instance<typeof FormItemStore>;
export type SFormItemStore = SnapshotIn<typeof FormItemStore>;