|
@@ -0,0 +1,295 @@
|
|
|
+import axios, {AxiosRequestConfig, AxiosResponse} from 'axios'
|
|
|
+import {PlainObject} from "../types";
|
|
|
+import _ from 'lodash'
|
|
|
+import Qs from 'qs'
|
|
|
+import {serverInvokeUrlTransform, sqlUrlTransform, ajax} from "./config";
|
|
|
+
|
|
|
+export type ApiMethod =
|
|
|
+ 'get'
|
|
|
+ | 'post'
|
|
|
+ | 'put'
|
|
|
+ | 'patch'
|
|
|
+ | 'delete'
|
|
|
+ | 'download'
|
|
|
+ | 'post-json'
|
|
|
+ | 'post-file'
|
|
|
+ | 'invoke'
|
|
|
+ | 'sql'
|
|
|
+
|
|
|
+export type ApiDataType = 'json' | 'form-data' | 'form'
|
|
|
+
|
|
|
+/**
|
|
|
+ * 调用服务器 Ajax
|
|
|
+ */
|
|
|
+export function invokeServer(url: string, ...args: any[]) {
|
|
|
+ // @ts-ignore
|
|
|
+ return ajax.func({
|
|
|
+ url: url,
|
|
|
+ method: 'invoke',
|
|
|
+ args: args
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+export interface ApiObject {
|
|
|
+ url: string
|
|
|
+ param: PlainObject
|
|
|
+ method: ApiMethod
|
|
|
+ data?: object
|
|
|
+ args: any[],
|
|
|
+ db?: string
|
|
|
+ headers?: PlainObject
|
|
|
+ filterModel?: { [key: string]: any; };
|
|
|
+ sortModel?: { colId: string | undefined; sort: string | null | undefined; }[];
|
|
|
+ config?: {
|
|
|
+ withCredentials?: boolean
|
|
|
+ cancelExecutor?: (cancel: Function) => void
|
|
|
+ }
|
|
|
+ dataType?: ApiDataType
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下载文件名
|
|
|
+ */
|
|
|
+ fileName?: string,
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 上传文件(如果需要的话)
|
|
|
+ */
|
|
|
+ file?: any,
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+export type ApiFunction = (api: ApiObject) => Promise<ApiResult>;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 组件中 Api 的声明
|
|
|
+ */
|
|
|
+export type Api = ApiFunction | ApiObject;
|
|
|
+
|
|
|
+export interface ApiResult {
|
|
|
+ rawData: object
|
|
|
+ status: number
|
|
|
+ headers: object
|
|
|
+ data?: any
|
|
|
+ pagination?: any
|
|
|
+ success: boolean
|
|
|
+ msg: string
|
|
|
+ errors?: {
|
|
|
+ [propName: string]: string
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export interface CreateAjaxOption {
|
|
|
+ baseUrl: string
|
|
|
+ timeout: number
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 创建一个 Ajax 客户端
|
|
|
+ */
|
|
|
+export function createAjax(createOption: CreateAjaxOption): ApiFunction {
|
|
|
+
|
|
|
+ if (createOption.baseUrl) {
|
|
|
+ axios.defaults.baseURL = createOption.baseUrl
|
|
|
+ axios.defaults.timeout = createOption.timeout
|
|
|
+ axios.defaults.timeoutErrorMessage = '网络超时'
|
|
|
+ }
|
|
|
+
|
|
|
+ return function (option: ApiObject) {
|
|
|
+
|
|
|
+ //@ts-ignore
|
|
|
+ option.method = (option.method || 'get').toLocaleLowerCase();
|
|
|
+
|
|
|
+ //@ts-ignore
|
|
|
+ const ax: AxiosRequestConfig = {
|
|
|
+ ...option
|
|
|
+ };
|
|
|
+
|
|
|
+ switch (option.method) {
|
|
|
+ case 'get':
|
|
|
+ ax.method = 'GET';
|
|
|
+ ax.params = option.param;
|
|
|
+ ax.headers = {
|
|
|
+ ...option.headers
|
|
|
+ };
|
|
|
+ break
|
|
|
+
|
|
|
+ case 'post':
|
|
|
+ ax.method = 'POST';
|
|
|
+ ax.headers = {
|
|
|
+ 'Content-Type': 'application/x-www-form-urlencoded',
|
|
|
+ ...option.headers
|
|
|
+ };
|
|
|
+ ax.params = option.param;
|
|
|
+ ax.data = Qs.stringify(option.data);
|
|
|
+ break
|
|
|
+
|
|
|
+ case 'put' :
|
|
|
+ case 'patch':
|
|
|
+ case 'delete':
|
|
|
+ ax.method = option.method;
|
|
|
+ ax.headers = option.headers;
|
|
|
+ ax.params = option.param;
|
|
|
+ ax.data = Qs.stringify(option.data);
|
|
|
+ break
|
|
|
+
|
|
|
+ case 'download':
|
|
|
+ downLoad(createOption.baseUrl + option.url, option.fileName || 'file',
|
|
|
+ option.data, option.headers);
|
|
|
+ return new Promise<ApiResult>((resolver, reject) => {
|
|
|
+ });
|
|
|
+ break
|
|
|
+
|
|
|
+ case "invoke":
|
|
|
+ ax.url = serverInvokeUrlTransform(option.url)
|
|
|
+ ax.method = 'POST';
|
|
|
+ ax.headers = {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ ...option.headers
|
|
|
+ };
|
|
|
+ if (typeof option.args === 'object') {
|
|
|
+ ax.data = JSON.stringify({
|
|
|
+ args: option.args,
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ ax.data = JSON.stringify({
|
|
|
+ args: [
|
|
|
+ {
|
|
|
+ ...option.data,
|
|
|
+ ...option.param
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ filterModel: option.filterModel,
|
|
|
+ sortModel: option.sortModel
|
|
|
+ })
|
|
|
+ }
|
|
|
+ break
|
|
|
+
|
|
|
+ case 'post-json':
|
|
|
+ ax.method = 'POST';
|
|
|
+ ax.headers = {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ ...option.headers
|
|
|
+ };
|
|
|
+ ax.data = JSON.stringify({...option.data, filterModel: option.filterModel, sortModel: option.sortModel})
|
|
|
+ break
|
|
|
+
|
|
|
+ case 'post-file':
|
|
|
+ //TODO 刘壮. 上传文件
|
|
|
+ var forms = new FormData();
|
|
|
+ ax.headers = {
|
|
|
+ 'Content-Type': 'multipart/form-data',
|
|
|
+ ...option.headers
|
|
|
+ };
|
|
|
+ _.forOwn(option.data, (value, key) => {
|
|
|
+ if (key === 'files') {
|
|
|
+ let i = 0;
|
|
|
+ _.each(value, f => {
|
|
|
+ // @ts-ignore
|
|
|
+ forms.append('file' + (++i), f)
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ forms.append(key, value)
|
|
|
+ }
|
|
|
+ });
|
|
|
+ ax.data = forms;
|
|
|
+ ax.method = 'POST'
|
|
|
+ break
|
|
|
+
|
|
|
+ case "sql":
|
|
|
+ ax.url = sqlUrlTransform(option.url)
|
|
|
+ ax.method = 'POST';
|
|
|
+ ax.headers = {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ ...option.headers
|
|
|
+ };
|
|
|
+ ax.data = JSON.stringify({
|
|
|
+ args: [option.data],
|
|
|
+ db: option.db,
|
|
|
+ filterModel: option.filterModel,
|
|
|
+ sortModel: option.sortModel
|
|
|
+ })
|
|
|
+ break
|
|
|
+
|
|
|
+ default:
|
|
|
+ throw new Error('not implements')
|
|
|
+ }
|
|
|
+
|
|
|
+ return new Promise<ApiResult>((resolver, reject) => {
|
|
|
+ axios(ax).then((resolverRaw: AxiosResponse<any>) => {
|
|
|
+ const apiResult: ApiResult = {
|
|
|
+ rawData: resolverRaw.data,
|
|
|
+ status: resolverRaw.status,
|
|
|
+ success: (resolverRaw.data && resolverRaw.data.success),
|
|
|
+ data: resolverRaw.data.data,
|
|
|
+ pagination: resolverRaw.data.pagination,
|
|
|
+ msg: (resolverRaw.data.msg),
|
|
|
+ errors: resolverRaw.data.errors,
|
|
|
+ headers: resolverRaw.headers
|
|
|
+ }
|
|
|
+ resolver(apiResult)
|
|
|
+
|
|
|
+ }).catch((reason: any) => {
|
|
|
+ reject(reason)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+export function downLoad(downLoadUrl: string, filename: string, data: any, header: any, isJson: boolean = false) {
|
|
|
+ const YvanUI: any = _.get(window, 'YvanUI');
|
|
|
+ YvanUI.loading();
|
|
|
+ const createObjectURL = (object: any) => {
|
|
|
+ return (window.URL) ? window.URL.createObjectURL(object) : _.get(window, 'webkitURL').createObjectURL(object)
|
|
|
+ };
|
|
|
+
|
|
|
+ // const formData = new FormData();
|
|
|
+ // _.forOwn(data, (v, k) => {
|
|
|
+ // formData.append(k, v);
|
|
|
+ // });
|
|
|
+ let formData = '';
|
|
|
+
|
|
|
+ const xhr = new XMLHttpRequest();
|
|
|
+ xhr.open('POST', downLoadUrl);
|
|
|
+ xhr.responseType = 'blob';
|
|
|
+ // xhr.setRequestHeader('Authorization', $.cookie('auth'))
|
|
|
+ if (isJson) {
|
|
|
+ formData = data ? JSON.stringify(data) : '';
|
|
|
+ xhr.setRequestHeader('Content-Type', 'application/json');
|
|
|
+ } else {
|
|
|
+ formData = data ? Qs.stringify(data) : '';
|
|
|
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
|
+ }
|
|
|
+ //
|
|
|
+ if (header) {
|
|
|
+ _.forOwn(header, (v, k) => {
|
|
|
+ xhr.setRequestHeader(k, v);
|
|
|
+ })
|
|
|
+ }
|
|
|
+ xhr.onload = function (e: any) {
|
|
|
+ if (this.status === 200) {
|
|
|
+ const blob = this.response;
|
|
|
+ if (_.hasIn(window, 'navigator.msSaveOrOpenBlob')) {
|
|
|
+ navigator.msSaveBlob(blob, filename)
|
|
|
+ YvanUI.clearLoading();
|
|
|
+
|
|
|
+ } else {
|
|
|
+ const a = document.createElement('a')
|
|
|
+ const url = createObjectURL(blob)
|
|
|
+ a.href = url
|
|
|
+ a.download = filename
|
|
|
+ document.append(a)
|
|
|
+ a.click()
|
|
|
+ a.remove()
|
|
|
+ window.URL.revokeObjectURL(url)
|
|
|
+ YvanUI.clearLoading()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ xhr.send(formData);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|