UNPKG

hc-components

Version:

基于react的通用组件库

451 lines (420 loc) 12.7 kB
import merge from 'lodash/merge'; // see: http://gitlab.alibaba-inc.com/openad/oa-ui/issues/57723 import React from 'react'; import PropTypes from 'prop-types'; function safeMerge(o, b) { for (let key in b) { if (o.hasOwnProperty(key)) { window.console.warn('存在相同属性,即将被覆盖'); } o[key] = b[key]; } return o; } function getParameters(pm, state) { const params = {}; if (pm) { pm.forEach(m => { params[m.name] = state[m.name] || m.value; }); } return params; } function getDataByStructure(ret, structure, fields) { const asyncProps = {}; const collections = []; let dataSource = ret; if (dataSource) { if (!Array.isArray(dataSource)) { dataSource = [dataSource]; } } else { dataSource = []; } for (let key in structure) { let field = structure[key]; // value: 'series[0].data if (typeof field === 'string') { field = { propName: field }; } /** * field = { * dataIndex, * propName, * // 只在对象时有效 * extend, * data, * district, * groupBy, * noLoop * } */ field.dataIndex = field.dataIndex || key; field.propName = field.propName || key; let data = []; if (field.noLoop) { // dataFilter还有这个用处 const _dataFilter = converter.parse(field.dataFilter); if (_dataFilter) { data = _dataFilter(ret, fields); } else { data = field.data || ret; } } if (field.groupBy) { const map = {}; let index = 0; dataSource.forEach(item => { if (!map[item[field.groupBy]]) { collections.push({ field: Object.assign({}, field, {propName: field.propName.replace('${x}', index++)}), data: field.noLoop ? data : [], dataMap: {} }); } map[item[field.groupBy]] = true; }); } else { collections.push({ field: field, data: data, dataMap: {} }); } } dataSource.forEach((item, index) => { collections.forEach(map => { if (map.field.noLoop) return; const value = item[map.field.dataIndex]; const _dataFilter = converter.parse(map.field.dataFilter); let newItem = item; if (_dataFilter) { newItem = _dataFilter(item, dataSource, fields, index); } else if (map.field.dataIndex) { newItem = value; } const flag = map.field.groupBy ? item[map.field.groupBy] !== undefined : true; if (flag) { if (map.field.district) { map.dataMap[value] = newItem; } else { map.data.push(newItem); } } }); }); collections.forEach(col => { let key = col.field.propName; const ks = key.split('.'); const last = ks.length - 1; let prop = asyncProps; let lastProp; ks.forEach((tmp, index) => { // xxx[x] if (tmp[tmp.length - 1] === ']') { const pos = tmp.indexOf('['); const num = tmp.slice(pos + 1, -1); const name = tmp.substr(0, pos); prop = prop[name] = prop[name] || []; // xxx[x].xx if (index < last) { if (num) { prop = prop[num] = {}; } else { const tmp = {}; prop.push(tmp); prop = tmp; } } else { // xxx[x] lastProp = prop; key = num; } } else if (index < last) { // xxx[x].xx prop = prop[tmp] = prop[tmp] || {}; } else { lastProp = prop; key = tmp; } }); let data; if (col.field.district) { data = []; for (let k in col.dataMap) { data.push(col.dataMap[k]); } } else { data = col.data; } if (Array.isArray(lastProp)) { if (key === undefined) { lastProp.push(data); } else { lastProp[key] = data; } } else { lastProp[key] = data; if (col.field.extend) { safeMerge(lastProp, col.field.extend); } } }); window.console.log(asyncProps); return asyncProps; } function dataRender(ret, structure, fields, dataFilter, dataPropName) { // 通过数据处理器返回 if (dataFilter) { ret = dataFilter(ret, fields); // 通过结构返回 } else if (structure) { ret = getDataByStructure(ret, structure, fields); // 通过赋值属性返回 } if (dataPropName) { return { [dataPropName]: ret }; } else { return ret || {}; } } function bindStateObserver(Com, props, pm, stateObserver) { if (pm || stateObserver) { let routeHelper; stateObserver = stateObserver ? [].concat(stateObserver) : []; stateObserver.forEach(({trigger, getValueFromEvent}) => { props[trigger] = (...args) => { getValueFromEvent = converter.parse(getValueFromEvent); const obj = getValueFromEvent ? getValueFromEvent.apply(undefined, args) : args[0]; routeHelper && routeHelper.setState(obj); }; }); class newCom extends Com { static contextTypes = { routeHelper: PropTypes.object } constructor(props, context) { super(props, context); routeHelper = context.routeHelper; } componentDidMount() { super.componentDidMount && super.componentDidMount(); if (pm) { this.__watcher = (nextState, prevState) => { let hasChange = false; let mastChange = true; pm.forEach(item => { // _ID_ && if (item.name[0] === '_' && item.name[item.name.length - 1] === '_') { mastChange = nextState[item.name] !== prevState[item.name]; } else { // || hasChange = hasChange || nextState[item.name] !== prevState[item.name]; } }); return mastChange && hasChange; }; this.context.routeHelper.watch(this.__watcher, (nextState) => { if (this && this.handleResolve) { this.handleResolve(nextState); } }); } } componentWillUnmount() { super.componentWillUnmount && super.componentWillUnmount(); this.context.routeHelper.unwatch(this.__watcher); } } return newCom; } else { return Com; } } function setFields(fields, elements, context) { const newFields = []; fields.forEach(item => { const _dataFilter = converter.parse(item.dataFilter); if (_dataFilter) { item = _dataFilter(item, fields, context); if (item.component) { item.Component = context.layer.findComponent(item.component); } } newFields.push(safeMerge(item, elements && elements[item.dataIndex])); }); return newFields; } const defaultLayerOptoin = {cname: 'SimpleLayer', componentType: 'custom'}; function formatLayerLoop(modules, layerOption, widgetsOption, dataQuery) { if (!layerOption) { return null; } const widgets = []; const widgetsMap = {}; widgetsOption = widgetsOption || modules; widgetsOption.forEach((item, index) => { if (typeof item === 'string') { widgetsMap[item] = {orderIndex: index, option: {}}; } else { widgetsMap[item.name] = {orderIndex: index, option: item}; } }); modules.forEach((mod) => { if (!mod.name || !widgetsMap[mod.name]) { return; } const orderIndex = widgetsMap[mod.name].orderIndex; const {layer, layout, blocks, elements, attrs, props} = widgetsMap[mod.name].option; const {name, pt, pm} = mod; const ds = mod.ds || {}; let widget; // 容器 if (pt.blocks) { widget = { layout: layout, layer: formatLayerLoop(pt.blocks, layer || defaultLayerOptoin, blocks, dataQuery) }; } else { // 组件 const fields = pt.fields; const {fieldPropName, dataPropName, structure, component, stateObserver} = pt.dataset; const dataFilter = converter.parse(pt.dataset.dataFilter); widget = component || {}; widget.key = widget.key || name; widget.contextTypes = widget.contextTypes || []; const map = {}; widget.contextTypes.forEach(t => map[t] = t); ['app', 'layer', 'hocCreator', 'routeHelper'].forEach(service => { if (map[service] === undefined) { widget.contextTypes.push(service); } }); if (!ds.data && (ds.api || pm || stateObserver)) { // 动态组件 widget.getComponent = (context, callback) => { const hasReady = widget.contextTypes.every(name => context[name]); if (hasReady) { const Com = context.layer.findComponent(widget.cname, widget.componentType); // 封装成Hoc组件,动态获取数据 const asyncProps = Object.assign({}, props); if (!asyncProps[fieldPropName] && fieldPropName && fields) { // 静态字段结构 asyncProps[fieldPropName] = setFields(fields, elements, context); } if (ds.api) { const RichCom = context.hocCreator.getRichComponent(Com, { getResolver: (state) => { state = state || context.routeHelper.state; // 发起请求 return context.app.ajax[ds.method || 'post'](ds.api, Object.assign({ structure: ds.structure, statement: ds.statement, parameters: getParameters(pm, state) }, dataQuery)).then(ret => { return dataRender(ret, structure, fields, dataFilter, dataPropName); }); }, childProps: asyncProps }); callback(null, bindStateObserver(RichCom, asyncProps, pm, stateObserver)); } else { callback(null, bindStateObserver(Com, asyncProps, pm, stateObserver), asyncProps); } } else { window.console.warn('服务丢失:' + widget.contextTypes.join(', ')); callback(null, () => (<div />)); } }; } else { const getProps = converter.parse(widget.getProps); widget.getProps = (props, context) => { const syncProps = getProps ? getProps(props, context) : {}; Object.assign(syncProps, dataRender(ds.data, structure, fields, dataFilter, dataPropName)); // 静态组件 if (!syncProps[fieldPropName] && fieldPropName && fields) { // 静态字段结构 // TODO layer syncProps[fieldPropName] = setFields(fields, elements, context); } return syncProps; }; widget.props = merge(widget.props || {}, props); } } // 把skeleton的属性和定位信息合并进来 widget.attrs = merge(widget.attrs || {}, attrs); // 是否有title if (pt.hasTitle) { if (pt.title) { widget.attrs.title = pt.title; } else { window.console.warn('title不能为空'); } } widgets[orderIndex] = widget; }); return Object.assign(layerOption, { // 组件处理 components: widgets }); } export const converter = { transform: (code) => code, stringify: (obj) => { try { if (Object(obj) === obj) { return JSON.stringify(obj, (k, v) => { if (typeof v === 'function') { return v.toString(); } else { return v; } }, 2); } else if (obj) { return obj.toString(); } } catch (e) { window.console.error(e); } }, parse: (obj) => { try { if (typeof obj === 'function') { return obj; } else if (Object(obj) === obj) { return JSON.parse(obj, (k, v) => { if (typeof v === 'string' && v.indexOf('function') === 0) { return new Function('return ' + obj)(); } else { return v; } }, 2); } else { return new Function('return ' + obj)(); } } catch (e) { window.console.error(e); } } }; export function formatLayer(pageSetting, dataQuery) { try { const {blocks, skeleton} = Object(pageSetting) === pageSetting ? pageSetting : JSON.parse(pageSetting); if (skeleton && blocks) { return { layout: skeleton.layout, layer: formatLayerLoop(blocks, skeleton.layer, skeleton.blocks, dataQuery) }; } else { return {}; } } catch (e) { window.console.error(e); } return {}; }