import uuid from 'uuid/v4'; import pickBy from 'lodash/pickBy'; import negate from 'lodash/negate'; import isUndefined from 'lodash/isUndefined'; import uniqueId from 'lodash/uniqueId'; import { getKeyName, parseMetas, normMetas, parseQueryResult } from '../../../utils/meta'; import { datasourceApi } from '../../../services/datasource'; const prefix = uuid(); const getSource = (property) => { if (property.source) { return (property.source.items || []).map((item) => { try { return JSON.parse(item); } catch (err) { return item; } }); } else { return []; } }; const makeProps = (meta) => { // noinspection JSUnresolvedVariable if (!meta || !meta.metas) { return {}; } const props = normMetas(meta.metas); if (!props.rowKey) { props.rowKey = getKeyName(meta); } return props; }; const getColumnIdx = (columns, name) => { return (columns || []).findIndex(column => name === column.dataIndex); }; const makeColumns = (meta) => { return (meta.properties || []) .filter(property => !property.skip) .map((property) => { // noinspection JSUnresolvedVariable const props = normMetas(property.metas); if (!props.title && props.label) { props.title = props.label; } if (props.order === undefined) { props.order = 0; } if ((props.fixed === true || props.fixed === 'left' || props.fixed === 'right') && props.width === undefined) { props.width = 150; } return pickBy({ ...props, dataIndex: property.name, key: property.name, sorter: property.sort, filterType: property.filterType, filterEnums: getSource(property), }, negate(isUndefined)); }) .filter((c) => { for (const key of Object.keys(c)) { if (key.startsWith('meta:')) { return false; } } return c.visible !== false; }) .sort((c1, c2) => { const c1Left = c1.fixed === true || c1.fixed === 'left'; const c1Right = c1.fixed === 'right'; const c2Left = c2.fixed === true || c2.fixed === 'left'; const c2Right = c2.fixed === 'right'; if (c1Left && !c2Left) { return -1; } if (!c1Left && c2Left) { return 1; } if (c1Right && !c2Right) { return 1; } if (!c1Right && c2Right) { return -1; } return c1.order - c2.order; }); }; const getSort = (columns) => { const column = (columns || []).find(c => c.sortOrder); return column ? { field: column.key, order: column.sortOrder, } : undefined; }; const modelCreator = () => { const name = 'model'; const namespace = uniqueId(prefix); const loadMeta = function* loadMeta({ select, call, put }) { const { coordinate, params } = yield select(state => state[namespace]); const api = datasourceApi(coordinate); const meta = yield call(api.queryMeta, { params }); yield put({ type: 'applyMeta', payload: meta }); }; const loadData = function* loadData({ select, put, call, start, end }) { if (start) { yield put({ type: start }); } try { const { coordinate, params, meta, columns, filters, current, pageSize } = yield select(state => state[namespace]); const api = datasourceApi(coordinate); const psz = pageSize; const pst = (current - 1) * psz; const sort = getSort(columns); const sortBys = sort ? [sort.field] : []; const sortTypes = sort ? [sort.order] : []; const options = { pst, psz, params, filters, sortBys, sortTypes }; const num = yield call(api.count, options); const dsb = yield call(api.query, options); const list = parseQueryResult(dsb, meta); yield put({ type: 'applyData', payload: { num, list } }); } finally { if (end) { yield put({ type: end }); } } }; return { name, model: { namespace, state: { coordinate: null, params: {}, meta: {}, parsedMeta: { global: { columnData: {}, rowData: {}, }, properties: {}, }, columns: [], props: {}, num: 0, list: [], filters: [], current: 1, pageSize: 10, }, reducers: { applyTarget(state, { payload: { coordinate, params } }) { return { ...state, coordinate, params, }; }, applyFilters(state, { payload: filters }) { return { ...state, filters, }; }, changeSorts(state, { payload: { field, order } }) { const idx = getColumnIdx(state.columns, field); if (idx !== -1) { const columns = [...state.columns]; for (let i = 0; i < columns.length; ++i) { if (i !== idx) { columns[i].sortOrder = false; } else { columns[i].sortOrder = order; } } return { ...state, columns, }; } else { return state; } }, applyCurrentPage(state, { payload: current }) { return { ...state, current, }; }, applyPageSize(state, { payload: pageSize }) { return { ...state, pageSize, }; }, applyMeta(state, { payload: meta }) { return { ...state, meta, parsedMeta: parseMetas(meta), props: makeProps(meta), columns: makeColumns(meta), }; }, applyData(state, { payload: { num, list } }) { return { ...state, num, list, }; }, queryMetaSuccess(state, { payload: { props, columns } }) { return { ...state, props, columns, }; }, queryCountSuccess(state, { payload: num }) { return { ...state, num, }; }, queryTasksSuccess(state, { payload: list }) { return { ...state, list, }; }, }, effects: { *doInit({ payload: { coordinate, params, current = 1, start, end } }, { put, call, select }) { yield put({ type: 'applyTarget', payload: { coordinate, params } }); yield put({ type: 'applyFilters', payload: [] }); yield put({ type: 'applyCurrentPage', payload: current }); yield call(loadMeta, { put, call, select }); yield call(loadData, { put, call, select, start, end }); }, *doFilter({ payload: filters }, { put, call, select }) { yield put({ type: 'applyFilters', payload: filters }); yield put({ type: 'applyCurrentPage', payload: 1 }); yield call(loadData, { put, call, select }); }, *doSort({ payload: { field, order } }, { put, call, select }) { yield put({ type: 'changeSorts', payload: { field, order } }); yield put({ type: 'applyCurrentPage', payload: 1 }); yield call(loadData, { put, call, select }); }, *changeCurrentPage({ payload: current }, { put, call, select }) { yield put({ type: 'applyCurrentPage', payload: current }); yield call(loadData, { put, call, select }); }, *changePageSize({ payload: pageSize }, { put, call, select }) { yield put({ type: 'applyCurrentPage', payload: 1 }); yield put({ type: 'applyPageSize', payload: pageSize }); yield call(loadData, { put, call, select }); }, // *fetchData({ payload: { coordinate, pst, psz, params, filters} }, { put, call }) { // const options = { pst, psz, params, filters }; // const api = datasourceApi(coordinate); // const meta = yield call(api.meta); // const props = makeProps(meta); // yield put({ type: 'queryMetaSuccess', payload: { props, columns: makeColumns(meta) } }); // const num = yield call(api.count, options); // yield put({ type: 'queryCountSuccess', payload: num }); // const dsb = yield call(api.query, options); // yield put({ type: 'queryTasksSuccess', payload: getArrayData(dsb, meta) }); // }, }, subscriptions: {}, }, }; }; export default modelCreator;