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

feat: 添加导入弹窗

parent ddfa33ce
import { DownloadOutlined } from '@ant-design/icons';
import { Modal, Button, Empty, Pagination } from 'antd';
import React, { useState, useEffect } from 'react';
import { unstable_batchedUpdates } from 'react-dom';
import styles from './index.less';
import { apiUploadResult } from './service';
const ImportListModal = props => {
const { visible } = props;
const [data, setData] = useState([]);
const [total, setTotal] = useState(0);
const [pageInfo, setPageInfo] = useState({
pageNo: 1,
pageSize: 2,
});
const getImportData = async params => {
const res = await apiUploadResult({
type: props.type,
...params,
});
if (res?.data) {
unstable_batchedUpdates(() => {
setData(res.data.records);
setTotal(res.data.total);
});
}
};
const onChangePage = (pageNo, pageSize) => {
const obj = { pageNo, pageSize };
setPageInfo(obj);
getImportData(obj);
};
const onDownload = url => {
window.location.href = url;
};
useEffect(() => {
getImportData(pageInfo);
}, []);
return (
<Modal
title={
<div>
查看导入记录<span className={styles.subTitle}>(仅展示近半年记录)</span>
</div>
}
open={visible}
onCancel={props.onCancel}
width="800px"
footer={false}
>
{data.length ? (
<div>
<div className={styles.tableBody}>
{data.map(item => (
<div className={styles.card} key={item.id}>
<div>
<div className={styles.top}>
<span>导入数据:{item.total}</span>
<span>成功数:{item.successCount}</span>
<span>失败数:{item.failedCount}</span>
</div>
<div>
<span>导入时间:{item.createdAt}</span>
<span>操作人:{item.createdBy}</span>
</div>
</div>
<div className={styles.errWrappper}>
{item.failedCount > 0 && (
<Button type="primary" onClick={() => onDownload(item.failedFileUrl)}>
<DownloadOutlined />
下载错误数据
</Button>
)}
{item.status && +item.status.code === 3 && (
<div className={styles.errorMessage}>{item.failedMessage}</div>
)}
</div>
</div>
))}
</div>
<div className={styles.pagewrapper}>
<Pagination
total={total}
showTotal={e => `总共 ${e} 条数据`}
pageSize={pageInfo.pageSize}
defaultCurrent={pageInfo.pageNo}
onChange={onChangePage}
onShowSizeChange={onChangePage}
showQuickJumper
// showSizeChanger
/>
</div>
</div>
) : (
<Empty />
)}
</Modal>
);
};
export default ImportListModal;
// 导入配置
export const ImportConfig = {
// 竞价商品批量选品
binding: {
title: '自营商品供货价库存批量更新',
type: 6,
tempPath: '',
limitNum: 5000,
hideDownload: true,
tip: 'SKU',
},
};
import React, { useState, useEffect } from 'react';
import { Form } from '@ant-design/compatible';
import { Modal, Button, Upload, notification } from 'antd';
import styles from './index.less';
import { apiImportGoods } from './service';
import ImportListModal from './ImportListModal';
import { ImportConfig } from './config';
const ImportGoods = React.memo(props => {
const [importFile, setImportFile] = useState([]);
const [loading, setLoading] = useState(false);
const [visibleRecord, setVisibleRecord] = useState(false);
const [config, setConfig] = useState({});
// 关闭弹窗
const onCancel = () => {
props.onHide();
};
// 查看导入记录
const onShowRecord = () => {
setVisibleRecord(true);
};
// 下载模板
const onDownTemplate = () => {
if (config.tempPath) {
window.location.href = config.tempPath;
} else if (props.onDownload) {
props.onDownload(config);
}
};
// 导入
const onImport = async () => {
if (!importFile.length) {
notification.error({
message: '请选择导入文件',
});
return;
}
setLoading(true);
const result = await apiImportGoods(importFile[0], config.type);
setLoading(false);
if (result?.success) {
setImportFile([]);
notification.success({
message: '导入成功',
});
}
};
// 导入按钮配置属性
const uploadFileAttr = {
name: 'file',
maxCount: 1,
fileList: importFile,
async customRequest(info) {
setImportFile([info.file]);
return false;
},
accept: '.xlsx',
showUploadList: true,
onRemove: () => {
setImportFile([]);
},
};
useEffect(() => {
if (props.visible) {
setConfig(ImportConfig[props.importType]);
}
}, [props.visible]);
return (
<>
<Modal
title={config.title}
open={props.visible}
onCancel={onCancel}
footer={[
<Button type="link" onClick={onShowRecord} key="btnlook">
查看导入记录
</Button>,
!config.hideDownload && (
<Button type="link" onClick={onDownTemplate} key="btndown">
下载模板
</Button>
),
<Button onClick={onCancel} key="btncancel">
关闭
</Button>,
<Button type="primary" loading={loading} onClick={onImport} key="btnimprot">
导入
</Button>,
]}
>
<Form>
<Form.Item label="导入文件">
<Upload {...uploadFileAttr}>
<Button type="link" key="btnsel">
选择文件
</Button>
</Upload>
<div className={styles.textDesc}>
<div>1、仅支持按商品{config.tip}导入,纵向排列</div>
<div>2、支持Excel格式文件,导入数量限制{config.limitNum}</div>
</div>
</Form.Item>
</Form>
</Modal>
{visibleRecord && (
<ImportListModal
visible={visibleRecord}
type={config.type}
onCancel={() => setVisibleRecord(false)}
/>
)}
</>
);
});
export default Form.create()(ImportGoods);
.card {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
padding: 20px;
background-color: #fafafa;
span {
display: inline-block;
padding-right: 15px;
}
}
.top {
margin-bottom: 15px;
font-weight: 600;
font-size: 16px;
}
.subTitle {
color: #333;
font-weight: normal;
font-size: 14px;
}
.tableBody {
min-height: 244px;
}
.pagewrapper {
text-align: right;
}
.errWrappper {
display: flex;
align-items: flex-end;
justify-content: flex-end;
}
.errorMessage {
max-width: 300px;
}
.textDesc {
color: #999;
line-height: 32px;
}
import request from '@/utils/request';
import config from '@/../config/env.config';
import qs from 'qs';
const { goodsApi } = config;
// 商品导入接口
export async function apiImportGoods(file, type) {
const params = new FormData();
params.append('file', file);
params.append('type', type);
const res = await request.post('/api/merchants/importFile/excel', {
data: params,
prefix: goodsApi,
});
return res;
}
// 分页查询上传文件结果
export async function apiUploadResult(params) {
const data = await request.get(
`/api/merchants/importFile/info/page${qs.stringify(params, { addQueryPrefix: true })}`,
{
prefix: goodsApi,
},
);
return data;
}
......@@ -2,6 +2,7 @@ import { Form, Button, Input, Select, notification, Cascader, InputNumber, Uploa
import React, { Component } from 'react';
import { SwapRightOutlined } from '@ant-design/icons';
import { connect } from 'dva';
import ImportGoodsModal from '@/components/ImportGoodsModal';
import styles from '../../style.less';
import { stateList } from '../../staticdata';
import { apiDownBiddingTemplate, apiUploadGoodsFile } from '../../service';
......@@ -17,7 +18,7 @@ class goodsManage extends Component {
state = {
productType: null,
loading: false,
visibleImport: false,
};
componentDidMount() {
......@@ -94,6 +95,19 @@ class goodsManage extends Component {
});
};
onShowImport = importType => {
this.setState({
visibleImport: true,
importType,
});
};
onHideImport = () => {
this.setState({
visibleImport: false,
});
};
// 上传文件设置
uploadConfig = () => {
const that = this;
......@@ -123,91 +137,112 @@ class goodsManage extends Component {
const filterOption = (input, op) => op.props.children.includes(input);
return (
<Form
ref={this.formRef}
name="horizontal_login"
initialValues={{ productType: 1 }}
layout="inline"
className={styles.searchForm}
>
<FormItem label="SKU编码" name="skuId">
<InputNumber placeholder="请输入SKU编码" max={99999999999999999} style={selectW} />
</FormItem>
<FormItem label="商品名称" name="skuName">
<Input placeholder="请输入商品名称" allowClear style={selectW} />
</FormItem>
<FormItem label="商品类型" name="productType">
<Select style={selectW} placeholder="请选择商品类型" onChange={this.onChangeProductType}>
<Option value={1}>实体商品</Option>
<Option value={4}>服务类商品</Option>
<Option value={5}>外卖商品</Option>
</Select>
</FormItem>
<FormItem label="类目" name="productCategoryId">
<Cascader
placeholder="请选择类目"
style={selectW}
showSearch
changeOnSelect
fieldNames={{ label: 'name', value: 'id', children: 'children' }}
options={treeData}
/>
</FormItem>
{this.state.productType !== 5 && (
<>
<FormItem label="审核状态" name="state">
<Select
style={selectW}
placeholder="请选择审核状态"
allowClear
filterOption={filterOption}
>
{stateList?.map(item => (
<Option key={item.value} value={item.value}>
{item.label}
</Option>
))}
</Select>
</FormItem>
<FormItem label="供货价区间">
<FormItem name="supplyPriceMin" className={styles.iptNumRight} noStyle>
<InputNumber placeholder="请输入" min={0} max={999999999} style={iptNumWidth} />
<div>
<Form
ref={this.formRef}
name="horizontal_login"
initialValues={{ productType: 1 }}
layout="inline"
className={styles.searchForm}
>
<FormItem label="SKU编码" name="skuId">
<InputNumber placeholder="请输入SKU编码" max={99999999999999999} style={selectW} />
</FormItem>
<FormItem label="商品名称" name="skuName">
<Input placeholder="请输入商品名称" allowClear style={selectW} />
</FormItem>
<FormItem label="商品类型" name="productType">
<Select
style={selectW}
placeholder="请选择商品类型"
onChange={this.onChangeProductType}
>
<Option value={1}>实体商品</Option>
<Option value={4}>服务类商品</Option>
<Option value={5}>外卖商品</Option>
</Select>
</FormItem>
<FormItem label="类目" name="productCategoryId">
<Cascader
placeholder="请选择类目"
style={selectW}
showSearch
changeOnSelect
fieldNames={{ label: 'name', value: 'id', children: 'children' }}
options={treeData}
/>
</FormItem>
{this.state.productType !== 5 && (
<>
<FormItem label="审核状态" name="state">
<Select
style={selectW}
placeholder="请选择审核状态"
allowClear
filterOption={filterOption}
>
{stateList?.map(item => (
<Option key={item.value} value={item.value}>
{item.label}
</Option>
))}
</Select>
</FormItem>
<span>
<SwapRightOutlined />
</span>
<FormItem name="supplyPriceMax" className={styles.iptNumRight} noStyle>
<InputNumber
style={iptNumWidth}
min={0}
max={999999999}
placeholder="请输入"
onChange={this.valueMin}
/>
<FormItem label="供货价区间">
<FormItem name="supplyPriceMin" className={styles.iptNumRight} noStyle>
<InputNumber placeholder="请输入" min={0} max={999999999} style={iptNumWidth} />
</FormItem>
<span>
<SwapRightOutlined />
</span>
<FormItem name="supplyPriceMax" className={styles.iptNumRight} noStyle>
<InputNumber
style={iptNumWidth}
min={0}
max={999999999}
placeholder="请输入"
onChange={this.valueMin}
/>
</FormItem>
</FormItem>
</FormItem>
<FormItem name="thirdSkuNo" label="第三方SKU编码">
<Input placeholder="请输入第三方SKU编码" allowClear style={selectW} />
</FormItem>
</>
)}
<FormItem className={styles.queryBtn}>
<Button onClick={() => this.handleSearch()} type="primary" className={styles.button}>
查询
</Button>
<Button onClick={() => this.onReset()} className={styles.button}>
重置
</Button>
<Upload {...this.uploadConfig()}>
<Button type="primary" loading={this.state.loading} ghost className={styles.button}>
导入
<FormItem name="thirdSkuNo" label="第三方SKU编码">
<Input placeholder="请输入第三方SKU编码" allowClear style={selectW} />
</FormItem>
</>
)}
<FormItem className={styles.queryBtn}>
<Button onClick={() => this.handleSearch()} type="primary" className={styles.button}>
查询
</Button>
<Button onClick={() => this.onReset()} className={styles.button}>
重置
</Button>
</Upload>
<Button onClick={() => this.onDownload()} type="link" className={styles.button}>
下载模板
</Button>
</FormItem>
</Form>
{/* <Upload {...this.uploadConfig()}>
<Button type="primary" loading={this.state.loading} ghost className={styles.button}>
导入
</Button>
</Upload> */}
<Button
type="primary"
className={styles.button}
onClick={() => this.onShowImport('binding')}
>
导入商品
</Button>
<Button onClick={() => this.onDownload()} type="link" className={styles.button}>
下载模板
</Button>
</FormItem>
</Form>
{this.state.visibleImport && (
<ImportGoodsModal
visible={this.state.visibleImport}
importType={this.state.importType}
onHide={this.onHideImport}
/>
)}
</div>
);
}
}
......
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