Commit ca70ccf0 authored by 武广's avatar 武广

feat: 添加外卖商品列表

parent f8cb4ca5
...@@ -11,10 +11,28 @@ export default [ ...@@ -11,10 +11,28 @@ export default [
name: 'TakeawayGoods', name: 'TakeawayGoods',
component: './businessGoods/takeawayGoods', component: './businessGoods/takeawayGoods',
}, },
{
title: '商户管理后台-企业团餐-外卖商品',
path: '/takeawayGoods',
name: 'TakeawayGoods',
component: './businessGoods/takeawayGoods',
},
{
title: '商户管理后台-企业团餐-外卖商品-添加商品',
path: '/takeawayGoodsInfo',
name: 'TakeawayGoodsInfo',
component: './businessGoods/takeawayGoodsInfo',
},
{ {
title: '商户管理后台-企业团餐-虚拟商品', title: '商户管理后台-企业团餐-虚拟商品',
path: '/virtualGoods', path: '/virtualGoods',
name: 'VirtualGoods', name: 'VirtualGoods',
component: './businessGoods/virtualGoods', component: './businessGoods/virtualGoods',
}, },
{
title: '商户管理后台-企业团餐-虚拟商品-添加商品',
path: '/takeawayGoodsInfo',
name: 'TakeawayGoodsInfo',
component: './businessGoods/virtualGoodsInfo',
},
]; ];
import React, { useState } from 'react';
import { Form, InputNumber, Modal } from 'antd';
import { layout } from '../staticData/goods';
import { isCheckPriceTwoDecimal } from '@/utils/validator';
const SaleDateModal = props => {
const [form] = Form.useForm();
// 关闭弹窗
const handleCancel = () => {
props.handleClose(false);
};
// 提交
const handleConfirm = async () => {
const res = await form.validateFields();
console.log('res :>> ', res);
};
return (
<Modal
title="修改企业商品价格"
open={props.visible}
destroyOnClose
maskClosable={false}
width="300px"
onOk={handleConfirm}
onCancel={handleCancel}
>
<Form name="basicInfo" {...layout} form={form}>
<Form.Item
label="企业商品价格"
name="types"
rules={[
{ required: true, message: '请输入企业商品价格!' },
{ validator: isCheckPriceTwoDecimal, message: '请输入正确的价格' },
]}
>
<InputNumber addonAfter="元" max={99999.99} />
</Form.Item>
</Form>
</Modal>
);
};
export default SaleDateModal;
import React, { useState } from 'react';
import { Form, InputNumber, Modal } from 'antd';
import { ExclamationCircleOutlined } from '@ant-design/icons';
import { jsonToArray } from '@/utils/utils';
import { layout } from '../staticData/goods';
import { isCheckPriceTwoDecimal } from '@/utils/validator';
const SaleDateModal = props => {
const [form] = Form.useForm();
const [value, setValue] = useState(1);
// 关闭弹窗
const handleCancel = () => {
props.handleClose(false);
};
const onChangeWeek = e => {
setValue(e.target.value);
};
// 提交
const handleConfirm = async () => {
const res = await form.validateFields();
console.log('res :>> ', res);
};
return (
<Modal
title="修改商品排序"
open={props.visible}
destroyOnClose
maskClosable={false}
width="300px"
onOk={handleConfirm}
onCancel={handleCancel}
>
<Form name="basicInfo" initialValues={{ sort: 1000 }} {...layout} form={form}>
<Form.Item label="排序" name="sort" rules={[{ required: true, message: '请输入排序!' }]}>
<InputNumber max={999999} min={1} />
</Form.Item>
</Form>
</Modal>
);
};
export default SaleDateModal;
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Form, Input, Radio, Space, Col, Row, Modal } from 'antd'; import { Form, Checkbox, Space, Col, Row, Modal } from 'antd';
import { ExclamationCircleOutlined } from '@ant-design/icons'; import { ExclamationCircleOutlined } from '@ant-design/icons';
import { jsonToArray } from '@/utils/utils'; import { jsonToArray } from '@/utils/utils';
import { weekOptions } from '../staticData/goods'; import { weekOptions } from '../staticData/goods';
const SaleDateModal = props => { const SaleDateModal = props => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [value, setValue] = useState(1); const [value, setValue] = useState([]);
// 关闭分组信息弹窗 // 关闭弹窗
const handleCancel = () => { const handleCancel = () => {
props.handleClose(false); props.handleClose(false);
}; };
const onChangeWeek = e => { const onChangeWeek = e => {
setValue(e.target.value); setValue(e);
}; };
// 添加/保存分组 // 提交
const handleConfirm = async () => { const handleConfirm = async () => {
const res = await form.validateFields(); const res = await form.validateFields();
console.log('res :>> ', res); console.log('res :>> ', res);
}; };
console.log('visible :>> ', props.visible);
return ( return (
<Modal <Modal
title="设置可售日期" title={props.title || '设置可售日期'}
open={props.visible} open={props.visible}
destroyOnClose destroyOnClose
maskClosable={false} maskClosable={false}
...@@ -35,13 +33,13 @@ const SaleDateModal = props => { ...@@ -35,13 +33,13 @@ const SaleDateModal = props => {
onOk={handleConfirm} onOk={handleConfirm}
onCancel={handleCancel} onCancel={handleCancel}
> >
<Radio.Group onChange={onChangeWeek} value={value}> <Checkbox.Group onChange={onChangeWeek} value={value}>
<Space direction="vertical"> <Space direction="vertical">
{Object.keys(weekOptions).map(key => ( {Object.keys(weekOptions).map(key => (
<Radio value={key}>{weekOptions[key]}</Radio> <Checkbox value={key}>{weekOptions[key]}</Checkbox>
))} ))}
</Space> </Space>
</Radio.Group> </Checkbox.Group>
</Modal> </Modal>
); );
}; };
......
import React, { useState } from 'react';
import { Form, Input, Checkbox, Space, Col, Row, Modal } from 'antd';
import { ExclamationCircleOutlined } from '@ant-design/icons';
import { jsonToArray } from '@/utils/utils';
import { mealColumn } from '../staticData/goods';
const SaleDateModal = props => {
const [form] = Form.useForm();
const [value, setValue] = useState([]);
// 关闭弹窗
const handleCancel = () => {
props.handleClose(false);
};
const onChangeMeal = e => {
setValue(e);
};
// 提交
const handleConfirm = async () => {
const res = await form.validateFields();
console.log('res :>> ', res);
};
return (
<Modal
title={props.title || '修改可售餐段'}
open={props.visible}
destroyOnClose
maskClosable={false}
width="200px"
onOk={handleConfirm}
onCancel={handleCancel}
>
<Checkbox.Group onChange={onChangeMeal} value={value}>
<Space direction="vertical">
{Object.keys(mealColumn).map(key => (
<Checkbox value={key}>{mealColumn[key]}</Checkbox>
))}
</Space>
</Checkbox.Group>
</Modal>
);
};
export default SaleDateModal;
import React, { useState } from 'react';
import { Form, Select, Modal, Table, Input, Button, Pagination } from 'antd';
import { SearchOutlined } from '@ant-design/icons';
import { apiTakeawayList } from '../service/api';
import { SelectGoodsColumn } from '../staticData/goods';
import style from '../style/index.less';
const { Option } = Select;
const SaleDateModal = props => {
const [form] = Form.useForm();
const [searchType, setSearchType] = useState('1');
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [dataSource, setDataSource] = useState([]);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const searchList = async params => {
console.log('params :>> ', params);
console.log('searchType :>> ', searchType);
// const data = {
// page: params.current,
// size: params.pageSize,
// data: params,
// };
// return apiTakeawayList(data);
};
// 关闭弹窗
const handleCancel = () => {
props.handleClose(false);
};
// 提交
const handleConfirm = async () => {
const res = await form.validateFields();
console.log('res :>> ', res);
};
const onSelectChange = newSelectedRowKeys => {
console.log('selectedRowKeys changed: ', newSelectedRowKeys);
setSelectedRowKeys(newSelectedRowKeys);
};
const onPageChange = (current, size) => {
setPage(current);
setPageSize(size);
};
const rowSelection = {
selectedRowKeys,
onChange: onSelectChange,
};
const selectBefore = (
<Select defaultValue="1" onChange={setSearchType}>
<Option value="1">名称</Option>
<Option value="2">SKU</Option>
</Select>
);
const selectAfter = <SearchOutlined onClick={searchList} />;
const footers = () => [
<div className={style.footers}>
<Pagination defaultCurrent={6} total={500} showQuickJumper onChange={onPageChange} />
<div className={style['footers-btn']}>
<div className={style['footers-desc']}>
已选商品(<span className={style['footers-num']}>0</span>)
</div>
<Button key="back" onClick={handleCancel}>
取消
</Button>
<Button key="submit" type="primary" loading={loading} onClick={handleConfirm}>
确定
</Button>
</div>
</div>,
];
return (
<Modal
title="选择商品"
open={props.visible}
destroyOnClose
maskClosable={false}
width="1000px"
onOk={handleConfirm}
onCancel={handleCancel}
footer={footers()}
>
<div className={style['select-goods-box']}>
<Select placeholder="请选择店铺" className={style['select-goods-box--select']} />
<Select
placeholder="请选择商品类型"
disabled
className={style['select-goods-box--select']}
/>
<Input
addonBefore={selectBefore}
addonAfter={selectAfter}
className={style['select-goods-box--txt']}
/>
</div>
<Table rowSelection={rowSelection} columns={SelectGoodsColumn} dataSource={dataSource} />
</Modal>
);
};
export default SaleDateModal;
...@@ -191,3 +191,125 @@ export const takeawayGoodsColumn = options => { ...@@ -191,3 +191,125 @@ export const takeawayGoodsColumn = options => {
}, },
]; ];
}; };
export const GoodsInfoColumn = options => {
const { onDel, companyEnum, shopEnum, onChangeFlag, setVisibleSaleDate } = options;
return [
{
title: '微店名称',
dataIndex: 'shopId',
},
{
title: '商品名称',
dataIndex: 'skuName',
width: 120,
align: 'center',
},
{
title: '商品售价',
dataIndex: 'price',
width: 120,
align: 'center',
},
{
title: '企业价格',
dataIndex: 'activityPrice',
width: 120,
align: 'center',
},
{
title: '库存',
dataIndex: 'status',
width: 120,
align: 'center',
},
{
title: '可售日期',
dataIndex: 'saleTimeType',
width: 120,
align: 'center',
hideInSearch: true,
render: (_, record) => (
<Space>
<span>{_}</span>
<span onClick={setVisibleSaleDate(true)}>
<FormOutlined />
</span>
</Space>
),
},
{
title: '可售餐段',
dataIndex: 'saleDate',
width: 120,
align: 'center',
hideInSearch: true,
render: (_, record) => (
<Space>
<span>{_}</span>
<span>
<FormOutlined />
</span>
</Space>
),
},
{
title: '餐品类型',
dataIndex: 'mealType',
width: 120,
align: 'center',
hideInSearch: true,
},
{
title: '操作',
hideInSearch: true,
dataIndex: 'action',
width: '100px',
align: 'center',
fixed: 'right',
render: (val, r) => (
<Button key="del" onClick={() => onDel(r, 'del')}>
删除
</Button>
),
},
];
};
export const SelectGoodsColumn = [
{
title: '商品ID',
width: 120,
dataIndex: 'id',
},
{
title: '商品名称',
dataIndex: 'skuName',
width: 120,
align: 'center',
},
{
title: '商品编号',
dataIndex: 'skuNo',
width: 120,
align: 'center',
},
{
title: '销售价',
dataIndex: 'price',
width: 120,
align: 'center',
},
{
title: '剩余库存',
dataIndex: 'status',
width: 120,
align: 'center',
},
{
title: '已参与活动',
dataIndex: 'mealType',
align: 'center',
hideInSearch: true,
},
];
...@@ -6,3 +6,52 @@ ...@@ -6,3 +6,52 @@
} }
} }
} }
.info-box {
min-height: 100%;
padding: 20px 40px;
background-color: #fff;
&--line {
min-height: 32px;
margin-bottom: 15px;
line-height: 32px;
}
&--label {
text-align: right;
}
&--select {
min-width: 200px;
}
&--btns {
margin-top: 20px;
&__confirm {
margin-right: 15px;
}
}
}
.select-goods-box {
display: flex;
padding: 5px 0;
.select-goods-box--select {
width: 200px;
}
.select-goods-box--txt {
width: 260px;
}
}
.footers {
display: flex;
align-items: center;
justify-content: space-between;
&-btn {
display: flex;
align-items: center;
justify-content: flex-end;
text-align: right;
}
&-desc {
margin-right: 10px;
}
&-num {
color: #1890ff;
}
}
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import { ProTable } from '@ant-design/pro-components'; import { ProTable } from '@ant-design/pro-components';
import { Button, Space } from 'antd'; import { Button, Space } from 'antd';
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
...@@ -6,25 +7,35 @@ import { takeawayGoodsColumn } from './staticData/goods'; ...@@ -6,25 +7,35 @@ import { takeawayGoodsColumn } from './staticData/goods';
import utilStyle from '@/utils/utils.less'; import utilStyle from '@/utils/utils.less';
import { apiTakeawayList } from './service/api'; import { apiTakeawayList } from './service/api';
import SaleDateModal from './components/SaleDateModal'; import SaleDateModal from './components/SaleDateModal';
import SaleSectionModal from './components/SaleSectionModal';
import GoodPriceModal from './components/GoodPriceModal';
import GoodSortModal from './components/GoodSortModal';
import { getToUrlQuery } from '@/utils/utils';
const BusinessCustomer = () => { const BusinessCustomer = () => {
const [visibleSaleDate, setVisibleSaleDate] = useState(true); // 可售日期弹窗 const history = useHistory();
const [visibleSaleSection, setVisibleSaleSection] = useState(true); // 可售餐段弹窗 const [visibleSaleDate, setVisibleSaleDate] = useState(false); // 可售日期弹窗
const [visiblePrice, setVisiblePrice] = useState(true); // 修改企业商品价格弹窗 const [visibleSaleSection, setVisibleSaleSection] = useState(false); // 可售餐段弹窗
const [visibleSort, setVisibleSort] = useState(true); // 商品排序弹窗 const [visiblePrice, setVisiblePrice] = useState(false); // 修改企业商品价格弹窗
const [visibleGoods, setVisibleGoods] = useState(true); // 添加外卖商品弹窗 const [visibleSort, setVisibleSort] = useState(false); // 商品排序弹窗
const [visibleGoods, setVisibleGoods] = useState(false); // 添加外卖商品弹窗
const [activeKey, setActiveKey] = useState('tab1'); const [activeKey, setActiveKey] = useState('tab1');
const query = async params => { const searchList = async params => {
console.log('params :>> ', params);
const data = { const data = {
page: params.current, page: params.current,
size: params.pageSize, size: params.pageSize,
data: params, data: params,
}; };
return apiTakeawayList(data); // return apiTakeawayList(data);
}; };
const onDel = async () => {}; const onDel = async () => {};
const onAdd = async () => {}; const onAdd = async () => {
const query = getToUrlQuery();
history.push({
pathname: '/takeawayGoodsInfo',
query,
});
};
const options = { const options = {
setVisibleSaleDate, setVisibleSaleDate,
setVisibleSaleSection, setVisibleSaleSection,
...@@ -45,7 +56,7 @@ const BusinessCustomer = () => { ...@@ -45,7 +56,7 @@ const BusinessCustomer = () => {
}} }}
tableClassName={utilStyle.formTable} tableClassName={utilStyle.formTable}
columns={takeawayGoodsColumn(options)} columns={takeawayGoodsColumn(options)}
request={params => query({ ...params })} request={params => searchList({ ...params })}
rowKey={r => r.id} rowKey={r => r.id}
expandIconColumnIndex={10} expandIconColumnIndex={10}
bordered bordered
...@@ -80,8 +91,24 @@ const BusinessCustomer = () => { ...@@ -80,8 +91,24 @@ const BusinessCustomer = () => {
}} }}
scroll={{ x: '100%', y: 400 }} scroll={{ x: '100%', y: 400 }}
/> />
{/* 可售日期弹窗 */}
{visibleSaleDate && ( {visibleSaleDate && (
<SaleDateModal visible={visibleSaleDate} close={() => setVisibleSaleDate(false)} /> <SaleDateModal visible={visibleSaleDate} handleClose={() => setVisibleSaleDate(false)} />
)}
{/* 可售餐段弹窗 */}
{visibleSaleSection && (
<SaleSectionModal
visible={visibleSaleSection}
handleClose={() => setVisibleSaleSection(false)}
/>
)}
{/* 修改企业商品价格弹窗 */}
{visiblePrice && (
<GoodPriceModal visible={visiblePrice} handleClose={() => setVisiblePrice(false)} />
)}
{/* 商品排序弹窗 */}
{visibleSort && (
<GoodSortModal visible={visibleSort} handleClose={() => setVisibleSort(false)} />
)} )}
</div> </div>
); );
......
import React, { useRef, useState, useEffect } from 'react';
import {
Input,
Checkbox,
Radio,
Button,
notification,
Spin,
Select,
Row,
Col,
Form,
Table,
} from 'antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { GoodsInfoColumn } from './staticData/goods';
import SaleDateModal from './components/SaleDateModal';
import SaleSectionModal from './components/SaleSectionModal';
import SelectGoodsModal from './components/SelectGoodsModal';
import style from './style/index.less';
const TakeawayGoodsInfo = props => {
const { id } = props.location.query;
const [loading, setLoading] = useState(false);
const [visibleSaleDate, setVisibleSaleDate] = useState(false); // 可售日期弹窗
const [visibleSaleSection, setVisibleSaleSection] = useState(false); // 可售餐段弹窗
const [visibleSelectGoods, setVisibleSelectGoods] = useState(false); // 选择商品弹窗
const [dataSource, setDataSource] = useState([]);
// 提交
// const onSubmit = () => {
// };
// 提交
const onDel = () => {};
// const initData = async () => {
// setLoading(true);
// };
// useEffect(() => {
// initData();
// }, []);
const options = {
setVisibleSaleDate,
setVisibleSaleSection,
onDel,
};
return (
<PageHeaderWrapper title="添加企业严选商品">
<div className={style['info-box']}>
<Spin spinning={loading}>
<Row className={style['info-box--line']}>
<Col span={3} className={style['info-box--label']}>
企业名称:
</Col>
<Col span={20}>企业名称111</Col>
</Row>
<Row className={style['info-box--line']}>
<Col span={3} className={style['info-box--label']}>
选择取餐点:
</Col>
<Col span={20}>
<Select
mode="multiple"
showSearch
className={style['info-box--select']}
placeholder="清选择"
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
/>
</Col>
</Row>
<Row className={style['info-box--line']}>
<Col span={3} className={style['info-box--label']}>
添加商品:
</Col>
<Col span={20}>
<Button type="primary" onClick={() => setVisibleSelectGoods(true)}>
选择商品
</Button>
</Col>
</Row>
<Row className={style['info-box--line']}>
<Col span={24}>
<Table columns={GoodsInfoColumn(options)} dataSource={dataSource} />
</Col>
</Row>
<Row className={style['info-box--btns']}>
<Col span={4} />
<Col span={20}>
<Button type="primary" className={style['info-box--btns__confirm']}>
确定
</Button>
<Button>取消</Button>
</Col>
</Row>
</Spin>
{/* 可售日期弹窗 */}
{visibleSaleDate && (
<SaleDateModal visible={visibleSaleDate} handleClose={() => setVisibleSaleDate(false)} />
)}
{/* 可售餐段弹窗 */}
{visibleSaleSection && (
<SaleSectionModal
visible={visibleSaleSection}
handleClose={() => setVisibleSaleSection(false)}
/>
)}
{/* 选择商品弹窗 */}
{visibleSelectGoods && (
<SelectGoodsModal
visible={visibleSelectGoods}
handleClose={() => setVisibleSelectGoods(false)}
/>
)}
</div>
</PageHeaderWrapper>
);
};
export default TakeawayGoodsInfo;
import React, { useRef, useState, useEffect } from 'react';
import {
Input,
Checkbox,
Radio,
Button,
notification,
Spin,
Select,
Row,
Col,
Form,
Table,
} from 'antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { GoodsInfoColumn } from './staticData/goods';
import SaleDateModal from './components/SaleDateModal';
import SaleSectionModal from './components/SaleSectionModal';
import SelectGoodsModal from './components/SelectGoodsModal';
import style from './style/index.less';
const TakeawayGoodsInfo = props => {
const { id } = props.location.query;
const [loading, setLoading] = useState(false);
const [visibleSaleDate, setVisibleSaleDate] = useState(false); // 可售日期弹窗
const [visibleSaleSection, setVisibleSaleSection] = useState(true); // 可售餐段弹窗
const [visibleSelectGoods, setVisibleSelectGoods] = useState(true); // 选择商品弹窗
const [dataSource, setDataSource] = useState([]);
// 提交
// const onSubmit = () => {
// };
// 提交
const onDel = () => {};
// const initData = async () => {
// setLoading(true);
// };
// useEffect(() => {
// initData();
// }, []);
const options = {
setVisibleSaleDate,
setVisibleSaleSection,
onDel,
};
return (
<PageHeaderWrapper title="添加企业严选商品">
<div className={style['info-box']}>
<Spin spinning={loading}>
<Row className={style['info-box--line']}>
<Col span={3} className={style['info-box--label']}>
企业名称:
</Col>
<Col span={20}>企业名称111</Col>
</Row>
<Row className={style['info-box--line']}>
<Col span={3} className={style['info-box--label']}>
选择店铺:
</Col>
<Col span={20}>
<Select className={style['info-box--select']} placeholder="清选择" />
</Col>
</Row>
<Row className={style['info-box--line']}>
<Col span={3} className={style['info-box--label']}>
添加商品:
</Col>
<Col span={20}>
<Button type="primary" onClick={() => setVisibleSelectGoods(true)}>
选择商品
</Button>
</Col>
</Row>
<Row className={style['info-box--line']}>
<Col span={24}>
<Table columns={GoodsInfoColumn(options)} dataSource={dataSource} />
</Col>
</Row>
<Row className={style['info-box--btns']}>
<Col span={4} />
<Col span={20}>
<Button type="primary" className={style['info-box--btns__confirm']}>
确定
</Button>
<Button>取消</Button>
</Col>
</Row>
</Spin>
{/* 可售日期弹窗 */}
{visibleSaleDate && (
<SaleDateModal visible={visibleSaleDate} handleClose={() => setVisibleSaleDate(false)} />
)}
{/* 可售餐段弹窗 */}
{visibleSaleSection && (
<SaleSectionModal
visible={visibleSaleSection}
handleClose={() => setVisibleSaleSection(false)}
/>
)}
{/* 选择商品弹窗 */}
{visibleSelectGoods && (
<SelectGoodsModal
visible={visibleSelectGoods}
handleClose={() => setVisibleSelectGoods(false)}
/>
)}
</div>
</PageHeaderWrapper>
);
};
export default TakeawayGoodsInfo;
...@@ -209,3 +209,15 @@ export const getToken = () => { ...@@ -209,3 +209,15 @@ export const getToken = () => {
} }
return localStorage.get('token'); return localStorage.get('token');
}; };
// 获取跳转参数
export const getToUrlQuery = () => {
// 从消费地图后管过来
if (getUrlParams('source') === 'tob' && localStorage.get('tobToken')) {
return {
source: 'tob',
token: localStorage.get('tobToken'),
};
}
return {};
};
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