import React from 'react'; import { Upload, Input, Button, Select, Icon, Row, Col, message, Tag, Tooltip, Card, Divider, Switch, InputNumber, Form, } from 'antd'; import AceEditor from 'react-ace'; import 'brace/mode/javascript'; import UUID from 'react-native-uuid'; const FormItem = Form.Item; const Option = Select.Option; const types = { string: '字符', number: '数字', boolean: '布尔值', method: '公式', regexp: '正则表达式', integer: '整数', float: '浮点数', array: '列表', object: '对象', enum: '枚举', date: '日期', url: '超链接', hex: '16进制数', email: '邮箱', any: '任意', }; class Enums extends React.Component { state = { inputVisible: false, inputValue: '', }; handleClose = (removedTag) => { const tags = this.props.value.filter((tag) => tag !== removedTag); this.props.onChange(tags); }; showInput = () => { this.setState({ inputVisible: true }, () => this.input.focus()); }; handleInputChange = (e) => { this.setState({ inputValue: e.target.value }); }; handleInputConfirm = () => { const { inputValue } = this.state; let tags = this.props.value; if (inputValue && tags.indexOf(inputValue) === -1) { tags = [...tags, inputValue]; } this.setState({ inputVisible: false, inputValue: '', }); this.props.onChange(tags); }; saveInputRef = (input) => (this.input = input); render() { const { inputVisible, inputValue } = this.state; const tags = this.props.value; return ( <div> {tags.map((tag, index) => { const isLongTag = tag.length > 20; const tagElem = ( <Tag key={tag} onClose={() => this.handleClose(tag)}> {isLongTag ? `${tag.slice(0, 20)}...` : tag} </Tag> ); return isLongTag ? ( <Tooltip title={tag} key={tag}> {tagElem} </Tooltip> ) : ( tagElem ); })} {inputVisible && ( <Input ref={this.saveInputRef} type="text" size="small" style={{ width: 78 }} value={inputValue} onChange={this.handleInputChange} onBlur={this.handleInputConfirm} onPressEnter={this.handleInputConfirm} /> )} {!inputVisible && ( <Tag onClick={this.showInput} style={{ background: '#fff', borderStyle: 'dashed' }}> <Icon type="plus" /> New Tag </Tag> )} </div> ); } } export default class Validator extends React.Component { constructor(props) { super(props); const value = props.value || []; this.state = { rules: value }; } triggerChange = (changedValue) => { // Should provide an event to pass value to Form. const onChange = this.props.onChange; if (onChange) { onChange(changedValue); } }; componentWillReceiveProps(nextProps) { // Should be a controlled component. if ('value' in nextProps) { const value = nextProps.value; this.setState(value); } } change = (i, t, e) => { const { rules } = this.state; if (t == 'message' || t == 'pattern') { rules[i][t] = e.target.value; } else { rules[i][t] = e; if (t == 'type' && e == 'date') { rules[i].validatorFunc = "var errors = [];if (!( typeof value.getTime === 'function' &&typeof value.getMonth === 'function' &&typeof value.getYear === 'function')) {errors.push(new Error('请输入日期!', rule.field));} callback(errors);"; } } if (!('value' in this.props)) { this.setState({ rules }); } this.triggerChange(rules); }; add = () => { const { rules } = this.state; rules.push({ id: UUID.v4(), message: '请输入' }); if (!('value' in this.props)) { this.setState({ rules }); } this.triggerChange(rules); }; delete = (i) => { const { rules } = this.state; rules.splice(i, 1); if (!('value' in this.props)) { this.setState({ rules }); } this.triggerChange(rules); }; render() { const { rules } = this.state; return ( <div> <Button size="small" type="primary" style={{ margin: 'auto' }} onClick={this.add}> 新增 </Button> <div style={{ minHeight: 10 }}> {rules.map((r, i) => ( <div key={r.id}> <FormItem label="类型" labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}> <Select style={{ width: 150 }} onChange={this.change.bind(this, i, 'type')} value={r.type}> {Object.keys(types).map((ty) => ( <Option key={ty} value={ty}> {types[ty]} </Option> ))} </Select> </FormItem> <FormItem label="是否必填" labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}> <Switch onChange={this.change.bind(this, i, 'required')} checked={r.required} /> </FormItem> <FormItem label="正则表达式" labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}> <Input onChange={this.change.bind(this, i, 'pattern')} value={r.pattern} /> </FormItem> <FormItem label="最小值" labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}> <InputNumber onChange={this.change.bind(this, i, 'min')} value={r.min} /> </FormItem> <FormItem label="最大值" labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}> <InputNumber onChange={this.change.bind(this, i, 'max')} value={r.max} /> </FormItem> <FormItem label="长度" labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}> <InputNumber onChange={this.change.bind(this, i, 'len')} value={r.len} /> </FormItem> <FormItem label={ <span> <span style={{ color: 'red' }}> * </span> 错误提示 </span> } labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}> <Input onChange={this.change.bind(this, i, 'message')} value={r.message} /> </FormItem> <FormItem label="枚举" labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}> <Enums onChange={this.change.bind(this, i, 'enum')} value={r.enum || []} /> </FormItem> <FormItem label="自定义验证" labelCol={{ span: 24 }} wrapperCol={{ span: 24 }}> <AceEditor height={300} width="100%" onChange={this.change.bind(this, i, 'validatorFunc')} placeholder="var errors = [];\n if (value == 'xxx') { errors.push(new Error('请输入正确值!', rule.field)); } callback(errors); " mode={'javascript'} theme={'textmate'} fontSize={12} showPrintMargin={true} showGutter={true} highlightActiveLine={true} value={r.validatorFunc} name="UNIQUE_ID_OF_DIV" // keyboardHandler="vim" setOptions={{ enableBasicAutocompletion: true, enableLiveAutocompletion: true, enableSnippets: true, showLineNumbers: true, tabSize: 2, }} editorProps={{ $blockScrolling: true }} /> </FormItem> <Button type="danger" style={{ margin: 'auto' }} size="small" onClick={this.delete.bind(this, i)}> 删除 </Button> </div> ))} </div> </div> ); } }