UNPKG

dua

Version:
525 lines (457 loc) 12.4 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.Dua = {})); }(this, (function (exports) { 'use strict'; const drive = { normalize: (list, total) => { const byId = list && list.reduce((prev, c) => { if (c && c.id) { prev[c.id] = c; } return prev; }, {}); return { byId: byId || {}, allIds: list || [], total: typeof total === "number" ? total : list.length }; }, transform: byId => Object.keys(byId || {}).reduce((prev, id) => prev.concat(byId[id]), []), reduce: state => state }; //一次遍历找出所有子节点的children const build = (workspace, current) => { //初始化 if (!workspace.roots) { workspace.roots = []; } if (!workspace.childMap) { workspace.childMap = {}; } if (current.parentId) { if (workspace.childMap[current.parentId]) { workspace.childMap[current.parentId].push(current); } else { workspace.childMap[current.parentId] = [current]; } } else { if (!workspace.childMap.hasOwnProperty(current.id)) { workspace.childMap[current.id] = []; } workspace.roots.push(current); } return workspace; }; const buildRelationShip = (node, map) => { const children = map[node.id]; children && children.forEach(element => { buildRelationShip(element, map); }); node.children = children; return node; }; const drive$1 = { normalize: (list, total) => { const normalized = list && list.reduce((prev, c) => { if (c && c.id) { prev.byId[c.id] = c; prev.workspace = build(prev.workspace, c); } return prev; }, { byId: {}, workspace: {} }) || { byId: {}, workspace: {} }; return { byId: normalized.byId, allIds: normalized.workspace.roots.map(i => buildRelationShip(i, normalized.workspace.childMap)), total: typeof total === "number" ? total : list.length }; }, transform: byId => { const normalized = Object.keys(byId || {}).reduce((workspace, id) => build(workspace, byId[id]), {}); return normalized.workspace.roots.map(i => buildRelationShip(i, normalized.workspace.childMap)); }, reduce: state => state }; //该算法时间复杂度是n,按层级深度先分类 const buildWorkspace = (workspace, current) => { const depth = current.parentIds && current.parentIds.length || 0; if (!workspace[depth]) { workspace[depth] = {}; } workspace[depth][current.id] = current; return workspace; }; //从最底层的节点开始遍历,慢慢的把节点挂到他的父节点上 const buildTree = workspace => { const depth = workspace.length - 1; for (let i = depth; i > 0; --i) { Object.keys(workspace[i]).forEach(c => { const element = workspace[i][c]; if (element.parentIds && element.parentIds.length > 0) { const parentId = element.parentIds[0]; const parent = workspace[i - 1][parentId]; if (parent) { if (parent.children) { parent.children.push(element); } else { parent.children = [element]; } } } }); } //最后取第一层,就是一个完整的树 if (workspace && workspace.length > 0) { return Object.keys(workspace[0]).map(c => workspace[0][c]); } else { return []; } }; const drive$2 = { normalize: (list, total) => { const normalized = list && list.reduce((prev, c) => { if (c && c.id) { prev.byId[c.id] = c; prev.workspace = buildWorkspace(prev.workspace, c); } return prev; }, { byId: {}, workspace: [] }) || { byId: {}, workspace: [] }; return { byId: normalized.byId, allIds: buildTree(normalized.workspace), total: typeof total === 'number' ? total : list.length }; }, transform: byId => { //这里为了防止出问题把byId里面的children给去掉 const normalized = Object.keys(byId || {}).reduce((workspace, id) => buildWorkspace(workspace, { ...byId[id], children: undefined }), {}); const workspace = Object.keys(normalized).map(i => normalized[i]); return buildTree(workspace); }, reduce: state => state }; const drives = {}; drives["flat"] = drive; drives["single-tree"] = drive$1; drives["multiple-tree"] = drive$2; var driver = { get: id => drives[id], clone: (id, drive) => { const dest = drives[id]; if (dest) { return { ...dest, ...drive }; } else { return null; } }, list: () => Object.keys(drives), install: (id, plugin) => drives[id] = plugin }; function create(namespace, api, option) { const { fetch, fetchPart, create, update, remove, detail } = api; const type = option && option.type || "flat"; const drive = option && option.drive || driver.get(type); if (!drive) { throw new Error(`no drive for this type [${type}]`); } const { transform, normalize, mixed } = drive; const reduce = drive.reduce; return { namespace, state: { byId: {}, allIds: [], total: 0 }, effects: { *fetch({ payload }, { call, put, select }) { if (fetch) { const response = yield call(fetch, payload); if (response && (response.code === 200 || response.code === 0)) { //TODO这个retlist是java的,以后肯定要一致 const list = response.data.list || response.data.retlist || response.data || []; const total = response.data.total || list.length; const __extra__ = mixed ? yield select(state => state) : null; yield put({ type: "onFetch", payload: { list, total, __extra__ } }); return response || true; } } return false; }, *fetchPart({ payload }, { call, put, select }) { if (fetchPart) { const response = yield call(fetchPart, payload); if (response && (response.code === 200 || response.code === 0)) { const list = response.data.list || response.data || []; const total = response.data.total; const __extra__ = mixed ? yield select(state => state) : null; yield put({ type: "onFetchPart", payload: { list, total, __extra__ } }); return response || true; } } return false; }, *create({ payload }, { call, put, select }) { if (create) { const response = yield call(create, payload); if (response && (response.code === 200 || response.code === 0)) { const data = response.data; const __extra__ = mixed ? yield select(state => state) : null; yield put({ type: "onCreate", payload: { ...payload, ...data, __extra__ } }); return response || true; } } return false; }, *update({ payload }, { call, put, select }) { if (update) { const { id, ...otherData } = payload || {}; const response = yield call(update, id || payload, otherData); if (response && (response.code === 200 || response.code === 0)) { const data = response.data; const __extra__ = mixed ? yield select(state => state) : null; yield put({ type: "onUpdate", payload: { ...payload, ...data, __extra__ } }); return response || true; } } return false; }, *remove({ payload }, { call, put, select }) { if (remove) { const id = payload && payload.id || payload; const response = yield call(remove, id); if (response && (response.code === 200 || response.code === 0)) { const __extra__ = mixed ? yield select(state => state) : null; yield put({ type: "onRemove", payload: { id: id, __extra__ }, __extra__ }); return response || true; } } return false; }, *detail({ payload }, { call, put, select }) { if (detail) { // const id = (payload && payload.id) || payload; const response = yield call(detail, payload); if (response && (response.code === 200 || response.code === 0)) { const data = response.data; const __extra__ = mixed ? yield select(state => state) : null; yield put({ type: "onUpdate", payload: data, __extra__ }); return response || true; } } return false; } }, reducers: { onFetch(state, { payload }) { const { list, total, __extra__ } = payload; const normalized = normalize(list, total); return reduce({ ...state, ...normalized }, __extra__); }, onFetchPart(state, { payload }) { const { list, total, __extra__ } = payload; function getListByTree(tree) { return tree.reduce((prev, c) => { if (c.children) { prev = prev.concat(getListByTree(c.children)); } prev = prev.concat({ ...c, children: undefined }); return prev; }, []); } const treeList = getListByTree(state.allIds); const normalized = normalize([].concat(treeList, list), total ? total : state.total + list.length); return reduce({ ...state, ...normalized }, __extra__); }, onCreate(state, { payload }) { if (payload && payload.id) { const byId = { ...state.byId, [payload.id]: payload }; const allIds = transform(byId); return reduce({ ...state, byId, allIds, total: state.total + 1 }, payload.__extra__); } else { return state; } }, onUpdate(state, { payload }) { if (payload) { if (payload.id) { const byId = { ...state.byId, [payload.id]: { ...state.byId[payload.id], ...payload } }; const allIds = transform(byId); return reduce({ ...state, byId, allIds }, payload.__extra__); } else { //如果没有ID的话给他一个固定ID(__id__) const byId = { ...state.byId, __auto_id__: { ...state.byId[payload.id], ...payload } }; const allIds = transform(byId); return reduce({ ...state, byId, allIds }, payload.__extra__); } } else { return state; } }, onRemove(state, { payload }) { if (payload && payload.id) { const byId = { ...state.byId }; delete byId[payload.id]; const allIds = transform(byId); return reduce({ ...state, byId, allIds, total: state.total - 1 }, payload.__extra__); } else { return state; } } } }; } exports.create = create; exports.driver = driver; Object.defineProperty(exports, '__esModule', { value: true }); })));