import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { Dropdown, Button, Menu, Icon, Input, NumberPicker, Switch, Select, Radio, DatePicker } from '@alifd/next'; import { isJSExpression, generateI18n } from './locale/utils'; import Expression from './expression-setter'; import zhCN from './locale/zh-CN'; import './index.scss'; const { Group: RadioGroup } = Radio; // const isJSExpression = (obj) => { // if(typeof obj === 'object' && obj.type === 'JSExpression') { // return true; // } // return false; // } export default class Mixin extends PureComponent { static displayName = 'Mixin'; static propTypes = { locale: PropTypes.string, messages: PropTypes.object, defaultType: PropTypes.string, types: PropTypes.arrayOf(PropTypes.string), onlyChangeType: PropTypes.bool, inputProps: PropTypes.object, expressionProps: PropTypes.object, monacoEditorProps: PropTypes.object, switchProps: PropTypes.object, selectProps: PropTypes.object, radioGroupProps: PropTypes.object, }; static defaultProps = { locale: 'zh-CN', messages: zhCN, types: ['StringSetter', 'ExpressionSetter', 'NumberSetter', 'BoolSetter', 'SelectSetter', 'RadioGroupSetter'], }; constructor(props) { super(props); let type = judgeTypeHandler(props, {}); this.i18n = generateI18n(props.locale, props.messages); this.state = { preType: type, type }; } static getDerivedStateFromProps(props, state) { if ('value' in props) { let curType = judgeTypeHandler(props, state); if (curType !== state.preType) { return { type: curType }; } } return null; } changeType(type) { if (typeof type === 'object' || type === this.state.type) return; let { onlyChangeType, value, onChange } = this.props; if (onlyChangeType) { this.setState({ type }); onChange && onChange(value); } else { let newValue = undefined; if (this.typeMap[type]['props']) { if (this.typeMap[type]['props']['value'] !== undefined) { newValue = this.typeMap[type]['props']['value']; } else if (this.typeMap[type]['props']['defaultValue'] !== undefined) { newValue = this.typeMap[type]['props']['defaultValue']; } } if (type === 'BoolSetter' && newValue === undefined) { newValue = false; //给切换到switch默认值为false } this.setState({ type }); onChange && onChange(newValue); } } render() { const { style = {}, className, locale, messages, types = [], defaultType, // inputProps, // expressionProps, // monacoEditorProps, // numberPickerProps, // switchProps, // selectProps, // radioGroupProps, ...restProps } = this.props; this.typeMap = { StringSetter: { label: this.i18n('input'), component: Input, // props: inputProps }, ExpressionSetter: { label: this.i18n('expression'), component: Expression, // props: expressionProps }, // MonacoEditor: { // label: this.i18n('monacoEditor'), // component: MonacoEditor, // props: monacoEditorProps // }, NumberSetter: { label: this.i18n('numberPicker'), component: NumberPicker, }, BoolSetter: { label: this.i18n('bool'), component: Switch, }, SelectSetter: { label: this.i18n('select'), component: Select, }, RadioGroupSetter: { label: this.i18n('radio'), component: RadioGroup, }, TextAreaSetter: { label: this.i18n('textarea'), component: Input.TextArea, }, DateSetter: { label: this.i18n('date'), component: DatePicker, }, DateYearSetter: { label: this.i18n('dateYear'), component: DatePicker, }, DateMonthSetter: { label: this.i18n('dateMonth'), component: DatePicker, }, DateRangeSetter: { label: this.i18n('dateRange'), component: DatePicker, } }; let realTypes = []; types.forEach( el => { const { name, props } = el; if (this.typeMap[name]) { this.typeMap[name].props = props; realTypes.push(name); } }) let moreBtnNode = null; //如果只有2种,且有变量表达式,则直接展示变量按钮 if (realTypes.length > 1) { let isTwoType = !!(realTypes.length === 2 && ~realTypes.indexOf('ExpressionSetter')); let btnProps = { size: 'small', text: true, style: { position: 'absolute', left: '100%', top: 0, bottom: 0, margin: 'auto 0 auto 8px', padding: 0, width: 16, height: 16, lineHeight: '16px', textAlign: 'center' } }; if (isTwoType) { btnProps.onClick = this.changeType.bind(this, realTypes.indexOf(this.state.type) ? realTypes[0] : realTypes[1]); } let triggerNode = ( ); if (isTwoType) { moreBtnNode = triggerNode; } else { let MenuItems = []; realTypes.map(type => { if (this.typeMap[type]) { MenuItems.push({this.typeMap[type]['label']}); } else { console.error( this.i18n('typeError', { type }) ); } }); let MenuNode = ( {MenuItems} ); moreBtnNode = ( {MenuNode} ); } } let TargetNode = this.typeMap[this.state.type] ? this.typeMap[this.state.type]['component'] : 'div'; let targetProps = this.typeMap[this.state.type] ? this.typeMap[this.state.type]['props'] : {}; // 特殊处理Switch的值 if (['BoolSetter', 'RadioGroupSetter'].includes(this.state.type)) { restProps.checked = this.props.checked !== undefined ? this.props.checked : this.props.value; } //判断如果Mixin内部有设置onChange, 则同时触发2处onChange if (targetProps && targetProps.onChange && typeof targetProps.onChange === 'function') { let tarOnChange = targetProps.onChange; targetProps.onChange = function() { tarOnChange.apply(null, arguments); restProps.onChange && restProps.onChange.apply(null, arguments); }; } let tarStyle = { position: 'relative', ...style }; let classes = classNames(className, 'lowcode-setter-mixin'); return (
{moreBtnNode}
); } } // 判断值类型 function judgeTypeHandler(props, state) { let { defaultType, types, value } = props; let selectProps: { dataSource: any[]; }; let radioGroupProps: { dataSource: any[]; }; let typeKeys: any[] = []; types.forEach( el => { typeKeys.push(el.name); }) types.forEach((el: { name: string; props: {}; }) => { if (el.name === 'SelectSetter') {selectProps === el.props;} if (el.name === 'RadioGroupSetter') {radioGroupProps === el.props;} }) if (!defaultType || !typeKeys) return; // 如果defaultType不在typeKeys列表中,默认返回typeKeys的第一项 if (!typeKeys.includes(defaultType)) return typeKeys[0]; if (isJSExpression(value)) return 'ExpressionSetter'; if (value && typeof value === 'string') { if (~typeKeys.indexOf('SelectSetter') && selectProps && selectProps.dataSource) { let hasOption = selectProps.dataSource.some(item => { if (typeof item === 'string' && item === value) return true; if (typeof item === 'object' && item.value === value) return true; }); if (hasOption) return 'SelectSetter'; } if (~typeKeys.indexOf('RadioGroupSetter') && radioGroupProps && radioGroupProps.dataSource) { let hasOption = radioGroupProps.dataSource.some(item => { if (typeof item === 'object' && item.value === value) return true; }); if (hasOption) return 'RadioGroupSetter'; } if (~typeKeys.indexOf('StringSetter')) return 'StringSetter'; } if (typeof value === 'number') { if (~typeKeys.indexOf('SelectSetter') && selectProps && selectProps.dataSource) { let hasOption = selectProps.dataSource.some(item => { if (typeof item === 'object' && item.value === value) return true; }); if (hasOption) return 'Select'; } if (~typeKeys.indexOf('RadioGroupSetter') && radioGroupProps && radioGroupProps.dataSource) { let hasOption = radioGroupProps.dataSource.some(item => { if (typeof item === 'object' && item.value === value) return true; }); if (hasOption) return 'RadioGroupSetter'; } if (~typeKeys.indexOf('NumberSetter')) return 'NumberSetter'; } if (~typeKeys.indexOf('NumberSetter') && typeof value === 'number') return 'NumberSetter'; if (~typeKeys.indexOf('BoolSetter') && (value === false || value === true)) return 'BoolSetter'; if (Array.isArray(value)) { if (~typeKeys.indexOf('SelectSetter') && typeof value[0] === 'string') return 'SelectSetter'; } return state.type || defaultType; }