Commit f4e553b1 authored by guang.wu's avatar guang.wu

feat: 添加商品竞价功能

parent acc5a333
...@@ -294,6 +294,12 @@ export default { ...@@ -294,6 +294,12 @@ export default {
name: 'brandManage', name: 'brandManage',
component: './BrandManage', component: './BrandManage',
}, },
{
title: '商户管理后台-自营商品供货价更新',
path: '/supplyPriceUpdate',
name: 'supplyPriceUpdate',
component: './GoodsManage/SupplyPriceUpdate',
},
...groupMealRoute, ...groupMealRoute,
{ {
component: './404', component: './404',
......
import React, { useState, createContext } from 'react';
import { Modal, Table, Form } from 'antd';
import { column } from '../staticdata';
import styles from '../style.less';
/**
* 更新供货价
* * */
const UpdatePriceStock = options => {
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const onSubmit = async () => {
const value = await form.validateFields();
console.log('value :>> ', value);
setLoading(true);
setLoading(false);
options.refresh();
options.onCancel();
};
const EditableContext = createContext(null);
return (
<Modal
title="修改供货价"
open={options.visible}
onCancel={options.onCancel}
onOk={onSubmit}
confirmLoading={loading}
width={900}
className={styles.priceStockTable}
destroyOnClose
>
<Form form={form} scrollToFirstError component={false}>
<EditableContext.Provider value={form}>
<Table
className={styles.priceStockTable}
rowKey="key"
columns={column.call(this)}
dataSource={options.data}
/>
</EditableContext.Provider>
</Form>
</Modal>
);
};
export default UpdatePriceStock;
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import { Card, Pagination, Table, notification, Drawer, Spin } from 'antd';
import React, { Component } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { connect } from 'dva';
import styles from '../style.less';
import UpdateStock from '../UpdateStock';
import {
categoryList,
apiCategoryListType,
getVirtualCategory,
getTemplateList,
specList,
queryAllAfterAddress,
apiEnableUpdataStock,
apiQueryLastChangeLog,
} from '../service';
import LogModal from '../LogModal';
import { column, JDSHOPID } from '../staticdata';
import SearchForm from '../SearchForm';
import TempleatModal from '../TempleatModal';
import ServiceGoods from '../../ServiceGoods';
import InfoAudit from '../infoAudit';
import UpdatePriceStock from './components/UpdatePriceStock';
import Takeaway from '../Takeaway';
import { GOOD_MANAGE } from '@/../config/permission.config';
import LocalStroage from '@/utils/localStorage';
import configApi from '@/../config/env.config';
@connect(({ goodsManage, menu }) => ({
goodsManage,
permissions: menu.permissions,
}))
class goodsManage extends Component {
state = {
pageNo: 1,
loading: false,
treeData: [],
categoryTree: [],
virtualTreeData: [],
pageSize: 20,
priceInfo: {},
logVisible: false,
previewVisible: false,
updateStockVisible: false,
createloading: false,
specListData: [],
templeatModalVisible: false,
selectedRowKeys: [],
isAll: 0,
templateList: [],
stockSkuIds: [],
isType: '',
serviceVisble: false,
serviceData: {},
visibleAuditModal: false,
auditRow: {}, // 查看审核信息使用
isEditDraft: false, // 是否编辑草稿
productType: 1, // 商品类型
takeAway: {}, // 弹窗外卖商品参数
searchValue: {}, // 搜索条件
refresh: '', // 外卖刷新
visibleUpdatePrice: false, // 修改价格弹窗
skuPriceStockList: [{ key: 1 }, { key: 2 }], // 修改价格弹窗数据
};
currentLog = null;
supplierId = null;
shopList = [];
canEditable = false;
componentDidMount() {
this.props.goodsManage.tableData = {};
this.categoryList(this.state.productType);
this.categoryListByType(this.state.productType);
this.getVirtualCategory();
this.specList();
console.log('this.state.productType', this.state.productType);
}
handleSearch = page => {
const searchValue = this.searchForm.getFieldsValue() || {};
this.setState({ searchValue });
if (searchValue.productType !== 5) {
this.onSelectChange([]);
const currentPage = this.state.pageNo;
this.setState(
{
pageNo: page || currentPage,
loading: true,
},
() => {
const { dispatch } = this.props;
const { pageSize, pageNo } = this.state;
dispatch({
type: 'goodsManage/getList',
payload: {
pageNo,
pageSize,
...searchValue,
},
}).finally(() => {
this.setState({
loading: false,
});
});
},
);
} else {
this.setState({
refresh: new Date().getTime(),
searchValue,
});
}
};
onPageChange = page => {
this.handleSearch(page);
};
audit = skuId => {
this.setState({
previewVisible: true,
src: `${configApi.prologueDomain}/goods/${skuId}?h=0&token=${LocalStroage.get(
'token',
)}&hideReport=1&time=${Date.now()}`,
});
};
onPageSizeChange = (current, size) => {
this.setState(
{
pageSize: size,
},
() => this.handleSearch(),
);
};
onReset = () => {
this.setState({
pageNo: 1,
pageSize: 20,
selectedRowKeys: [],
});
this.handleSearch();
};
onLoad = error => {
if (!error) {
notification.success({ message: '操作成功' });
this.setState({
selectedRowKeys: [],
});
this.handleSearch();
}
};
viewLog = async rows => {
this.currentLog = rows;
this.setState({
logVisible: true,
});
};
setArea = async (isAll, type) => {
// distribution配送区域 after售后地址
if (!this.state.selectedRowKeys.length && !isAll) {
notification.error({ message: '请选择商品' });
return;
}
const data = type === 'distribution' ? await getTemplateList() : await queryAllAfterAddress();
const length = type === 'distribution' ? data.data.length : data.data.records.length;
if (data.code === '0000' && length) {
this.setState({
templeatModalVisible: true,
isAll,
templateList: type === 'distribution' ? data.data : data.data.records,
isType: type,
});
} else {
notification.error({ message: '暂无数据' });
}
};
filterShopList = (list = [], isEdit) =>
list.filter(item => isEdit || !JDSHOPID.includes(item.id));
// 验证是否可以修改库存
checkEnableUpdateStock = async () => {
const ids = this.state.selectedRowKeys.join(',');
if (ids) {
const res = await apiEnableUpdataStock(ids);
if (res.data) {
if (res.data.successSkuIds?.length) {
this.setState({
priceInfo: {},
stockSkuIds: res.data.successSkuIds,
});
this.openModal({}, 1);
} else {
const message = res.data.failedInfoList[0]?.message || '未存在可修改库存的商品';
notification.info({ message });
}
}
} else {
notification.info({ message: '请选择' });
}
};
openModal = (
{
skuId,
supplyPrice,
marketPrice,
salePrice,
marketableStock,
supplierId,
stock,
productStock,
state,
},
isStock,
) => {
let visible = {};
if (isStock) {
visible = { updateStockVisible: true };
}
this.setState({
...visible,
priceInfo: {
id: skuId,
stock,
productStock,
marketableStock,
supplyPrice,
marketPrice,
salePrice,
supplierId,
state,
},
});
};
onShowStockModal = async row => {
const res = await apiQueryLastChangeLog(row.skuId);
let priceInfo = {
id: row.skuId,
curStock: row.productStock,
supplierId: row.supplierId,
marketableStock: row.stock,
};
if (res.data && [1, 3].includes(+res.data.status)) {
priceInfo = Object.assign(
{
changeReason: res.data.changeReason,
stock: +res.data.afterChange,
changeType: res.data.changeType,
status: res.data.status,
stateDesc: res.data.statusDesc,
rejectReason: res.data.rejectReason,
},
priceInfo,
);
}
this.setState({
updateStockVisible: true,
priceInfo,
stockSkuIds: [row.skuId],
});
};
cancel = query => {
this.setState({ updateStockVisible: false });
if (query) {
this.handleSearch();
}
};
categoryList = async () => {
try {
const { data: treeData } = await categoryList({});
if (!treeData) return;
this.setState({ treeData });
} catch (e) {
console.log(e);
}
};
categoryListByType = async type => {
try {
const { data: categoryTree } = await apiCategoryListType(type);
if (!categoryTree) return;
this.setState({ categoryTree });
} catch (e) {
console.log(e);
}
};
changeProductType = e => {
this.setState({
productType: e || 1,
});
this.categoryListByType(e);
if (e !== 5) {
this.handleSearch(1);
}
};
getVirtualCategory = async () => {
try {
const { data: virtualTreeData } = await getVirtualCategory();
if (!virtualTreeData) return;
this.setState({ virtualTreeData });
} catch (e) {
console.log(e);
}
};
specList = async () => {
const data = await specList();
if (data.businessCode === '0000' && data.data.length) {
this.setState({ specListData: data.data });
}
};
onSelectChange = selectedRowKeys => {
this.setState({
selectedRowKeys,
});
};
serviceVisbleChange = async row => {
this.setState({
visibleUpdatePrice: true,
});
};
// 显示新增商品弹窗
serviceVisbleClose = (flag, refresh) => {
this.setState({
serviceVisble: flag,
isEditDraft: false,
serviceData: {},
takeAway: {},
});
if (refresh) {
this.handleSearch();
}
};
onEdit = () => {
this.setState({ visibleAuditModal: false, auditRow: {} });
this.serviceVisbleChange(this.state.auditRow);
};
// 显示外卖商品弹窗
handleTakeawayEdit = params => {
this.setState({
takeAway: params,
serviceVisble: true,
});
};
render() {
const {
goodsManage: { tableData = {} },
permissions,
} = this.props;
const rowSelection = {
selectedRowKeys: this.state.selectedRowKeys,
onChange: this.onSelectChange,
};
const { pageNo, pageSize, selectedRowKeys } = this.state;
this.canEditable = permissions[GOOD_MANAGE.EDITABLE];
return (
<PageHeaderWrapper>
<Spin spinning={this.state.createloading}>
<Card>
<SearchForm
handleSearch={this.handleSearch}
onReset={this.onReset}
onLoad={this.onLoad}
onRef={ref => {
this.searchForm = ref;
}}
treeData={this.state.categoryTree}
shopList={this.shopList}
checkStock={this.checkEnableUpdateStock}
selectNum={selectedRowKeys.length}
changeProductType={this.changeProductType}
setArea={(isALL, type) => this.setArea(isALL, type)}
/>
</Card>
{this.state.productType === 5 ? (
<Takeaway
handleEdit={this.handleTakeawayEdit}
searchValue={this.state.searchValue}
permissions={permissions}
refresh={this.state.refresh}
/>
) : (
<>
<Spin spinning={this.state.loading}>
<Table
dataSource={tableData?.records}
bordered
columns={column.call(this)}
rowKey={record => record.skuId}
pagination={false}
className={styles.tabletop}
scroll={{ x: '100%', y: 500 }}
rowSelection={rowSelection}
/>
</Spin>
<br />
{tableData && (
<Pagination
style={{ marginBottom: 10 }}
onChange={this.onPageChange}
total={tableData.total}
showTotal={total => `共${total}条`}
current={pageNo}
pageSize={pageSize}
showSizeChanger
onShowSizeChange={this.onPageSizeChange}
/>
)}
<LogModal
visible={this.state.logVisible}
spuId={this.currentLog?.spuId}
id={this.currentLog?.skuId}
onCancel={() => {
this.currentLog = null;
this.setState({ logVisible: false });
}}
/>
<Drawer
visible={this.state.previewVisible}
width="450"
onClose={() => {
this.setState({ previewVisible: false });
}}
title="商品预览"
bodyStyle={{ height: '90%' }}
>
<iframe
src={this.state.src}
frameBorder="0"
height="100%"
width="375"
title="商品预览"
></iframe>
</Drawer>
<UpdateStock
visible={this.state.updateStockVisible}
skuIds={this.state.stockSkuIds}
info={this.state.priceInfo}
onCancel={this.cancel}
/>
<TempleatModal
visible={this.state.templeatModalVisible}
selectedRowKeys={this.state.selectedRowKeys}
total={tableData.total || 0}
onCancel={() => {
this.setState({ templeatModalVisible: false, selectedRowKeys: [] });
this.handleSearch();
}}
isALL={this.state.isAll}
isType={this.state.isType}
templateList={this.state.templateList}
/>
</>
)}
</Spin>
{this.state.serviceVisble && (
<ServiceGoods
visible={this.state.serviceVisble}
onChange={this.serviceVisbleClose}
SourceData={this.state.serviceData}
shopList={this.shopList}
categoryList={this.state.treeData}
virtualCategoryList={this.state.virtualTreeData}
specListData={this.state.specListData}
permissions={permissions}
isDraft={this.state.isEditDraft}
productType={this.state.productType}
takeAway={this.state.takeAway}
/>
)}
{this.state.visibleAuditModal && (
<InfoAudit
visible={this.state.visibleAuditModal}
skuInfo={this.state.auditRow}
canEditable={this.canEditable}
onCancel={() => {
this.setState({ visibleAuditModal: false, auditRow: {} });
}}
onEdit={this.onEdit}
/>
)}
{this.state.visibleUpdatePrice && (
<UpdatePriceStock
visible={this.state.visibleUpdatePrice}
onCancel={() => {
this.setState({ visibleUpdatePrice: false });
}}
data={this.state.skuPriceStockList}
refresh={this.handleSearch}
/>
)}
</PageHeaderWrapper>
);
}
}
export default Form.create()(goodsManage);
import React from 'react';
import { Input, Form } from 'antd';
import styles from '../style.less';
import { isNumberSection, isCheckPriceTwoDecimal } from '@/utils/validator';
export function column() {
return [
{
title: '供货价',
dataIndex: 'supplyPrice',
width: 150,
align: 'center',
render: (_, row, index) => (
<div className={styles.price}>
<Form.Item
label=""
key="supplyPrice"
name={['data', index, 'supplyPrice']}
initialValue={row.supplyPrice}
rules={[
{ required: true, message: '请输入供货价!' },
{ validator: isCheckPriceTwoDecimal },
]}
>
<Input allowClear />
</Form.Item>
</div>
),
},
{
title: '市场价',
width: 135,
align: 'center',
dataIndex: 'marketPrice',
},
{
title: '重量(kg)',
width: 135,
align: 'center',
dataIndex: 'weight',
},
{
title: '库存',
width: 120,
dataIndex: 'productStock',
align: 'center',
render: (_, row, index) => (
<div>
<Form.Item
label=""
key="productStock"
name={['data', index, 'productStock']}
initialValue={row.productStock}
rules={[
{ required: true, message: '请输入库存!' },
{ validator: isNumberSection, min: 1, max: 500, message: '请输入1-500的整数' },
]}
>
<Input allowClear />
</Form.Item>
</div>
),
},
{
title: '库存预警',
width: 120,
dataIndex: 'productStockWarning',
align: 'center',
render: (_, row, index) => (
<div>
<Form.Item
label=""
key="productStockWarning"
name={['data', index, 'productStockWarning']}
rules={[
{ required: true, message: '请输入库存!' },
{ validator: isNumberSection, min: 1, max: 500, message: '请输入1-500的整数' },
]}
initialValue={row.productStockWarning}
>
<Input allowClear />
</Form.Item>
</div>
),
},
{
title: '商品自编码',
dataIndex: 'thirdSkuNo',
width: 200,
align: 'center',
},
];
}
.priceStockTable {
:global(.ant-table-cell) {
padding: 5px 0 0 0 !important;
}
}
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