一、form表单
Attach.js
/** * 表单附件上传组件 * * @date 2017-07-10 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { ImagePicker } from 'antd-mobile'; import FormConfigs from './configs'; import common from '../../../configs/common'; class Attach extends React.Component { static get propTypes() { return { title: PropTypes.string, defaultValue:PropTypes.array, onValueChange: PropTypes.func, isrequired: PropTypes.number, }; } static get defaultProps() { return { defaultValue:[], isrequired:0, onValueChange: () => {}, }; } constructor(props) { super(props); const {defaultValue}=this.props; this.state = { files: defaultValue }; } onChange = (files, type, index) => { console.log(files); this.setState({ files, }); }; onAddImageClick = (e) => { //e.preventDefault(); // this.setState({ // files: this.state.files.concat({ // url: 'https://zos.alipayobjects.com/rmsportal/hqQWgTXdrlmVVYi.jpeg', // id: '3', // }), // }); }; onTabChange = (key) => { console.log(key); }; render() { const {style,placeholder,title,isrequired,defaultValue}=this.props; const { files } = this.state; return ( <div style={{ height:this.MultilineHeight, ...common.theme.borderBottomStyle, ...style, }} > { title? <div> <div style={{ ...common.theme.commonTextStyle, padding:'.3rem .2rem', fontSize:'.3rem' }} > {isrequired?'*':null}{title} </div> <div style={{ ...common.theme.borderBottomStyle, height:1, margin:'0rem .2rem' }} /> </div>:null } <div style={{ ...common.theme.commonFlexStyle, height:'100%', padding:'.2rem', }} > <ImagePicker files={files} onChange={this.onChange} onImageClick={(index, fs) => console.log(index, fs)} onAddImageClick={this.onAddImageClick} /> </div> </div> ); } } export default Attach;
AttachUpload.js
/** * 表单文本输入框组件 * * @date 2017-06-21 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { Icon} from 'antd-mobile'; import common from '../../../configs/common'; class AttachUpload extends React.Component { static get propTypes() { return { title: PropTypes.string, onValueChange: PropTypes.func, placeholder: PropTypes.string, defaultValue: PropTypes.string, isrequired: PropTypes.number, style:PropTypes.object, maxlength: PropTypes.number, }; } static get defaultProps() { return { onValueChange() {}, placeholder: '请输入', defaultValue: '', isrequired: 0, style:{}, maxlength:200 }; } constructor(props) { super(props); const {style}=this.props; this.state = { }; } componentDidMount() { const { defaultValue,onValueChange } = this.props; if (defaultValue && defaultValue !== '') { if(onValueChange) onValueChange(defaultValue); } } //渲染单行文本 returnSingleInput(){ const {style,placeholder,title,maxlength,isrequired,defaultValue,onValueChange}=this.props; return( <div style={{ ...style, }} > <div style={{ ...common.theme.commonFlexStyle, //...common.theme.borderBottomStyle, flexDirection:'row', alignItems:'center', padding:'.2rem 0rem' }} > <div style={{ ...common.theme.commonTextStyle, padding:'.3rem .2rem', fontSize:'.3rem', width:'1.5rem' }} > {isrequired?'*':null}{title} </div> <div style={{ ...common.theme.commonFlexStyle, flex:1, flexDirection:'row', justifyContent:'flex-end', alignItems:'center', position:'relative' }} > <input style={{ position:'absolute', width:'100%', height:'100%', opacity:'0', }} onChange={()=>{ console.log('dd'); }} type='file' accept="image/png,image/gif,image/jpg" /> <img style={{ width: '1.4rem', height: '1.4rem', borderRadius:'1.4rem', }} src={defaultValue} /> {/*<InputItem style={{ backgroundColor:'transparent', height:'auto', minHeight:'auto', color:'#fff', boder:'none' }} placeholder={placeholder?placeholder:'请输入'} defaultValue={defaultValue} onChange={(text)=>{ if(onValueChange) onValueChange(text); //this.setState({keyWord:text}) }} />*/} <Icon style={{ width:'.6rem', height:'.6rem', color:'#fff', justifyContent:'center' }} type='right' /> </div> </div> <div style={{ ...common.theme.borderBottomStyle, height:1, }} /> </div> ); } render() { const {style}=this.props; return( this.returnSingleInput() ); } } export default AttachUpload;
Calculate.js
/** * 表单公式计算组件 * * @date 2017-07-12 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { Text, View, } from 'react-native'; import FormConfigs from './configs'; import common from '../../../configs/common'; class TaskFormCalculate extends React.Component { static get propTypes() { return { title: PropTypes.string, currentValue: PropTypes.object, onValueChange: PropTypes.func, formulaString: PropTypes.string, }; } static get defaultProps() { return { title: '标题', onValueChange() {}, }; } constructor(props) { super(props); this.state = { value: 0, formula: {}, }; } componentDidMount() { const { formulaString, currentValue } = this.props; const json = formulaString.replace(/\'/g, '"'); const formula = JSON.parse(json); this.setState({ formula }); this._computed(formula, currentValue); } componentWillReceiveProps(nextProps) { const { currentValue } = this.props; if (currentValue._count !== nextProps.currentValue._count) { // 值改变以后根据计算公式重新计算值 this._computed(this.state.formula, nextProps.currentValue); } } // 开始计算 _computed(formula, formValue) { let value = 0; const { type, params } = formula; if (type && Array.isArray(params)) { value = this._calc(type, params, formValue); } this.setState({ value }); } // 展开公式 _calc(type, params, formValue) { let result = 0; if (Array.isArray(params)) { for (let i = 0; i < params.length; i++) { const temp = this._calc(params[i].type, params[i].params, formValue); if (i === 0) { // 第一个数为初始化值 result = temp; } else { switch (type) { case 'ADD': result += temp; break; case 'SUB': result -= temp; break; case 'MUL': result *= (temp === 0 ? 1 : temp); break; case 'DIV': result /= (temp === 0 ? 1 : temp); break; default: result = 0; break; } } } } else { switch (type) { case 'FIELD': result = this._getFieldValueFromFormValue(params, formValue); break; case 'VALUE': result = isNaN(params) ? 0 : parseFloat(params); break; default: result = 0; break; } } return result; } // 从表单中取出字段值 _getFieldValueFromFormValue (ctrlName, formValue) { let result = 0; try { if (ctrlName.indexOf(';') > 0) { // 子表列求和 const ctrlArr = ctrlName.split(';'); const tableValue = formValue[ctrlArr[0]]; if (tableValue) { for (let i = 0; i < tableValue.length; i ++) { const subTableValue = tableValue[i][ctrlArr[1]]; if (subTableValue && !isNaN(subTableValue)) { result += parseFloat(subTableValue); } } } } else { // 直接去主表值 result = parseFloat(formValue[ctrlName]); } } catch (e) { result = 0; } return isNaN(result) ? 0 : result; } // 渲染标题 renderTitle() { const { title } = this.props; return ( <View style={{ width: FormConfigs.titleWidth, justifyContent: 'center', }} > <Text style={{ fontSize: 14, color: common.theme.txtColor, }} >{title}</Text> </View> ); } render() { return ( <View style={{ width: common.size.width, height: FormConfigs.lineHeight, backgroundColor: '#ffffff', flexDirection: 'row', paddingLeft: FormConfigs.paddingLeftAndRight, paddingRight: FormConfigs.paddingLeftAndRight, alignItems: 'center', borderBottomColor: common.theme.borderColor, borderBottomWidth: 1, }} > { this.renderTitle() } <View style={{ flex: 1 }} /> <Text style={{ fontSize: 14, color: common.theme.txtColor, }}>{this.state.value}</Text> </View> ); } } export default TaskFormCalculate;
configs.js
/** * 表单设置 * * @route TaskForm * @date 2017-06-21 * @author shuwenjie<4483378@qq.com> */ const FormConfigs = { titleWidth: 80, paddingLeftAndRight: 15, lineHeight: 45, buttonHeight: 50, placeholderTextColor: 'rgba(255, 255, 255,0.5)', // 配置转换 KEYBOARD_TYPE: { DEFAULT: 'default', NUMERIC: 'numeric', }, SELECT_TYPE: { SELECT_SINGLE_PAGE: 'SELECT_SINGLE_PAGE', SELECT_YES_OR_NO: 'SELECT_YES_OR_NO', }, TEXT_TYPE: { TEXT_SINGLE_DEFAULT: 'TEXT_SINGLE_DEFAULT', // 单行普通文本 TEXT_SINGLE_NUMBER: 'TEXT_SINGLE_NUMBER', // 单行数字文本 TEXT_SINGLE_MONEY: 'TEXT_SINGLE_MONEY', // 单行金额文本 TEXT_MULTIPLE: 'TEXT_MULTIPLE', // 多行普通文本 }, OPERATE_TYPE: { START: 'start', AUDIT: 'audit', REJECT: 'reject', } }; export default FormConfigs;
DatePicker.js
/** * 表单日期选择组件 * * @date 2017-06-22 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { DatePicker,List } from 'antd-mobile'; import FormConfigs from './configs'; import common from '../../../configs/common'; import moment from 'moment'; class TaskFormDatePicker extends React.Component { static get propTypes() { return { style:PropTypes.object, mode:PropTypes.string, title: PropTypes.string, placeholder: PropTypes.string, defaultValue: PropTypes.any, onValueChange: PropTypes.func, isrequired: PropTypes.number, minDate:PropTypes.any, maxDate:PropTypes.any }; } static get defaultProps() { return { style:{}, mode:'datetime', title: '标题', placeholder: '请选择日期', defaultValue:moment(), isrequired:0, onValueChange() {}, minDate:null, maxDate:null }; } constructor(props) { super(props); this.state = { }; } componentDidMount() { const { defaultValue,mode,onValueChange } = this.props; if (defaultValue && defaultValue !== '') { switch(mode){ case 'date': if(onValueChange) onValueChange(defaultValue); break; default: break; } } } render() { const {style,isrequired,title,placeholder,onValueChange,mode,minDate,maxDate,defaultValue}=this.props; return( <div style={{ ...style, }} > <DatePicker mode={mode} title='选择日期' extra={placeholder} minDate={minDate} maxDate={maxDate} value={this.state.selectedDate?this.state.selectedDate:defaultValue} onChange={(date)=>{ switch(mode){ case 'date': this.setState({ selectedDate:date}); if(onValueChange) onValueChange(date); break; default: break; } }} > <List.Item style={{ paddingLeft:'.2rem' }} arrow="horizontal" > {isrequired?'*':null}{title} </List.Item> </DatePicker> <div style={{ ...common.theme.borderBottomStyle, height:1, }} /> </div> ); } } export default TaskFormDatePicker;
Input.js
/** * 表单文本输入框组件 * * @date 2017-06-21 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { TextareaItem,InputItem} from 'antd-mobile'; import common from '../../../configs/common'; class FormInput extends React.Component { static get propTypes() { return { type: PropTypes.string, multiline: PropTypes.bool, title: PropTypes.string, onValueChange: PropTypes.func, placeholder: PropTypes.string, defaultValue: PropTypes.string, isrequired: PropTypes.number, style:PropTypes.object, maxlength: PropTypes.number, }; } static get defaultProps() { return { type:'text', multiline: false, onValueChange() {}, placeholder: '请输入', defaultValue: '', isrequired: 0, style:{}, maxlength:200 }; } constructor(props) { super(props); const {style}=this.props; this.state = { }; this.MultilineHeight='3rem'; if(style.flex==1){ this.MultilineHeight='100%'; } } componentDidMount() { const { defaultValue,onValueChange } = this.props; if (defaultValue && defaultValue !== '') { if(onValueChange) onValueChange(defaultValue); } } //渲染单行文本 returnSingleInput(){ const {style,type,placeholder,title,maxlength,isrequired,defaultValue,onValueChange}=this.props; return( <div style={{ ...style, }} > <div style={{ height:'1rem', ...common.theme.commonFlexStyle, //...common.theme.borderBottomStyle, flexDirection:'row', alignItems:'center' }} > <div style={{ ...common.theme.commonTextStyle, padding:'.3rem .2rem', fontSize:'.3rem', width:'1.5rem' }} > {isrequired?'*':null}{title} </div> <div style={{ ...common.theme.commonFlexStyle, flex:1, }} > <InputItem style={{ backgroundColor:'transparent', height:'auto', minHeight:'auto', color:'#fff', boder:'none' }} maxLength={maxlength} type={type} placeholder={placeholder?placeholder:'请输入'} defaultValue={defaultValue} onChange={(text)=>{ if(onValueChange) onValueChange(text); //this.setState({keyWord:text}) }} /> </div> </div> <div style={{ ...common.theme.borderBottomStyle, height:1, }} /> </div> ); } //渲染多行文本 returnMultilineInput(){ const {style,placeholder,title,maxlength,isrequired,defaultValue,onValueChange}=this.props; return( <div style={{ height:this.MultilineHeight, ...common.theme.borderBottomStyle, ...style, }} > { title? <div style={{ ...common.theme.commonTextStyle, padding:'.3rem .2rem', fontSize:'.3rem' }} > {isrequired?'*':null}{title} </div> :null } { title? <div style={{ ...common.theme.borderBottomStyle, height:1, margin:'0rem .2rem' }} />:null } <div style={{ ...common.theme.commonFlexStyle, flex:1, height:'100%', padding:'.2rem', boxSizing: 'border-box' }} > <TextareaItem placeholder={placeholder} maxLength={maxlength?maxlength:200} count={maxlength?maxlength:100} style={{ width:'100%', height:'100%', minHeight:'1.5rem', backgroundColor: 'transparent', ...common.theme.commonTextStyle, border:'none' }} onChange={(text)=>{ if(onValueChange) onValueChange(text); }} defaultValue={defaultValue} /> </div> </div> ); } render() { const {multiline,style}=this.props; let returnObj=null; if(multiline) { returnObj=this.returnMultilineInput(); }else{ returnObj=this.returnSingleInput() } return( returnObj ); } } export default FormInput;
ListItem.js
/** * 下拉选择组件 * * @date 2017-08-12 * @author wuxiaoyan<408991702@qq.com> */ import React, { PropTypes } from 'react'; import { Menu,Icon } from 'antd-mobile'; import FormConfigs from './configs'; import common from '../../../configs/common'; import './ListItem.less'; class ListItem extends React.Component { static get propTypes() { return { title: PropTypes.string, onValueChange: PropTypes.func, placeholder: PropTypes.string, defaultValue:PropTypes.string || PropTypes.object, isrequired: PropTypes.number, dataSource:PropTypes.array, relationfield:PropTypes.array, }; } static get defaultProps() { return { title: '标题', onValueChange() {}, placeholder: '请选择', isrequired:0, relationfield:['value','label'] }; } constructor(props) { super(props); const { placeholder,defaultValue,onValueChange } = this.props; let state={ isShowPanel:false }; if(defaultValue) { state = {...state, value:defaultValue}; if (onValueChange && defaultValue) onValueChange(defaultValue); }else{ state = {...state, value:placeholder}; } this.state=state; } // 渲染选中值 renderValue() { const { placeholder, } = this.props; let styles={}; if(this.state.value==placeholder) { styles = { padding: 0, fontSize: '.3rem', color:FormConfigs.placeholderTextColor, textAlign:'right', }; }else{ styles = { padding: 0, fontSize: '.3rem', color:common.theme.txtColor, textAlign:'right', }; } return ( <span style={styles} >{this.state.value}</span> ); } // 渲染向右的箭头 renderIcon() { return ( <Icon style={{ color:'#fff' }} type='right' /> ); } render() { const {style,title,isrequired,defaultValue,onValueChange,dataSource,relationfield}=this.props; let dataForMenu=[]; dataSource.map((item,index)=>{ dataForMenu.push({ value:item[relationfield[0]], label:item[relationfield[1]], }); }); return ( <div style={{ ...style, }} > <div style={{ height:'1rem', ...common.theme.commonFlexStyle, flexDirection:'row', alignItems:'center' }} > <div style={{ ...common.theme.commonTextStyle, padding:'.3rem .2rem', fontSize:'.3rem', width:'1.5rem' }} > {isrequired?'*':null}{title} </div> <div style={{ ...common.theme.commonFlexStyle, flex:1, flexDirection:'row' }} onClick={()=>{ this.setState({isShowPanel:true}) }} > <div style={{ ...common.theme.commonFlexStyle, flex:1, justifyContent:'center', }} > { this.renderValue() } </div> { this.renderIcon() } </div> </div> <div style={{ ...common.theme.borderBottomStyle, height:1, }} /> { dataForMenu.length>0 && this.state.isShowPanel? <Menu style={{ position:'fixed', width:'100%', height:'100%', bottom:0, zIndex:'9999', backgroundImage:'-webkit-linear-gradient(120deg,#19194B,#30C8D3)', padding:'.3rem', boxSizing:'border-box' }} className='Menu' data={dataForMenu} level={1} onChange={(value)=>{ this.setState({isShowPanel:false}); dataSource.map((item)=>{ if(item[relationfield[0]]==value){ this.setState({value:item[relationfield[1]]}); if(onValueChange) onValueChange(item); } }); }} height={document.documentElement.clientHeight} />:null } </div> ); } } export default ListItem;
ListItem.less
.Menu{ background: red; .am-flexbox{ background: red; } }
RichText.js
/** * 表单文本输入框组件 * * @date 2017-06-21 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import common from '../../../configs/common'; class RichText extends React.Component { static get propTypes() { return { id: PropTypes.string, height:PropTypes.number }; } static get defaultProps() { return { height:200, }; } constructor(props) { super(props); const {style}=this.props; this.state = { }; } componentDidMount() { this.initEditor(); } componentWillUnmount() { // 组件卸载后,清除放入库的id UE.delEditor(this.props.id); } initEditor() { const id = this.props.id; const ueEditor = UE.getEditor(this.props.id, { toolbars:[[ "fullscreen", "source", "|", 'undo', 'redo', '|',"bold", "italic", "underline","|", 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', 'cleardoc', '|', 'rowspacingtop', 'rowspacingbottom', 'lineheight', '|', 'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|', 'directionalityltr', 'directionalityrtl', 'indent', '|', "justifyleft", "justifycenter", "justifyright", "justifyjustify", "simpleupload",'insertvideo']],wordCount:false,elementPathEnabled:false,autoHeight: false } ); const self = this; ueEditor.ready((ueditor) => { if (!ueditor) { UE.delEditor(id); self.initEditor(); } }) } render() { return( <div id={this.props.id} name="content" type="text/plain"></div> ); } } export default RichText;
SingleSelect.js
/** * 表单单选组件 * * @date 2017-06-21 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { Text, View, Switch, TouchableOpacity, Platform, DeviceEventEmitter, } from 'react-native'; import FormConfigs from './configs'; import common from '../../../configs/common'; import Ionicons from 'react-native-vector-icons/Ionicons'; import { toastShort } from '../../../utils/Toast'; import LabelGroup from '../LabelGroup'; class TaskFormSingleSelect extends React.Component { static get propTypes() { return { title: PropTypes.string, type: PropTypes.oneOf(Object.keys(FormConfigs.SELECT_TYPE)), value: PropTypes.string, placeholder: PropTypes.string, defalutValue: PropTypes.string, options: PropTypes.array, onValueChange: PropTypes.func, disabled: PropTypes.bool, dataSourceId: PropTypes.string, dataSourceType: PropTypes.string, reference: PropTypes.array, displayFieldName: PropTypes.string, displayReferName: PropTypes.string, ctrlId: PropTypes.string, rowIndex: PropTypes.number, isrequired: PropTypes.any, defaultDisplay: PropTypes.string, onSelectValueChange: PropTypes.func, }; } static get defaultProps() { return { title: '标题', type: '', value: '', placeholder: '请选择', defalutValue: '', options: [], onValueChange() {}, onSelectValueChange() {}, disabled: false, reference: [], displayFieldName: '', defaultDisplay: '', }; } constructor(props) { super(props); this.state = { val: false, display: '', current: '', reference: {}, }; } componentDidMount() { const { type, defalutValue, options } = this.props; if (type === FormConfigs.SELECT_TYPE.SELECT_YES_OR_NO && defalutValue === '1') { this.setState({ val: true }); return; } if (defalutValue !== '') { let display = ''; for (let i = 0; i < options.length; i++) { if (options[i].value === defalutValue) { display = options[i].title; } } this.setState({ display }); } } _selecting() { const { title, type, disabled, navigation, dataSourceId, dataSourceType, displayFieldName, ctrlId, rowIndex, } = this.props; if (disabled) { toastShort(`${title}不能改变`); return; } if (type === FormConfigs.SELECT_TYPE.SELECT_YES_OR_NO) { return; } // 注册一次性事件 const event = `event_${(new Date()).valueOf()}`; navigation.navigate('TaskSubmitFormSingleSelectOption', { data: { title, event, dataSourceId, dataSourceType, value: this.state.current } }); DeviceEventEmitter.addListener(event, (option, complex) => { if (option && option !== null) { const { onSelectValueChange, reference, displayReferName } = this.props; if (complex) { this.setState({ display: option.data[displayFieldName], reference: option.data, current: option.value }); const complexValue = [ { ctrlId, value: option.value, rowIndex }, { ctrlId: displayReferName, value: option.data[displayFieldName], rowIndex }, ]; for (let i = 0; i < reference.length; i++) { const refer = reference[i]; const key = refer.dataSourceId.substring(refer.dataSourceId.indexOf(';') + 1); complexValue.push({ ctrlId: refer.name, value: option.data[key], rowIndex, }); } onSelectValueChange(complexValue); } else { this.setState({ display: option.title, current: option.value, }); const complexValue = [ { ctrlId, value: option.value, rowIndex }, { ctrlId: `_display_${ctrlId}`, value: option.title, rowIndex }, ]; onSelectValueChange(complexValue); } } DeviceEventEmitter.removeCurrentListener(); }); } // 渲染标题 renderTitle() { const { title, isrequired } = this.props; const showTitle = isrequired === 1 ? `* ${title}` : title; return ( <View style={{ width: FormConfigs.titleWidth, justifyContent: 'center', }} > <Text style={{ fontSize: 14, color: common.theme.txtColor, }} >{showTitle}</Text> </View> ); } // 渲染值显示 renderValueDisplay() { const { type, placeholder, defaultDisplay } = this.props; if (type === FormConfigs.SELECT_TYPE.SELECT_YES_OR_NO) { return <View style={{ flex: 1 }} />; } let display = ''; if (defaultDisplay !== '') { display = defaultDisplay; } if (this.state.display !== '') { display = this.state.display; } return ( <View style={{ flex: 1, alignItems: 'flex-end', }} > <Text style={{ color: display && display !== '' ? common.theme.txtColor : FormConfigs.placeholderTextColor, fontSize: 14, }} >{display && display !== '' ? display : placeholder}</Text> </View> ); } // 渲染操作指示 renderOperation() { const { type, onValueChange, ctrlId, rowIndex } = this.props; if (type === FormConfigs.SELECT_TYPE.SELECT_YES_OR_NO) { return ( <View style={{ paddingLeft: 10, }} > <Switch thumbTintColor={this.state.val ? common.theme.mainColor : '#999999'} onTintColor="rgba(70, 149, 247, 0.5)" tintColor="#dddddd" value={this.state.val} onValueChange={(val) => { onValueChange(ctrlId, val ? '1' : '2', rowIndex); this.setState({ val }); }} /> </View> ); } return ( <View style={Platform.OS === 'ios' ? { paddingLeft: 10, paddingTop: 3, } : { paddingLeft: 10, }} > <Ionicons color={common.theme.txtColor} size={20} name="ios-arrow-forward" /> </View> ); } render() { const { type, reference } = this.props; const group = []; for (let i = 0; i < reference.length; i++) { const refer = reference[i]; const key = refer.dataSourceId.substring(refer.dataSourceId.indexOf(';') + 1); // const display = this.state.reference[key]; let display = ''; if (refer.defaultDisplay && refer.defaultDisplay !== '') { display = refer.defaultDisplay; } if (this.state.reference[key] && this.state.reference[key] !== '') { display = this.state.reference[key]; } group.push({ title: refer.title, info: <Text>{display}</Text>, }); } return ( <View> <TouchableOpacity style={{ width: common.size.width, height: FormConfigs.lineHeight, backgroundColor: '#ffffff', flexDirection: 'row', paddingLeft: FormConfigs.paddingLeftAndRight, paddingRight: FormConfigs.paddingLeftAndRight, alignItems: 'center', borderBottomColor: common.theme.borderColor, borderBottomWidth: 1, }} activeOpacity={type !== FormConfigs.SELECT_TYPE.SELECT_YES_OR_NO ? 0.8 : 1} onPress={this._selecting.bind(this)} > { this.renderTitle() } { this.renderValueDisplay() } { this.renderOperation() } </TouchableOpacity> {group.length > 0 ? <LabelGroup group={group} titleSize={14} rowHeight={40} noborder={true} txtColor={common.theme.txtColor} /> : null} {group.length > 0 ? <View style={{ borderBottomColor: common.theme.borderColor, borderBottomWidth: 1, }}/> : null} </View> ); } } export default TaskFormSingleSelect;
SubmitButton.js
/** * 提交表单按钮 * * @date 2017-07-11 * @author wuxiaoyan<408991702@qq.com> */ import React, { PropTypes } from 'react'; import { Button } from 'antd-mobile'; import common from '../../../configs/common'; class SubmitButton extends React.Component { // 接口属性 static get propTypes() { return { onPress: PropTypes.func, text:PropTypes.string }; } constructor(props) { super(props); // Initialize the view state this.state = { showIndex:0, }; } render() { const {onPress} = this.props; const {text} = this.props; return ( <div style={{ alignItems:'center', margin:'.2rem .5rem' }} > <Button className="btn" type="primary" onClick={(e) => { if (onPress) onPress(); }} style={{ ...common.theme.submitButtonStyle }} > {text?text:'提交'} </Button> </div> ); } } export default SubmitButton;
二、其他
BannerScroll.js
/** * 广告图轮播组件 * * @date 2017-07-08 * @author wuxiaoyan<408991702@qq.com> */ /** * 引用格式 * <BannerScroll height={200} navigation={navigation} dataList={}/> */ /** * 配置格式 * dataList:[ { url:'SystemLogin', //跳转链接 选填 默认30 path:require('../../images/index/u84.jpg') } ] */ import React,{PropTypes} from 'react'; import { Image, TouchableOpacity } from 'react-native'; import ViewPager from 'react-native-viewpager'; import common from '../../configs/common'; class BannerScroll extends React.Component { // injection reduer object and other params static get propTypes() { return { dataList: PropTypes.array, height: PropTypes.number, }; } constructor(props) { super(props); this.renderPage = this.renderPage.bind(this); this.bannerImgClick = this.bannerImgClick.bind(this); let dataSource=new ViewPager.DataSource({ pageHasChanged:(p1,p2)=> p1!==p2, }); // Initialize the view state this.state = { dataSource:dataSource.cloneWithPages(this.props.dataList) }; } //渲染单张轮播图 renderPage(data,pageID){ let url=data?data.url:''; if(data.url){ return( <TouchableOpacity style={{ flex: 1, width:common.size.width, height:this.props.height, }} onPress={this.bannerImgClick.bind(this, url)} > <Image source={data.path} style={{ width:common.size.width, flex:1, height:this.props.height, resizeMode:'stretch' }} /> </TouchableOpacity> ); }else{ return( <Image source={data.path} style={{ width:common.size.width, flex:1, height:this.props.height, resizeMode:'stretch' }} /> ); } } //图片点击事件 bannerImgClick(url){ const {navigation} = this.props; navigation.navigate(url); } render() { return ( <ViewPager style={{height:this.props.height}} dataSource={this.state.dataSource} renderPage={this.renderPage} isLoop={true} autoPlay={true}/> ); } } // export redux component export default BannerScroll;
Calendar.js
/** * 日历组件 * * @date 2017-08-10 * @author wuxiaoyan<408991702@qq.com> */ import React from 'react' import {render} from 'react-dom' import CalendarHeader from './CalendarHeader' import CalendarMain from './CalendarMain' const displayDaysPerMonth = (year)=> { //定义每个月的天数,如果是闰年第二月改为29天 let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) { daysInMonth[1] = 29 } //以下为了获取一年中每一个月在日历选择器上显示的数据, //从上个月开始,接着是当月,最后是下个月开头的几天 //定义一个数组,保存上一个月的天数 let daysInPreviousMonth = [].concat(daysInMonth) daysInPreviousMonth.unshift(daysInPreviousMonth.pop()) //获取每一个月显示数据中需要补足上个月的天数 let addDaysFromPreMonth = new Array(12) .fill(null) .map((item, index)=> { let day = new Date(year, index, 1).getDay() if (day === 0) { return 6 } else { return day } }) //已数组形式返回一年中每个月的显示数据,每个数据为6行*7天 return new Array(12) .fill([]) .map((month, monthIndex)=> { let addDays = addDaysFromPreMonth[monthIndex], daysCount = daysInMonth[monthIndex], daysCountPrevious = daysInPreviousMonth[monthIndex], monthData = [] //补足上一个月 for (; addDays > 0; addDays--) { monthData.unshift(daysCountPrevious--) } //添入当前月 for (let i = 0; i < daysCount;) { monthData.push(++i) } //补足下一个月 for (let i = 42 - monthData.length, j = 0; j < i;) { monthData.push(++j) } return monthData }) } class Calendar extends React.Component { constructor() { //继承React.Component super() let now = new Date() this.state = { year: now.getFullYear(), month: now.getMonth(), day: now.getDate(), //picked: false } } componentDidMount() { this.datePick(new Date().getDate()); } //切换到下一个月 nextMonth() { if (this.state.month === 11) { this.setState({ year: ++this.state.year, month: 0 }) } else { this.setState({ month: ++this.state.month }) } } //切换到上一个月 prevMonth() { if (this.state.month === 0) { this.setState({ year: --this.state.year, month: 11 }) } else { this.setState({ month: --this.state.month }) } } //选择日期 datePick(day) { const {onValueChange}=this.props; this.setState({day},()=>{ if(onValueChange) onValueChange(this.state.year,this.state.month,this.state.day); }); } //标记日期已经选择 picked() { this.state.picked = true } render() { let props = { viewData: displayDaysPerMonth(this.state.year), datePicked: `${this.state.year} 年 ${this.state.month + 1} 月 ${this.state.day} 日` } const {style}=this.props; return ( <div style={{ ...style, color:'#fff' }} ref="main" > <CalendarHeader prevMonth={::this.prevMonth} nextMonth={::this.nextMonth} year={this.state.year} month={this.state.month} day={this.state.day}/> <CalendarMain {...props} prevMonth={::this.prevMonth} nextMonth={::this.nextMonth} datePick={::this.datePick} year={this.state.year} month={this.state.month} day={this.state.day}/> </div> ) } } //将calender实例添加到window上以便获取日期选择数据 export default Calendar;
CalendarHeader.js
import React from 'react' export default class CalendarHeader extends React.Component { render() { return ( <div style={{ display:'flex', flexDirection:'row', alignItems:'center', height:'.8rem' }} > <div style={{ display:'flex', width:'1rem', justifyContent:'center', fontSize:'.4rem' }} onClick={this.props.prevMonth} > < </div> <div style={{ display:'flex', flex:1, justifyContent:'center', fontSize:'.3rem' }} > {this.props.year}年{this.props.month + 1}月 </div> <div style={{ display:'flex', width:'1rem', justifyContent:'center', fontSize:'.4rem' }} onClick={this.props.nextMonth} > > </div> </div> ) } }
CalendarMain.js
import React from 'react' export default class CalendarMain extends React.Component { //处理日期选择事件,如果是当月,触发日期选择;如果不是当月,切换月份 handleDatePick(index, styleName) { switch (styleName) { case 'thisMonth': let month = this.props.viewData[this.props.month] this.props.datePick(month[index]) break case 'prevMonth': this.props.prevMonth() break case 'nextMonth': this.props.nextMonth() break } } //处理选择时选中的样式效果 //利用闭包保存上一次选择的元素, //在月份切换和重新选择日期时重置上一次选择的元素的样式 changeColor() { let previousEl = null return function (event) { let name = event.target.nodeName.toLocaleLowerCase() if (previousEl && (name === 'i' || name === 'td')) { previousEl.style = '' } if (event.target.className === 'thisMonth') { event.target.style = 'background:#F8F8F8;color:#000' previousEl = event.target } } } //绑定颜色改变事件 componentDidMount() { // let changeColor = this.changeColor() // document.getElementById('calendarContainer') // .addEventListener('click', changeColor, false); } render() { //确定当前月数据中每一天所属的月份,以此赋予不同className let month = this.props.viewData[this.props.month], rowsInMonth = [], i = 0, styleOfDays = (()=> { let i = month.indexOf(1), j = month.indexOf(1, i + 1), arr = new Array(42) arr.fill('prevMonth', 0, i) arr.fill('thisMonth', i, j) arr.fill('nextMonth', j) return arr })() //把每一个月的显示数据以7天为一组等分 month.forEach((day, index)=> { if (index % 7 === 0) { rowsInMonth.push(month.slice(index, index + 7)) } }) return ( <table style={{ width:'100%' }} > <thead> <tr style={{ lineHeight:'.6rem' }} > <th style={{ fontSize:'.25rem' }} > 日 </th> <th style={{ fontSize:'.25rem' }} >一</th> <th style={{ fontSize:'.25rem' }} >二</th> <th style={{ fontSize:'.25rem' }} >三</th> <th style={{ fontSize:'.25rem' }} >四</th> <th style={{ fontSize:'.25rem' }} >五</th> <th style={{ fontSize:'.25rem' }} >六</th> </tr> </thead> <tbody> { rowsInMonth.map((row, rowIndex)=> { return ( <tr key={rowIndex}> { row.map((day)=> { let tdStyle={}; if(this.props.day==day && styleOfDays[i]=='thisMonth'){ tdStyle={ backgroundColor:'#11ACE9' }; } if(styleOfDays[i]!='thisMonth'){ tdStyle={ backgroundColor:'rgba(40,40,40,0.1)', color:'rgba(180,180,180,1)' }; } return ( <td style={{ backgroundColor:'rgba(255,255,255,0.1)', textAlign:'center', lineHeight:'.8rem', fontSize:'.25rem', ...tdStyle }} onClick={ this.handleDatePick.bind (this, i, styleOfDays[i])} key={i++}> {day} </td> ) }) } </tr> ) }) } </tbody> </table> ) } }
detailsLay.js
import React, {PropTypes} from 'react' import {connect} from 'react-redux' import {link, hushHistory} from 'react-router' import ReactDOM from 'react-dom' import { Table, Input, Icon, Button, Popconfirm, Row, Col, Select, DatePicker } from 'antd' export default function creatRow12(option) { const Option = option return (<Row style={{marginBottom: '40px'}}> <Col span={12} style={{display: 'flex'}}> <div style={{lineHeight:'.55rem', fontWeight:'bold',width:'15%',textAlign:'right'}}> {Option.leftTitle} </div> {creatLeft(Option)} </Col> <Col span={12} style={{display: 'flex'}}> <div style={{lineHeight:'.55rem', fontWeight:'bold',width:'15%',textAlign:'right'}}> {Option.rightTitle} </div> {creatRight(Option)} </Col> </Row>) } var a = { leftType: 'select', leftMust: false, rightType: 'input', rightMust: false, selectMap: [], leftTitle: 'aaa', rightTitle: 'bbb' } //左侧栅格渲染 function creatLeft(option) { function handleChange(value) { console.log(`selected ${value}`); } function onChange(date, dateString) { console.log(date, dateString); } if (option.leftType && option.leftType == 'select') { if (option.selectMap && option.selectMap.length > 0) { return creatSelect(option.selectMap) } } else if (option.leftType && option.leftType == 'input') { return creatInput(option) } else if (option.leftType && option.leftType == 'date') { return creatDate() } } //右侧栅格渲染 function creatRight(option) { function handleChange(value) { console.log(`selected ${value}`); } function onChange(date, dateString) { console.log(date, dateString); } if (option.rightType && option.rightType == 'select') { if (option.selectMap && option.selectMap.length > 0) { return creatSelect(option.selectMap) } } else if (option.rightType && option.rightType == 'input') { return creatInput(option) } else if (option.rightType && option.rightType == 'date') { return creatDate() } } //渲染下拉选择框 function creatSelect(map) { function handleChange(value) { console.log(`selected ${value}`); } if (map && map.length > 0) { let arr = [] for(let i of map) { arr.push(<Select.Option key={i} value={i} style={{}}>{i}</Select.Option>) } return ( <Select defaultValue={map[0]} style={{ width: '60%', marginLeft: '20px'}} onChange={handleChange}> {arr.map((item)=>{return(item);})} </Select> ) } } //渲染输入框 function creatInput(option) { return (<Input placeholder="" style={{width: '60%',marginLeft: '20px'}} disabled={true} placeholder={option.leftTitle}/>) } //渲染双输入框 function dobulInput() { return ( <div> <Input placeholder="" style={{width: '60%',height:40,marginLeft: '20px'}}/>到 <Input placeholder="" style={{width: '60%',height:40,marginLeft: '20px'}}/> </div> ) } //渲染日期选择框 function creatDate() { function onChange(date, dateString) { console.log(date, dateString); } return ( <div style={{marginLeft: '20px'}}> <DatePicker onChange={onChange} /> 到 <DatePicker onChange={onChange} /> </div> ) }
FunNavigation.js
/** * 功能列表组件 * * @date 2017-07-08 * @author wuxiaoyan<408991702@qq.com> */ /** * 引用格式 * <FunNavigation navigation={} funNavigateCon={}/> */ /** * 配置格式 * funNavigateCon:{ rowNum:4,//一行展示几个 选填 默认4 imgSize:40,//图片大小 选填 默认30 textStyle:{//文字样式 选填 fontSize:12, color:common.theme.txtColor }, list:[//必填 { name:'水费', icon:require('../../images/index/u162.png'), url:'SystemAgreement', backgroundColor:'#7AC00D' } ] } */ import React,{PropTypes} from 'react'; import { Image, View, Text, TouchableOpacity } from 'react-native'; import common from '../../configs/common'; class FunNavigation extends React.Component { // injection reduer object and other params static get propTypes() { return { funNavigateCon: PropTypes.object, }; } constructor(props) { super(props); // Initialize the view state this.state = { }; } //渲染单个图标 renderFunNavigateItem(item,index){ let rowNum=this.props.funNavigateCon.rowNum?this.props.funNavigateCon.rowNum:4; const {navigation} = this.props; return( <TouchableOpacity key={'item'+index} onPress={()=>navigation.navigate(...item.url)} > <View style={{ alignItems:'center', justifyContent:'center', //width:(common.size.width-(common.size.width-(this.props.funNavigateCon.imgSize?this.props.funNavigateCon.imgSize:30+10)*rowNum)/(rowNum+1))/rowNum, width:common.size.width/(rowNum), marginBottom:10, }} > <View style={{ backgroundColor:item.backgroundColor, borderRadius:8, padding:5, alignItems:'center', justifyContent:'center', marginBottom:5 }}> <Image source={item.icon} style={{ width:this.props.funNavigateCon.imgSize?this.props.funNavigateCon.imgSize:30, height:this.props.funNavigateCon.imgSize?this.props.funNavigateCon.imgSize:30 }} /> </View> <Text style={{ alignItems:'center', justifyContent:'center', fontSize:12, color:'#333333', ...this.props.funNavigateCon.textStyle }}> {item.name} </Text> </View> </TouchableOpacity> ); } render() { return( <View style={{ flexDirection:'row', flexWrap:'wrap', alignItems:'center', backgroundColor:'#fff', justifyContent:'center', width:common.size.width, paddingTop:10, paddingBottom:10 }} > { this.props.funNavigateCon.list.map((item,index) => this.renderFunNavigateItem(item,index) ) } </View> ); } } // export redux component export default FunNavigation;
LabelGroup.js
/** * 文本标签组 * * @date 2017-05-24 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { Link } from 'react-router'; import { Icon } from 'antd-mobile'; import common from '../../configs/common'; class Label extends React.Component { // 接口属性 static get propTypes() { return { style: PropTypes.object, group: PropTypes.array, rowHeight: PropTypes.number, titleSize: PropTypes.number, arrowForwardIconSize: PropTypes.number, }; } static get defaultProps() { return { rowHeight: 50, titleSize: 14, arrowForwardIconSize: common.size.arrowForwardIconSize, }; } render() { const { group, style, rowHeight, titleSize, } = this.props; return ( <div style={{ backgroundColor: common.theme.mainColor, ...style }} > {group.map((item, index) => { const { icon, imageSource, title, onPress, info, navigation } = item; return ( <div key={index} style={{ height: '1rem', }} onClick={() => { if (onPress) onPress(() => { }); }} > <div style={{ display:'flex', height: '1rem', flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start', }} > {imageSource ? <div style={{ display:'flex', width: '.5rem', height: '.5rem', marginLeft:'.2rem', }} > <img style={{ width: '.5rem', height: '.5rem' }} src={imageSource} /> </div> : null} { info? <div style={{ display:'flex', width: '2rem', marginLeft:'.2rem', alignItems: 'center', justifyContent: 'flex-start', textAlign:'left', ...common.theme.commonTextStyle, fontSize:'.3rem' }} > {title} </div>: <div style={{ display:'flex', flex: 1, marginLeft:'.2rem', alignItems: 'center', justifyContent: 'flex-start', textAlign:'left', ...common.theme.commonTextStyle, fontSize:'.3rem' }} > {title} </div> } { info? <div style={{ ...common.theme.commonFlexStyle, ...common.theme.commonTextStyle, flex: 1, paddingRight: '.2rem', alignItems: 'flex-end', justifyContent: 'flex-end', fontSize:'.3rem', color: 'rgba(255, 255, 255,.7)' }} > {info} </div> : <div style={{ ...common.theme.commonFlexStyle, ...common.theme.commonTextStyle, paddingRight: '.2rem', alignItems: 'flex-end', justifyContent: 'flex-end', fontSize:'.3rem' }} > <Icon style={{ fontSize:'.3rem' }} type="right" color="#fff" /> </div> } </div> {group.length > index + 1 ? <div style={{ float:'flex', height: 1, marginLeft: 20, marginRight:20, backgroundColor: common.theme.borderColor, }} /> : null} </div> ); })} </div> ); } } export default Label;
Loading.js
/** * 数据交互提示框 * * @date 2017-06-01 * @author shuwenjie<4483378@qq.com> */ import React from 'react'; import { Icon } from 'antd'; import common from '../../configs/common'; const SIZES = ['small', 'large']; class Loading extends React.Component { // 接口属性 static get propTypes() { return { visible: React.PropTypes.bool, color: React.PropTypes.string, size: React.PropTypes.oneOf(SIZES), overlayColor: React.PropTypes.string, onRequestClose: React.PropTypes.func, loadTip: React.PropTypes.string, }; } static get defaultProps() { return { visible: false, color: 'white', size: 'large', overlayColor: 'transparent', onRequestClose() {}, loadTip: '数据加载中...' }; } render() { const {visible,loadTip}=this.props; let obj=null; if(visible) { obj=<div style={{ ...common.theme.commonFlexStyle, flex: 1, backgroundColor: 'transparent', position: 'absolute', top: 0, bottom: 0, left: 0, right: 0, alignItems: 'center', justifyContent: 'center', zIndex:'99999' }} > <div style={{ ...common.theme.commonFlexStyle, alignItems: 'center', justifyContent: 'center', width: '3rem', height: '3rem', borderRadius: '.1rem', backgroundColor: 'rgba(0, 0, 0, 1)' }} > <Icon type="loading" /> <p style={{ marginTop: '.2rem', textAlign: 'center', ...common.theme.commonTextStyle }} > {loadTip} </p> </div> </div>; } return ( obj ); } } export default Loading;
NavBar.js
/** * 文本标签组 * * @date 2017-05-24 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { NavBar } from 'antd-mobile'; import { hashHistory } from 'react-router'; import common from '../../configs/common'; class NavBarControl extends React.Component { static get propTypes() { return { goBack: PropTypes.string, title: PropTypes.string, }; } render() { const {goBack,title}=this.props; document.title=title; return ( // <NavBar // mode='dark' // style={{ // backgroundColor:'rgba(255, 255, 255,0.1)', // ...common.theme.borderBottomStyle // }} // onLeftClick={() => { // if(goBack) // { // hashHistory.push(goBack); // } // else{ // window.history.go(-1); // } // }} // > // {title} // </NavBar> null ); } } export default NavBarControl;
NoticeScroll.js
/** * 通知公告上下滚动组件 * * @date 2017-07-10 * @author wuxiaoyan<408991702@qq.com> */ /** * 引用格式 * <NoticeScroll navigation={} NoticeScrollList={}/> */ /** * 配置格式 * NoticeScrollList:[ { url:'SystemRegister', text:'各位业主,车辆请停到车位上,不能在小区门口随位上,不能在小区门口随' }, { url:'SystemRegister', text:'1各位业主,车辆请停到车位上,不能在小区门口随位上,不能在小区门口随' } ] */ import React,{PropTypes} from 'react'; import { Text, TouchableOpacity } from 'react-native'; import common from '../../configs/common'; class NoticeScroll extends React.Component { // injection reduer object and other params static get propTypes() { return { NoticeScrollList: PropTypes.array, }; } constructor(props) { super(props); // Initialize the view state this.state = { showIndex:0, }; } componentWillMount(){ let showIndex=this.state.showIndex; this.timer = setInterval(() => { if(showIndex>=this.props.NoticeScrollList.length-1) { showIndex=0; }else{ showIndex=showIndex+1; } this.setState({showIndex:showIndex}); }, 3000 ); } componentWillUnmount() { this.timer && clearTimeout(this.timer); } render() { return( <TouchableOpacity onPress={()=>{ const {navigation} = this.props; navigation.navigate(this.props.NoticeScrollList[this.state.showIndex].url); }} > <Text style={{ fontSize:12, color:common.theme.txtColor, }} numberOfLines={1} > {this.props.NoticeScrollList[this.state.showIndex].text} </Text> </TouchableOpacity> ); } } // export redux component export default NoticeScroll;
PagerListTree.js
/** * 数据列表组件 * * @date 2017-06-12 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { Table,Pagination, Row,Col } from 'antd' import common from '../../configs/common'; import Loading from './Loading'; export default class PagerListView extends React.Component { static get propTypes() { return { pager: PropTypes.array, columns: PropTypes.array, childrenKey:PropTypes.string, rowSelection:PropTypes.object }; } constructor(props) { super(props); this.state = { }; } componentWillUnmount() { } changeChild(data){ const { childrenKey } = this.props; data.map((item)=>{ item.key=item.id; if(item[childrenKey] && item[childrenKey].length==0){ delete item[childrenKey]; } if(item[childrenKey] && !item.children){ item.children=item[childrenKey]; delete item[childrenKey]; if (item.children.length>0 && item.children[0][childrenKey]) { this.changeChild(item.children); } } }) } // 渲染项目列表 renderListContent() { const { pager,columns,rowSelection } = this.props; // 加载中 if (pager === null) { return ( <Loading visible={true}/> ); } let productType=pager; this.changeChild(productType); // 正常显示数据 return ( rowSelection? <Table bordered dataSource={productType} rowSelection={rowSelection} pagination={false} columns={columns} />: <Table bordered dataSource={productType} pagination={false} columns={columns} /> ); } render() { return this.renderListContent(); } }
PagerListView.css
.am-list-body{ background: transparent; border-top:none; } .am-list-body:after{display: none}
PagerListView.js
/** * 数据列表组件 * * @date 2017-06-12 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { Table,Pagination, Row,Col } from 'antd' import common from '../../configs/common'; import Loading from './Loading'; import style from './PagerListView.css'; let canLoadMore; let loadMoreTime = 0; export default class PagerListView extends React.Component { static get propTypes() { return { pager: PropTypes.object, onPage: PropTypes.func, columns: PropTypes.array, }; } constructor(props) { super(props); this.state = { }; } componentWillReceiveProps(nextProps) { const {pager}=this.props; } componentWillUnmount() { } // 渲染项目列表 renderListContent() { const { pager,onPage,columns } = this.props; // 加载中 if (pager.data === null || pager.initing) { return ( <Loading visible={true}/> ); } // 正常显示数据 return ( <div> <Table bordered dataSource={pager.data} pagination={false} columns={columns} /> <Row key="4" style={{marginTop:15}}> <Col span={4}> 共<span>{pager.total}</span>条 </Col> <Col span={20} style={{textAlign:'right'}}> <Pagination showQuickJumper showSizeChanger className="antd-page" current={pager.pageNum+1} total={pager.total} pageSize={pager.pageSize} onChange={pageNo => { pager.setPageNum(pageNo-1); if (onPage){ onPage() } }} onShowSizeChange={(n,pageSize) => { pager.setpageSize(pageSize); if (onPage){ onPage() } }} /> </Col> </Row> </div> ); } render() { return this.renderListContent(); } }
PageTitle.js
/** * 页面标题组件 * * @date 2017-10-12 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import common from '../../configs/common'; export default class PageTitle extends React.Component { static get propTypes() { return { title: PropTypes.string }; } constructor(props) { super(props); this.state = { }; } render() { const { title } = this.props; return ( <div style={{ height: '45px', lineHeight: '45px', fontSize: 16, borderBottom: '1px solid #ddd', marginBottom: '10px', color:'#333' }} > {title} </div> ); } }
SearchBar.css
.am-list-item.am-input-item:after{display: none;}
.am-list-item .am-input-control input{color: #fff}
SearchBar.js
/** * 文本标签组 * * @date 2017-05-24 * @author shuwenjie<4483378@qq.com> */ import React, { PropTypes } from 'react'; import { Link } from 'react-router'; import { Input,Button } from 'antd'; import common from '../../configs/common'; class SearchBar extends React.Component { // 接口属性 static get propTypes() { return { group: PropTypes.array, buttons:PropTypes.any, }; } render() { const { group,buttons } = this.props; return ( <div style={{ marginTop: 15 }} > { group? group.map((item,index)=>{ const {title,type,key}=item; switch(type){ case 'input': return( <div key={index} style={{ display:'inline-block', marginBottom: 15, }} > <label style={{padding:'0 10px 0 20px'}}>{title}</label><Input placeholder='请输入' style={{width:220}}/> </div> ) default: return null } }) :null } { group? <Button style={{ marginLeft: 15, marginBottom: 15, }} type="primary" size='large' > 查询 </Button>:null } { buttons?buttons:null } </div> ); } } export default SearchBar;
SendVerificationCode.js
/** * 发送验证码组件 * * @date 2017-07-08 * @author wuxiaoyan<408991702@qq.com> */ import React,{PropTypes} from 'react'; import { Text, TouchableOpacity } from 'react-native'; import common from '../../configs/common'; import utils from '../../utils/Index'; import * as signinAction from '../../store/actions/signin'; class SendVerificationCode extends React.Component { // injection reduer object and other params static get propTypes() { return { telPhone: PropTypes.string, }; } constructor(props) { super(props); // Initialize the view state this.state = { text:'获得验证码', intervalTime:60, tempText:'获得验证码', disable:false, sendUrl:'' }; } componentWillUnmount() { this.timer && clearTimeout(this.timer); } //点击按钮发送操作 sendCode(){ if(this.state.disable==false) { const { dispatch,telPhone } = this.props; if(!telPhone || typeof(telPhone)==undefined) { utils.toastShort('请输入手机号'); return false; } if(!(/^1[34578]\d{9}$/.test(telPhone))) { utils.toastShort('手机号格式有误,请重新输入'); return false; } this.setState({disable:true}); dispatch(signinAction.requestSigninSendSMSCode(telPhone)); let thisObj=this; let t=thisObj.state.intervalTime; this.timer = setInterval( () => { if(t==0) { thisObj.setState({tempText:thisObj.state.text}); this.setState({disable:false}); clearInterval(this.timer); }else{ thisObj.setState({tempText:t+'秒'}); t--; } }, 1000 ); } } render() { return ( <TouchableOpacity style={{ justifyContent: 'center', alignItems: 'center' }} disable={this.state.disable} activeOpacity={0.8} onPress={() => this.sendCode()} > <Text style={{ ...common.theme.commonTextStyle }} > {this.state.tempText} </Text> </TouchableOpacity> ); } } // export redux component export default SendVerificationCode;
StarList.js
/** * 星星评价组件 * * @date 2017-07-08 * @author wuxiaoyan<408991702@qq.com> */ /** * 引用格式 * <StarList praiseStar={0} //必填 实心星星的个数 size={20} //选填 星星的大小 onPress={(text) => this.setState({star: text})} //选填 点击星星的回调 /> */ import React,{PropTypes} from 'react'; import { Icon } from 'antd-mobile'; import common from '../../configs/common'; class StarList extends React.Component { // injection reduer object and other params static get propTypes() { return { praiseStar: PropTypes.number, onPress:PropTypes.func, size:PropTypes.number, }; } constructor(props) { super(props); // Initialize the view state this.state = { giveStar:0 }; } render() { let {praiseStar}=this.props; let {onPress}=this.props; let {size}=this.props; let res = []; for(var i = 0; i < 5; i++) { let tempI=i+1; res.push( <div key={'star'+(i+1)} style={{ ...common.theme.commonFlexStyle, flex:1, justifyContent:'center', alignItems:'center', }} onClick={()=>{ if(onPress){ this.setState({giveStar: tempI}); onPress(tempI); } }} > { onPress? <Icon type='star' size='sm' color={((!onPress &&i<praiseStar) || (onPress&& i< this.state.giveStar))?common.theme.starColor:common.theme.grayColor} /> : <Icon type='star' size='sm' color={i<praiseStar ?common.theme.starColor:common.theme.grayColor} /> } </div> ); } return ( <div style={{ ...common.theme.commonFlexStyle, flexDirection:'row' }}> {res} </div> ); } } // export redux component export default StarList;
三、config
api.js
/** * 数据交互配置 * * @date 2017-06-09 * @author shuwenjie<4483378@qq.com> */ import { Link,hashHistory } from 'react-router'; import {toastShort} from '../utils/Toast'; const api = { /** * 中南服务器 */ HOST: '/', SOCKETHOST: 'ws://192.168.10.120:8082/', RESOURCES: 'https://zn.ijianjian.cn/pmc/resources/', /** * URI 列表 */ //首页 URI_SYSTEM_LOGIN: 'repair-master/login',// URI_SYSTEM_ENGINEER_LOGIN: 'repair-master/user/repair_engineer/bind_wx_openid',// URI_SYSTEM_MESSAGE: 'data/URI_SYSTEM_MESSAGE.json', URI_SYSTEM_MESSAGE_DETAIL: 'data/URI_SYSTEM_MESSAGE_DETAIL.json', URI_SYSTEM_MAINTAIN_HOMEDATA:'data/URI_SYSTEM_MAINTAIN_HOMEDATA.json', URI_SYSTEM_NissinSystemMain: 'data/URI_SYSTEM_NissinSystemMain.json', URI_SYSTEM_EXPLORATIONBUSINESS: 'data/URI_SYSTEM_EXPLORATIONBUSINESS.json', URI_SYSTEM_KNOWLEDGEBASE: 'data/URI_SYSTEM_KNOWLEDGEBASE.json', URI_SYSTEM_KNOWLEDGEBASEDETAIL: 'data/URI_SYSTEM_KNOWLEDGEBASEDETAIL.json', URI_SYSTEM_COLLECT:'data/URI_SYSTEM_COLLECT.json', URI_SYSTEM_EXPLORATION_PIC:'data/URI_SYSTEM_EXPLORATION_PIC.json', URI_SYSTEM_CUSTOMER_HOMEDATE:'data/URI_SYSTEM_CUSTOMER_HOMEDATE.json', URI_SYSTEM_SENG_ACCOUNT:'data/URI_SYSTEM_SENG_ACCOUNT.json', URI_SYSTEM_SEND_VERIFICATIONCODE:'data/URI_SYSTEM_SEND_VERIFICATIONCODE.json', URI_SYSTEM_CHECK_ACCOUNT:'data/URI_SYSTEM_CHECK_ACCOUNT.json', URI_SYSTEM_MODIFY_ACCOUNT_PASSWORD:'data/URI_SYSTEM_MODIFY_ACCOUNT_PASSWORD.json', //客户相关 URI_CUSTOMER_CUSTOMER_LIST:'data/URI_CUSTOMER_CUSTOMER_LIST.json', URI_NEWS_NEWS_LIST: 'data/URI_NEWS_NEWS_LIST.json', //订单 URI_ORDER_PRODUCT_TYPE: 'repair-master/product/system',//'data/URI_ORDER_PRODUCT_TYPE.json',//系统列表 URI_ORDER_PRODUCT_LIST: 'repair-master/product/product/page_by_product_group',//data/URI_ORDER_PRODUCT_LIST.json',//关键字查产品 URI_ORDER_PRODUCT_VERSION:'repair-master/product/product_type/list_by_product',//data/URI_ORDER_PRODUCT_VERSION.json',//查产品类型 URI_ORDER_PRODUCT_PROJECT:'repair-master/product/product/page_by_product_group_and_project_name',//根据项目名进行查询 URI_ORDER_PRODUCT_COMPANY:'repair-master/product/product/page_by_product_group_and_company_name',//根据公司名进行查询 URI_ORDER_PRODUCTINFO_PAGE:'repair-master/product/product/product_and_info',//根基id查询产品详情信息 URI_ORDER_PRODUCT_NUMBER:'repair-master/product/product/page_by_product_group_and_number',//根据物料编码进行查询 URI_ORDER_CREATE_ORDER: 'data/URI_ORDER_CREATE_ORDER.json', //URI_ORDER_ORDER_LIST: 'data/URI_ORDER_ORDER_LIST.json',//客户端订单列表 URI_ORDER_ORDER_LIST: 'data/URI_ORDER_ORDER_LIST1.json',//维修师端订单列表 URI_ORDER_ORDER_DETAIL: 'data/URI_ORDER_ORDER_DETAIL.json', URI_ORDER_CHANGE_ORDER: 'data/URI_ORDER_CHANGE_ORDER.json', URI_ORDER_MODIFY_ORDER: 'data/URI_ORDER_MODIFY_ORDER.json', URI_ORDER_SELECT_ENGINEER: 'data/URI_ORDER_MODIFY_ORDER.json', URI_ORDER_CUSTOMER_EVALUATE: 'data/URI_ORDER_CHANGE_ORDER.json', URI_ORDER_ENGINEER_EVALUATE: 'data/URI_ORDER_MODIFY_ORDER.json', URI_ORDER_NEW_ORDER: 'data/URI_ORDER_NEW_ORDER.json', URI_ORDER_GET_EVALUATE: 'data/URI_ORDER_GET_EVALUATE.json', URI_ORDER_STATUS_LIST: 'data/URI_ORDER_STATUS_LIST.json', URI_ORDER_BACK_VISIT: 'data/URI_ORDER_CHANGE_ORDER.json', URI_ORDER_CREATE_KNOWLEDGE: 'data/URI_ORDER_CHANGE_ORDER.json', URI_ORDER_PRODUCT_INFO:'data/URI_ORDER_PRODUCT_INFO.json', URI_ORDER_PRODUCT_MANAGER: 'data/URI_ORDER_PRODUCT_MANAGER.json', //维修师 URI_ENGINEER_ENGINEER_LIST: 'data/URI_ENGINEER_ENGINEER_LIST.json', //产品 URI_PRODUCT_PRODUCT_LIST: 'data/URI_PRODUCT_PRODUCT_LIST.json', URI_PRODUCT_REPAIR_ORDER_LIST: 'data/URI_PRODUCT_REPAIR_ORDER_LIST.json', URI_PRODUCT_ORDER_MANAGER: 'data/URI_PRODUCT_ORDER_MANAGER.json', URI_PRODUCT_PRODUCT_MANAGER: 'repair-master/product/project',//'data/URI_PRODUCT_PRODUCT_MANAGER.json',//项目管理 URI_PRODUCT_PRODUCT_MANAGER_FORM: 'repair-master/product/project', URI_PRODUCT_ADD_PRODUCT: 'repair-master/product/productCase',//产品录入 //供应商 URI_SUPPLIER_SUPPLIER_LIST: 'data/URI_SUPPLIER_SUPPLIER_LIST.json', //工作 URI_WORK_SUPPLEMENT: 'data/URI_WORK_SUPPLEMENT.json', URI_WORKS_MSHEETRANKING: 'data/URI_WORKS_MSHEETRANKING.json', URI_WORKS_KONWRAKING: 'data/URI_WORKS_KONWRAKING.json', URI_WORKS_CSCORERANKING: 'data/URI_WORKS_CSCORERANKING.json', //我的 URI_MINE_CUSTOMER_INFO_DETAIL: 'data/URI_MINE_CUSTOMER_INFO_DETAIL.json', URI_MINE_SAVE_CUSTOMER_INFO: 'data/URI_ORDER_CHANGE_ORDER.json', URI_MINE_ENGINEER_INFO_DETAIL: 'data/URI_MINE_ENGINEER_INFO_DETAIL.json', URI_MINE_SAVE_ENGINEER_INFO: 'data/URI_ORDER_CHANGE_ORDER.json', URI_MINE_COLLECT:'data/URI_MINE_COLLECT.json', URI_MINE_EVALUATE:'data/URI_MINE_EVALUATE.json', URI_MINE_EVALUATE_NUMBER:'data/URI_MINE_EVALUATE_NUMBER.json', URI_MINE_COMPLAINT:'data/URI_MINE_COMPLAINT.json', URI_MINE_MY_DEVICE:'data/URI_MINE_MY_DEVICE.json', //qq地图相关 QQ_MAP_NAME:'myapp', QQ_MAP_KEY:'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77', /** * tip相关 */ networkTip: '网络错误,请重试!', getErrorTip, validResponse }; /** * api调用错误提示 * @param {object} error - 异常信息 */ function getErrorTip(error) { if (process.env.NODE_ENV === 'development') { //toastShort(`网络错误,${error}`); } else { //toastShort(api.networkTip); } } /** * 验证服务器响应对象 * @param {object} res - 服务器响应对象 */ function validResponse(res) { if (res && res.resultCode == 0) return true; if (res && res.resultCode === 1002 ) { toastShort('登录失败,账号或密码错误'); }else if(res && res.resultCode ===1004 || res && res.resultCode ===1005 || res && res.resultCode ===1006){ toastShort('您的登录已失效,请重新登录'); hashHistory.replace('/SystemLogin'); } else { toastShort(res && res.resultMsg ? res.resultMsg : '网络错误,请重试'); } return false; } export default api;
common.js
/** * 公用配置集合 * * @date 2017-07-06 * @author shuwenjie<4483378@qq.com> */ import theme from './theme'; import size from './size'; import api from './api'; const common = { theme, size, api, }; export default common;
func.js
/** * 公共方法 * * @date 2017-08-02 * @author wuxiaoyan<408991702@qq.com> */ import { hashHistory } from 'react-router'; const func = { goBack }; /** * api调用错误提示 * @param {object} error - 异常信息 */ function goBack(url) { if(url) { hashHistory.push(url); }else{ window.history.go(-1); } } export default func;
history.js
import { useRouterHistory } from 'react-router' import createHashHistory from 'history/lib/createHashHistory' export default useRouterHistory(createHashHistory)()
routes.js
import React from 'react' import { Route, IndexRoute } from 'react-router' import SystemMenuScreen from '../components/system/Menu'; import SystemHomeScreen from '../components/system/Home'; import SystemNotFoundScreen from '../components/system/NotFound'; import SystemLoginScreen from '../components/system/Login'; //账号管理 import SystemAccountManagerScreen from '../components/system/AccountManager'; import SystemAccountModifyScreen from '../components/system/AccountModify'; import SystemRoleListScreen from '../components/system/roleList'; import SystemDistributionAuthorityScreen from '../components/system/DistributionAuthority'; import SystemDistributionRoleScreen from '../components/system/DistributionRole'; import SystemOrganizationListScreen from '../components/system/OrganizationList'; //资讯管理 import NewsNewListScreen from '../components/news/NewList' import NewsNewGroupScreen from '../components/news/NewGroup'; import NewsNewEditScreen from '../components/news/NewEdit'; import NewsNewRecomScreen from '../components/news/NewRecom'; import NewsNewContentScreen from '../components/news/NewContent'; //客户资料管理 import CustomerCustomerListScreen from '../components/customer/CustomerList'; import CustomerCustomerContactsScreen from '../components/customer/CustomerContacts'; import CustomerCustomerOrderDetailsScreen from '../components/customer/CustomerOrderDetails'; import CustomerCustomerEstabilshScreen from '../components/customer/CustomerEstablish'; import CustomerOrderStatusScreen from '../components/customer/OrderStatus'; import CustomerRelatedContactsScreen from '../components/customer/relatedContacts'; //项目管理 import ProductProductManagerScreen from '../components/product/productManager'; //项目管理添加 import ProductProductManagerDetailsChangeScreen from '../components/product/productManagerDetailsChange'; //项目详情页面 import ProductProductManagerDetailsScreen from '../components/product/productManagerDetails'; //材料详情 import ProductMaterialDetailsScreen from '../components/product/materialDetails'; //供应商管理 import SupplierSupplierListScreen from '../components/supplier/SupplierList'; import SupplierSuppilerInfoInputScreen from '../components/supplier/SuppilerInfoInput'; import SupplierSuppilerDetailsScreen from '../components/supplier/SuppilerDetails'; //维修人员管理 import EngineerEngineerListScreen from '../components/engineer/EngineerList'; //维修人员录入 import EngineerEngineerEditScreen from '../components/engineer/EngineerEdit'; //产品列表 import ProductProductListScreen from '../components/product/productList'; //产品列表详情 import ProductProductListDetailsScreen from '../components/product/productListDetails'; // import ProductRepairOrderListScreen from '../components/product/repairOrderList' // import ProductRepairOrderListDetailsScreen from '../components/product/repairOrderListDetails' // import SystemAuthorityManagerScreen from '../components/system/authorityManager' //订单管理 import ProductOrderManagerScreen from '../components/product/orderManager' //订单管理详情 import ProductOrderManagerDetailsScreen from '../components/product/orderManagerDetails' //配件修改 import ProductProductPartsListEditScreen from '../components/product/ProductPartsListEdit' //待派单列表 import ProductOrderingListScreen from '../components/product/orderingList' //配件单管理 import ProductPartsListScreen from '../components/product/partsList' //配件单详情 import ProductPartsListDetailsScreen from '../components/product/partsListDetails' //维修师详情 import ProductEngineerDetailsScreen from '../components/engineer/engineerDetails' //返厂订单 import ProductReturnListScreen from '../components/product/returnList' //投诉订单 import ProductComplainListScreen from '../components/product/complainList' //产品管理 import ProductProductGroupScreen from '../components/product/ProductGroup'; //产品录入 import ProductProductListEditScreen from '../components/product/productListEdit'; //配件退货 import ProductRejectedScreen from '../components/product/rejected'; //知识库管理 import KnowledgeKnowledgeListScreen from '../components/knowledge/KnowledgeList'; import KnowledgeKnowledgeGroupScreen from '../components/knowledge/KnowledgeGroup'; import KnowledgeKnowledgeEditScreen from '../components/knowledge/KnowledgeEdit'; //数据统计 import StatisticsIndexScreen from '../components/statistics/Index'; //KPI管理 import StatisticsKPIManagerScreen from '../components/statistics/KPIManager'; function checkLogin(nextState, replaceState) { if(!sessionStorage.getItem('USER_API_TOKEN') ){ replaceState('/SystemLogin'); } } const routes = ( <Route> <Route path="/" component={SystemMenuScreen} > <IndexRoute onEnter={checkLogin} component={SystemHomeScreen} /> <Route path="/SystemAccountManager" component={SystemAccountManagerScreen} /> <Route path="/SystemAccountModify" component={SystemAccountModifyScreen} /> <Route path="/SystemDistributionAuthority" component={SystemDistributionAuthorityScreen} /> <Route path="/SystemRoleList" component={SystemRoleListScreen} /> <Route path="/SystemDistributionRole" component={SystemDistributionRoleScreen} /> <Route path="/SystemOrganizationList" component={SystemOrganizationListScreen} /> <Route path="/NewsNewList" component={NewsNewListScreen} /> <Route path="/NewsNewGroup" component={NewsNewGroupScreen} /> <Route path="/NewsNewEdit" component={NewsNewEditScreen} /> <Route path="/NewsNewRecom" component={NewsNewRecomScreen} /> <Route path="/NewsNewContent" component={NewsNewContentScreen} /> <Route path="/CustomerCustomerList" component={CustomerCustomerListScreen} /> <Route path="/CustomerCustomerContacts" component={CustomerCustomerContactsScreen} /> <Route path="/CustomerCustomerOrderDetails" component={CustomerCustomerOrderDetailsScreen} /> <Route path="/CustomerCustomerEstabilsh" component={CustomerCustomerEstabilshScreen} /> <Route path="/CustomerOrderStatus" component={CustomerOrderStatusScreen} /> <Route path="/CustomerRelatedContacts" component={CustomerRelatedContactsScreen} /> <Route path="/SupplierSupplierList" component={SupplierSupplierListScreen} /> <Route path="/SupplierSuppilerInfoInput" component={SupplierSuppilerInfoInputScreen} /> <Route path="/SupplierSuppilerDetails" component={SupplierSuppilerDetailsScreen} /> <Route path="/EngineerEngineerList" component={EngineerEngineerListScreen} /> <Route path="/ProductEngineerDetails" component={ProductEngineerDetailsScreen} /> <Route path="/ProductRepairOrderList" component={ProductRepairOrderListScreen} /> <Route path="/ProductRepairOrderListDteails" component={ProductRepairOrderListDetailsScreen} /> <Route path="/ProductPartsList" component={ProductPartsListScreen} /> <Route path="/SystemAuthorityManager" component={SystemAuthorityManagerScreen} /> <Route path="/ProductOrderManager" component={ProductOrderManagerScreen} /> <Route path="/ProductPartsListEdit" component={ProductProductPartsListEditScreen} /> <Route path="/ProductPartsListDetails" component={ProductPartsListDetailsScreen} /> <Route path="/ProductOrderManagerDetails" component={ProductOrderManagerDetailsScreen} /> <Route path="/ProductOrderingList" component={ProductOrderingListScreen} /> <Route path="/ProductReturnList" component={ProductReturnListScreen} /> <Route path="/ProductComplainList" component={ProductComplainListScreen} /> <Route path="/ProductComplainList" component={ProductComplainListScreen} /> <Route path="/EngineerEngineerEdit" component={EngineerEngineerEditScreen} /> <Route path="/ProductProductListEdit" component={ProductProductListEditScreen} /> <Route path="/ProductEngineerDetails" component={ProductEngineerDetailsScreen} /> <Route path="/ProductRejected" component={ProductRejectedScreen} /> <Route path="/ProductProductGroup" component={ProductProductGroupScreen} /> <Route path="/ProductProductManager" component={ProductProductManagerScreen} /> <Route path="/ProductProductManagerDetailsChange" component={ProductProductManagerDetailsChangeScreen} /> <Route path="/ProductProductManagerDetails" component={ProductProductManagerDetailsScreen} /> <Route path="/ProductProductList" component={ProductProductListScreen} /> <Route path="/ProductProductListDetails" component={ProductProductListDetailsScreen} /> <Route path="/ProductMaterialDetails" component={ProductMaterialDetailsScreen} /> <Route path="/KnowledgeKnowledgeList" component={KnowledgeKnowledgeListScreen} /> <Route path="/KnowledgeKnowledgeGroup" component={KnowledgeKnowledgeGroupScreen} /> <Route path="/KnowledgeKnowledgeEdit" component={KnowledgeKnowledgeEditScreen} /> <Route path="/StatisticsIndex" component={StatisticsIndexScreen} /> <Route path="/StatisticsKPIManager" component={StatisticsKPIManagerScreen} /> </Route> <Route path="/SystemLogin" component={SystemLoginScreen} /> <Route path="*" component={SystemNotFoundScreen} /> </Route> ); export default routes;
size.js
/** * 应用尺寸配置 * * @date 2017-07-06 * @author wuxiaoyan<408991702@qq.com> */ const size = { width: window.screen.width ,// 返回实际屏幕宽度 height: window.screen.height ,// 返回实际屏幕高度 iosStatusBarHeight: 6, inputComponentHeight: 40,// 输入框高度 arrowForwardIconWidth: 30, arrowForwardIconSize: 20, }; export default size;
theme.js
/** * 应用主题配置 * * @date 2017-07-06 * @author shuwenjie<4483378@qq.com> */ const theme = { backgroundImage:'-webkit-linear-gradient(120deg,#19194B,#30C8D3);', nilColor: '#ffffff', // 空白背景色 mainColor: 'rgba(255, 255, 255,0.1)', // 主色调 statusBarColor:'#0290fe',//状态栏颜色 oppColor: '#ffffff', // 反色调 grayColor: '#aaaaaa', // 灰色 txtColor: '#fff', // 文字颜色 linkTxtColor: 'blue', // 链接文字颜色 borderColor: 'rgba(220, 220, 220,0.2)', // 边框色 placeholderColor:'rgba(255, 255, 255,0.5)', // 输入框提示颜色 starColor:'#FFCC00',//星星颜色 borderBottomStyle:{//边框样式 borderBottomColor: 'rgba(225, 225, 225, 0.5)', borderBottomWidth:1, borderBottomStyle:'solid' }, borderLeftStyle:{//边框样式 borderLeftColor: 'rgba(225, 225, 225, 0.25)', borderLeftWidth:1, borderLeftStyle:'solid' }, inputLableStyle:{//输入框对应文字样式 color:'#222' }, submitButtonStyle:{//提交按钮样式 height: '.9rem', backgroundColor: '#11ACE9', borderRadius: '.1rem', borderColor:'rgba(121,121,121,0.1)', borderWidth:1, borderStyle:'solid' }, submitButtonTextStyle:{//提交按钮文字样式 color: '#ffffff', fontSize: 18 }, commonTextStyle:{//普通文字样式 color: '#fff', fontSize: '.24rem' }, commonFlexStyle:{//通用flex模型 display:'flex', flexDirection:'column', }, navBarStyle:{//导航栏的样式 backgroundColor:'rgba(255, 255, 255,0.1)', marginBottom:1, position: 'fixed', left:0, right:0 }, buttonListStyle:{ margin:'0px 10px', color:'rgb(0,153,0)', cursor: 'pointer' } }; export default theme;
三 、utils
ajax.js
import fetch from 'isomorphic-fetch' import { API_PREFIX, API_SUFFIX } from '../constants' // todo : 连接store // const code = global.$GLOBALCONFIG.STAFF.code function buildParams(obj) { if (!obj) { return '' } const params = [] for (const key of Object.keys(obj)) { const value = obj[key] === undefined ? '' : obj[key] params.push(`${key}=${encodeURIComponent(value)}`) } const arg = params.join('&') return arg } // 下面是注释用formdata的方式传输数据 /*export function fetchJSON(url, params) { params = { ...params, headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', ...params.headers, }, } url = `${API_PREFIX}${url}${API_SUFFIX}` return fetch(url, params) }*/ export function fetchJSON(url, params, target) { let data = { 'method': 'POST', 'Content-Type': 'application/json', 'body': JSON.stringify(params) } if(target){ url = `${target}${url}${API_SUFFIX}` } else { url = `${API_PREFIX}${url}${API_SUFFIX}` } return fetch(url, data) } // eslint-disable-next-line arrow-parens export const fetchJSONByPost = (url, target) => query => { // 下面是注释用formdata的方式传输数据 /*const params = { method: 'POST', body: buildParams(query), } return fetchJSON(url, params)*/ return fetchJSON(url, query, target) } export const fetchJSONStringByPost = url => query => { const params = { method: 'POST', body: query, headers: { 'Content-Type': 'application/json;charset=UTF-8', }, } return fetchJSON(url, params) }
ApiClient.js
/** * 数据交换工具 * * @date 2017-05-09 * @author shuwenjie<4483378@qq.com> */ import common from '../configs/common'; import Storage from './Storage'; //get方式 export const get = (url, params) => { if(url.indexOf('.json')>=0){ url=url.split('.json')[0]+'.json'; } if (params) { let paramsArray = []; Object.keys(params).forEach(key => paramsArray.push(key + '=' + encodeURIComponent(params[key]))); url += '?' + paramsArray.join('&'); } /*eslint-disable */ console.log('ApiRequest',{ url, params }); /*eslint-enable */ return request(url, 'get', null, getheaders()); }; function getheaders() { return { 'Authorization':sessionStorage.getItem('USER_API_TOKEN') }; } //post请求 export const postForm = (url, params) => { /*eslint-disable */ console.log('ApiRequest',{ url, params }); /*eslint-enable */ let body; if(url.indexOf('.json')>=0) {//本地调试 body = params; return get(url, params); }else{ body = new FormData(); for (let key in params){ body.append(key, params[key]); } return request(url, 'post', body, getFormDataHeaders(url)); } }; function getFormDataHeaders(url) { if(url=='login') { return {}; }else{ let Authorization=sessionStorage.getItem('USER_API_TOKEN'); return { //'Content-Type': 'multipart/form-data', 'Authorization':Authorization }; } } //x-www-form-urlencoded请求 export const formUrlencoded = (url, params) => { /*eslint-disable */ console.log('ApiRequest',{ url, params }); /*eslint-enable */ let body; if(url.indexOf('.json')>=0) {//本地调试 body = params; return get(url, params); }else{ body = ''; for (let key in params){ if(body==''){ body=body+key+'='+params[key]; }else{ body=body+'&'+key+'='+params[key]; } } return request(url, 'post', body, getformUrlencodedHeaders(url)); } }; function getformUrlencodedHeaders(url) { if(url=='login') { return { 'Content-Type': 'application/x-www-form-urlencoded' }; }else{ let Authorization=sessionStorage.getItem('USER_API_TOKEN'); return { 'Authorization':Authorization }; } } function request(url, method, body, headers) { let isOk; return new Promise((resolve, reject) => { fetch(common.api.HOST + url, { method, headers: headers ? headers : {}, body }).then((response) => { if (response.ok) { isOk = true; } else { isOk = false; } return response.json(); }).then((responseData) => { if (process.env.NODE_ENV === 'development') { /*eslint-disable */ console.log('ApiClient', { state: 'success', url, method, body, headers, res: responseData }); /*eslint-enable */ } if (isOk) { resolve(responseData); } else { reject(responseData); } }).catch((error) => { if (process.env.NODE_ENV === 'development') { /*eslint-disable */ console.log('ApiClient', { state: 'error', url, method, body, headers, error }); /*eslint-enable */ } reject(error); }); }); }
Formcheck.js
/** * 提示语工具 * * @date 2017-05-09 * @author shuwenjie<4483378@qq.com> */ import { toastShort } from './Toast'; export const checkIsrequire = (checkObject) => { let result=true; for(var key in checkObject){ if(checkObject[key].require && checkObject[key].value ==='' ) { toastShort(checkObject[key].errorTip); result=false; return result; } } return result; };
index.js
/** * 公用工具集合 * * @date 2017-07-08 * @author wuxiaoyan<408991702@qq.com> */ import * as toast from './Toast'; import * as ApiClient from './ApiClient'; const utils = { ...toast, ...ApiClient, }; export default utils;
Storage.js
/** * 本地存储操作工具 * * @date 2017-05-09 * @author shuwenjie<4483378@qq.com> */ class DeviceStorage { static saveToken(token) { return null; } static getToken() { return sessionStorage.getItem('USER_API_TOKEN'); } static getToken(key) { return sessionStorage.getItem(key); } } export default DeviceStorage;
Toast.js
/** * 提示语工具 * * @date 2017-05-09 * @author shuwenjie<4483378@qq.com> */ import { message } from 'antd'; let toast; export const toastShort = (content) => { message.info(content); };
tools.js
import {Toast} from 'antd-mobile'; import { hashHistory } from 'react-router' export function ajaxFn(returnData,callback,javaUrl){ $.ajax({ type:"post", url:javaUrl, data:returnData, dataType: "json", //async:false, //false 表示ajax执行完成之后在执行后面的代码 success(data){ Toast.hide(); switch(data.resultCode){ case ('5'): Toast.offline('登录超时,请重新登录!', 1.5,()=>{ // const url = window.location.href.split("#/")[0]; // window.location.href = url; hashHistory.push('login'); }); break; } callback.call(this,data); }, error(a,b,c){ console.log(a,b,c); Toast.hide(); Toast.offline('网络连接失败!', 1); } }); } /*获取传入时间的当月最后一天*/ export function getLastDay(time) { let date = new Date(time); let new_year = date.getFullYear(); //取当前的年份 let new_month = date.getMonth() + 1;//取下一个月的第一天,方便计算(最后一天不固定) let new_date = new Date(new_year,new_month,1); //取当年当月中的第一天 return (new Date(new_date.getTime()-1000*60*60*24)).getDate();//获取当月最后一天日期 } /*获取对象长度*/ export function getObjectCount(object){ var n, count = 0; for(n in object){ da if(object.hasOwnProperty(n)){ count++; } } return count; }; /*根据内容设置iframe高度*/ export function iframeAutoHeight(id){ parent.document.getElementById(id).height=0; parent.document.getElementById(id).height=document.body.scrollHeight; } /*获取今天的日期*/ export function getNowFormatDate(time=new Date(),type,seperator="-") { let date = new Date(time); let year = date.getFullYear(); let month = date.getMonth() + 1; let day = date.getDate(); let hour = date.getHours(); let minute = date.getMinutes(); let second = date.getSeconds(); if (month >= 1 && month <= 9)month = "0" + month; if (day >= 0 && day <= 9) day = "0" + day; if(hour >= 0 && hour <= 9) hour = "0"+hour; if(minute >= 0 && minute <= 9) minute = "0"+minute; if(type == "dateTime"){ return `${year + seperator + month + seperator + day} ${hour}:${minute}:${second}`; }else if(type == "time"){ return `${hour}:${minute}:${second}`; }else{ return year + seperator + month + seperator + day; } } /*根据毫秒数转成正常时间格式*/ export function msConversionDate(millisecond,format){ let date = new Date(millisecond); return getNowFormatDate(date,format); } /*滚动条加载数据*/ export function scrollLoad(callback){ let contrastValue = 0; /*滚到底部加载下一页*/ window.onscroll = () => { const contentHeight = document.body.scrollHeight; /*内容总高度*/ const winHeight = window.innerHeight; /*当前窗口高度*/ const scrollTop = document.body.scrollTop; /*滚动条距离顶部的距离*/ /*两次距离一样就不操作*/ if(scrollTop + winHeight >= contentHeight && scrollTop != contrastValue ){ contrastValue = scrollTop; callback.call(this,contentHeight); } }; } /*获取链接上的参数*/ export function geturl(name) { var reg = new RegExp("(^|\\?|&)" + name + "=([^&]*)(\\s|&|$)", "i"); if (reg.test(location.href)) return decodeURI(RegExp.$2.replace(/\+/g, " ")); return ""; }; export function isWeiXin(){ var ua = window.navigator.userAgent.toLowerCase(); if(ua.match(/MicroMessenger/i) == 'micromessenger'){ return true; }else{ return false; } }