fastlion-amis
Version:
一种MIS页面生成工具
547 lines (477 loc) • 14.3 kB
text/typescript
import { types, flow, getEnv, isAlive, Instance } from 'mobx-state-tree';
import { iRendererStore } from './iRenderer';
import { Api, ApiObject, Payload, fetchOptions } from '../types';
import { extendObject, isEmpty, isObject } from '../utils/helper';
import { ServerError } from '../utils/errors';
import { normalizeApiResponseData } from '../utils/api';
export const ServiceStore = iRendererStore
.named('ServiceStore')
.props({
msg: '',
error: false,
fetching: false,
saving: false,
busying: false,
checking: false,
initializing: false,
schema: types.optional(types.frozen(), null),
schemaKey: ''
})
.views(self => ({
get loading() {
return self.fetching || self.saving || self.busying || self.initializing;
}
}))
.actions(self => {
let fetchCancel: Function | null;
let fetchSchemaCancel: Function | null;
function markFetching(fetching = true) {
self.fetching = fetching;
}
function markSaving(saving = true) {
self.saving = saving;
}
function markBusying(busying = true) {
self.busying = busying;
}
function reInitData(data: object | undefined, replace: boolean = false) {
const newData = extendObject(self.pristine, data, !replace);
self.data = self.pristine = newData;
}
function updateMessage(msg?: string, error: boolean = false) {
self.msg = (msg && String(msg)) || '';
self.error = error;
}
function clearMessage() {
updateMessage('');
}
const fetchInitData: (
api: Api,
data?: object,
options?: fetchOptions
) => Promise<any> = flow(function* getInitData(
api: Api,
data: object,
options?: fetchOptions
) {
try {
if (fetchCancel) {
fetchCancel();
fetchCancel = null;
self.fetching = false;
}
if (self.fetching) {
return;
}
// if (!!(options?.markFetching && options?.setFormLoading)) {
// options?.setFormLoading?.(true)
// }
// Jay
// options?.markFetching:表单下多个tab页的service组件一起发起请求时loading的控制
// (options && options.silent) || markFetching(true);
(options && options.silent) || markFetching(options?.markFetching ?? true);
const json: Payload = yield getEnv(self).fetcher(api, data, {
...options,
cancelExecutor: (executor: Function) => (fetchCancel = executor)
});
fetchCancel = null;
if (!json.ok) {
updateMessage(json.msg ?? (options && options.errorMessage), true);
getEnv(self).notify(
'error',
json.msg,
json.msgTimeout !== undefined
? {
closeButton: true,
timeout: json.msgTimeout
}
: undefined
);
} else {
self.updatedAt = Date.now();
let replace = !!(api as ApiObject).replaceData;
let data = {
...(replace ? {} : self.data),
...normalizeApiResponseData(json.data)
};
reInitData(data, replace);
self.hasRemoteData = true;
// Jay
options?.markFetching &&
options?.setFormLoading?.(false)
if (options && options.onSuccess) {
const ret = options.onSuccess(json);
if (ret && ret.then) {
yield ret;
}
}
updateMessage(json.msg ?? (options && options.successMessage));
// 配置了获取成功提示后提示,默认是空不会提示。
options &&
options.successMessage &&
getEnv(self).notify('success', self.msg);
}
markFetching(false);
// if (!!(options?.markFetching && options?.setFormLoading)) {
// options?.setFormLoading?.(false)
// }
return json;
} catch (e) {
const env = getEnv(self);
// if (!!(options?.markFetching && options?.setFormLoading)) {
// options?.setFormLoading?.(false)
// }
if (!isAlive(self) || self.disposed) {
return;
}
if (env.isCancel(e)) {
return;
}
markFetching(false);
e.stack && console.error(e.stack);
let message = e.message || e;
if (e && e.message === 'Network Error') {
message = self.__('networkError');
}
env.notify('error', message);
return;
}
});
const fetchWSData = (ws: string, afterDataFetch: (data: any) => any) => {
const env = getEnv(self);
env.wsFetcher(
ws,
(data: any) => {
self.updateData(data, undefined, false);
setHasRemoteData();
// 因为 WebSocket 只会获取纯数据,所以没有 msg 之类的
afterDataFetch({ ok: true, data: data });
},
(error: any) => {
updateMessage(error, true);
env.notify('error', error);
}
);
};
const setHasRemoteData = () => {
self.hasRemoteData = true;
};
const fetchData: (
api: Api,
data?: object,
options?: fetchOptions
) => Promise<any> = flow(function* getInitData(
api: Api,
data: object,
options?: fetchOptions
) {
try {
if (fetchCancel) {
fetchCancel();
fetchCancel = null;
self.fetching = false;
}
if (self.fetching) {
return;
}
(options && options.silent) || markFetching(true);
const json: Payload = yield getEnv(self).fetcher(api, data, {
...options,
cancelExecutor: (executor: Function) => (fetchCancel = executor)
});
fetchCancel = null;
if (!isEmpty(json.data) || json.ok) {
self.updatedAt = Date.now();
json.data &&
self.updateData(
normalizeApiResponseData(json.data),
undefined,
!!(api as ApiObject).replaceData
);
self.hasRemoteData = true;
}
if (!json.ok) {
updateMessage(json.msg ?? (options && options.errorMessage), true);
getEnv(self).notify(
'error',
self.msg,
json.msgTimeout !== undefined
? {
closeButton: true,
timeout: json.msgTimeout
}
: undefined
);
} else {
if (options && options.onSuccess) {
const ret = options.onSuccess(json);
if (ret && ret.then) {
yield ret;
}
}
updateMessage(json.msg ?? (options && options.successMessage));
// 配置了获取成功提示后提示,默认是空不会提示。
options &&
options.successMessage &&
getEnv(self).notify('success', self.msg);
}
markFetching(false);
return json;
} catch (e) {
const env = getEnv(self);
if (!isAlive(self) || self.disposed) {
return;
}
if (env.isCancel(e)) {
return;
}
markFetching(false);
e.stack && console.error(e.stack);
let message = e.message || e;
if (e && e.message === 'Network Error') {
message = self.__('networkError');
}
env.notify('error', message);
return;
}
});
const saveRemote: (
api: Api,
data?: object,
options?: fetchOptions
) => Promise<any> = flow(function* saveRemote(
api: Api,
data: object,
options: fetchOptions = {}
) {
try {
options = {
method: 'post', // 默认走 post
...options
};
if (!self.saving) {
return;
}
markSaving(true);
const json: Payload = yield getEnv(self).fetcher(api, data, options);
if (!isEmpty(json.data) || json.ok) {
self.updatedAt = Date.now();
json.data &&
self.updateData(
normalizeApiResponseData(json.data),
undefined,
!!(api as ApiObject).replaceData
);
}
if (!json.ok) {
if (options && options.onFailed) {
const ret = options.onFailed(json);
if (ret && ret.then) {
yield ret;
}
}
updateMessage(
json.msg ??
(options && options.errorMessage) ??
self.__('saveFailed'),
true
);
throw new ServerError(self.msg, json);
} else {
if (options && options.onSuccess) {
const ret = options.onSuccess(json);
if (ret && ret.then) {
yield ret;
}
}
updateMessage(json.msg ?? (options && options.successMessage));
self.msg &&
getEnv(self).notify(
'success',
self.msg,
json.msgTimeout !== undefined
? {
closeButton: true,
timeout: json.msgTimeout
}
: undefined
);
}
markSaving(false);
return json.data;
} catch (e) {
self.saving = false;
if (!isAlive(self) || self.disposed) {
return;
}
if (e.type === 'ServerError') {
const result = (e as ServerError).response;
getEnv(self).notify(
'error',
e.message,
result.msgTimeout !== undefined
? {
closeButton: true,
timeout: result.msgTimeout
}
: undefined
);
} else {
getEnv(self).notify('error', e.message);
}
throw e;
}
});
const fetchSchema: (
api: Api,
data?: object,
options?: fetchOptions,
notify?: boolean
) => Promise<any> = flow(function* fetchSchema(
api: Api,
data: object,
options: fetchOptions = {},
notify?: boolean
) {
try {
options = {
method: 'post', // 默认走 post
...options,
cancelExecutor: (executor: Function) => (fetchSchemaCancel = executor)
};
if (fetchSchemaCancel) {
fetchSchemaCancel();
fetchSchemaCancel = null;
self.initializing = false;
}
if (self.initializing) {
return;
}
// if (!!( options?.setFormLoading)) {
// options?.setFormLoading?.(true)
// }
self.initializing = true;
if (typeof api === 'string') {
api += (~api.indexOf('?') ? '&' : '?') + '_replace=1';
} else {
api = {
...(api as any),
url:
(api as ApiObject).url +
(~(api as ApiObject).url.indexOf('?') ? '&' : '?') +
'_replace=1'
};
}
const json: Payload = yield getEnv(self).fetcher(api, data, options);
fetchSchemaCancel = null;
if (!json.ok) {
updateMessage(
json.msg ??
(options && options.errorMessage) ??
self.__('fetchFailed'),
true
);
getEnv(self).notify(
'error',
self.msg,
json.msgTimeout !== undefined
? {
closeButton: true,
timeout: json.msgTimeout
}
: undefined
);
} else {
if (json.data) {
self.schema = Array.isArray(json.data)
? json.data
: {
type: 'wrapper',
wrap: false,
...normalizeApiResponseData(json.data)
};
self.schemaKey = '' + Date.now();
isObject(json.data.data) &&
self.updateData(
json.data.data,
undefined,
!!(api as ApiObject).replaceData
);
}
updateMessage(json.msg ?? (options && options.successMessage));
// 配置了获取成功提示后提示,默认是空不会提示。
!notify && options &&
options.successMessage &&
getEnv(self).notify('success', self.msg);
}
self.initializing = false;
// if (!!(options?.setFormLoading)) {
// options?.setFormLoading?.(false)
// }
return json.data;
} catch (e) {
const env = getEnv(self);
// if (!!(options?.setFormLoading)) {
// options?.setFormLoading?.(false)
// }
self.initializing = false;
if (!isAlive(self) || self.disposed) {
return;
}
if (env.isCancel(e)) {
return;
}
e.stack && console.error(e.stack);
let message = e.message || e;
if (e && e.message === 'Network Error') {
message = self.__('networkError');
}
env.notify('error', message);
}
});
const checkRemote: (
api: Api,
data?: object,
options?: fetchOptions
) => Promise<any> = flow(function* checkRemote(
api: Api,
data: object,
options?: fetchOptions
) {
if (self.checking) {
return;
}
try {
self.checking = true;
const json: Payload = yield getEnv(self).fetcher(api, data, options);
json.ok &&
self.updateData(
json.data,
undefined,
!!(api as ApiObject).replaceData
);
if (!json.ok) {
throw new Error(json.msg);
}
return json.data;
} finally {
self.checking = false;
}
});
return {
markFetching,
markSaving,
markBusying,
fetchInitData,
fetchData,
fetchWSData,
reInitData,
updateMessage,
clearMessage,
setHasRemoteData,
saveRemote,
fetchSchema,
checkRemote
};
});
export type IServiceStore = Instance<typeof ServiceStore>;