提交 1e163db8 authored 作者: 钟是志's avatar 钟是志

导入组件 2.0修改. 顺哥写的新接口

上级 d5fc19e1
.nomal {
background: #fff;
padding: 10px;
}
.title {
display: flex;
margin-bottom: 20px;
}
.info {
text-align: center;
font-weight: bold;
font-size: 12px;
}
.detail {
text-align: center;
margin: 30px auto;
}
.detail img {
margin: auto 10px;
}
.button {
display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit browsers. */
display: -moz-box; /* 老版本语法: Firefox (buggy) */
display: -ms-flexbox; /* 混合版本语法: IE 10 */
display: -webkit-flex; /* 新版本语法: Chrome 21+ */
display: -moz-flex;
display: flex;
-moz-box-pack: center; /*Firefox*/
-webkit-box-pack: center; /*Safari,Opera,Chrome*/
box-pack: center;
-moz-justify-content: center;
-webkit-justify-content: center;
justify-content: center;
}
.operation {
display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit browsers. */
display: -moz-box; /* 老版本语法: Firefox (buggy) */
display: -ms-flexbox; /* 混合版本语法: IE 10 */
display: -webkit-flex; /* 新版本语法: Chrome 21+ */
display: -moz-flex;
display: flex;
-moz-box-pack: center; /*Firefox*/
-webkit-box-pack: center; /*Safari,Opera,Chrome*/
box-pack: center;
-moz-justify-content: center;
-webkit-justify-content: center;
justify-content: center;
}
.button Button {
margin: auto 10px;
}
.titleInfo p span {
font-weight: bold;
}
.import {
color: #6ca3c9;
font-size: 12px;
}
.button {
// background: #eff3f8;
text-align: center;
padding: 20px;
margin-top: 20px;
}
.tip {
border-top: 1px solid #ccc;
}
.tip span {
display: block;
margin: 10px;
font-size: 12px;
}
.tip::after {
content: '';
position: absolute;
width: 5px;
height: 57px;
background: #e5eaf1;
margin-top: -141px;
margin-left: -13px;
}
.select button {
color: #fff;
padding: 10px;
background: #abbac3;
border: none;
margin: 10px;
}
.attentionItem {
background: #f4f5f4;
padding: 10px;
box-shadow: 1px 1px 1px #ccc;
}
.attentionItem p:nth-child(1) {
font-size: 12px;
margin-left: 0;
}
.attentionItem p {
font-size: 12px;
margin-left: 45px;
}
.submitButtons {
margin-left: 34px;
}
.contentTable {
display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit browsers. */
display: -moz-box; /* 老版本语法: Firefox (buggy) */
display: -ms-flexbox; /* 混合版本语法: IE 10 */
display: -webkit-flex; /* 新版本语法: Chrome 21+ */
display: -moz-flex;
display: flex;
-moz-box-pack: justify; /*Firefox*/
-webkit-box-pack: justify; /*Safari,Opera,Chrome*/
box-pack: justify;
-moz-justify-content: space-between;
-webkit-justify-content: space-between;
justify-content: space-between;
margin-top: 20px;
:global{
.ant-table-scroll{
height: 294px;
overflow: auto !important;
overflow-x: auto !important;
}
}
}
.left {
width: 50%;
height: 350px;
}
.right {
width: 50%;
height: 350px;
border-left: 1px solid #317ecc;
}
.error p {
color: #fff;
background: #317ecc;
// margin: 10px auto;
text-align: left;
font-size: 12px;
}
.download {
background: #f5f5f5;
padding: 5px;
margin-top: -16px;
}
.download img {
margin-top: -2px;
margin-right: 5px;
}
.download button {
border: none;
background: #f5f5f5
}
.download button:nth-child(1) {
border-right: 1px solid #ccc;
}
.download button:nth-child(2) {
border-right: 1px solid #ccc;
}
.buttonDown {
display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit browsers. */
display: -moz-box; /* 老版本语法: Firefox (buggy) */
display: -ms-flexbox; /* 混合版本语法: IE 10 */
display: -webkit-flex; /* 新版本语法: Chrome 21+ */
display: -moz-flex;
display: flex;
-moz-box-pack: start; /*Firefox*/
-webkit-box-pack: start; /*Safari,Opera,Chrome*/
box-pack: start;
-moz-justify-content: flex-start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
margin-bottom: 20px;
}
.buttonDown > button {
margin-left: 10px;
background: #abbac3;
border: none;
color: #fff;
padding: 5px 12px;
border-radius: 5px;
}
import React from 'react';
import {
Button,
Modal,
Steps,
Upload,
Icon,
message,
Spin,
Table,
} from 'antd';
import styles from './ImportUtil.less';
import reqwest from 'reqwest';
import ButtonDiy from '@/baseComponent/ButtonDiy';
import { getToken } from '@/utils/authority';
import config, { getUploadUrl } from '@/config/config';
import { Row, Col } from 'antd';
import { hrefWithToken } from '@/highOrderComponent/Service';
import request from '@/utils/request';
const Step = Steps.Step;
const get_length = (s) => {
let char_length = 0;
for (let i = 0; i < s.length; i++) {
let son_char = s.charAt(i);
encodeURI(son_char).length > 2 ? char_length += 2 : char_length += 1;
}
if (char_length > 0 && char_length < 5) {
char_length = 5;
}
return char_length;
};
const calcWidth = (columns = []) => {
let width = 0;
columns.forEach(i => {
width += get_length(i.title) * 15;
});
return width;
};
const calcColumns = (columns) => {
return columns.map(i => {
let length = 1;
if (i.title) {
length = get_length(i.title);
i.width = length * 16;
//i.
}
return i;
});
};
export default class ImportUtil extends React.PureComponent {
constructor(props) {
super(props);
const { api, serviceBean, serviceKey } = props;
var importFileUrl, analyseFileUrl, queryFileUrl, exportTemplateUrl;
if (api != null) {
const x = api; // 学工的 接口地址
importFileUrl = x + `/importApi/execute?token=${getToken()}&cacheKey=`;
queryFileUrl = x + `/importApi/findData?token=${getToken()}&cacheKey=`;
analyseFileUrl = x + `/importApi/analyse?token=${getToken()}&filePath=`;
exportTemplateUrl = x + `/importApi/downLoadTemplate?serviceBean=${serviceBean}&serviceKey=${serviceKey}`;
} else {
importFileUrl = props.importFileUrl;
queryFileUrl = props.queryFileUrl;
analyseFileUrl = props.analyseFileUrl;
exportTemplateUrl = props.exportTemplateUrl;
}
this.state = {
visible: false,
current: 0,
isShow: true,
filekey: '',
sucData: [],
errData: [],
tableWidth: 0,
column: [],
importFileUrl,
queryFileUrl,
analyseFileUrl,
exportTemplateUrl,
loading: false,
isNextDisabled: false,
};
}
static getDerivedStateFromProps(props, state) {
if (props.api != null) {
const { api, serviceBean, serviceKey } = props;
const x = api; // // 学工的 接口地址
state.importFileUrl = x + `/importApi/execute?token=${getToken()}&cacheKey=`;
state.queryFileUrl = x + `/importApi/findData?token=${getToken()}&cacheKey=`;
state.analyseFileUrl = x + `/importApi/analyse?token=${getToken()}&filePath=`;
state.exportTemplateUrl = x + `/importApi/downLoadTemplate?serviceBean=${serviceBean}&serviceKey=${serviceKey}`;
} else {
state.importFileUrl = props.importFileUrl;
state.queryFileUrl = props.queryFileUrl;
state.analyseFileUrl = props.analyseFileUrl;
state.exportTemplateUrl = props.exportTemplateUrl;
}
return {
...state,
};
}
//导入按钮
showModal = () => {
//console.log('导入按钮');
this.setState({
visible: true,
});
};
handleOk = (e) => {
this.setState({
visible: false,
});
};
handleCancel = (e) => {
this.setState({
visible: false,
});
};
next() {
const current = this.state.current + 1;
if (current === 2) {
if (this.state.errData.length > 0) {
message.warning('请检查数据');
return;
}
this.setState({
current: current,
isShow: false,
});
this.import();
}
if (current === 3) {
this.setState({
current: current,
isShow: true,
});
if (this.props.callback) {
this.props.callback();
}
}
}
prev() {
const current = this.state.current - 1;
this.setState({ current });
}
import() {
const importFileUrl = this.state.importFileUrl;
this.setState({ loading: true });
const { importParams } = this.props;
reqwest({
url: importFileUrl + this.state.filekey
, type: 'json'
, method: 'post'
, data: importParams || {}
, crossOrigin: true
, withCredentials: false
, error: (err) => {
this.setState({ loading: false });
message.warning('网络故障');
}
, success: (res) => {
if (res && res.errMsg) {
this.setState({
loading: false,
isNextDisabled: true,
});
message.warning('服务器返回错误' + res.errMsg);
return false;
}
this.next();
message.success('导入成功');
this.setState({
current: 3,
isShow: true,
visible: false,
loading: false,
});
if (this.props.callback) {
this.props.callback();
}
},
});
}
getCachKey = (filePath) => {
const analyseFileUrl = this.state.analyseFileUrl;
const { serviceBean, serviceKey } = this.props;
this.setState({ loading: true });
let dataAnalyse = {
serviceBean,
serviceKey,
filePath,
isLocal: true,
};
const { importParams } = this.props;
if (importParams) {
dataAnalyse.serviceParam = importParams;
}
const urlAnaly = analyseFileUrl;
reqwest({
url: urlAnaly,
type: 'json',
method: 'post',
data: JSON.stringify(dataAnalyse),
headers: {
Accept: 'application/json;charset=UTF-8',
'Content-Type': 'application/json',
},
crossOrigin: true,
withCredentials: false,
error: (err) => {
message.warning('网络故障');
this.setState({ loading: false });
},
success: (res) => {
let key = '';
if (res && typeof res === 'object' && Object.keys(res).length) {
key = Object.keys(res)[0];
}
if (key) {
this.setState({
filekey: key,
loading: false,
});
this.queryFile(key);
} else {
if (res.errMsg) {
message.warning(res.errMsg);
}
this.setState({
loading: false,
});
}
},
});
};
queryFile = (key) => {
const { importParams, serviceBean, serviceKey } = this.props;
const queryFileUrl = this.state.queryFileUrl;
this.setState({ loading: true });
let queryData = {
serviceParam: {
...importParams,
},
serviceBean,
serviceKey,
cacheKey: key,
};
reqwest({
url: queryFileUrl
, type: 'json'
, method: 'post'
, data: JSON.stringify(queryData),
headers: {
Accept: 'application/json;charset=UTF-8',
'Content-Type': 'application/json',
}
, crossOrigin: true
, withCredentials: false
, error: (err) => {
this.setState({ loading: false });
message.warning('网络故障');
}
, success: (res) => {
if (!res || !res[key] || typeof res[key].columns === 'undefined') {
if (res.errMsg) {
message.warning('导入数据错误!');
}
return false;
}
res = res[key];
let id = 1;
res.passList = res.passList.filter((x) => {
return x && typeof x === 'object';
});
if (res.passList) {
res.passList.filter((x) => {
return !!x;
});
for (let item of res.passList) {
item.rowKeyId = id++;
}
}
res.column = [];
if (res.columns) {
for(let item in res.columns){
if(res.columns[item] !== '错误信息'){
res.column.push({
dataIndex: item,
title: res.columns[item],
})
}
}
}
id = 1;
res.noPassList = res.noPassList.filter((x) => {
return x && typeof x === 'object';
});
if (res.noPassList) {
res.noPassList.filter((x) => {
return !!x;
});
for (let item of res.noPassList) {
item.rowKeyId = id++;
}
}
this.setState({
current: 1,
isShow: false,
loading: false,
sucData: res.passList,
errData: res.noPassList,
column: res.column,
tableWidth: calcWidth(res.column),
});
if (!!res.pass && !res.pass.length) {
message.warning('当前没有验证成功的数据,无法导入。');
this.setState({
isNextDisabled: true,
});
} else {
this.setState({
isNextDisabled: false,
});
}
},
});
};
// 分析数据后,导出表格里的数据
// key='pass', 导出通过数据; key='notPass',导出未通过数据
exportData = (isPass) => {
const type = isPass ? 'pass' : 'notPass';
const { filekey } = this.state;
hrefWithToken(`/CmsExApi/exportImport?key=${filekey}&type=${type}`);
};
continueImport = () => {
this.setState({
current: 2,
isShow: false,
});
this.import();
};
render() {
const props = {
name: 'file',
action: getUploadUrl(),
headers: {
authorization: 'authorization-text',
},
accept: '.xlsx',
showUploadList: false,
onChange: (info) => {
if (info.file.status !== 'uploading') {
}
if (info.file.status === 'done') {
message.success(`${info.file.name} 上传成功`);
let x = info.file.response.filePath;
this.getCachKey(x);
} else if (info.file.status === 'error') {
message.warning(`${info.file.name} 上传文件失败.`);
}
},
};
const steps = [
{
title: '上传Excel',
},
{
title: '验证数据',
},
{
title: '数据导入',
},
{
title: '导入完成',
}];
const { current, loading, sucData, errData } = this.state;
const { name } = this.props;
const column = calcColumns(this.state.column);
const hasErrorData = !!errData && !!errData.length;
const hasSucData = !!sucData && !!sucData.length;
return (
<span>
<ButtonDiy name={name || '批量导入'}
type='default'
className='defaultBlue'
handleClick={this.showModal}/>
<Modal
visible={this.state.visible}
onOk={this.handleOk}
maskClosable={false}
destroyOnClose
onCancel={this.handleCancel}
title={null}
footer={null}
style={{ height: '700px' }}
width={'80%'}
>
<Spin spinning={loading}>
<div className={styles.nomal}>
<p className={styles.import}>
EXCEL导入向导
</p>
<div style={{ margin: 'auto 12px', fontSize: '12px' }}
>
<Steps current={current}>
{steps.map(item =>
<Step key={item.title}
title={item.title}/>)}
</Steps>
<div className="steps-content">
{steps[this.state.current].content}
</div>
<div className={styles.button}>
{
(this.state.current < steps.length - 1 && this.state.current !== 0)
&&
<ButtonDiy name={this.state.current == 3 ? '确认导入' : '下一步'} type="primary"
disabled={this.state.current != 3 && this.state.isNextDisabled} className='primaryBlue'
handleClick={() => this.next()}/>
}
{
this.state.current > 0
&&
<ButtonDiy style={{ marginLeft: 8 }} name="上一步" className='defaultBlue' handleClick={() => this.prev()}/>
}
</div>
</div>
<div className={styles.tip}>
<p className={styles.tipContent}>
<span>欢迎使用EXCEL导入向导,首先请您上传需要导入的EXCEL文件。</span>
<span>点击“选择文件”选择您要导入的EXCEL文件,点击“开始上传”将其上传到服务器上,点击“清空队列”清空当前上传文件队列。</span>
</p>
</div>
{
this.state.isShow ?
<div className={styles.buttonDown}>
<Upload {...props}>
<Button shape='round'>
<Icon type="upload"/>点击上传
</Button>
</Upload>
<Button
shape='round'
style={{ marginLeft: 14 }}
href={this.props.fileName ?
this.state.exportTemplateUrl + '&token=' + getToken() + '&fileName=' + this.props.fileName :
this.state.exportTemplateUrl + '&token=' + getToken()
}
target="_blank"
type='primary'
ghost
>
下载模板
</Button>
</div> : (
<Row>
<Col span={12}>
<Upload {...props}>
<Button shape='round'>
<Icon type="upload"/>
重新上传
</Button>
</Upload>
{
hasErrorData && hasSucData && (
<Button style={{ marginLeft: 12 }} shape='round' onClick={this.continueImport}>
继续上传
</Button>
)
}
{
hasSucData && (
<Button style={{ marginLeft: 12 }} shape='round' onClick={() => this.exportData(true)}>
正确信息导出
</Button>
)
}
</Col>
<Col span={12}>
{hasErrorData && (
<Button shape='round' onClick={() => this.exportData(false)}>
错误信息导出
</Button>
)}
</Col>
</Row>
)
}
{
this.state.isShow ? <div className={styles.attentionItem}>
<p>导入事项</p>
<p>1. 导入操作一次只能上传 1 EXCEL文件。</p>
<p>2. 导入文件最大文件大小上传 1 GB</p>
<p>3. 只能上传EXCEL文件(XLS, XLSX) </p>
<p>4. 请将EXCEL文件的所有单元格格式设置为“文本”格式</p>
</div> :
<div className={styles.error}>
<div className={styles.contentTable}>
{/* 左边 */}
<div className={styles.left}>
<p>验证成功列表</p>
<Table
columns={column}
rowKey={'rowKeyId'}
dataSource={this.state.sucData}
pagination={
{
size: 'small',
total: this.state.sucData.length,
}
}
scroll={{ x: this.state.tableWidth }}
style={{ overflow: 'auto' }}
bordered={true}/>
</div>
{/* 右边 */}
<div className={styles.right}>
<p>验证错误列表</p>
<Table
columns={column && column.length ? [
{
title: '错误信息',
dataIndex: 'errMsg',
width: 150,
},
...column,
] : []}
style={{ overflow: 'auto' }}
rowKey={'rowKeyId'}
pagination={
{
size: 'small',
total: this.state.errData.length,
}
}
scroll={{ x: this.state.tableWidth }}
dataSource={this.state.errData}
bordered={true}/>
</div>
</div>
</div>
}
</div>
</Spin>
</Modal>
</span>
);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论