- 前端:满减送列表

- 前端:限时折扣列表
This commit is contained in:
YunaiV 2019-05-08 00:18:18 +08:00
parent f44a6d49d7
commit e7b9b4fd2a
12 changed files with 931 additions and 4 deletions

View File

@ -130,6 +130,16 @@ export default [
name: 'coupon-card-template-list',
component: './Promotion/CouponCardTemplateList',
},
{
path: '/promotion/time-limit-discount-list',
name: 'time-limit-discount-list',
component: './Promotion/TimeLimitedDiscountList',
},
{
path: '/promotion/full-privilege-list',
name: 'full-privilege-list',
component: './Promotion/FullPrivilegeList',
}
],
},
{

View File

@ -58,4 +58,6 @@ export default {
'menu.promotion.promotion-banner-list': '首页广告',
'menu.promotion.product-recommend-list': '商品推荐',
'menu.promotion.coupon-card-template-list': '优惠劵管理',
'menu.promotion.time-limit-discount-list': '限时折扣',
'menu.promotion.full-privilege-list': '满减送',
};

View File

@ -0,0 +1,126 @@
import { message } from 'antd';
import { productSpuPage, productSpuUpdateSort } from '../../services/product';
import {routerRedux} from "dva/router";
import PaginationHelper from '../../../helpers/PaginationHelper';
import {getPromotionActivityPage} from "../../services/promotion";
const SEARCH_PARAMS_DEFAULT = {
title: '',
activityType: 2,
status: 'ALL',
};
export default {
namespace: 'fullPrivilegeList',
state: {
// 分页列表相关
list: [],
listLoading: false,
pagination: PaginationHelper.defaultPaginationConfig,
searchParams: SEARCH_PARAMS_DEFAULT,
// 添加 or 修改表单相关
},
effects: {
*page({ payload }, { call, put }) {
// const { queryParams } = payload;
// const response = yield call(productSpuPage, payload);
// message.info('查询成功!');
// yield put({
// type: 'treeSuccess',
// payload: {
// list: response.data,
// },
// });
// 显示加载中
yield put({
type: 'changeListLoading',
payload: true,
});
// 请求
const response = yield call(getPromotionActivityPage, payload);
// 响应
yield put({
type: 'setAll',
payload: {
list: response.data.list,
pagination: PaginationHelper.formatPagination(response.data, payload),
searchParams: {
title: payload.title,
status: payload.status,
activityType: payload.activityType,
}
},
});
// 隐藏加载中
yield put({
type: 'changeListLoading',
payload: false,
});
},
*updateSort({ payload }, { call, put }) {
// 显示加载中
yield put({
type: 'changeSortModalLoading',
payload: true,
});
// 请求
const { callback, body } = payload;
// 响应
const response = yield call(productSpuUpdateSort, body);
if(response.code === 0) {
if (callback) {
callback(response);
}
yield put({
type: 'page',
payload: {
...this.state.pagination,
...this.state.searchParams,
},
});
}
// 隐藏加载中
yield put({
type: 'changeSortModalLoading',
payload: false,
});
},
},
reducers: {
treeSuccess(state, { payload }) {
return {
...state,
...payload,
};
},
// 修改加载中的状态
changeSortModalLoading(state, { payload }) {
return {
...state,
sortModalLoading: payload,
};
},
changeListLoading(state, { payload }) {
return {
...state,
listLoading: payload,
};
},
// 设置所有属性
setAll(state, { payload }) {
return {
...state,
...payload,
};
}
},
};

View File

@ -7,7 +7,7 @@ import {
updateProductRecommendStatus,
} from '../../services/promotion';
import PaginationHelper from '../../../helpers/PaginationHelper';
import {productSpuList, productSpuSearchList} from "../../services/product";
import {productSpuSearchList} from "../../services/product";
const SEARCH_PARAMS_DEFAULT = {
type: undefined,

View File

@ -0,0 +1,126 @@
import { message } from 'antd';
import { productSpuPage, productSpuUpdateSort } from '../../services/product';
import {routerRedux} from "dva/router";
import PaginationHelper from '../../../helpers/PaginationHelper';
import {getPromotionActivityPage} from "../../services/promotion";
const SEARCH_PARAMS_DEFAULT = {
title: '',
activityType: 1,
status: 'ALL',
};
export default {
namespace: 'timeLimitedDiscountList',
state: {
// 分页列表相关
list: [],
listLoading: false,
pagination: PaginationHelper.defaultPaginationConfig,
searchParams: SEARCH_PARAMS_DEFAULT,
// 添加 or 修改表单相关
},
effects: {
*page({ payload }, { call, put }) {
// const { queryParams } = payload;
// const response = yield call(productSpuPage, payload);
// message.info('查询成功!');
// yield put({
// type: 'treeSuccess',
// payload: {
// list: response.data,
// },
// });
// 显示加载中
yield put({
type: 'changeListLoading',
payload: true,
});
// 请求
const response = yield call(getPromotionActivityPage, payload);
// 响应
yield put({
type: 'setAll',
payload: {
list: response.data.list,
pagination: PaginationHelper.formatPagination(response.data, payload),
searchParams: {
title: payload.title,
status: payload.status,
activityType: payload.activityType,
}
},
});
// 隐藏加载中
yield put({
type: 'changeListLoading',
payload: false,
});
},
*updateSort({ payload }, { call, put }) {
// 显示加载中
yield put({
type: 'changeSortModalLoading',
payload: true,
});
// 请求
const { callback, body } = payload;
// 响应
const response = yield call(productSpuUpdateSort, body);
if(response.code === 0) {
if (callback) {
callback(response);
}
yield put({
type: 'page',
payload: {
...this.state.pagination,
...this.state.searchParams,
},
});
}
// 隐藏加载中
yield put({
type: 'changeSortModalLoading',
payload: false,
});
},
},
reducers: {
treeSuccess(state, { payload }) {
return {
...state,
...payload,
};
},
// 修改加载中的状态
changeSortModalLoading(state, { payload }) {
return {
...state,
sortModalLoading: payload,
};
},
changeListLoading(state, { payload }) {
return {
...state,
listLoading: payload,
};
},
// 设置所有属性
setAll(state, { payload }) {
return {
...state,
...payload,
};
}
},
};

View File

@ -0,0 +1,325 @@
/* eslint-disable */
import React, { PureComponent, Fragment } from 'react';
import { connect } from 'dva';
import moment from 'moment';
import {
Card,
Form,
Input,
Row,
Col,
Button,
Modal,
message,
Table,
Divider,
Tree,
Tabs,
TreeSelect,
Spin,
InputNumber
} from 'antd';
const TabPane = Tabs.TabPane;
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import styles from './FullPrivilegeList.less';
import PaginationHelper from "../../../helpers/PaginationHelper";
const FormItem = Form.Item;
const statuses = {
10: '未开始',
20: '进行中',
30: '已结束',
40: '已撤销',
50: '已删除',
};
const meetTypes = {
1: '满 N 元减/送',
2: '满 N 件减/送',
};
// 列表
function List({ dataSource, loading, pagination, searchParams, dispatch,}) {
const handleTabsChange = (value) => {
dispatch({
type: 'fullPrivilegeList/page',
payload: {
...searchParams,
status: value,
...PaginationHelper.defaultPayload,
}
})
};
function onPageChange(page) { // 翻页
dispatch({
type: 'fullPrivilegeList/page',
payload: {
pageNo: page.current,
pageSize: page.pageSize,
...searchParams
}
})
}
function formatFullPrivilegeText(activity) {
let text = '';
let fullPrivilege = activity.fullPrivilege;
for (let i in fullPrivilege.privileges) {
let privilege = fullPrivilege.privileges[i];
if (i > 0) {
text += ';';
}
if (fullPrivilege.cycled) {
text += '每';
}
if (privilege.meetType === 1) {
text += '满 ' + privilege.meetValue / 100.0 + ' 元,';
} else if (privilege.meetType === 2) {
text += '满 ' + privilege.meetValue + ' 件,';
}
if (privilege.preferentialType === 1) {
text += '减 ' + privilege.preferentialValue / 100.0 + ' 元';
} else if (privilege.preferentialType === 2) {
text += '打 ' + privilege.preferentialValue / 10.0 + ' 折';
}
}
return text;
};
const columns = [
// {
// title: 'id',
// dataIndex: 'id',
// render: text => <strong>{text}</strong>,
// },
{
title: '活动名称',
dataIndex: 'title',
},
{
title: '类型',
dataIndex: 'fullPrivilege',
render: val => meetTypes[val.privileges[0].meetType + ''],
},
{
title: '活动详情',
render: (text, record) => formatFullPrivilegeText(record),
},
{
title: '活动时间',
render: (text, record) => (
<span>
{moment(record.startTime).format('YYYY-MM-DD HH:mm:ss')}
&nbsp;&nbsp;
{moment(record.endTime).format('YYYY-MM-DD HH:mm:ss')}
</span>
),
},
{
title: '状态',
dataIndex: 'status',
render: val => statuses[val + ''],
},
{
title: '创建时间',
dataIndex: 'createTime',
render: val => <span>{moment(val).format('YYYY-MM-DD')}</span>,
},
{
title: '操作',
width: 300,
render: (text, record) => (
<Fragment>
{/*<a onClick={() => this.handleModalVisible(true, 'update', record)}>更新</a>*/}
<a onClick={() => alert('正在开发中')}>编辑</a>
{
record.status === 10 || record.status === 20 ? <span>
<Divider type="vertical" />
<a onClick={() => alert('正在开发中')}>
撤销
</a>
</span> : undefined
}
{
record.status !== 50 ? <span>
<Divider type="vertical" />
<a className={styles.tableDelete} onClick={() => alert('正在开发中')}>
删除
</a>
</span> : undefined
}
</Fragment>
),
},
];
// console.log(pagination);
return (
<div>
<Tabs defaultActiveKey={searchParams.status} onChange={handleTabsChange}>
<TabPane tab="所有活动" key="ALL" />
<TabPane tab="未开始" key="WAIT" />
<TabPane tab="进行中" key="RUN" />
<TabPane tab="已结束" key="END" />
<TabPane tab="已撤销" key="INVALID" />
</Tabs>
<Table
columns={columns}
dataSource={dataSource}
rowKey="id"
pagination={pagination}
onChange={onPageChange}
loading={loading} />
</div>
)
}
// 搜索表单
const SearchForm = Form.create()(props => {
const {
form,
form: { getFieldDecorator },
dispatch,
searchParams,
} = props;
function search() {
dispatch({
type: 'fullPrivilegeList/page',
payload: {
...PaginationHelper.defaultPayload,
...searchParams,
...form.getFieldsValue(),
}
})
}
// 提交搜索
function handleSubmit(e) {
// 阻止默认事件
e.preventDefault();
// 提交搜索
search();
}
// 重置搜索
function handleReset() {
// 重置表单
form.resetFields();
// 执行搜索
search();
}
return (
<Form onSubmit={handleSubmit} layout="inline">
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={8} sm={24}>
<FormItem label="活动名称">
{getFieldDecorator('title')(<Input placeholder="请输入" />)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<span className={styles.submitButtons}>
<Button type="primary" htmlType="submit">
查询
</Button>
<Button style={{ marginLeft: 8 }} onClick={handleReset}>
重置
</Button>
</span>
</Col>
</Row>
</Form>
);
});
// fullPrivilegeList
@connect(({ fullPrivilegeList }) => ({
...fullPrivilegeList,
// list: fullPrivilegeList.list.spus,
// loading: loading.models.fullPrivilegeList,
}))
@Form.create()
class FullPrivilegeList extends PureComponent {
state = {
modalVisible: false,
modalType: 'add', //add update
initValues: {},
};
componentDidMount() {
const { dispatch, searchParams } = this.props;
// 查询初始数据
dispatch({
type: 'fullPrivilegeList/page',
payload: {
...searchParams,
...PaginationHelper.defaultPayload,
},
});
}
handleSortModalVisible = (sortModalVisible, record) => {
const { dispatch } = this.props;
dispatch({
type: 'fullPrivilegeList/setAll',
payload: {
sortModalVisible,
formVals: record || {}
},
});
};
render() {
const { dispatch,
list, listLoading, searchParams, pagination,
categoryTree, formVals, } = this.props;
// 列表属性
const listProps = {
dataSource: list,
pagination,
searchParams,
dispatch,
categoryTree,
loading: listLoading,
handleSortModalVisible: this.handleSortModalVisible, // Func
};
// 搜索表单属性
const searchFormProps = {
dispatch,
categoryTree,
searchParams,
};
return (
<PageHeaderWrapper title="">
<Card bordered={false}>
<div className={styles.tableList}>
<div className={styles.tableListOperator}>
<Button
icon="plus"
type="primary"
onClick={() => alert('正在开发中')}
>
新建满减送
</Button>
</div>
</div>
<SearchForm {...searchFormProps} />
<List {...listProps} />
</Card>
</PageHeaderWrapper>
);
}
}
export default FullPrivilegeList;

View File

@ -0,0 +1,15 @@
@import '~antd/lib/style/themes/default.less';
@import '~@/utils/utils.less';
.tableList {
.tableListOperator {
margin-bottom: 16px;
button {
margin-right: 8px;
}
}
}
.tableDelete {
color: red;
}

View File

@ -0,0 +1,290 @@
/* eslint-disable */
import React, { PureComponent, Fragment } from 'react';
import { connect } from 'dva';
import moment from 'moment';
import {
Card,
Form,
Input,
Row,
Col,
Button,
Modal,
message,
Table,
Divider,
Tree,
Tabs,
TreeSelect,
Spin,
InputNumber
} from 'antd';
const TabPane = Tabs.TabPane;
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import styles from './TimeLimitedDiscountList.less';
import PaginationHelper from "../../../helpers/PaginationHelper";
const FormItem = Form.Item;
const statuses = {
10: '未开始',
20: '进行中',
30: '已结束',
40: '已撤销',
50: '已删除',
}
// 列表
function List({ dataSource, loading, pagination, searchParams, dispatch,}) {
const handleTabsChange = (value) => {
dispatch({
type: 'timeLimitedDiscountList/page',
payload: {
...searchParams,
status: value,
...PaginationHelper.defaultPayload,
}
})
};
function onPageChange(page) { // 翻页
dispatch({
type: 'timeLimitedDiscountList/page',
payload: {
pageNo: page.current,
pageSize: page.pageSize,
...searchParams
}
})
}
const columns = [
// {
// title: 'id',
// dataIndex: 'id',
// render: text => <strong>{text}</strong>,
// },
{
title: '活动名称',
dataIndex: 'title',
},
{
title: '活动标签', // TODO 芋艿,未来增加
},
{
title: '活动时间',
render: (text, record) => (
<span>
{moment(record.startTime).format('YYYY-MM-DD HH:mm:ss')}
&nbsp;&nbsp;
{moment(record.endTime).format('YYYY-MM-DD HH:mm:ss')}
</span>
),
},
{
title: '状态',
dataIndex: 'status',
render: val => statuses[val + ''],
},
{
title: '创建时间',
dataIndex: 'createTime',
render: val => <span>{moment(val).format('YYYY-MM-DD')}</span>,
},
{
title: '操作',
width: 300,
render: (text, record) => (
<Fragment>
{/*<a onClick={() => this.handleModalVisible(true, 'update', record)}>更新</a>*/}
<a onClick={() => alert('正在开发中')}>编辑</a>
{
record.status === 10 || record.status === 20 ? <span>
<Divider type="vertical" />
<a onClick={() => alert('正在开发中')}>
撤销
</a>
</span> : undefined
}
{
record.status !== 50 ? <span>
<Divider type="vertical" />
<a className={styles.tableDelete} onClick={() => alert('正在开发中')}>
删除
</a>
</span> : undefined
}
</Fragment>
),
},
];
// console.log(pagination);
return (
<div>
<Tabs defaultActiveKey={searchParams.status} onChange={handleTabsChange}>
<TabPane tab="所有活动" key="ALL" />
<TabPane tab="未开始" key="WAIT" />
<TabPane tab="进行中" key="RUN" />
<TabPane tab="已结束" key="END" />
<TabPane tab="已撤销" key="INVALID" />
</Tabs>
<Table
columns={columns}
dataSource={dataSource}
rowKey="id"
pagination={pagination}
onChange={onPageChange}
loading={loading} />
</div>
)
}
// 搜索表单
const SearchForm = Form.create()(props => {
const {
form,
form: { getFieldDecorator },
dispatch,
searchParams,
} = props;
function search() {
dispatch({
type: 'timeLimitedDiscountList/page',
payload: {
...PaginationHelper.defaultPayload,
...searchParams,
...form.getFieldsValue(),
}
})
}
// 提交搜索
function handleSubmit(e) {
// 阻止默认事件
e.preventDefault();
// 提交搜索
search();
}
// 重置搜索
function handleReset() {
// 重置表单
form.resetFields();
// 执行搜索
search();
}
return (
<Form onSubmit={handleSubmit} layout="inline">
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={8} sm={24}>
<FormItem label="活动名称">
{getFieldDecorator('title')(<Input placeholder="请输入" />)}
</FormItem>
</Col>
<Col md={8} sm={24}>
<span className={styles.submitButtons}>
<Button type="primary" htmlType="submit">
查询
</Button>
<Button style={{ marginLeft: 8 }} onClick={handleReset}>
重置
</Button>
</span>
</Col>
</Row>
</Form>
);
});
// timeLimitedDiscountList
@connect(({ timeLimitedDiscountList }) => ({
...timeLimitedDiscountList,
// list: timeLimitedDiscountList.list.spus,
// loading: loading.models.timeLimitedDiscountList,
}))
@Form.create()
class TimeLimitedDiscountList extends PureComponent {
state = {
modalVisible: false,
modalType: 'add', //add update
initValues: {},
};
componentDidMount() {
const { dispatch, searchParams } = this.props;
// 查询初始数据
dispatch({
type: 'timeLimitedDiscountList/page',
payload: {
...searchParams,
...PaginationHelper.defaultPayload,
},
});
}
handleSortModalVisible = (sortModalVisible, record) => {
const { dispatch } = this.props;
dispatch({
type: 'timeLimitedDiscountList/setAll',
payload: {
sortModalVisible,
formVals: record || {}
},
});
};
render() {
const { dispatch,
list, listLoading, searchParams, pagination,
categoryTree, formVals, } = this.props;
// 列表属性
const listProps = {
dataSource: list,
pagination,
searchParams,
dispatch,
categoryTree,
loading: listLoading,
handleSortModalVisible: this.handleSortModalVisible, // Func
};
// 搜索表单属性
const searchFormProps = {
dispatch,
categoryTree,
searchParams,
};
return (
<PageHeaderWrapper title="">
<Card bordered={false}>
<div className={styles.tableList}>
<div className={styles.tableListOperator}>
<Button
icon="plus"
type="primary"
onClick={() => alert('正在开发中')}
>
新建限时折扣
</Button>
</div>
</div>
<SearchForm {...searchFormProps} />
<List {...listProps} />
</Card>
</PageHeaderWrapper>
);
}
}
export default TimeLimitedDiscountList;

View File

@ -0,0 +1,15 @@
@import '~antd/lib/style/themes/default.less';
@import '~@/utils/utils.less';
.tableList {
.tableListOperator {
margin-bottom: 16px;
button {
margin-right: 8px;
}
}
}
.tableDelete {
color: red;
}

View File

@ -90,3 +90,12 @@ export async function updateCouponCardTemplateStatus(params) {
method: 'POST',
});
}
// Promotion Activity
export async function getPromotionActivityPage(params) {
return request(`/promotion-api/admins/promotion_activity/page?${stringify(params)}`, {
method: 'GET',
});
}

View File

@ -26,8 +26,8 @@ public class AdminsPromotionActivityController {
private PromotionActivityService promotionActivityService;
@GetMapping("/page") // TODO 芋艿BO => VO
public CommonResult<PromotionActivityPageBO> page(@RequestParam("title") String title,
@RequestParam("activityType") Integer activityType,
public CommonResult<PromotionActivityPageBO> page(@RequestParam(value = "title", required = false) String title,
@RequestParam(value = "activityType") Integer activityType,
@RequestParam(value = "status") String status,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {

View File

@ -4,6 +4,7 @@ import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Data
@ -30,6 +31,14 @@ public class PromotionActivityBO implements Serializable {
* 参见 {@link cn.iocoder.mall.promotion.api.constant.PromotionActivityStatusEnum} 枚举
*/
private Integer status;
/**
* 开始时间
*/
private Date startTime;
/**
* 结束时间
*/
private Date endTime;
/**
* 限制折扣
*/
@ -40,7 +49,7 @@ public class PromotionActivityBO implements Serializable {
private FullPrivilege fullPrivilege;
/**
* 折扣
* 折扣
*/
@Data
@Accessors(chain = true)