UNPKG

@magic_npm/simple-tools

Version:

`simple-tools` is a simple set of tools

1 lines 12 kB
{"version":3,"file":"index.mjs","sources":["../../../src/utils/useData.ts","../../../src/utils/useApi.ts"],"sourcesContent":["import type { UseDataModel } from './types'\n\n/**\n * 数据声明hook\n * @param func - 返回初始数据的函数\n * @returns [数据模型, 数据更新函数]\n */\nconst useData: UseDataModel = function (func) {\n const model = func()\n return [\n model,\n /**\n * 合并数据,数据初始化的合并\n * @param coverData - 需要合并的数据\n * @param isReset - 是否重置性合并\n * @returns 合并后的数据\n */\n (coverData, isReset) => {\n // 待合并的数据\n const cover = (isReset || !coverData) ? useData.mergeData(func(), coverData) : coverData\n // 合并到数据模型上\n return useData.mergeData(model, cover)\n }\n ]\n}\n\n/**\n * 获取数据类型\n * @param data - 需要检测的数据\n * @returns 数据类型字符串 ('null' | 'undefined' | 'object' | 'array' | 'number' | 'string' | 'set')\n */\nuseData.getDataType = function (data) {\n return Object.prototype.toString.call(data).slice(8, -1).toLowerCase()\n}\n\n/**\n * 合并数据,只有类型相同的数据才会被合并\n * @param data - 原始数据\n * @param cover - 需要合并的数据\n * @returns 合并后的数据\n */\nuseData.mergeData = function (data, cover) {\n if (data && useData.getDataType(data) === 'object' && ['object', 'undefined'].includes(useData.getDataType(cover))) {\n cover && Object.keys(data).forEach((k) => {\n if (k in cover) {\n (data as any)[k] = cover[k]\n }\n })\n }\n return data\n}\n\nexport default useData","/**\n * 用于接口请求,规范代码结构\n * \n * @param api - 接口方法\n * @param options - 配置选项\n * @returns [apiFunc, loading, apiObj]\n * \n * @example\n * const [apiFunc, loading, apiObj] = useApi(api, {\n * isCancel: true, // 连续请求,是否只响应最后一个请求结果\n * isRepeat: true, // 是否可重复请求/提交\n * isSingle: false, // 是否开启单例模式\n * loading: {}, // 定义 loading 状态\n * params: () => ({}), // 预设接口参数\n * before: (params) => true, // 请求前处理\n * outputModel: (params) => params, // 输出数据处理\n * inputModel: (res) => res, // 输入数据处理\n * success: (data, loadingKey, res) => {}, // 成功回调\n * error: (err) => {}, // 失败回调\n * loadingStart: (params, loadingKey) => {}, // loading开始回调\n * loadingEnd: (loadingState) => {} // loading结束回调\n * });\n */\nimport useData from './useData'\nimport type { useApiFuncModel, useApiOptionsModel, useApiObjStatusModel } from './types'\n\nexport default function useApi<\n Q extends object, // 基础参数类型\n OQ extends object | void, // outputModel 方法处理后参数类型\n R extends object | unknown | void, // 接口返回值类型\n RD extends object | void, // inputModel 返回值处理后结果类型\n L extends object | undefined, // loading 对象类型\n LK extends keyof L, // loading 对象键名类型\n LS // loadingStart 方法返回值类型\n>(\n api: (arg?: OQ, opt?: any) => Promise<R>,\n options?: useApiOptionsModel<R, RD, Q, OQ, L, LK, LS>\n): [useApiFuncModel<R, RD, Q, LK>, L, useApiObjStatusModel<R, RD, LK, Q, OQ>] {\n const {\n isCancel,\n isRepeat,\n isSingle,\n loading,\n params,\n loadingStart,\n loadingEnd,\n before,\n success,\n error,\n inputModel,\n outputModel\n } = {\n isCancel: true,\n isRepeat: true,\n isSingle: false,\n ...options\n }\n\n const apiObj: useApiObjStatusModel<R, RD, LK, Q, OQ> = {\n status: 0, // Api请求的状态,0 待请求, 1 请求中, 2 成功, 3 失败\n sendNum: {}, // 根据 loadingKey 来记录请求次数\n sendLatestKey: undefined, // 最新请求的 loadingKey\n pm: undefined, // 最新一次请求结果\n err: '', // 请求错误结果记录\n params: undefined, // 请求参数记录\n output: undefined, // 输出参数数据记录\n result: {\n res: undefined as R, // 未处理前的数据\n data: undefined as RD, // 经过 inputModel 处理后的结果\n loadingKey: '' as LK // loading键名\n },\n\n /**\n * 关闭正在请求的Api\n */\n cancelApi: async () => {\n const cancel = apiObj.pm?.cancel\n const pm = Promise.resolve()\n\n if (cancel) {\n cancel?.()\n apiObj.status = 0\n\n try {\n await apiObj.pm\n } catch (err) { }\n\n console.log('[cancel successful]')\n } else {\n console.log('[cancel error] find not cancel function.')\n }\n\n return pm\n }\n }\n\n /**\n * 调用API函数\n * @param query - 接口请求参数\n * @param loadingKey - 指定响应对应的loading键名\n */\n const apiFunc: useApiFuncModel<R, RD, Q, LK> = async (query, loadingKey = 'value' as LK) => {\n // 用来建立连接 loadingStart loadingEnd\n let loadingState = undefined as LS\n const sameSend: { [key in LK]?: number } = {}\n\n try {\n // 设置请求参数\n apiObj.params = params?.()\n apiObj.params && useData.mergeData(apiObj.params, query)\n\n // 请求前处理\n if (typeof before === 'function') {\n let bPm = before(apiObj.params && JSON.parse(JSON.stringify(apiObj.params)))\n\n if (bPm === false) {\n throw 'close send api.'\n }\n\n if (bPm instanceof Promise) {\n await bPm\n }\n }\n\n // 禁止重复请求处理\n if (!isRepeat && apiObj.status === 1) {\n return Promise.reject('操作频繁,请稍后再试')\n }\n\n // 是否单例模式\n if (isSingle && apiObj.status === 2) {\n success?.(apiObj.result.data, apiObj.result.loadingKey, apiObj.result.res)\n return Promise.resolve(apiObj.result)\n }\n\n // 输出给外部的参数数据\n apiObj.output = typeof outputModel === 'function'\n ? outputModel(apiObj.params && JSON.parse(JSON.stringify(apiObj.params)))\n : apiObj.params && JSON.parse(JSON.stringify(apiObj.params))\n\n // 连续请求模式,关闭上一次正在请求的此接口\n if (isCancel && isRepeat && apiObj.status === 1) {\n await apiObj.cancelApi()\n }\n\n // 取反 (相同 loadingKey 重复请求,上一个请求未完成)\n if (!(apiObj.sendLatestKey === loadingKey && apiObj.status === 1)) {\n // loading 处理\n if (loading && loadingKey && loadingKey in loading) {\n (loading as any)[loadingKey] = true\n }\n\n // loadingStart 回调\n if (loadingStart) {\n loadingStart(\n apiObj.params && JSON.parse(JSON.stringify(apiObj.params)),\n loadingKey\n )\n }\n }\n\n // 根据 loadingKey 分别记录请求次数\n if (loadingKey) {\n const k = loadingKey\n apiObj.sendNum[k] = (apiObj.sendNum[k] || 0) + 1\n sameSend[k] = apiObj.sendNum[k]\n }\n\n apiObj.sendLatestKey = loadingKey\n apiObj.status = 1\n\n // 调用 api\n apiObj.pm = api(apiObj.output)\n const res = await apiObj.pm\n\n apiObj.status = 2\n apiObj.result.res = res\n apiObj.result.loadingKey = loadingKey\n if (typeof inputModel === 'function') {\n apiObj.result.data = inputModel?.(res)\n }\n\n // 成功回调处理\n success?.(apiObj.result.data, loadingKey, apiObj.result.res)\n } catch (err: any) {\n // 失败处理\n apiObj.status = 3\n apiObj.err = err\n error?.(apiObj.err)\n }\n\n // 1. 最新请求的 loadingKey 与上一次不一样 || 2. 相同 loadingKey 的请求次数一致\n // 备注:条件1 不一致则直接处理loading关闭;条件2 请求次数一致则表示没有重复的请求\n const slk = apiObj.sendLatestKey\n\n if (apiObj.sendLatestKey != loadingKey || (slk && sameSend[slk] === apiObj.sendNum[slk])) {\n // loading 处理\n if (loading && loadingKey && loadingKey in loading) {\n (loading as any)[loadingKey] = false\n }\n\n // loadingEnd 处理\n loadingEnd?.(loadingState)\n }\n\n // 返回处理\n return new Promise((resolve, reject) => {\n if (apiObj.status === 2) {\n resolve(apiObj.result)\n } else if (apiObj.status === 3) {\n reject(apiObj.err)\n } else {\n reject(new Error('useApi exception'))\n }\n })\n }\n\n return [apiFunc, loading as L, { ...apiObj }]\n}"],"names":[],"mappings":"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"}