Commit 9b2c994c authored by superman's avatar superman

update

parent deccc40d
This diff is collapsed.
...@@ -24,5 +24,55 @@ module.exports = { ...@@ -24,5 +24,55 @@ module.exports = {
}); });
}, 500); }, 500);
}, },
'/api/*': 'http://react.yanky.cn/', //'http://192.168.1.126:8080/', '/api/catessddsd': function (req, res) {
setTimeout(()=>{
res.json({
status:1,
result:[
{
value:1,
label:'信托',
children:[
{
value:101,
label:'房产'
},{
value:102,
label:'政府'
},{
value:103,
label:'企业流贷'
}
]
},{
value:2,
label:'资管',
children:[
{
value:201,
label:'房产'
},{
value:202,
label:'政府'
},{
value:203,
label:'企业流贷'
}
]
},{
value:3,
label:'私募',
children:[
{
value:301,
label:'契约型'
}
]
}
]
})
},100);
},
'/api/*':'http://react.yanky.cn/', //'http://192.168.1.126:8080/'
}; };
import React, {Component, PropTypes} from 'react';
import {
Row,
Col,
Form,
Input,
Button,
Checkbox,
Select,
message,
Tabs,
Cascader,
Radio,
Upload,
Icon,
Modal,
DatePicker,
Table
} from 'antd';
@Form.create()
export default class HuikuanInfoForm extends Component {
constructor(props, context) {
super(props, context);
}
static propsType = {};
render() {
const formItemLayout = {
labelCol: {span: 4},
wrapperCol: {span: 14},
};
const {form:{getFieldProps}} = this.props;
return (
<Form horizontal>
<Form.Item label="名称" {...formItemLayout} wrapperCol={{span:6}}>
<Input placeholder="" {...getFieldProps('hkzhnc')} />
</Form.Item>
<Form.Item label="银行帐号" {...formItemLayout} wrapperCol={{span:6}}>
<Input placeholder="" {...getFieldProps('yhzh')} />
</Form.Item>
<Form.Item label="开户行" {...formItemLayout}>
<Input placeholder="" {...getFieldProps('khh')} />
</Form.Item>
<Form.Item label="打款须知" {...formItemLayout}>
<Input type="textarea" rows={10} placeholder="" {...getFieldProps('dkxz')} />
</Form.Item>
</Form>
);
}
}
import React, {Component, PropTypes} from 'react';
import {
Row,
Col,
Form,
Input,
Button,
Checkbox,
Select,
message,
Tabs,
Cascader,
Radio,
Upload,
Icon,
Modal,
DatePicker,
Table
} from 'antd';
import {UUID} from '../../utils';
export function BaseElementTransform(objs) {
return Object.keys(objs).map(key=>({
key: UUID(),
title: key,
content: objs[key]
}));
}
export function CreateBaseElement() {
return {key: UUID()};
}
export default class ProductBaseElement extends Component {
constructor(props, context) {
super(props, context);
}
static propsType = {
title: PropTypes.string,
content: PropTypes.string,
remove: PropTypes.func
};
render() {
return (
<Input.Group>
<Col span="6">
<Input placeholder="标题" defaultValue={this.props.title}/>
</Col>
<Col span="10">
<Input type="textarea" style={{height:28}} placeholder="内容" defaultValue={this.props.content}/>
</Col>
<Col span="4">
<Icon type="cross" onClick={this.props.remove}/>
</Col>
</Input.Group>
);
}
}
import React, {Component, PropTypes} from 'react';
import {
Row,
Col,
Form,
Input,
Button,
Checkbox,
Select,
message,
Tabs,
Cascader,
Radio,
Upload,
Icon,
Modal,
DatePicker,
Table
} from 'antd';
import {PRODUCT_STATUS, arrayRemoveIndex, UUID} from '../../utils';
const ProductStatus = Object.keys(PRODUCT_STATUS);
@Form.create()
export default class ProductBaseInfo extends Component {
static propsType = {
cates: PropTypes.array,
product: PropTypes.object,
user: PropTypes.object,
dispatch: PropTypes.func
};
constructor(props, context) {
super(props, context);
this.state = {
priviewVisible: false,
priviewImage: '',
fileList: []
};
const {itemPic} = props;
if (itemPic) {
this.state.fileList.push({
uid: UUID(),
status: 'done',
url: itemPic,
thumbUrl: itemPic
});
}
}
handleCancel() {
this.setState({
priviewVisible: false,
});
};
onChange(value) {
console.log(value);
};
handleSubmit(e) {
e.preventDefault();
const data = this.props.form.getFieldsValue();
if(Array.isArray(data.categoryL1) && data.categoryL1.length===2){
data.categoryL2 = data.categoryL1[1];
data.categoryL1 = data.categoryL1[0];
}else{
delete data.categoryL1;
}
if(this.state.fileList && this.state.fileList[0] && this.state.fileList[0].url){
data['item-pic'] = this.state.fileList[0].url;
}
data.id = this.props.product.id;
console.log('收到表单值:', data);
this.props.dispatch({
type:'UPDATE_PRODUCT_ITEM',
item: data
});
};
normFile(e) {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
};
handleUpload(info) {
let fileList = info.fileList;
// 3. 按照服务器返回信息筛选成功上传的文件
fileList = fileList.filter((file) => {
if (file.response) {
return file.response.status === 1;
}
return true;
});
// 1. 上传列表数量的限制
// 只显示最近上传的一个,旧的会被新的顶掉
fileList = fileList.slice(-2);
// 2. 读取远程路径并显示链接
fileList = fileList.map((file) => {
if (file.response) {
// 组件会将 file.url 作为链接进行展示
//file.url = file.response.url;
const {result, status, message} = file.response;
if (status === 1 && result && result.length >= 1 && result[0].url) {
file.url = result[0].url;
file.thumbUrl = result[0].url + '!t';
}
}
return file;
});
this.setState({fileList});
};
render() {
const formItemLayout = {
labelCol: {span: 4},
wrapperCol: {span: 14},
};
const {user, cates, product, form:{getFieldProps}} = this.props;
let productCate = [];
if (product && product.categoryId && product.categoryParentId) {
productCate = [product.categoryParentId, product.categoryId];
}
const styles = require('./ProductBaseInfo.less');
return (
<Form horizontal onSubmit={this.handleSubmit.bind(this)}>
<Form.Item label="商品类目" {...formItemLayout} wrapperCol={{span: 6}}>
<Cascader
options={cates}
defaultValue={productCate}
{...getFieldProps('categoryL1', {initialValue: productCate})}
placeholder="请选产品类目"/>
</Form.Item>
{
product &&
<Form.Item label="商品状态" {...formItemLayout}>
<Radio.Group {...getFieldProps('status', {initialValue: product.status + ''})}>
{
ProductStatus.map((status, index)=>
<Radio.Button key={status} data-value={status}
value={status}>{PRODUCT_STATUS[status]}</Radio.Button>
)
}
</Radio.Group>
</Form.Item>
}
<Form.Item label="商品标题" {...formItemLayout}>
<Input placeholder="商品标题" {...getFieldProps('itemTitle', {initialValue: product.itemTitle})} />
</Form.Item>
<Form.Item label="商品短标题" {...formItemLayout} wrapperCol={{span: 6}}>
<Input placeholder="商品短标题"
{...getFieldProps('itemShortTitle', {initialValue: product.itemShortTitle})} />
</Form.Item>
<Form.Item label="商品主图" {...formItemLayout}>
<Upload action="/api/fileUpload/upload" listType="picture-card"
multiple={true}
headers={{
authorization: user && user.token,
}}
onChange={this.handleUpload.bind(this)}
onPreview={(file) => {
this.setState({
priviewImage: file.url,
priviewVisible: true,
});
}}
fileList={this.state.fileList}>
<Icon type="upload"/>
<div className="ant-upload-text">上传照片</div>
</Upload>
<Modal visible={this.state.priviewVisible} footer={null}
width="100vw"
className={styles.imgPriviewDialog}
style={{height:'100vh', background:'transparent'}}
onCancel={this.handleCancel.bind(this)}>
<img src={this.state.priviewImage} style={{maxWidth:'100%'}}/>
</Modal>
</Form.Item>
<Form.Item label="商品简介" {...formItemLayout}>
<Input type="textarea" rows={5}
placeholder="商品简介"
{...getFieldProps('summary', {initialValue: product.summary})} />
</Form.Item>
<Form.Item wrapperCol={{offset: 4, span:10}} style={{marginTop:30}}>
<Button type="primary" htmlType="submit"><Icon type="save"/>保存</Button>
</Form.Item>
</Form>
);
}
}
.imgPriviewDialog{
:global(.ant-modal-content){
background-color: transparent;
}
}
import React, {Component, PropTypes} from 'react';
import {
Row,
Col,
Form,
Input,
Button,
Checkbox,
Select,
message,
Tabs,
Cascader,
Radio,
Upload,
Icon,
Modal,
DatePicker,
Table
} from 'antd';
import YongjingSuanFaItem, {
YongjingTransform,
CreateYongjing
} from '../YongjingSuanFaItem/YongjingSuanFaItem';
import {arrayRemoveIndex} from '../../utils';
@Form.create()
export default class ShouyiYongjingForm extends Component {
static propsType = {
product: PropTypes.object,
user: PropTypes.object,
dispatch: PropTypes.func
};
constructor(props, context) {
super(props, context);
this.state = {
yongjing: YongjingTransform(props.yongjing)
}
}
/**
* 添加佣金算法
* @param e
*/
handleAddYongjing(e) {
e.preventDefault();
let yongjing = [].concat(this.state.yongjing);
yongjing.push(CreateYongjing());
this.setState({yongjing: yongjing});
}
/**
* 删除佣金算法
* @param index
* @param e
*/
handleRemoveYongjin(index, e) {
e.preventDefault();
const yongjing = arrayRemoveIndex(this.state.yongjing, index);
console.log(yongjing);
this.setState({yongjing: yongjing});
}
render() {
const formItemLayout = {
labelCol: {span: 4},
wrapperCol: {span: 14},
};
const {form:{getFieldProps}} = this.props;
return (
<Form horizontal>
<Form.Item label="产品的预期收益" {...formItemLayout} wrapperCol={{span:6}}>
<Input placeholder="产品的预期收益" {...getFieldProps('yqsy')} />
</Form.Item>
<Form.Item label="佣金算法" {...formItemLayout}>
<Input.Group>
<Col span="5" className="tac">最小投资额</Col>
<Col span="5" className="tac">最大投资额</Col>
<Col span="5" className="tac">收益</Col>
<Col span="5" className="tac">佣金</Col>
</Input.Group>
{
this.state.yongjing.map((item, index)=>
<YongjingSuanFaItem {...item}
remove={this.handleRemoveYongjin.bind(this, index)}/>
)
}
<Row style={{marginTop:15}}>
<Col span="20" className="tac">
<Button style={{marginRight:'.5em'}}
onClick={this.handleAddYongjing.bind(this)}><Icon
type="plus"/>添加</Button>
<Button type="ghost" style={{marginLeft:'.5em'}}><Icon type="code"/>高级</Button>
</Col>
</Row>
</Form.Item>
<Form.Item label="最高佣金" {...formItemLayout} wrapperCol={{span:6}}>
<Input placeholder="最高佣金" readOnly disabled defaultValue={'jsdcjkdsh'} />
</Form.Item>
</Form>
);
}
}
import React, {Component, PropTypes} from 'react';
import {
Row,
Col,
Form,
Input,
Button,
Checkbox,
Select,
message,
Tabs,
Cascader,
Radio,
Upload,
Icon,
Modal,
DatePicker,
Table
} from 'antd';
import {UUID} from '../../utils';
export function YongjingTransform(arr) {
return arr.map(item=>({
...item,
key: UUID()
}));
}
export function CreateYongjing() {
return {key: UUID(), result: {}};
};
export default class YongjingSuanFaItem extends Component {
constructor(props, context) {
super(props, context);
}
static propsType = {
min: PropTypes.string,
max: PropTypes.string,
result: PropTypes.any,
remove: PropTypes.func
}
render() {
const {min, max, result:{sy, yj}} = this.props;
return (
<Input.Group>
<Col span="5">
<Input defaultValue={min}/>
</Col>
<Col span="5">
<Input defaultValue={max}/>
</Col>
<Col span="5">
<Input defaultValue={sy}/>
</Col>
<Col span="5">
<Input defaultValue={yj}/>
</Col>
<Col span="4">
<Icon type="cross" onClick={this.props.remove}/>
</Col>
</Input.Group>
);
}
}
...@@ -31,11 +31,10 @@ export default class App extends Component { ...@@ -31,11 +31,10 @@ export default class App extends Component {
<Collapse accordion> <Collapse accordion>
<Panel header="产品管理"> <Panel header="产品管理">
<Link to="/products">产品列表</Link><br/> <Link to="/products">产品列表</Link><br/>
<Link to="/products/add">增加产品</Link> <Link to="/products/create">增加产品</Link>
</Panel> </Panel>
<Panel header="订单管理"> <Panel header="订单管理">
<Link to="/trades">订单列表</Link><br/> <Link to="/trades">订单列表</Link><br/>
<Link to="/trade/add">增加订单</Link>
</Panel> </Panel>
</Collapse> </Collapse>
</div> </div>
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
.login-bg { .login-bg {
width: 50%; width: 50%;
height:100vh;
overflow: hidden; overflow: hidden;
} }
......
This diff is collapsed.
.normal {
display: flex;
flex-direction: column;
height: 100%;
& > :global(.ant-tabs) {
flex: 1;
overflow: auto;
}
}
This diff is collapsed.
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import {Link} from 'react-router';
import {
Row,
Col,
Form,
Input,
Button,
Checkbox,
Select,
message,
Tabs,
Cascader,
Radio,
Upload,
Icon,
Modal,
DatePicker,
Table,
Spin
} from 'antd';
@connect(state=>({
item: state.product.item,
loading: state.product.loading
}))
export default class Item extends Component {
componentWillMount() {
this.fetchItem(this.props.params.id);
};
fetchItem(id) {
this.props.dispatch({
type: 'FETCH_PRODUCT_ITEM',
id
});
};
handleGoBack(e) {
e.preventDefault();
this.props.history.goBack();
};
render() {
const tw = 6;
const vw = 18;
const styles = require('../Trade/Item.less');
const {item, loading} = this.props;
return (
<Spin spinning={loading}>
{
item &&
<div className={styles.trade}>
<div className={styles.tradeTable}>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>产品标题</Col>
<Col span={vw}>{item.itemTitle}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>产品短标题</Col>
<Col span={vw}>{item.itemShortTitle}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>产品标题</Col>
<Col span={vw}>{item.itemTitle}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>产品标题</Col>
<Col span={vw}>{item.itemTitle}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>产品标题</Col>
<Col span={vw}>{item.itemTitle}</Col>
</Row>
</div>
<p>
<Button onClick={this.handleGoBack.bind(this)}>返回</Button>
<Link to={'/products/'+ item.id+'/edit'}><Button>编辑</Button></Link>
<Link to={'/product/'+ item.id+'/edit'}><Button>公告</Button></Link>
<Link
to={'/trades/create/'+ item.id+'?title='+ item.itemShortTitle}><Button>报单</Button></Link>
</p>
</div>
}
</Spin>
);
}
}
...@@ -2,13 +2,21 @@ import React, {Component, PropTypes} from 'react'; ...@@ -2,13 +2,21 @@ import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {Table, Icon} from 'antd'; import {Table, Icon} from 'antd';
import {params, formatDateTime, productStatusToString} from '../../utils'; import {params, formatDateTime, productStatusToString} from '../../utils';
import {Link} from 'react-router';
const columns = [ const columns = [
{ {
title: 'ID',
dataIndex: 'id',
key: 'id',
width: 60
}, {
title: '类目', title: '类目',
dataIndex: 'cateId', dataIndex: 'cateId',
key: 'cateId', key: 'cateId',
width: 80,
className:'tac',
render: (cateId, record)=>(<span data-cate-id={cateId}>{record.cateName}</span>) render: (cateId, record)=>(<span data-cate-id={cateId}>{record.cateName}</span>)
}, { }, {
title: '标题', title: '标题',
...@@ -18,16 +26,22 @@ const columns = [ ...@@ -18,16 +26,22 @@ const columns = [
}, { }, {
title: '募集比率', title: '募集比率',
dataIndex: 'rate', dataIndex: 'rate',
key: 'rate' key: 'rate',
width:120,
className:'tac',
}, { }, {
title: '状态', title: '状态',
dataIndex: 'status', dataIndex: 'status',
key: 'status', key: 'status',
width:120,
className:'tac',
render: (status, record)=>(<span data-status={status}>{productStatusToString(status)}</span>) render: (status, record)=>(<span data-status={status}>{productStatusToString(status)}</span>)
}, { }, {
title: '创建时间', title: '创建时间',
dataIndex: 'dateCreated', dataIndex: 'dateCreated',
key: 'dateCreated', key: 'dateCreated',
width:150,
className:'tac',
render: (dateCreated, record)=>( render: (dateCreated, record)=>(
<span> <span>
{dateCreated && formatDateTime(dateCreated)} {dateCreated && formatDateTime(dateCreated)}
...@@ -36,11 +50,15 @@ const columns = [ ...@@ -36,11 +50,15 @@ const columns = [
}, { }, {
title: '操作', title: '操作',
key: 'operation', key: 'operation',
width:120,
className:'tac',
render: (text, record)=>( render: (text, record)=>(
<span> <span>
<a href={'/product/item?id='+ record.id}>详情</a> <a href={'/product/item?id='+ record.id}>详情</a>
<span className="ant-divider"></span> <span className="ant-divider"></span>
<a href="#">公告</a> <a href="#">公告</a>
<span className="ant-divider"></span>
<Link to={'/trades/add/'+record.id+'?title='+record.shortTitle}>报单</Link>
</span> </span>
) )
} }
...@@ -69,6 +87,10 @@ export default class List extends Component { ...@@ -69,6 +87,10 @@ export default class List extends Component {
}); });
}; };
handleRowClick({id}){
this.props.history.push('/products/'+id);
}
render() { render() {
...@@ -101,7 +123,8 @@ export default class List extends Component { ...@@ -101,7 +123,8 @@ export default class List extends Component {
dataSource={Array.isArray(items)?items:[]} dataSource={Array.isArray(items)?items:[]}
loading={loading} loading={loading}
pagination={pagination} pagination={pagination}
scroll={{ y: window.innerHeight-280 }} scroll={{ y: window.innerHeight-290 }}
onRowClick={this.handleRowClick.bind(this)}
/> />
</div>; </div>;
} }
......
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import {Form, Input, Button, Checkbox, message, Tabs, DatePicker, Upload, Icon, Modal} from 'antd';
@Form.create()
export default class AddItem extends Component {
constructor() {
super(...arguments);
this.state = {
priviewVisible: false,
priviewImage: '',
};
}
handleCancel() {
this.setState({
priviewVisible: false,
});
}
render() {
const formItemLayout = {
labelCol: {span: 6},
wrapperCol: {span: 14},
};
const props = {
action: '/upload.do',
listType: 'picture-card',
defaultFileList: [{
uid: -1,
name: 'xxx.png',
status: 'done',
url: 'https://os.alipayobjects.com/rmsportal/NDbkJhpzmLxtPhB.png',
thumbUrl: 'https://os.alipayobjects.com/rmsportal/NDbkJhpzmLxtPhB.png',
}],
onPreview: (file) => {
this.setState({
priviewImage: file.url,
priviewVisible: true,
});
},
};
return (
<div>
<Form horizontal>
<Form.Item {...formItemLayout} label="产品">
<Input value={this.props.location.query.title} readOnly/>
<Input type="hidden"/>
</Form.Item>
<Form.Item {...formItemLayout} label="理财师手机号">
<Input />
</Form.Item>
<Form.Item {...formItemLayout} label="投资人姓名">
<Input />
</Form.Item>
<Form.Item {...formItemLayout} label="投资人身份证号码">
<Input />
</Form.Item>
<Form.Item {...formItemLayout} label="投资人身份证正反面照片">
<Upload {...props}>
<Icon type="plus"/>
<div className="ant-upload-text">上传照片</div>
</Upload>
<Modal visible={this.state.priviewVisible} footer={null}
onCancel={this.handleCancel.bind(this)}>
<img alt="example" src={this.state.priviewImage}/>
</Modal>
</Form.Item>
<Form.Item {...formItemLayout} label="投资人实际打款金额">
<Input />
</Form.Item>
<Form.Item {...formItemLayout} label="投资人实际打款时间">
<DatePicker showTime format="yyyy-MM-dd HH:mm:ss" placeholder="请选择时间"/>
</Form.Item>
<Form.Item {...formItemLayout} label="投资人银行卡开户行">
<Input />
</Form.Item>
<Form.Item {...formItemLayout} label="投资人银行卡照片">
<Upload {...props}>
<Icon type="plus"/>
<div className="ant-upload-text">上传照片</div>
</Upload>
<Modal visible={this.state.priviewVisible} footer={null}
onCancel={this.handleCancel.bind(this)}>
<img alt="example" src={this.state.priviewImage}/>
</Modal>
</Form.Item>
<Form.Item {...formItemLayout} label="投资人打款凭条照片">
<Upload {...props}>
<Icon type="plus"/>
<div className="ant-upload-text">上传照片</div>
</Upload>
<Modal visible={this.state.priviewVisible} footer={null}
onCancel={this.handleCancel.bind(this)}>
<img alt="example" src={this.state.priviewImage}/>
</Modal>
</Form.Item>
<Form.Item {...formItemLayout} className="clearfix" label="投资人合同签字页照片">
<Upload {...props}>
<Icon type="plus"/>
<div className="ant-upload-text">上传照片</div>
</Upload>
<Modal visible={this.state.priviewVisible} footer={null}
onCancel={this.handleCancel.bind(this)}>
<img alt="example" src={this.state.priviewImage}/>
</Modal>
</Form.Item>
<Form.Item wrapperCol={{ span: 14, offset: 6 }}>
<Button type="primary" style={{marginRight:'1em'}}>提交</Button>
<Button onClick={(e)=>{e.preventDefault(); this.props.history.goBack();}}>返回</Button>
</Form.Item>
</Form>
</div>
);
}
}
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import {Form, Input, Button, Checkbox, message, Row, Col} from 'antd';
@connect(state=>({
item: state.trade.item
}))
export default class Commission extends Component {
componentWillMount() {
const {dispatch, params:{id}} = this.props;
dispatch({
type: 'FETCH_TRADE_ITEM',
id
});
};
handleGoBack(e) {
e.preventDefault();
this.props.history.goBack();
};
handleCommission(e){
e.preventDefault();
alert('二次确认后发放');
}
render() {
const {item} = this.props;
const styles = require('./Item.less');
const tw = 8;
const vw = 16;
return (
<div className={styles.trade}>
<h1 className="tac">佣金发放</h1>
<div className={styles.tradeTable}>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>产品</Col>
<Col span={vw}>{item.title}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>确认打款金额</Col>
<Col span={vw}>{item.remittanceAmount}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>实际佣金</Col>
<Col span={vw}>{item.realReturn && item.realReturn.yj}</Col>
</Row>
</div>
<p>
<Button onClick={this.handleGoBack.bind(this)}>返回</Button>
<Button onClick={this.handleCommission.bind(this)}>发放</Button>
</p>
</div>
);
}
}
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import {Form, Input, Button, Checkbox, message, Row, Col} from 'antd';
@connect(state=>({
item: state.trade.item
}))
export default class Contract extends Component {
componentWillMount() {
const {dispatch, params:{id}} = this.props;
dispatch({
type: 'FETCH_TRADE_ITEM',
id
});
};
handleGoBack(e) {
e.preventDefault();
this.props.history.goBack();
};
handleSubmit(e){
e.preventDefault();
alert('实现保存物流订单号的流程');
}
render() {
const {item} = this.props;
const styles = require('./Item.less');
const tw = 8;
const vw = 16;
return (
<div className={styles.trade}>
<h1 className="tac">合同物流</h1>
<div className={styles.tradeTable}>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>产品</Col>
<Col span={vw}>{item.title}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>确认打款金额</Col>
<Col span={vw}>{item.remittanceAmount}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw}>实际佣金</Col>
<Col span={vw}>{item.realReturn && item.realReturn.yj}</Col>
</Row>
<Row type="flex" justify="space-around" align="middle">
<Col span={tw} className="isRequire">顺丰运单</Col>
<Col span={vw}><Input placeholder="请填写顺丰运单编号" /></Col>
</Row>
</div>
<p>
<Button onClick={this.handleGoBack.bind(this)}>返回</Button>
<Button onClick={this.handleSubmit.bind(this)}>保存</Button>
</p>
</div>
);
}
}
import React, {Component, PropTypes} from 'react'; import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {Link} from 'react-router';
import {Form, Input, Button, Checkbox, message, Row, Col} from 'antd'; import {Form, Input, Button, Checkbox, message, Row, Col} from 'antd';
import { import {
formatDateTime, formatDateTime,
...@@ -19,10 +20,11 @@ export default class Item extends Component { ...@@ -19,10 +20,11 @@ export default class Item extends Component {
id id
}); });
}; };
handleGoBack(e){ handleGoBack(e){
e.preventDefault(); e.preventDefault();
this.props.history.goBack(); this.props.history.goBack();
} };
render() { render() {
const {item} = this.props; const {item} = this.props;
...@@ -32,7 +34,7 @@ export default class Item extends Component { ...@@ -32,7 +34,7 @@ export default class Item extends Component {
return ( return (
<div className={styles.trade}> <div className={styles.trade}>
<div className={styles.tradeTable}> <div className={styles.tradeTable}>
<Row type="flex" justify="space-around" align="middle"> <Row type="flex" justify="space-around" align="middle">
<Col span={tw}>产品</Col> <Col span={tw}>产品</Col>
<Col span={vw}>{item.title}</Col> <Col span={vw}>{item.title}</Col>
...@@ -115,6 +117,8 @@ export default class Item extends Component { ...@@ -115,6 +117,8 @@ export default class Item extends Component {
</div> </div>
<p> <p>
<Button onClick={this.handleGoBack.bind(this)}>返回</Button> <Button onClick={this.handleGoBack.bind(this)}>返回</Button>
<Link to={'/trades/commission/'+ item.id}><Button>发放佣金</Button></Link>
<Link to={'/trades/contract/'+ item.id}><Button>邮寄合同</Button></Link>
</p> </p>
</div> </div>
); );
......
...@@ -2,7 +2,10 @@ ...@@ -2,7 +2,10 @@
p { p {
text-align: center; text-align: center;
padding: 20px 0; padding: 20px 0;
max-width: 800px; //max-width: 800px;
button {
margin: auto 10px;
}
} }
} }
...@@ -10,7 +13,7 @@ ...@@ -10,7 +13,7 @@
.tradeTable { .tradeTable {
border-top: 1px solid #e9e9e9; border-top: 1px solid #e9e9e9;
border-bottom: 1px solid #e9e9e9; border-bottom: 1px solid #e9e9e9;
max-width: 800px; //max-width: 800px;
//margin: auto; //margin: auto;
font-size: 14px; font-size: 14px;
:global(.ant-row), :global(.ant-row),
......
...@@ -62,9 +62,9 @@ const columns = [ ...@@ -62,9 +62,9 @@ const columns = [
className:'tac', className:'tac',
render: (text, record)=>( render: (text, record)=>(
<span> <span>
<Link to={'/trades/'+ record.id}>邮寄合同</Link> <Link to={'/trades/contract/'+ record.id} onClick={e=>e.stopPropagation()}>合同</Link>
<span className="ant-divider"></span> <span className="ant-divider"></span>
<Link to={'/trades/'+ record.id}>发放佣金</Link> <Link to={'/trades/commission/'+ record.id} onClick={e=>e.stopPropagation()}>佣金</Link>
</span> </span>
) )
} }
......
:global { :global {
html, body, #root { html, body, #root {
height: 100%; height: 100%;
} font-size: 14px;
}
.ant-table{
font-size: 14px !important;
}
} }
import { handleActions } from 'redux-actions'; import {handleActions} from 'redux-actions';
import { combineReducer } from 'redux'; import {combineReducer} from 'redux';
const product = handleActions({ const product = handleActions({
['FETCH_PRODUCT_LIST'](state) { ['FETCH_PRODUCT_LIST'](state) {
return { ...state, loading: true, }; return {...state, loading: true,};
}, },
['FETCH_PRODUCT_LIST_SUCCESS'](state, action) { ['FETCH_PRODUCT_LIST_SUCCESS'](state, action) {
return { ...state, loading: false, items: action.items, total:action.total }; return {...state, loading: false, items: action.items, total: action.total};
}, },
['FETCH_PRODUCT_LIST_FAILED'](state, action) { ['FETCH_PRODUCT_LIST_FAILED'](state, action) {
return { ...state, err: action.err, loading: false, }; return {...state, err: action.err, loading: false,};
} },
['FETCH_PRODUCT_CATES'](state){
return {...state, loading: true};
},
['FETCH_PRODUCT_CATES_SUCCESS'](state, action){
return {...state, loading: false, cates: action.cates};
},
['FETCH_PRODUCT_CATES_FAILED'](state, action){
return {...state, err: action.err, loading: false};
},
['FETCH_PRODUCT_ITEM'](state){
return {...state, loading: true}
},
['FETCH_PRODUCT_ITEM_SUCCESS'](state, action){
return {...state, loading: false, item: action.item}
},
['FETCH_PRODUCT_ITEM_FAILED'](state, action){
return {...state, err: action.err, loading: false}
},
['UPDATE_PRODUCT_ITEM'](state){
return {...state, loading:true};
},
['UPDATE_PRODUCT_ITEM_SUCCESS'](state){
return {...state, loading:false};
},
['UPDATE_PRODUCT_ITEM_FAILED'](state, action){
return {...state, loading:false, err: action.err};
}
}, { }, {
items: [], cates:[],
loading: false, items: [],
loading: false,
}); });
export default product; export default product;
...@@ -17,7 +17,7 @@ const trade = handleActions({ ...@@ -17,7 +17,7 @@ const trade = handleActions({
['FETCH_TRADE_ITEM_SUCCESS'](state, action){ ['FETCH_TRADE_ITEM_SUCCESS'](state, action){
return {...state, loading: false, item: action.item} return {...state, loading: false, item: action.item}
}, },
['FETCH_TRADE_ITEM_FAILED'](state){ ['FETCH_TRADE_ITEM_FAILED'](state, action){
return {...state, err: action.err, loading: false} return {...state, err: action.err, loading: false}
} }
}, { }, {
......
...@@ -6,8 +6,13 @@ import Login from '../containers/Login/Login'; ...@@ -6,8 +6,13 @@ import Login from '../containers/Login/Login';
import App from '../containers/App/App'; import App from '../containers/App/App';
import ProductList from '../containers/Product/List'; import ProductList from '../containers/Product/List';
import ProductAddItem from '../containers/Product/AddItem'; import ProductAddItem from '../containers/Product/AddItem';
import ProductEditItem from '../containers/Product/EditItem';
import ProductItem from '../containers/Product/Item';
import TradeList from '../containers/Trade/List'; import TradeList from '../containers/Trade/List';
import TradeItem from '../containers/Trade/Item'; import TradeItem from '../containers/Trade/Item';
import Commission from '../containers/Trade/Commission';
import Contract from '../containers/Trade/Contract';
import TradeAddItem from '../containers/Trade/AddItem';
export default (store)=> { export default (store)=> {
...@@ -24,11 +29,16 @@ export default (store)=> { ...@@ -24,11 +29,16 @@ export default (store)=> {
<IndexRoute component={Home}/> <IndexRoute component={Home}/>
<Route path="products" > <Route path="products" >
<IndexRoute component={ProductList} /> <IndexRoute component={ProductList} />
<Route path="add" component={ProductAddItem} /> <Route path=":id" component={ProductItem} />
<Route path="create" component={ProductAddItem} />
<Route path=":id/edit" component={ProductEditItem} />
</Route> </Route>
<Route path="trades" > <Route path="trades" >
<IndexRoute component={TradeList} /> <IndexRoute component={TradeList} />
<Route path=":id" component={TradeItem} /> <Route path=":id" component={TradeItem} />
<Route path="commission/:id" component={Commission} />
<Route path="contract/:id" component={Contract} />
<Route path="create/:pid" component={TradeAddItem} />
</Route> </Route>
<Route path="/actived" component={Home}/> <Route path="/actived" component={Home}/>
<Route path="/completed" component={Home}/> <Route path="/completed" component={Home}/>
......
import {takeLatest} from 'redux-saga'; import {takeLatest} from 'redux-saga';
import {take, call, put, fork, cancel, select} from 'redux-saga/effects'; import {take, call, put, fork, cancel, select} from 'redux-saga/effects';
import {fetchList} from '../services/product'; import {fetchList, fetchCates, fetchItem, updateItem} from '../services/product';
import {message} from 'antd'; import {message} from 'antd';
function* getList(query) { function* getList(query) {
...@@ -15,8 +15,8 @@ function* getList(query) { ...@@ -15,8 +15,8 @@ function* getList(query) {
console.log(err); console.log(err);
message.error(err); message.error(err);
yield put({ yield put({
type: 'FETCH_PRODUCT_LIST_FAILED', type: 'FETCH_PRODUCT_LIST_FAILED',
err, err,
}); });
} }
} }
...@@ -28,6 +28,79 @@ function* watchProductList() { ...@@ -28,6 +28,79 @@ function* watchProductList() {
} }
} }
function* getCates() {
try {
const cates = yield call(fetchCates);
yield put({
type: 'FETCH_PRODUCT_CATES_SUCCESS',
cates
});
} catch (err) {
console.log(err);
message.error(err);
yield put({
type: 'FETCH_PRODUCT_CATES_FAILED',
err,
});
}
}
function* watchProductCates() {
yield takeLatest('FETCH_PRODUCT_CATES', getCates);
}
function* getItem(id) {
try {
const item = yield call(fetchItem, id);
yield put({
type: 'FETCH_PRODUCT_ITEM_SUCCESS',
item
});
} catch (err) {
console.log(err);
message.error(err);
yield put({
type: 'FETCH_PRODUCT_ITEM_FAILED',
err
});
}
}
function* watchProductItem() {
while (true) {
const {id} = yield take('FETCH_PRODUCT_ITEM');
yield fork(getItem, id);
}
}
function* editItem(item) {
try{
yield call(updateItem, item);
yield put({
type: 'UPDATE_PRODUCT_ITEM_SUCCESS',
});
}catch(err){
console.log(err);
message.error(err);
yield put({
type:'UPDATE_PRODUCT_ITEM_FAILED',
err
});
}
}
function* watchEditProductItem(){
while(true){
const {item} = yield take('UPDATE_PRODUCT_ITEM');
yield fork(editItem, item);
}
}
export default function*() { export default function*() {
yield fork(watchProductList); yield fork(watchProductList);
yield fork(watchProductCates);
yield fork(watchProductItem);
yield fork(watchEditProductItem);
} }
import xFetch from './xFetch'; import xFetch from './xFetch';
import {params} from '../utils'; import {serialize} from '../utils';
export async function fetchList(query) { export async function fetchList(query) {
return xFetch('/api/products' +'?' + params(query)); return xFetch('/api/products' + '?' + serialize(query));
}
export async function fetchCates() {
return xFetch('/api/cates');
}
export async function fetchItem(id) {
return xFetch('/api/products/' + id, {
method: 'GET'
});
}
export async function updateItem(item){
let form = new FormData();
Object.keys(item).map((key)=>{
form.append(key, item[key]);
});
//return xFetch('/api/products/create');
return xFetch('/api/products/'+ item.id, {
method:'PUT',
body: serialize(item)
});
} }
...@@ -5,7 +5,7 @@ const errorMessages = (res) => `${res.status} ${res.statusText}`; ...@@ -5,7 +5,7 @@ const errorMessages = (res) => `${res.status} ${res.statusText}`;
function check401(res) { function check401(res) {
if (res.status === 401) { if (res.status === 401) {
//location.href = '/401'; location.href = '/login';
} }
return res; return res;
} }
...@@ -33,7 +33,7 @@ function xFetch(url, options) { ...@@ -33,7 +33,7 @@ function xFetch(url, options) {
const opts = {...options}; const opts = {...options};
let user; let user;
try{ try{
user = JSON.parse(sessionStorage.getItem('user')); user = JSON.parse(sessionStorage.getItem('user')) || {};
}catch(ex){ }catch(ex){
user = {}; user = {};
} }
...@@ -41,6 +41,11 @@ function xFetch(url, options) { ...@@ -41,6 +41,11 @@ function xFetch(url, options) {
...opts.headers, ...opts.headers,
authorization: user.token || '', authorization: user.token || '',
}; };
if(opts.method!='GET'){
opts.headers['content-type'] = 'application/x-www-form-urlencoded';
}
return fetch(url, opts) return fetch(url, opts)
.then(check401) .then(check401)
......
export const params = query => Object.keys(query).map((key)=> { // export const params = query => Object.keys(query).map((key)=> {
return key + '=' + query[key]; // return key + '=' + query[key];
}).join('&'); // }).join('&');
export function serialize(obj, prefix) {
var str = [];
for(var p in obj) {
if (obj.hasOwnProperty(p)) {
var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
str.push(typeof v == "object" ?
serialize(v, k) :
encodeURIComponent(k) + "=" + encodeURIComponent(v));
}
}
return str.join("&");
}
export const leftPad = num => { export const leftPad = num => {
return num >= 10 ? num : ('0' + num); return num >= 10 ? num : ('0' + num);
...@@ -21,28 +36,19 @@ export const formatDateTime = (time = 0, format = 'YYYY-MM-DD hh:mm:ss') => { ...@@ -21,28 +36,19 @@ export const formatDateTime = (time = 0, format = 'YYYY-MM-DD hh:mm:ss') => {
}); });
}; };
export const PRODUCT_STATUS = {
'-9':'草稿',
0:'已删除',
1:'未发布',
5:'预热中',
11:'募集中',
17:'已暂停',
21:'已封账',
31:'已成立',
}
export const productStatusToString = status => { export const productStatusToString = status => {
switch (status) { return PRODUCT_STATUS[status] || '未定义';
case 0 :
return '无效, 已删除';
case 1 :
return '未发布';
case 5 :
return '预热中';
case 11:
return '募集中';
case 17:
return '暂停';
case 21:
return '已封账';
case 31:
return '产品成立';
case -9:
return '草稿';
default:
return '未定义';
}
}; };
...@@ -82,4 +88,15 @@ export const tradeCreateTypeToString = type => { ...@@ -82,4 +88,15 @@ export const tradeCreateTypeToString = type => {
default: default:
return '未知创建者'; return '未知创建者';
} }
} };
export const arrayRemoveIndex = (arr, index) => {
return arr.concat(arr.splice(index).splice(1));
};
export const UUID = (()=> {
let _UUID = 0;
return ()=> {
return _UUID++;
}
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment