Commit 95b4583c authored by 武广's avatar 武广

feat: 添加外卖搜索条件

parent 06a12267
...@@ -8,17 +8,20 @@ import { apiGoodsActionBatch } from '../../service'; ...@@ -8,17 +8,20 @@ import { apiGoodsActionBatch } from '../../service';
const ActionBar = options => { const ActionBar = options => {
// 上下架 // 上下架
const changeStatus = async state => { const changeStatus = async state => {
console.log('options.shopId :>> ', options.shopId);
Modal.confirm({ Modal.confirm({
icon: <ExclamationCircleOutlined />, icon: <ExclamationCircleOutlined />,
content: `确认${+state === 6 ? '下架' : '上架'}商品?`, content: `确认${+state === 6 ? '下架' : '上架'}商品?`,
onOk: async () => { onOk: async () => {
const res = await apiGoodsActionBatch({ const res = await apiGoodsActionBatch({
ids: options.selectedRowKeys, skuIds: options.selectedRowKeys,
type: 2, type: 2,
productState: +state === 6 ? 7 : 6, // 6:上架,7:下架 shopId: options.shopId,
productStatus: +state === 6 ? 0 : 1, // 6:上架,7:下架
}); });
if (res.businessCode === '0000' && res.code === '0000') { if (res.businessCode === '0000' && res.code === '0000') {
options.handleSearch(); options.handleSearch();
message.success('处理成功!');
} }
}, },
}); });
......
...@@ -21,6 +21,7 @@ const MinimumPurchase = options => { ...@@ -21,6 +21,7 @@ const MinimumPurchase = options => {
title="修改最少购买数量" title="修改最少购买数量"
onOk={handleOk} onOk={handleOk}
maskClosable={false} maskClosable={false}
keyboard={false}
confirmLoading={options.loading} confirmLoading={options.loading}
destroyOnClose destroyOnClose
onCancel={handleCancel} onCancel={handleCancel}
...@@ -35,7 +36,10 @@ const MinimumPurchase = options => { ...@@ -35,7 +36,10 @@ const MinimumPurchase = options => {
<Form.Item <Form.Item
label="最少购买/份" label="最少购买/份"
name="minPurchaseNum" name="minPurchaseNum"
rules={[{ required: true, message: '请输入最少购买数量!' }]} rules={[
{ required: true, message: '请输入最少购买数量!' },
{ min: 1, message: '最小输入1' },
]}
> >
<Input maxLength={6} type="number" /> <Input maxLength={6} type="number" />
</Form.Item> </Form.Item>
......
...@@ -24,6 +24,7 @@ const SendModal = options => { ...@@ -24,6 +24,7 @@ const SendModal = options => {
title="设置单点不送" title="设置单点不送"
onOk={handleOk} onOk={handleOk}
maskClosable={false} maskClosable={false}
keyboard={false}
confirmLoading={options.loading} confirmLoading={options.loading}
destroyOnClose destroyOnClose
onCancel={handleCancel} onCancel={handleCancel}
......
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Modal, Form, Input, Checkbox, Radio, Switch } from 'antd'; import { Modal, Form, InputNumber, Checkbox, Switch } from 'antd';
import { deepClone } from '@/utils/utils'; import { deepClone } from '@/utils/utils';
import styles from '../../style.less'; import styles from '../../style.less';
import { apiProductStock } from '../../service';
const StockModal = options => { const StockModal = options => {
const [stockType, setStockType] = useState(0); const [stockType, setStockType] = useState(0);
const [maxStock, setMaxStock] = useState(0); const [maxStock, setMaxStock] = useState(0);
const [isChecked, setIsChecked] = useState(false);
const [form] = Form.useForm(); const [form] = Form.useForm();
const onChangeType = v => { const onChangeType = v => {
...@@ -28,13 +30,28 @@ const StockModal = options => { ...@@ -28,13 +30,28 @@ const StockModal = options => {
const values = await form.validateFields(); const values = await form.validateFields();
const params = deepClone(values); const params = deepClone(values);
params.autoStock = values.autoStock ? 1 : 0; params.autoStock = values.autoStock ? 1 : 0;
console.log('values :>> ', values);
options.confirm({ options.confirm({
type: 7, type: 7,
...values, ...params,
}); });
}; };
const getStockInfo = async () => {
const res = await apiProductStock({
skuId: options.skuIds[0],
shopId: options.shopId,
});
if (res && res.code === '0000' && res.businessCode === '0000') {
const info = res.data;
form.setFieldsValue({
autoStockStep: info.autoStockStep,
productStock: info.stock,
autoStock: info.autoStock === 1,
});
setIsChecked(info.autoStock === 1);
}
};
const initialValues = Object.assign( const initialValues = Object.assign(
{ {
productStock: '', productStock: '',
...@@ -52,12 +69,30 @@ const StockModal = options => { ...@@ -52,12 +69,30 @@ const StockModal = options => {
} }
}, [maxStock, stockType]); }, [maxStock, stockType]);
useEffect(() => {
if (options.visible) {
setStockType(0);
setMaxStock(0);
setIsChecked(false);
form.resetFields();
if (options.skuIds && options.skuIds.length) {
getStockInfo();
}
}
}, [options.visible]);
const maxStockRule = [];
if (isChecked) {
maxStockRule.push({ required: true, message: '请输入最大库存!' });
}
return ( return (
<Modal <Modal
visible={options.visible} visible={options.visible}
title="修改库存" title="修改库存"
onOk={handleOk} onOk={handleOk}
maskClosable={false} maskClosable={false}
keyboard={false}
confirmLoading={options.loading} confirmLoading={options.loading}
destroyOnClose destroyOnClose
onCancel={handleCancel} onCancel={handleCancel}
...@@ -78,7 +113,12 @@ const StockModal = options => { ...@@ -78,7 +113,12 @@ const StockModal = options => {
wrapperCol={{ span: 8 }} wrapperCol={{ span: 8 }}
rules={[{ required: true, message: '请输入剩余库存!' }]} rules={[{ required: true, message: '请输入剩余库存!' }]}
> >
<Input type="number" disabled={stockType > 0} /> <InputNumber
min={0}
max={999999999}
className={styles['stock-box--inputnum']}
disabled={stockType > 0}
/>
</Form.Item> </Form.Item>
<div className={styles['stock-box--btns']}> <div className={styles['stock-box--btns']}>
<Checkbox checked={stockType === 1} onChange={() => onChangeType(1)}> <Checkbox checked={stockType === 1} onChange={() => onChangeType(1)}>
...@@ -88,15 +128,21 @@ const StockModal = options => { ...@@ -88,15 +128,21 @@ const StockModal = options => {
最大 最大
</Checkbox> </Checkbox>
</div> </div>
<Form.Item <Form.Item label="最大库存" name="autoStockStep" rules={maxStockRule}>
label="最大库存" <InputNumber
name="autoStockStep" min={0}
rules={[{ required: true, message: '请输入最大库存!' }]} max={999999999}
> className={styles['stock-box--inputnum']}
<Input type="number" onChange={onChangeMaxStock} /> onChange={onChangeMaxStock}
/>
</Form.Item> </Form.Item>
<Form.Item label="自动补足" name="autoStock"> <Form.Item label="自动补足" name="autoStock">
<Switch checkedChildren="开启" unCheckedChildren="关闭" /> <Switch
checkedChildren="开启"
checked={isChecked}
unCheckedChildren="关闭"
onChange={setIsChecked}
/>
</Form.Item> </Form.Item>
</Form> </Form>
<div className={styles['stock-box--red']}>修改成功后,原库存将被替换,请谨慎操作</div> <div className={styles['stock-box--red']}>修改成功后,原库存将被替换,请谨慎操作</div>
......
...@@ -25,6 +25,7 @@ const SwitchGroupModal = options => { ...@@ -25,6 +25,7 @@ const SwitchGroupModal = options => {
title="更改分组" title="更改分组"
onOk={handleOk} onOk={handleOk}
maskClosable={false} maskClosable={false}
keyboard={false}
confirmLoading={options.loading} confirmLoading={options.loading}
destroyOnClose destroyOnClose
onCancel={handleCancel} onCancel={handleCancel}
......
...@@ -8,7 +8,7 @@ import styles from '../../style.less'; ...@@ -8,7 +8,7 @@ import styles from '../../style.less';
const WeekTime = options => { const WeekTime = options => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [type, setType] = useState(1); const [type, setType] = useState(0);
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
...@@ -37,16 +37,13 @@ const WeekTime = options => { ...@@ -37,16 +37,13 @@ const WeekTime = options => {
options.cancel(false); options.cancel(false);
}; };
const handleOk = async () => { const handleOk = async () => {
const values = await form.validateFields(); const params = await form.validateFields();
const params = deepClone(values); // const params = values;
if (params.saleTimes && params.saleTimes.length) { if (params.saleTimes && params.saleTimes.length) {
params.saleTimes = values.saleTimes.map(item => { params.saleTimes = params.saleTimes.map(item => ({
if (item && item.length > 1) { startTime: moment(item[0]).format('HH:mm'),
item[0] = moment(item[0]).format('HH:mm'); endTime: moment(item[1]).format('HH:mm'),
item[1] = moment(item[1]).format('HH:mm'); }));
}
return item;
});
} }
options.confirm({ options.confirm({
...@@ -57,7 +54,7 @@ const WeekTime = options => { ...@@ -57,7 +54,7 @@ const WeekTime = options => {
const initialValues = Object.assign( const initialValues = Object.assign(
{ {
saleTimeType: 1, saleTimeType: 0,
saleDates: [], saleDates: [],
saleTimes: [[]], saleTimes: [[]],
}, },
...@@ -69,8 +66,9 @@ const WeekTime = options => { ...@@ -69,8 +66,9 @@ const WeekTime = options => {
visible={options.visible} visible={options.visible}
title="售卖时间" title="售卖时间"
onOk={handleOk} onOk={handleOk}
maskClosable={false}
confirmLoading={options.loading} confirmLoading={options.loading}
maskClosable={false}
keyboard={false}
destroyOnClose destroyOnClose
onCancel={handleCancel} onCancel={handleCancel}
> >
...@@ -95,7 +93,7 @@ const WeekTime = options => { ...@@ -95,7 +93,7 @@ const WeekTime = options => {
buttonStyle="solid" buttonStyle="solid"
/> />
</Form.Item> </Form.Item>
{type === 2 ? ( {type === 1 ? (
<> <>
<Form.Item <Form.Item
label="售卖日期" label="售卖日期"
......
import React, { useState, useEffect, useCallback, useMemo } from 'react'; import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { Spin, Table, Modal, message, notification } from 'antd'; import { Spin, Table, Modal, message, notification } from 'antd';
import { unstable_batchedUpdates } from 'react-dom';
import { MenuOutlined, HolderOutlined, FormOutlined, CloseCircleOutlined } from '@ant-design/icons'; import { MenuOutlined, HolderOutlined, FormOutlined, CloseCircleOutlined } from '@ant-design/icons';
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
import { arrayMoveImmutable } from 'array-move'; import { arrayMoveImmutable } from 'array-move';
...@@ -35,12 +36,15 @@ const Takeaway = options => { ...@@ -35,12 +36,15 @@ const Takeaway = options => {
const getDataList = async () => { const getDataList = async () => {
setLoading(true); setLoading(true);
const params = { const params = Object.assign({}, options.searchValue, {
pageNo: 1, pageNo: 1,
productType: 5, productType: 5,
pageSize: 100000, pageSize: 100000,
storageRackId: groupId, storageRackId: groupId,
}; });
const productCategoryId = options.searchValue?.productCategoryId || [];
params.productCategoryId =
(productCategoryId.length && productCategoryId[productCategoryId.length - 1]) || '';
const res = await apiTakeawayGoods(params); const res = await apiTakeawayGoods(params);
setLoading(false); setLoading(false);
if (res && res.data) { if (res && res.data) {
...@@ -93,15 +97,19 @@ const Takeaway = options => { ...@@ -93,15 +97,19 @@ const Takeaway = options => {
shopId, shopId,
}; };
setActionLoading(true); setActionLoading(true);
const params2 = {
...json,
...params,
};
console.log('params2 :>> ', params2);
const res = await apiGoodsActionBatch(Object.assign({}, json, params)); const res = await apiGoodsActionBatch(Object.assign({}, json, params));
setActionLoading(false); unstable_batchedUpdates(() => {
setActionLoading(false);
setVisibleWeekTime(false);
setVisibleStock(false);
setVisibleSwitchGroup(false);
setVisibleBuy(false);
setVisibleSend(false);
});
getDataList(); getDataList();
message.success('处理成功!'); if (res.businessCode === '0000' && res.code === '0000') {
message.success('处理成功!');
}
}; };
// 显示弹窗 // 显示弹窗
...@@ -133,18 +141,22 @@ const Takeaway = options => { ...@@ -133,18 +141,22 @@ const Takeaway = options => {
}); });
}; };
// 置顶 // 置顶
const toTop = row => {}; const toTop = oldIndex => {
onSortEnd({ oldIndex, newIndex: 0 });
};
useEffect(() => { useEffect(() => {
if (groupId) { if (groupId) {
getDataList(); getDataList();
} }
}, [groupId]); }, [groupId, options.refresh]);
const actions = { const actions = {
onShowStockModal, onShowStockModal,
toTop, toTop,
onEdit, onEdit,
getDataList,
shopId,
}; };
return ( return (
...@@ -153,6 +165,7 @@ const Takeaway = options => { ...@@ -153,6 +165,7 @@ const Takeaway = options => {
<GoodsGroup shopId={shopId} changeShop={setShopId} changeGroup={setGroupId} /> <GoodsGroup shopId={shopId} changeShop={setShopId} changeGroup={setGroupId} />
<ActionBar <ActionBar
selectedRowKeys={selectedRowKeys} selectedRowKeys={selectedRowKeys}
shopId={shopId}
handleSearch={getDataList} handleSearch={getDataList}
openModal={openModal} openModal={openModal}
newGoods={onNew} newGoods={onNew}
...@@ -182,6 +195,8 @@ const Takeaway = options => { ...@@ -182,6 +195,8 @@ const Takeaway = options => {
<StockModal <StockModal
visible={visibleStock} visible={visibleStock}
loading={actionLoading} loading={actionLoading}
skuIds={selectedRowKeys}
shopId={shopId}
confirm={handleBatchAction} confirm={handleBatchAction}
cancel={setVisibleStock} cancel={setVisibleStock}
/> />
......
...@@ -40,6 +40,7 @@ class goodsManage extends Component { ...@@ -40,6 +40,7 @@ class goodsManage extends Component {
pageNo: 1, pageNo: 1,
loading: false, loading: false,
treeData: [], treeData: [],
categoryTree: [],
virtualTreeData: [], virtualTreeData: [],
pageSize: 20, pageSize: 20,
priceInfo: {}, priceInfo: {},
...@@ -63,6 +64,8 @@ class goodsManage extends Component { ...@@ -63,6 +64,8 @@ class goodsManage extends Component {
isEditDraft: false, // 是否编辑草稿 isEditDraft: false, // 是否编辑草稿
productType: 1, // 商品类型 productType: 1, // 商品类型
takeAway: {}, // 弹窗外卖商品参数 takeAway: {}, // 弹窗外卖商品参数
searchValue: {}, // 搜索条件
refresh: '', // 外卖刷新
}; };
currentLog = null; currentLog = null;
...@@ -76,36 +79,45 @@ class goodsManage extends Component { ...@@ -76,36 +79,45 @@ class goodsManage extends Component {
componentDidMount() { componentDidMount() {
this.props.goodsManage.tableData = {}; this.props.goodsManage.tableData = {};
this.categoryList(); this.categoryList();
this.categoryListByType(this.state.productType);
this.getVirtualCategory(); this.getVirtualCategory();
this.specList(); this.specList();
this.setState({ productType: 5 });
} }
handleSearch = page => { handleSearch = page => {
this.onSelectChange([]); const searchValue = this.searchForm.getFieldsValue();
const currentPage = this.state.pageNo; this.setState({ searchValue });
this.setState( if (this.state.productType !== 5) {
{ this.onSelectChange([]);
pageNo: page || currentPage, const currentPage = this.state.pageNo;
loading: true, this.setState(
}, {
() => { pageNo: page || currentPage,
const { dispatch } = this.props; loading: true,
const { pageSize, pageNo } = this.state; },
dispatch({ () => {
type: 'goodsManage/getList', const { dispatch } = this.props;
payload: { const { pageSize, pageNo } = this.state;
pageNo, dispatch({
pageSize, type: 'goodsManage/getList',
...this.searchForm.getFieldsValue(), payload: {
}, pageNo,
}).finally(() => { pageSize,
this.setState({ ...searchValue,
loading: false, },
}).finally(() => {
this.setState({
loading: false,
});
}); });
}); },
}, );
); } else {
this.setState({
refresh: new Date().getTime(),
searchValue,
});
}
}; };
onPageChange = page => { onPageChange = page => {
...@@ -270,10 +282,9 @@ class goodsManage extends Component { ...@@ -270,10 +282,9 @@ class goodsManage extends Component {
} }
}; };
categoryList = async type => { categoryList = async () => {
const api = type ? apiCategoryListType : categoryList;
try { try {
const { data: treeData } = await api(type); const { data: treeData } = await categoryList({});
if (!treeData) return; if (!treeData) return;
this.setState({ treeData }); this.setState({ treeData });
} catch (e) { } catch (e) {
...@@ -281,11 +292,21 @@ class goodsManage extends Component { ...@@ -281,11 +292,21 @@ class goodsManage extends Component {
} }
}; };
categoryListByType = async type => {
try {
const { data: categoryTree } = await apiCategoryListType(type);
if (!categoryTree) return;
this.setState({ categoryTree });
} catch (e) {
console.log(e);
}
};
changeProductType = e => { changeProductType = e => {
this.setState({ this.setState({
productType: e || 1, productType: e || 1,
}); });
this.categoryList(e); this.categoryListByType(e);
}; };
getVirtualCategory = async () => { getVirtualCategory = async () => {
...@@ -421,7 +442,7 @@ class goodsManage extends Component { ...@@ -421,7 +442,7 @@ class goodsManage extends Component {
onRef={ref => { onRef={ref => {
this.searchForm = ref; this.searchForm = ref;
}} }}
treeData={this.state.treeData} treeData={this.state.categoryTree}
shopList={this.shopList} shopList={this.shopList}
checkStock={this.checkEnableUpdateStock} checkStock={this.checkEnableUpdateStock}
selectNum={selectedRowKeys.length} selectNum={selectedRowKeys.length}
...@@ -430,7 +451,11 @@ class goodsManage extends Component { ...@@ -430,7 +451,11 @@ class goodsManage extends Component {
/> />
</Card> </Card>
{this.state.productType === 5 ? ( {this.state.productType === 5 ? (
<Takeaway handleEdit={this.handleTakeawayEdit} /> <Takeaway
handleEdit={this.handleTakeawayEdit}
searchValue={this.state.searchValue}
refresh={this.state.refresh}
/>
) : ( ) : (
<> <>
<Spin spinning={this.state.loading}> <Spin spinning={this.state.loading}>
......
...@@ -363,3 +363,10 @@ export async function apiStorageList(params) { ...@@ -363,3 +363,10 @@ export async function apiStorageList(params) {
headers, headers,
}); });
} }
// 获取库存信息
export async function apiProductStock(data) {
return request.get('/api/merchants/products/sku/getStockInfo', {
prefix: goodsApi,
params: data,
});
}
import React from 'react'; import React from 'react';
import { Button, Badge, Switch, Modal } from 'antd'; import { Button, Badge, Switch, Modal, message } from 'antd';
import { SortableHandle } from 'react-sortable-hoc'; import { SortableHandle } from 'react-sortable-hoc';
import { ExclamationCircleOutlined, MenuOutlined } from '@ant-design/icons'; import { ExclamationCircleOutlined, MenuOutlined } from '@ant-design/icons';
import styles from './style.less'; import styles from './style.less';
import { resetTime } from '../../utils/utils'; import { resetTime } from '../../utils/utils';
import { apiChangeStateGoods } from './service'; import { apiChangeStateGoods, apiGoodsActionBatch } from './service';
const { confirm } = Modal; const { confirm } = Modal;
...@@ -252,22 +252,19 @@ export function takeawayColumn(actions) { ...@@ -252,22 +252,19 @@ export function takeawayColumn(actions) {
icon: <ExclamationCircleOutlined />, icon: <ExclamationCircleOutlined />,
content: `确认${+state === 6 ? '下架' : '上架'}商品?`, content: `确认${+state === 6 ? '下架' : '上架'}商品?`,
onOk: async () => { onOk: async () => {
const res = await apiChangeStateGoods({ const res = await apiGoodsActionBatch({
skuIds: skuId, skuIds: [skuId],
productStatus: +state === 6 ? 7 : 6, // 6:上架,7:下架 shopId: actions.shopId,
productStatus: +state === 6 ? 0 : 1, // 6:上架,7:下架
type: 2,
}); });
if (res.businessCode === '0000' && res.code === '0000') { if (res.businessCode === '0000' && res.code === '0000') {
this.handleSearch(); actions.getDataList();
message.success('处理成功!');
} }
}, },
}); });
}; };
const onShowAudit = row => {
this.setState({
auditRow: row,
visibleAuditModal: true,
});
};
const DragHandle = SortableHandle(() => ( const DragHandle = SortableHandle(() => (
<MenuOutlined style={{ cursor: 'grab', color: '#999' }} /> <MenuOutlined style={{ cursor: 'grab', color: '#999' }} />
)); ));
...@@ -295,15 +292,9 @@ export function takeawayColumn(actions) { ...@@ -295,15 +292,9 @@ export function takeawayColumn(actions) {
}, },
{ {
title: '售卖价格(元)', title: '售卖价格(元)',
dataIndex: 'marketPrice', dataIndex: 'salePrice',
width: 150, width: 150,
align: 'center', align: 'center',
render: (_, row) => (
<div className={styles.price}>
<div>供货价:{(row.supplyPrice || 0).toFixed(2)}</div>
<div>市场价:{(row.marketPrice || 0).toFixed(2)}</div>
</div>
),
}, },
{ {
title: '库存', title: '库存',
...@@ -351,7 +342,7 @@ export function takeawayColumn(actions) { ...@@ -351,7 +342,7 @@ export function takeawayColumn(actions) {
修改库存 修改库存
</Button> </Button>
{index > 0 && ( {index > 0 && (
<Button key="top" className={styles.button} onClick={() => actions.toTop(row)}> <Button key="top" className={styles.button} onClick={() => actions.toTop(index)}>
置顶 置顶
</Button> </Button>
)} )}
......
...@@ -279,4 +279,7 @@ ...@@ -279,4 +279,7 @@
&--red { &--red {
color: #ff1616; color: #ff1616;
} }
&--inputnum {
width: 100%;
}
} }
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