123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786 |
- /* eslint-disable no-trailing-spaces */
- import React, { Component } from 'react';
- import { connect } from 'dva';
- import { Tooltip, Card, Modal, Form, Table, List, Steps, Select, Button, Input, Icon } from 'antd';
- import Ellipsis from '../../../components/Ellipsis';
- import Selector from '../../../components/AXTableSelector/Selector';
- import FooterToolbar from '../../../components/FooterToolbar';
- import { checkProductType, toDecimal2 } from '../../../utils/utils';
- import { Hotax } from '../../../utils/config';
- import styles from './OrderCreate.less';
- const formItemLayout = {
- labelCol: {
- xs: { span: 24 },
- sm: { span: 7 },
- },
- wrapperCol: {
- xs: { span: 24 },
- sm: { span: 14 },
- md: { span: 10 },
- },
- };
- @connect(({ terminal, shelves, trade, loading }) => ({
- trade,
- shelves,
- terminal,
- sLoading: loading.models.shelves,
- tLoading: loading.models.terminal,
- submitting: loading.models.trade,
- }))
- @Form.create()
- export default class OrderCreatePage extends Component {
- state = {
- currentStep: 0,
- selectedGoods: [],
- adjustPrice: 0,
- deliveryInfo: {},
- terminalSelectorDestroy: true,
- goodsSelectorDestroy: true,
- packageFixModalDestroy: true,
- packageContent: {},
- width: '100%',
- };
- componentDidMount() {
- // 监听视图窗口变化
- window.addEventListener('resize', this.resizeFooterToolbar);
- this.resizeFooterToolbar();
- }
- componentWillUnmount() {
- window.removeEventListener('resize', this.resizeFooterToolbar);
- }
- resizeFooterToolbar = () => {
- const sider = document.querySelectorAll('.ant-layout-sider')[0];
- const width = `calc(100% - ${sider.style.width})`;
- if (this.state.width !== width) {
- this.setState({ width });
- }
- };
- // 终端模态选择器显示
- handleTerminalSelectorModalShow = () => {
- this.setState({
- terminalSelectorDestroy: false,
- });
- this.props.dispatch({
- type: 'terminal/fetchTerminalList',
- payload: {},
- });
- };
- // 终端模态选择器完成
- handleTerminalSelectorFinish = (rows) => {
- this.setState({
- terminalSelectorDestroy: true,
- });
- if (!rows || !rows.length) {
- return;
- }
- const {
- id, code, name, campusName, merchantId, contactName, mobile, address,
- } = rows[0];
- this.setState({
- deliveryInfo: {
- id, code, name, campusName, merchantId, contactName, mobile, address,
- },
- });
- };
- // 终端模态选择器取消
- handleTerminalSelectorCancel = () => {
- this.setState({
- terminalSelectorDestroy: true,
- });
- };
- // 终端模态选择器变化
- handleTerminalSelectorChange = (params) => {
- this.props.dispatch({
- type: 'terminal/fetchTerminalList',
- payload: params,
- });
- };
- // 商品模态选择器展现
- handleGoodsSelectorModalShow = () => {
- const { deliveryInfo } = this.state;
- const { merchantId } = deliveryInfo;
- this.setState({
- goodsSelectorDestroy: false,
- });
- this.props.dispatch({
- type: 'shelves/fetchItemList',
- payload: { merchantId },
- });
- };
- // 商品模态选择器变化
- handleGoodsSelectorChange = (params) => {
- const { deliveryInfo } = this.state;
- const { merchantId } = deliveryInfo;
- this.props.dispatch({
- type: 'shelves/fetchItemList',
- payload: { merchantId, ...params },
- });
- };
- // 商品模态选择器完成
- handleGoodsSelectorFinish = (rows) => {
- // 去掉没有定价的商品
- const newRows = rows.filter((row) => {
- return !(!row.goods || !row.goods.length);
- });
- this.setState({
- goodsSelectorDestroy: true,
- selectedGoods: newRows,
- });
- };
- // 商品模态选择器取消
- handleGoodsSelectorCancel = () => {
- this.setState({
- goodsSelectorDestroy: true,
- });
- };
- // 套餐包详情模态框展现
- handlePackageFixModalShow = (contents) => {
- this.setState({
- packageFixModalDestroy: false,
- packageContent: contents,
- });
- };
- // 套餐包详情模态框取消
- handlePackageFixCancel = () => {
- this.setState({
- packageFixModalDestroy: true,
- });
- };
- // 响应价格变化
- handleGoodsSelectChange = (rowIndex, goodsId) => {
- const { selectedGoods } = this.state;
- const targetRow = selectedGoods[rowIndex];
- const { goods } = targetRow;
- const targetGoods = goods.find(goodsItem => goodsItem.id === goodsId);
- if (targetGoods) {
- targetRow.selectedGoodsId = targetGoods.id;
- targetRow.selectedChargeUnit = targetGoods.chargeUnit;
- targetRow.selectedPrice = targetGoods.merchantPrice;
- selectedGoods[rowIndex] = targetRow;
- this.setState({ selectedGoods });
- }
- };
- // 响应数量变化 - 填写
- handleQuantityInputChange = (rowIndex, e) => {
- const { selectedGoods } = this.state;
- const targetRow = selectedGoods[rowIndex];
- targetRow.quantity = e.target.value;
- selectedGoods[rowIndex] = targetRow;
- this.setState({ selectedGoods });
- };
- // 响应数量变化 - 加减
- handleQuantityStepChange = (rowIndex, type) => {
- const { selectedGoods } = this.state;
- const targetRow = selectedGoods[rowIndex];
- const { quantity } = targetRow;
- if (type === 'plus') {
- targetRow.quantity = quantity + 1;
- } else if (type === 'minus' && quantity > 1) {
- targetRow.quantity = quantity - 1;
- }
- selectedGoods[rowIndex] = targetRow;
- this.setState({ selectedGoods });
- };
- // 优惠价格调整
- handleAdjustPriceChange = (value) => {
- this.setState({ adjustPrice: value });
- };
- // 下一步
- nextStep = () => {
- const { currentStep } = this.state;
- if (currentStep === 0) {
- this.props.form.validateFieldsAndScroll((error, values) => {
- if (!error) {
- this.setState({
- currentStep: this.state.currentStep + 1,
- deliveryInfo: {
- ...this.state.deliveryInfo,
- ...values,
- },
- });
- }
- });
- return;
- }
- this.setState({ currentStep: this.state.currentStep + 1 });
- };
- // 上一步
- prevStep = () => {
- this.setState({ currentStep: this.state.currentStep - 1 });
- };
- // 提交订单
- handleSubmitOrder = (goodsList) => {
- const { deliveryInfo, adjustPrice } = this.state;
- const { id, contactName, mobile, address } = deliveryInfo;
- const goods = goodsList.map(item => ({
- goodsId: item.selectedGoodsId,
- quantity: item.quantity,
- }));
- const jsonBody = {
- mobile,
- address,
- goods,
- adjustPrice,
- uid: id,
- name: contactName,
- status: Hotax.ORDER_UNPAID,
- };
- this.props.dispatch({
- type: 'trade/createOrderItem',
- payload: jsonBody,
- });
- };
- render() {
- const {
- currentStep, selectedGoods, adjustPrice = 0, deliveryInfo, packageContent,
- terminalSelectorDestroy, goodsSelectorDestroy, packageFixModalDestroy,
- } = this.state;
- const {
- code, name, campusName, contactName, mobile, address,
- } = deliveryInfo;
- const { terminal, tLoading, shelves, sLoading, form } = this.props;
- const { getFieldDecorator } = form;
- // ##### Card1: 终端选择及收货信息填写 #####
- const terminalInfoCard = () => {
- const getTerminalModal = () => {
- return (
- <Modal
- visible
- width={1100}
- footer={null}
- title="终端列表"
- maskClosable={false}
- onCancel={this.handleTerminalSelectorCancel}
- >
- <Selector
- multiple={false}
- loading={tLoading}
- selectorName="Terminal"
- list={terminal.list}
- pageNo={terminal.pageNo}
- pageSize={terminal.pageSize}
- totalSize={terminal.totalSize}
- onCancel={this.handleTerminalSelectorCancel}
- onChange={this.handleTerminalSelectorChange}
- onFinish={this.handleTerminalSelectorFinish}
- />
- </Modal>
- );
- };
- return (
- <Card title="终端信息" style={{ marginTop: 10, marginBottom: 70 }}>
- <Form>
- <Form.Item
- {...formItemLayout}
- label={<Button size="small" type="primary" onClick={this.handleTerminalSelectorModalShow}>选择终端</Button>}
- >
- <List
- bordered
- size="small"
- dataSource={[
- `终端编号: ${code || ''}`,
- `终端名称: ${name || ''}`,
- `所属校区: ${campusName || ''}`,
- ]}
- renderItem={item => <List.Item>{item}</List.Item>}
- />
- </Form.Item>
- <Form.Item label="收货人" {...formItemLayout}>
- {getFieldDecorator('contactName', {
- rules: [{ required: true, message: '请填写收货人' }],
- initialValue: contactName,
- })(
- <Input placeholder="请填写" />
- )}
- </Form.Item>
- <Form.Item label="收货地址" {...formItemLayout}>
- {getFieldDecorator('address', {
- rules: [{ required: true, message: '请填写收货地址' }],
- initialValue: address,
- })(
- <Input placeholder="请填写" />
- )}
- </Form.Item>
- <Form.Item label="手机号码" {...formItemLayout}>
- {getFieldDecorator('mobile', {
- rules: [
- {
- required: true, message: '请填写联系电话',
- }, {
- pattern: /^[1][34578][0-9]{9}$/g, message: '请输入11位有效手机号!',
- },
- ],
- initialValue: mobile,
- })(
- <Input placeholder="请填写" />
- )}
- </Form.Item>
- </Form>
- {!terminalSelectorDestroy && getTerminalModal()}
- </Card>
- );
- };
- // ##### Card2: 商品选择 #####
- const rowDataFormatter = (rows) => {
- // 默认选定第一个价格类型
- const findSelectedPrice = (goodsArr) => {
- if (!goodsArr) { return; }
- let selectedGoodsId = null;
- let selectedChargeUnit = null;
- let selectedPrice = null;
- goodsArr.forEach((item, index) => {
- if (index === 0) {
- selectedGoodsId = item.id;
- selectedChargeUnit = item.chargeUnit;
- selectedPrice = parseInt(item.merchantPrice, 10);
- }
- });
- return { selectedGoodsId, selectedChargeUnit, selectedPrice };
- };
- const newRows = [];
- for (let row of rows) {
- // 设置默认数量
- if (!row.quantity) {
- row.quantity = 1;
- }
- // 设置默认选中价格
- if (!row.selectedGoodsId) {
- const price = findSelectedPrice(row.goods);
- row = { ...row, ...price };
- }
- // 小计
- row.subTotal = row.quantity * row.selectedPrice;
- newRows.push(row);
- }
- return newRows;
- };
- // 按需求处理后的数据
- const formattedDataSource = rowDataFormatter(selectedGoods);
- // 计算总价
- const computeTotalPrice = (rows) => {
- let sum = 0;
- rows.forEach((row) => {
- sum += row.subTotal;
- });
- return sum;
- };
- const totalPrice = computeTotalPrice(formattedDataSource);
- const goodsSelectCard = () => {
- const getGoodsModal = () => {
- return (
- <Modal
- visible
- width={1100}
- footer={null}
- title="商品列表"
- maskClosable={false}
- onCancel={this.handleGoodsSelectorCancel}
- >
- <Selector
- multiple
- loading={sLoading}
- selectorName="Product"
- list={shelves.list}
- pageNo={shelves.pageNo}
- pageSize={shelves.pageSize}
- totalSize={shelves.totalSize}
- selectedRows={selectedGoods}
- onCancel={this.handleGoodsSelectorCancel}
- onChange={this.handleGoodsSelectorChange}
- onFinish={this.handleGoodsSelectorFinish}
- />
- </Modal>
- );
- };
- // 修正课程包内配套数量
- const getPackageFixModal = () => {
- const { products } = packageContent;
- const packageColumns = [{
- title: '产品编号',
- dataIndex: 'code',
- key: 'code',
- width: '20%',
- }, {
- title: '产品名称',
- dataIndex: 'name',
- key: 'name',
- width: '40%',
- }, {
- title: '产品类型',
- dataIndex: 'type',
- key: 'type',
- render: text => checkProductType(text),
- width: '20%',
- align: 'center',
- }, {
- title: '单价',
- dataIndex: 'merchantPrice',
- key: 'merchantPrice',
- width: '20%',
- render: (text, record) => {
- if (record.type !== Hotax.PRODUCT_SUPPORT) {
- return '-';
- }
- return `¥${text}/件`;
- },
- align: 'center',
- /* TODO: 套餐包内配套数量修改
- }, {
- title: '数量',
- dataIndex: 'quantity',
- key: 'quantity',
- width: '20%',
- render: (text, record, index) => {
- if (record.type !== Hotax.PRODUCT_SUPPORT) {
- return '-';
- }
- return (
- <Input
- style={{ width: 150 }}
- addonBefore={
- <Icon
- type="minus"
- className={styles.icon}
- onClick={() => this.handleQuantityStepChange(index, 'minus', record.id)}
- />
- }
- addonAfter={
- <Icon
- type="plus"
- className={styles.icon}
- onClick={() => this.handleQuantityStepChange(index, 'plus', record.id)}
- />
- }
- value={text}
- onChange={e => this.handleQuantityInputChange(index, e, record.id)}
- />
- );
- },
- align: 'center',
- */
- }];
- return (
- <Modal
- visible
- width={1100}
- title="套餐包详情"
- maskClosable={false}
- onCancel={this.handlePackageFixCancel}
- >
- <Table
- bordered
- pagination={false}
- columns={packageColumns}
- dataSource={products}
- rowKey={record => record.id}
- scroll={{ y: 500 }}
- />
- </Modal>
- );
- };
- const goodsColumns = [{
- title: '商品编号',
- dataIndex: 'code',
- key: 0,
- render: (text, record) => {
- if (record.type === Hotax.PRODUCT_PACKAGE) {
- return (
- <Tooltip placement="top" title="点击查看套餐包内容">
- <a className="a-link" onClick={() => this.handlePackageFixModalShow(record)}>{text}</a>
- </Tooltip>
- );
- }
- return text;
- },
- width: '17%',
- }, {
- title: '商品名称',
- dataIndex: 'name',
- key: 1,
- width: '28%',
- render: text => (
- <Ellipsis tooltip lines={1}>{text}</Ellipsis>
- ),
- }, {
- title: '商品类型',
- key: 2,
- dataIndex: 'type',
- render: text => checkProductType(text),
- width: '12%',
- align: 'center',
- }, {
- title: '单价',
- key: 3,
- dataIndex: 'goods',
- render: (goodsArr, record, index) => {
- if (!goodsArr) {
- return null;
- }
- return (
- <Select
- style={{ width: 150 }}
- value={record.selectedGoodsId}
- onChange={goodsId => this.handleGoodsSelectChange(index, goodsId)}
- >
- {
- goodsArr.map(item => (
- <Select.Option key={item.id} value={item.id}>
- {`¥${item.merchantPrice}/${item.chargeUnit}`}
- </Select.Option>
- ))
- }
- </Select>
- );
- },
- width: '12%',
- align: 'center',
- }, {
- title: '数量',
- key: 4,
- dataIndex: 'quantity',
- width: '13%',
- render: (text, _, index) => {
- return (
- <Input
- style={{ width: 150 }}
- addonBefore={
- <Icon
- type="minus"
- className={styles.icon}
- onClick={() => this.handleQuantityStepChange(index, 'minus')}
- />
- }
- addonAfter={
- <Icon
- type="plus"
- className={styles.icon}
- onClick={() => this.handleQuantityStepChange(index, 'plus')}
- />
- }
- value={text}
- onChange={e => this.handleQuantityInputChange(index, e)}
- />
- );
- },
- align: 'center',
- }, {
- title: '小计',
- key: 5,
- dataIndex: 'subTotal',
- width: '13%',
- render: text => (
- <span style={{ fontWeight: 500 }}>{`¥${text}`}</span>
- ),
- align: 'center',
- }];
- return (
- <Card
- title={<Button type="primary" onClick={this.handleGoodsSelectorModalShow}>选择商品</Button>}
- style={{ marginTop: 10, marginBottom: 70 }}
- >
- <Table
- border={false}
- pagination={false}
- columns={goodsColumns}
- dataSource={formattedDataSource}
- rowKey={record => record.id}
- />
- {!goodsSelectorDestroy && getGoodsModal()}
- {!packageFixModalDestroy && getPackageFixModal()}
- </Card>
- );
- };
- // ##### Card3: 确认订单 #####
- const confirmInfoCard = () => {
- const columns = [{
- title: '商品名称',
- dataIndex: 'name',
- key: 1,
- width: '20%',
- }, {
- title: '商品编号',
- dataIndex: 'code',
- key: 2,
- width: '20%',
- }, {
- title: '商品类型',
- dataIndex: 'type',
- key: 3,
- align: 'center',
- render: text => checkProductType(text),
- width: '12%',
- }, {
- title: '单价',
- dataIndex: 'selectedPrice',
- key: 4,
- align: 'center',
- render: text => `¥${text}`,
- width: '12%',
- }, {
- title: '数量',
- dataIndex: 'quantity',
- key: 5,
- align: 'center',
- render: text => `×${text}`,
- width: '12%',
- }, {
- title: '单位',
- dataIndex: 'selectedChargeUnit',
- key: 6,
- align: 'center',
- width: '12%',
- }, {
- title: '小计',
- dataIndex: 'subTotal',
- key: 7,
- align: 'center',
- render: text => `¥${text}`,
- width: '12%',
- }];
- return (
- <div>
- <Card title="商品清单" style={{ marginTop: 10 }}>
- <Table
- bordered
- columns={columns}
- pagination={false}
- rowKey={record => record.id}
- dataSource={formattedDataSource}
- />
- </Card>
- <Card title="收货信息" style={{ marginTop: 10, marginBottom: 70 }}>
- <List
- bordered
- size="small"
- dataSource={[
- `终端账号: ${code || ''}`,
- `收货人: ${contactName || ''}`,
- `收货地址: ${address || ''}`,
- `手机号码: ${mobile || ''}`,
- ]}
- renderItem={item => <List.Item>{item}</List.Item>}
- />
- </Card>
- </div>
- );
- };
- // 步骤条配置
- const steps = [{
- title: '选择购买终端',
- stepKey: 0,
- icon: 'shop',
- content: terminalInfoCard(),
- }, {
- title: '选择商品',
- stepKey: 1,
- icon: 'environment',
- content: goodsSelectCard(),
- }, {
- title: '确认订单',
- stepKey: 2,
- icon: 'profile',
- content: confirmInfoCard(),
- }];
- return (
- <div>
- <Steps current={currentStep}>
- {steps.map((item, index) =>
- (
- <Steps.Step
- key={item.stepKey}
- title={item.title}
- icon={<Icon type={steps[index].icon} />}
- />
- )
- )}
- </Steps>
- {steps[currentStep].content}
- <FooterToolbar
- extra={
- <div>
- <span className={styles.quantity}>
- 已选择
- <span style={{ color: '#f60', fontWeight: 500 }}>
- {selectedGoods.length}
- </span>
- 件商品
- </span>
- {/*
- <span className={styles.adjustPrice}>
- <span style={{ color: '#2f7d0d' }}>
- 优惠: ¥
- </span>
- <InputNumber
- min={0}
- max={totalPrice}
- size="small"
- value={adjustPrice}
- onChange={this.handleAdjustPriceChange}
- />
- </span>
- */}
- <span className={styles.totalPrice}>
- 总价:
- <span style={{ color: '#f60', fontSize: 24 }}>
- {`¥ ${toDecimal2(totalPrice - adjustPrice)}`}
- </span>
- </span>
- </div>
- }
- style={{ width: this.state.width }}
- >
- {
- (currentStep > 0) && (
- <Button onClick={this.prevStep}>
- {`上一步: ${steps[currentStep - 1].title}`}
- </Button>
- )
- }
- {/* 步骤一:选择终端 */}
- {
- (currentStep === 0) && (
- <Button
- type="primary"
- disabled={Object.keys(deliveryInfo).length === 0}
- onClick={this.nextStep}
- >
- {`下一步: ${steps[currentStep + 1].title}`}
- </Button>
- )
- }
- {/* 步骤二:选择产品 */}
- {
- (currentStep === 1) && (
- <Button
- type="primary"
- disabled={Object.keys(selectedGoods).length === 0}
- onClick={this.nextStep}
- >
- {`下一步: ${steps[currentStep + 1].title}`}
- </Button>
- )
- }
- {/* 步骤三:确认订单 */}
- {
- (currentStep === 2) && (
- <Button
- type="primary"
- onClick={() => this.handleSubmitOrder(formattedDataSource)}
- >
- 确认下单
- </Button>
- )
- }
- </FooterToolbar>
- </div>
- );
- }
- }
|