提交 5b51d529 authored 作者: sin's avatar sin

- 添加订单取消

- 优化订单列表 - 添加订单备注
上级 85a1be39
......@@ -65,7 +65,7 @@ if (APP_TYPE === 'site') {
export default {
// add for transfer to umi
base: basePath,
publicPath: basePath,
// publicPath: basePath,
plugins,
define: {
APP_TYPE: APP_TYPE || '',
......
......@@ -69,6 +69,11 @@ export default [
name: 'order-list',
component: './Order/OrderList',
},
{
path: '/order/order-refunds',
name: 'order-refunds',
component: './Order/OrderRefunds',
},
],
},
// product
......
// import React, { PureComponent } from 'react';
// import {} from 'antd';
//
// export default class OrderTable extends PureComponent {
// render() {
// return <div>cc</div>;
// }
// }
......@@ -52,6 +52,7 @@ export default {
// 订单
'menu.order': '订单管理',
'menu.order.order-list': '订单管理',
'menu.order.order-refunds': '退货维权',
// 营销相关
'menu.promotion.promotion-banner-list': 'Banner 管理'
'menu.promotion.promotion-banner-list': 'Banner 管理',
};
// import { cancelOrder } from '../../services/order';
//
// export default {
// namespace: 'orderDelivery',
//
// state: {
// orderId: 0,
// visible: false,
// },
//
// effects: {
// *getLogistics({ payload }, { call, put }) {},
// },
//
// reducers: {
// changeVisible(state, { payload }) {
// const { orderId, visible } = payload;
// return {
// ...state,
// orderId,
// visible,
// };
// },
// },
// };
import { message } from 'antd';
import { orderPage, updateOrderItem, updateOrderItemPayAmount } from '../../services/order';
import {
orderPage,
updateOrderItem,
updateOrderItemPayAmount,
updateRemark,
cancelOrder,
} from '../../services/order';
export default {
namespace: 'orderList',
......@@ -18,6 +24,12 @@ export default {
orderId: 0,
orderItemId: 0,
searchParams: {},
remarkVisible: false,
remark: '',
orderCancelVisible: false,
orderCancelShowOther: false,
},
effects: {
......@@ -70,6 +82,40 @@ export default {
},
});
yield put({
type: 'queryPage',
payload: {
...searchParams,
},
});
},
*updateRemake({ payload }, { call, put }) {
const { searchParams, params } = payload;
yield call(updateRemark, params);
yield put({
type: 'changeRemakeVisible',
payload: {
remarkVisible: false,
},
});
yield put({
type: 'queryPage',
payload: {
...searchParams,
},
});
},
*cancelOrder({ payload }, { call, put }) {
const { searchParams, params } = payload;
yield call(cancelOrder, params);
yield put({
type: 'changeOrderCancelVisible',
payload: {
orderCancelVisible: false,
},
});
yield put({
type: 'queryPage',
payload: {
......@@ -99,5 +145,23 @@ export default {
...payload,
};
},
changeRemakeVisible(state, { payload }) {
return {
...state,
...payload,
};
},
changeOrderCancelVisible(state, { payload }) {
return {
...state,
...payload,
};
},
changeOrderCancelShowOther(state, { payload }) {
return {
...state,
...payload,
};
},
},
};
import React from 'react';
import { Form, Input, Modal } from 'antd';
import DictionarySelect from '@/components/Dictionary/DictionarySelect';
import dictionary from '@/utils/dictionary';
const FormItem = Form.Item;
// 订单 - 更新支付金额
const OrderCancel = Form.create()(props => {
const { form, dispatch, loading } = props;
const { orderId, orderCancelVisible, orderCancelShowOther, searchParams } = props.orderList;
const { getFieldDecorator } = props.form;
const handleOk = e => {
e.preventDefault();
form.validateFields((err, fields) => {
if (err) return;
dispatch({
type: 'orderList/cancelOrder',
payload: {
params: {
orderId,
reasons: fields.reasons,
otherReasons: fields.otherReasons,
},
searchParams,
},
});
});
};
const handleCancel = () => {
dispatch({
type: 'orderList/changeRemakeVisible',
payload: {
remarkVisible: false,
},
});
};
const handleReasonsChange = key => {
dispatch({
type: 'orderList/changeOrderCancelShowOther',
payload: {
orderCancelShowOther: key === '20',
},
});
};
return (
<Modal
destroyOnClose
title="取消订单"
visible={orderCancelVisible}
onOk={handleOk}
okText="保存"
onCancel={handleCancel}
confirmLoading={loading}
>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="原因">
{getFieldDecorator('reasons', {
rules: [{ required: true, message: '请选择取消原因!' }],
})(
<DictionarySelect
onChange={handleReasonsChange}
style={{ minWidth: '100%' }}
dicKey={dictionary.ORDER_CANCEL_REASONS}
/>
)}
</FormItem>
{orderCancelShowOther ? (
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="其他原因">
{getFieldDecorator('otherReasons', {
rules: [{ required: true, message: '请输填写退款原因!' }],
})(<Input.TextArea autosize={{ minRows: 3, maxRows: 6 }} placeholder="请输入退款原因" />)}
</FormItem>
) : (
''
)}
</Modal>
);
});
export default OrderCancel;
// import React, { PureComponent } from 'react';
//
// class OrderDelivery extends PureComponent {}
//
// export default OrderDelivery;
差异被折叠。
@import '~antd/lib/style/themes/default.less';
@import '~@/utils/utils.less';
.tableList {
.tableListOperator {
margin-bottom: 16px;
button {
margin-right: 8px;
}
}
}
.tableListForm {
:global {
.ant-form-item {
display: flex;
margin-right: 0;
margin-bottom: 24px;
> .ant-form-item-label {
width: auto;
padding-right: 8px;
line-height: 32px;
}
.ant-form-item-control {
line-height: 32px;
}
}
.ant-form-item-control-wrapper {
flex: 1;
}
}
.submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
}
@media screen and (max-width: @screen-lg) {
.tableListForm :global(.ant-form-item) {
margin-right: 24px;
}
}
@media screen and (max-width: @screen-md) {
.tableListForm :global(.ant-form-item) {
margin-right: 8px;
}
}
......@@ -6,6 +6,8 @@ import { Button, Card, Col, Divider, Form, Input, Row, Tabs, DatePicker, List }
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import DictionaryText from '@/components/Dictionary/DictionaryText';
import OrderUpdatePayAmount from './OrderUpdatePayAmount';
import OrderRemark from './OrderRemark';
import OrderCancel from './OrderCancel';
import dictionary from '@/utils/dictionary';
import styles from './OrderList.less';
......@@ -14,8 +16,10 @@ const { RangePicker } = DatePicker;
const FormItem = Form.Item;
const { TabPane } = Tabs;
const OrderContent = orderItem => {
const { dispatch, skuName, skuImage, quantity, price, payAmount, createTime, status } = orderItem;
const OrderContent = props => {
const { dispatch, item } = props;
const { createTime, status, payAmount } = item;
const { name, mobile } = item.orderRecipient;
const handleUpdatePayAmount = updateOrderItem => {
dispatch({
......@@ -29,27 +33,58 @@ const OrderContent = orderItem => {
});
};
// const handleCancelOrder = ({ orderId }) => {
// dispatch({
// type: 'orderList/changeOrderCancelVisible',
// payload: {
// orderCancelVisible: true,
// orderId,
// },
// });
// };
//
// const handleRenderGoods = () => {};
const renderStatusButtons = () => {
let res = '';
if (status === 1) {
res = <Button>取消订单</Button>;
} else if (status === 2) {
res = <Button>发货</Button>;
}
return res;
};
const renderGoods = orderItems => {
return orderItems.map(({ skuName, skuImage, quantity, price }) => {
return (
<div className={styles.orderGoods}>
<img alt={skuName} className={`${styles.image}`} src={skuImage} />
<div className={styles.contentItem}>
<div>
<a>{skuName}</a>
</div>
<div>秋季精选</div>
</div>
<div className={styles.contentItem}>
<div>{quantity}</div>
<div>
{price / 100} /{quantity * (price / 100)}
</div>
</div>
</div>
);
});
};
return (
<div className={styles.order}>
<img alt={skuName} className={`${styles.image}`} src={skuImage} />
<div className={styles.contentItem}>
<div className={styles.columnName}>(名称)</div>
<div>
<a>{skuName}</a>
</div>
<div>秋季精选</div>
<div className={`${styles.contentItem} ${styles.goodsContainer}`}>
{renderGoods(item.orderItems)}
</div>
<div className={styles.contentItem}>
<div className={styles.columnName}>(金额/物件)</div>
<div>{quantity}</div>
<div>
{price / 100} /{quantity * (price / 100)}
</div>
</div>
<div className={styles.contentItem}>
<div className={styles.columnName}>(购买人)</div>
<div>范先生</div>
<div>13302926050</div>
<div>{name}</div>
<div>{mobile}</div>
</div>
<div className={styles.contentItem}>
<div className={styles.columnName}>(下单时间)</div>
......@@ -57,17 +92,16 @@ const OrderContent = orderItem => {
<div>&nbsp;</div>
</div>
<div className={styles.contentItem}>
<div className={styles.columnName}>(订单状态)</div>
<div>
<DictionaryText dicKey={dictionary.ORDER_STATUS} dicValue={status} />
</div>
<div>{[0, 1, 2].indexOf(status) ? <Button>取消订单</Button> : ''}</div>
<div>{renderStatusButtons()}</div>
</div>
<div className={styles.contentItem}>
<div className={styles.columnName}>(实付金额)</div>
<div>{payAmount / 100}</div>
<div>
<a onClick={() => handleUpdatePayAmount(orderItem)}>修改价格</a>
<a onClick={() => handleUpdatePayAmount(props)}>修改价格</a>
</div>
</div>
</div>
......@@ -82,6 +116,18 @@ const OrderList = props => {
...pagination,
};
const handleRemakeClick = item => {
const { id, remark } = item;
dispatch({
type: 'orderList/changeRemakeVisible',
payload: {
remarkVisible: true,
orderId: id,
remark,
},
});
};
return (
<List
size="large"
......@@ -102,13 +148,11 @@ const OrderList = props => {
<div>
<a>查看详情</a>
<Divider type="vertical" />
<a>备注</a>
<a onClick={() => handleRemakeClick(item)}>备注</a>
</div>
</div>
{item.orderItems.map(orderItem => {
return <OrderContent key={orderItem.id} dispatch={dispatch} {...orderItem} />;
})}
<OrderContent item={item} dispatch={dispatch} />
</div>
</List.Item>
)}
......@@ -131,11 +175,9 @@ const SearchForm = Form.create()(props => {
form.validateFields((err, fields) => {
const buildTime = (fieldValue, key) => {
const res = {};
if (fieldValue) {
if (fieldValue && fieldValue.length >= 2) {
const keySuffix = key.substring(0, 1).toUpperCase() + key.substring(1);
// res[`start${keySuffix}`] = fieldValue[0].valueOf();
res[`start${keySuffix}`] = fieldValue[0].format('YYYY-MM-DD HH:mm:ss');
// res[`end${keySuffix}`] = fieldValue[1].valueOf();
res[`end${keySuffix}`] = fieldValue[1].format('YYYY-MM-DD HH:mm:ss');
}
return res;
......@@ -186,9 +228,6 @@ const SearchForm = Form.create()(props => {
<Col md={8} sm={24}>
<FormItem label="创建时间">{getFieldDecorator('createTime')(<RangePicker />)}</FormItem>
</Col>
<Col md={8} sm={24}>
<FormItem label="成交时间">{getFieldDecorator('closingTime')(<RangePicker />)}</FormItem>
</Col>
<Col md={8} sm={24}>
<span className={styles.submitButtons}>
<Button type="primary" htmlType="submit">
......@@ -234,9 +273,7 @@ class BasicList extends PureComponent {
});
};
handleEditorClick = () => {
console.info('edit');
};
handleEditorClick = () => {};
handleSearch = fields => {
const {
......@@ -287,6 +324,8 @@ class BasicList extends PureComponent {
</div>
<OrderUpdatePayAmount {...this.props} />
<OrderRemark {...this.props} />
<OrderCancel {...this.props} />
</PageHeaderWrapper>
);
}
......
......@@ -239,6 +239,8 @@
// 订单content
.orderGroup {
@padding-slid: 10px;
@solid-color: rgba(167, 157, 160, 0.92);
@header-background: rgba(210, 219, 238, 0.99);
display: flex;
flex: 1;
......@@ -254,7 +256,26 @@
font-weight: bold;
font-size: 15px;
line-height: 35px;
background-color: #c0bfb9;
background-color: @header-background;
}
.goodsContainer {
:first-child {
border-top: none;
border-bottom: none;
}
:last-child {
border-bottom: none;
}
}
.orderGoods {
display: flex;
flex: 2;
flex-direction: row;
width: 500px;
border: 1px solid @solid-color;
}
.order {
......@@ -264,7 +285,7 @@
padding-right: @padding-slid;
padding-left: @padding-slid;
line-height: 100px;
border: 1px solid #c0bfb9;
border: 1px solid @solid-color;
.contentItem {
display: flex;
......@@ -285,8 +306,8 @@
}
.image {
width: 100px;
height: 100px;
width: 80px;
height: 80px;
}
}
}
import React, { PureComponent } from 'react';
import moment from 'moment';
import { connect } from 'dva';
import { Button, Card, Col, Divider, Form, Input, Row, Tabs, DatePicker, List } from 'antd';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import DictionaryText from '@/components/Dictionary/DictionaryText';
import OrderUpdatePayAmount from './OrderUpdatePayAmount';
import OrderRemark from './OrderRemark';
import dictionary from '@/utils/dictionary';
import styles from './OrderList.less';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
const { TabPane } = Tabs;
const OrderContent = props => {
const {
dispatch,
skuName,
skuImage,
quantity,
price,
payAmount,
createTime,
status,
item,
} = props;
const { name, mobile } = item.orderLogistics;
const handleUpdatePayAmount = updateOrderItem => {
dispatch({
type: 'orderList/changePayAmountVisible',
payload: {
payAmountVisible: true,
payAmount: updateOrderItem.payAmount,
orderId: updateOrderItem.orderId,
orderItemId: updateOrderItem.id,
},
});
};
const renderStatusButtons = () => {
let res = '';
if (status === 1) {
res = <Button>取消订单</Button>;
} else if (status === 2) {
res = <Button>发货</Button>;
}
return res;
};
return (
<div className={styles.order}>
<img alt={skuName} className={`${styles.image}`} src={skuImage} />
<div className={styles.contentItem}>
<div>
<a>{skuName}</a>
</div>
<div>秋季精选</div>
</div>
<div className={styles.contentItem}>
<div>{quantity}</div>
<div>
{price / 100} /{quantity * (price / 100)}
</div>
</div>
<div className={styles.contentItem}>
<div>{name}</div>
<div>{mobile}</div>
</div>
<div className={styles.contentItem}>
<div className={styles.columnName}>(下单时间)</div>
<div>{moment(createTime).format('YYYY-MM-DD HH:mm')}</div>
<div>&nbsp;</div>
</div>
<div className={styles.contentItem}>
<div>
<DictionaryText dicKey={dictionary.ORDER_STATUS} dicValue={status} />
</div>
<div>{renderStatusButtons()}</div>
</div>
<div className={styles.contentItem}>
<div className={styles.columnName}>(实付金额)</div>
<div>{payAmount / 100}</div>
<div>
<a onClick={() => handleUpdatePayAmount(props)}>修改价格</a>
</div>
</div>
</div>
);
};
const OrderList = props => {
const { list, dispatch, loading } = props;
const { pagination, dataSource } = list;
const paginationProps = {
...pagination,
};
const handleRemakeClick = item => {
const { id, remark } = item;
dispatch({
type: 'orderList/changeRemakeVisible',
payload: {
remarkVisible: true,
orderId: id,
remark,
},
});
};
return (
<List
size="large"
rowKey="id"
loading={loading}
pagination={paginationProps}
dataSource={dataSource}
renderItem={item => (
<List.Item>
<div className={styles.orderGroup}>
<div className={styles.header}>
<div>
<span>订单号: {item.orderNo}</span>
<Divider type="vertical" />
<span>支付金额: {item.payAmount / 100} </span>
</div>
<div>
<a>查看详情</a>
<Divider type="vertical" />
<a onClick={() => handleRemakeClick(item)}>备注</a>
</div>
</div>
{item.orderItems.map(orderItem => {
return (
<OrderContent key={orderItem.id} item={item} dispatch={dispatch} {...orderItem} />
);
})}
</div>
</List.Item>
)}
/>
);
};
// SearchForm
const SearchForm = Form.create()(props => {
const {
form: { getFieldDecorator },
form,
handleSearch,
} = props;
const handleFormReset = () => {};
const onSubmit = e => {
e.preventDefault();
form.validateFields((err, fields) => {
const buildTime = (fieldValue, key) => {
const res = {};
if (fieldValue && fieldValue.length >= 2) {
const keySuffix = key.substring(0, 1).toUpperCase() + key.substring(1);
res[`start${keySuffix}`] = fieldValue[0].format('YYYY-MM-DD HH:mm:ss');
res[`end${keySuffix}`] = fieldValue[1].format('YYYY-MM-DD HH:mm:ss');
}
return res;
};
const timeFields = ['createTime', 'closingTime'];
const buildSearchParams = fields2 => {
let res = {};
Object.keys(fields).map(objectKey => {
const fieldValue = fields2[objectKey];
if (timeFields.indexOf(objectKey) !== -1) {
// 处理时间
res = {
...res,
...buildTime(fieldValue, objectKey),
};
} else if (fieldValue !== undefined) {
res[objectKey] = fieldValue;
}
return true;
});
return res;
};
const searchParams = buildSearchParams(fields);
if (handleSearch) {
handleSearch(searchParams);
}
});
};
return (
<Form onSubmit={onSubmit} layout="inline">
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={8} sm={24}>
<FormItem label="订单id">
{getFieldDecorator('id')(<Input placeholder="请输入订单id" />)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<FormItem label="订单号">
{getFieldDecorator('orderNo')(<Input placeholder="请输入订单号" />)}
</FormItem>
</Col>
</Row>
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={8} sm={24}>
<FormItem label="创建时间">{getFieldDecorator('createTime')(<RangePicker />)}</FormItem>
</Col>
<Col md={8} sm={24}>
<span className={styles.submitButtons}>
<Button type="primary" htmlType="submit">
查询
</Button>
<Button style={{ marginLeft: 8 }} onClick={handleFormReset}>
重置
</Button>
</span>
</Col>
</Row>
</Form>
);
});
@connect(({ orderList, loading }) => ({
orderList,
list: orderList.list,
loading: loading.models.orderList,
}))
class BasicList extends PureComponent {
componentDidMount() {
const {
list: { pagination },
} = this.props;
this.queryList({
pageNo: pagination.current,
pageSize: pagination.pageSize,
});
}
queryList = params => {
const { dispatch } = this.props;
// 保存每次操作 searchParams
this.searchParams = params;
// dispatch
dispatch({
type: 'orderList/queryPage',
payload: {
...params,
},
});
};
handleEditorClick = () => {};
handleSearch = fields => {
const {
list: { pagination },
} = this.props;
this.queryList({
...fields,
pageNo: pagination.current,
pageSize: pagination.pageSize,
});
};
handleTabsChange = key => {
const params = {
...this.searchParams,
status: key,
};
this.queryList(params);
};
render() {
return (
<PageHeaderWrapper>
<div className={styles.standardList}>
<Card
className={styles.listCard}
bordered={false}
title="订单列表"
style={{ marginTop: 24 }}
bodyStyle={{ padding: '0 32px 40px 32px' }}
>
<div className={styles.tableListForm}>
<SearchForm {...this.props} handleSearch={this.handleSearch} />
</div>
<Tabs defaultActiveKey={null} onChange={this.handleTabsChange}>
<TabPane tab="全部" key={null} />
<TabPane tab="待付款" key={0} />
<TabPane tab="待发货" key={1} />
<TabPane tab="已发货" key={2} />
<TabPane tab="已完成" key={3} />
<TabPane tab="已关闭" key={4} />
</Tabs>
<OrderList {...this.props} handleEditorClick={this.handleEditorClick} />
</Card>
</div>
<OrderUpdatePayAmount {...this.props} />
<OrderRemark {...this.props} />
</PageHeaderWrapper>
);
}
}
export default BasicList;
import React from 'react';
import { Form, Input, Modal } from 'antd';
const FormItem = Form.Item;
// 订单 - 更新支付金额
const OrderRemark = Form.create()(props => {
const { dispatch, loading } = props;
const { orderId, remark, remarkVisible, searchParams } = props.orderList;
const { getFieldDecorator, getFieldsValue } = props.form;
const handleOk = e => {
e.preventDefault();
const fieldsValue = getFieldsValue();
dispatch({
type: 'orderList/updateRemake',
payload: {
params: {
remark: fieldsValue.remark,
orderId,
},
searchParams,
},
});
};
const handleCancel = () => {
dispatch({
type: 'orderList/changeRemakeVisible',
payload: {
remarkVisible: false,
},
});
};
return (
<Modal
destroyOnClose
title="添加备注信息"
visible={remarkVisible}
onOk={handleOk}
okText="保存"
onCancel={handleCancel}
confirmLoading={loading}
>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="备注">
{getFieldDecorator('remark', {
initialValue: remark,
})(<Input.TextArea autosize={{ minRows: 2, maxRows: 6 }} placeholder="请输入备注信息" />)}
</FormItem>
</Modal>
);
});
export default OrderRemark;
import React from 'react';
import { Form, Input, Modal } from 'antd';
import { Form, InputNumber, Modal } from 'antd';
const FormItem = Form.Item;
......@@ -52,7 +52,7 @@ const OrderUpdatePayAmount = Form.create()(props => {
{ max: 10000, min: 0, message: '金额值 0 - 100000 元' },
],
initialValue: payAmount / 100,
})(<Input placeholder="请输入修改的金额" />)}
})(<InputNumber min={0} max={100000} placeholder="请输入修改的金额" />)}
</FormItem>
</Modal>
);
......
......@@ -14,6 +14,18 @@ export async function updateOrderItemPayAmount(params) {
});
}
export async function updateRemark(params) {
return request(`/order-api/admins/order/update_remark?${stringify(params)}`, {
method: 'PUT',
});
}
export async function cancelOrder(params) {
return request(`/order-api/admins/order/cancel_order?${stringify(params)}`, {
method: 'PUT',
});
}
export async function updateOrderItem(params) {
return request(`/order-api/admins/order_item/update?${stringify(params)}`, {
method: 'PUT',
......@@ -22,3 +34,12 @@ export async function updateOrderItem(params) {
},
});
}
export async function getLogistics(params) {
return request(`/order-api/admins/order_item/update?${stringify(params)}`, {
method: 'PUT',
body: {
...params,
},
});
}
......@@ -3,6 +3,7 @@
const DictionaryConstants = {
GENDER: 'gender',
ORDER_STATUS: 'order_status',
ORDER_CANCEL_REASONS: 'order_cancel_reasons',
};
export default DictionaryConstants;
......@@ -9,11 +9,9 @@ import qs from 'qs';
function filterEmptyStr(params) {
function filterObject(object) {
const res = {};
for (const key in params) {
const val = params[key];
if (typeof val === 'string' && val) {
res[key] = val;
} else {
for (const key in object) {
const val = object[key];
if (val !== undefined && val !== 'undefined' && val !== null && val !== 'null') {
res[key] = val;
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论