提交 0240d3ec authored 作者: 钟是志's avatar 钟是志

3764 多人串行 【一站式新增功能】新增同一个流程同一节点可以导入数据进行审批

上级 382fb19f
import React, { useEffect, useState, useRef, useMemo, Fragment } from 'react'; import React, { useMemo, Fragment } from 'react';
import styles from './styles.less';
import { connect } from 'dva'; import { connect } from 'dva';
import { Modal, Button } from 'antd'; import ImportUtilBatchAudit from '@/webPublic/one_stop_public/App/ImportUtilBatchAudit';
import { isJSON } from '@/webPublic/one_stop_public/2022beidianke/isJSON';
function Index(props) { function Index(props) {
const { const {
auditPageData: { searchCondition, searchParams }, auditPageData: { searchCondition, searchParams },
appId,
} = props; } = props;
console.log('🚀 ~ file:index method:Index line:7 -----', searchParams, searchCondition); console.log("🚀 ~ file:index method:Index line:11 -----", props, "props");
const formPropertConfig = useMemo( const formPropertConfig = useMemo(
() => { () => {
if (searchParams && searchParams.taskDefKey) { if (searchParams && searchParams.taskDefKey) {
...@@ -28,21 +28,45 @@ function Index(props) { ...@@ -28,21 +28,45 @@ function Index(props) {
[searchParams], [searchParams],
); );
const disabled = useMemo( const componentProps = useMemo(() => {
() => { if(!formPropertConfig || !formPropertConfig.variable){
if (formPropertConfig && formPropertConfig.id === 'ImportReview') { return null;
return false;
} }
return true; const disabled = !(formPropertConfig && formPropertConfig.id === 'ImportReview');
const taskDefName = searchCondition.find((x) => x.key === 'taskDefKey').options.find((x) => x.key === searchParams.taskDefKey).name;
const variable = formPropertConfig && isJSON(formPropertConfig.variable) ? JSON.parse(formPropertConfig.variable) : {};
return {
btn: {
disabled,
name: variable?.btn?.name || '导入审批',
type: 'primary',
}, },
[searchParams], importConfig: formPropertConfig && isJSON(formPropertConfig.variable) ? JSON.parse(formPropertConfig.variable) : {},
); importParams: {
...searchParams,
taskDefName: taskDefName,
appId,
},
};
}, [formPropertConfig, searchParams]);
console.log({
formPropertConfig,
searchParams,
searchCondition,
componentProps,
});
if(!componentProps){
return null;
}
return ( return (
<Fragment key={'ssddd'}> <Fragment key={'ssddd'}>
<Button type={'primary'} disabled={disabled}> <ImportUtilBatchAudit {...componentProps}
批量导入审批 callback={() => {
</Button> props.getPage();
}}
/>
</Fragment> </Fragment>
); );
} }
......
...@@ -248,13 +248,13 @@ class Index extends React.Component { ...@@ -248,13 +248,13 @@ class Index extends React.Component {
}, },
}); // 解决禅道 32366 二级学院审核,所有二级学院审核后在已处理中加导出功能 103152 }); // 解决禅道 32366 二级学院审核,所有二级学院审核后在已处理中加导出功能 103152
} }
if(JSON.stringify(auditPageData.searchCondition).includes('ImportReview') && false){ // TODO 未完成. if(JSON.stringify(auditPageData.searchCondition).includes('ImportReview')){
tab1Buttons.push({ tab1Buttons.push({
type: 'importBatchAudit', type: 'importBatchAudit',
name: '批量导入审批', name: '批量导入审批',
component: 'RenderComponent', component: 'RenderComponent',
render: (props) => { render: (props) => {
return <ImportBatchAudit {...props}/> return <ImportBatchAudit {...props} appId={workId} key={'asdasd'}/>;
}, },
}); });
} }
......
...@@ -251,6 +251,7 @@ export default class ImportUtil extends React.PureComponent { ...@@ -251,6 +251,7 @@ export default class ImportUtil extends React.PureComponent {
fileName, fileName,
importParams, importParams,
importConfig, importConfig,
downloadTemplateUrl,
} = this.props; } = this.props;
const { trueObjId } = this.state; const { trueObjId } = this.state;
const params = { const params = {
...@@ -259,7 +260,7 @@ export default class ImportUtil extends React.PureComponent { ...@@ -259,7 +260,7 @@ export default class ImportUtil extends React.PureComponent {
objId: trueObjId || objId, objId: trueObjId || objId,
fileName, fileName,
}; };
let url = `${config.httpServer}/DataObjApi/importTemplateDownload`; let url = downloadTemplateUrl || `${config.httpServer}/DataObjApi/importTemplateDownload`;
let newParams = giveFilePostDataInfoForTrue(params, url); let newParams = giveFilePostDataInfoForTrue(params, url);
if (newParams && newParams.datas) { if (newParams && newParams.datas) {
newParams.datas.token = getToken(); newParams.datas.token = getToken();
......
import React, { Fragment } from 'react';
import { Button, Steps, Upload, Icon, Tabs, Table } from 'antd';
import styles from './ImportUtil.less';
import ButtonDiy from './ButtonDiy/ButtonDiy';
import { getToken } from '../utils/token';
import FormdataWrapper from '../utils/object-to-formdata-custom';
import config from '@/webPublic/one_stop_public/config';
import { connect } from 'dva';
import { getMessage, getModal } from '@/webPublic/one_stop_public/utils/utils';
import { giveFilePostDataInfoForTrue } from '@/webPublic/one_stop_public/Base16';
import { getTransformApi } from '@/webPublic/one_stop_public/2022beidianke/localstorageTransform';
import ProgressDiy from './ProgressDiy';
import {
getSassApiHeader,
getSysCode
} from '@/webPublic/one_stop_public/2023yunshangguizhou/utils';
import { decodeObjKey, getServicesNomal, importExecute2 } from '../Services/services';
const Modal = getModal();
const message = getMessage();
const Step = Steps.Step;
const TabPane = Tabs.TabPane;
@connect(({
DataObj,
loading,
}) => ({
DataObj,
loading: loading.models.DataObj,
}))
export default class ImportUtilBatchAudit extends React.PureComponent {
constructor(props) {
super(props);
this.tempCallback = this.props.callback || function() {};
this.state = {
ch: false,
currentKey: '1',
visible: false,
current: 0,
isShow: true,
fileCacheKey: '',
sucData: [],
errData: [],
column: [],
confirmLoading: false,
openProgress: false,
// exportTemplateUrl,
isNextDisabled: false,
trueObjId: '',
};
}
showModal = () => {
this.setState({
sucData: [],
errData: [],
column: [],
current: 0,
isShow: true,
isNextDisabled: false,
fileCacheKey: '',
visible: true,
});
};
handleOk = (e) => {
this.setState({
visible: false,
});
};
handleCancel = (e) => {
this.setState({
visible: false,
});
};
next() {
const current = this.state.current + 1;
if (current === 2) {
this.setState({
current: current,
isShow: false,
});
if (this.state.errData.lenth > 0) {
message.error('请检查数据');
return;
} else {
this.import();
}
}
if (current === 3) { // 导入完成后
this.setState(
{
current: current,
isShow: true,
},
() => {
if (this.tempCallback) {
this.tempCallback();
}
},
);
}
}
prev() {
const current = this.state.current - 1;
this.setState({ current });
}
changeOpenProgress = (v) => {
if (v === false) {
this.next();
message.success('导入成功', 1);
this.setState({
current: 3,
isShow: true,
visible: false,
openProgress: false,
});
}
};
import() {
const {
importParams,
objId,
} = this.props;
const {
trueObjId
} = this.state;
importExecute2({
...(importParams || {}),
cacheKey: this.state.fileCacheKey,
objId: trueObjId || objId,
examineeMap: JSON.stringify({ examine: 1 }), // 默认都是同意
}).then(res => {
if (res && res.sync === false && res.total) {
this.setState({
openProgress: res,
});
return;
}
if(res && res.sync === true){
this.next();
message.success('导入成功', 1);
this.setState({
current: 3,
isShow: true,
visible: false,
});
}else{
const current = this.state.current - 2;
this.setState({ current });
}
});
}
getCachKey = (filePath) => {
const {
importParams,
importConfig,
objId,
} = this.props;
const { trueObjId } = this.state;
getServicesNomal('/UnifiedAppFormApi/importAnalyse', {
...(importParams || {}),
isLocal: false,
filePath,
importConfig: importConfig ? JSON.stringify(importConfig) : null,
objId: trueObjId || objId,
}).then(res => {
this.setState({
fileCacheKey: res.cacheKey,
});
this.queryFile(res.cacheKey);
});
};
queryFile = (cacheKey) => {
const {
importParams,
objId,
} = this.props;
const { trueObjId } = this.state;
getServicesNomal('/UnifiedAppFormApi/importDataQuery', {
...(importParams || {}),
cacheKey,
objId: trueObjId || objId,
}).then(res => {
this.setState({
current: 1,
isShow: false,
sucData: res.pass,
errData: res.noPass,
column: res.column,
});
if (res.noPass && res.noPass.length === 0) {
if (res.pass.length === 0) {
message.error('当前没有验证成功的数据,无法导入。');
this.setState({
currentKey: '1',
ch: !this.state.ch,
isNextDisabled: true,
});
} else {
message.success('所有数据验证通过,请确认后点击下一步。');
this.setState({
currentKey: '2',
ch: !this.state.ch,
isNextDisabled: false,
});
}
} else {
message.error('当前存在未验证通过的数据,请按错误提示检测更正导入文件');
this.setState({
currentKey: '1',
ch: !this.state.ch,
isNextDisabled: true,
});
}
});
};
changePane = (activeKey) => {
this.setState({ currentKey: activeKey });
};
componentDidMount() { // 1396 考场监考老师、QQ群等信息能批量导入。
if(this.props.importConfig?.objKey && typeof this.props.importConfig.objKey === 'string' &&
this.props.importConfig.objKey.length > 10
){
decodeObjKey(this.props.importConfig.objKey).then((res) => {
if(res && typeof res === 'string' && res.length > 10) {
console.log(res, res.length);
this.setState({
trueObjId: res,
})
}
})
}
}
downloadFile = async () => {
this.setState({ confirmLoading: true });
const {
objId,
fileName,
importParams,
importConfig,
downloadTemplateUrl,
} = this.props;
const { trueObjId } = this.state;
const params = {
...importParams,
importConfig: importConfig ? JSON.stringify(importConfig) : null,
objId: trueObjId || objId,
fileName,
};
let url = downloadTemplateUrl || `${config.httpServer}/UnifiedAppFormApi/importTemplateDownload`;
let newParams = giveFilePostDataInfoForTrue(params, url);
if (newParams && newParams.datas) {
newParams.datas.token = getToken();
}
const {
transformApi,
headersApi,
} = await getTransformApi(newParams.url);
fetch(transformApi, {
method: 'POST',
body: FormdataWrapper(newParams.datas),
})
.then((res) => {
console.log(res.status);
if (res.status != 200 && res.status !== 202) {
return res.json();
} else {
return res.blob();
}
})
.then((data) => {
if (data instanceof Blob) {
let a = document.createElement('a');
let url = window.URL.createObjectURL(data);
let filename =
(this.props.fileName ? this.props.fileName : '导入模板.') + (this.props.ext || 'xlsx');
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
a = null;
} else {
message.error(`文件导出错误`);
}
})
.catch((err) => {
console.error(err);
message.error(`网络请求超时`);
})
.finally(() => {
this.setState({ confirmLoading: false });
});
};
render() {
const props = {
name: 'file',
action: config.uploadUrl,
headers: getSassApiHeader(),
data: {
token: getToken(),
},
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;
this.getCachKey(x);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} 上传失败`);
}
},
};
const steps = [
{
title: '上传Excel',
},
{
title: '验证数据',
},
{
title: '数据导入',
},
{
title: '导入完成',
},
];
const {
current,
openProgress,
fileCacheKey,
} = this.state;
const { name } = this.props;
const column1 = this.state.column
? [
{
title: '序号',
dataIndex: 'index',
fixed: 'left',
width: 50,
render: (v, r, i) => i + 1,
},
{
title: '数据行数',
dataIndex: 'row_index',
width: 50,
},
...this.state.column,
]
: [];
let column2 = this.state.column ? [{
title: '数据行数',
dataIndex: 'row_index',
width: 50,
}, ...this.state.column] : [];
if (column1.length > 1) {
column1[1].render = (val) => <span style={{ color: 'red' }}>{val}</span>;
}
if (column2) {
let xuhao = column2.find((g) => g.dataIndex === '序号');
if (!xuhao) {
column2.unshift({
title: '序号',
fixed: 'left',
width: 50,
render: (v, r, i) => i + 1,
dataIndex: '序号',
});
}
}
const btn = {
name: name || '批量导入',
type: 'default',
className: 'defaultBlue',
...(this.props.btn ? this.props.btn : {}),
};
if(this.state.visible){
console.log(this.props);
}
return (
<span>
<ButtonDiy {...btn} handleClick={this.showModal} />
<Modal
visible={this.state.visible}
onOk={this.handleOk}
maskClosable={false}
destroyOnClose
onCancel={this.handleCancel}
title={null}
footer={null}
width={'80%'}>
{
!!openProgress ? <ProgressDiy fileCacheKey={fileCacheKey}
{...openProgress}
importProcessUrl={'/UnifiedAppFormApi/importProcess'}
changeOpenProgress={this.changeOpenProgress}
/> :
<div className={styles.nomal}>
<p className={styles.import}>EXCEL导入向导</p>
<div style={{ margin: 'auto 23px' }}>
<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>
<Icon type='upload' />
点击上传
</Button>
</Upload>
<ButtonDiy
name={'下载模板'}
type='primary'
// className='primaryBlue'
handleClick={() => this.downloadFile()}
loading={this.state.confirmLoading}
/>
</div>
) : (
<Upload {...props}>
<Button>
<Icon type='upload' />
重新上传
</Button>
</Upload>
)}
{this.state.isShow ? (
<div className={styles.attentionItem}>
<p>导入事项</p>
<p>1. 导入操作一次只能上传 1 EXCEL文件。</p>
<p>2. 导入文件最大文件大小上传 1 GB</p>
<p>3. 只能上传EXCEL文件(XLS, XLSX) 默认支持EXCEL 2003EXCEL 2007</p>
<p>4. 请将EXCEL文件的所有单元格格式设置为“文本”格式</p>
</div>
) : (
<div className={styles.error} style={{ marginTop: 20 }}>
<Tabs
activeKey={this.state.currentKey}
key={this.state.ch}
onChange={this.changePane}
type='card'>
{this.state.errData && this.state.errData.length == 0 ? (
''
) : (
<TabPane tab={<span style={{ color: 'red' }}>验证错误列表</span>} key='1'>
<Table
columns={column1}
size='small'
style={{ overflow: 'auto' }}
dataSource={this.state.errData}
bordered={true}
scroll={{ x: 'max-content' }}
/>
</TabPane>
)}
<TabPane tab={<span style={{ color: 'green' }}>验证成功列表</span>} key='2'>
<Table
columns={column2}
size='small'
style={{ overflow: 'auto' }}
dataSource={this.state.sucData}
bordered={true}
scroll={{ x: 'max-content' }}
/>
</TabPane>
</Tabs>
</div>
)}
</div>
}
</Modal>
</span>
);
}
}
...@@ -7,6 +7,7 @@ import { importProcessApi } from '../Services/apiConfig'; ...@@ -7,6 +7,7 @@ import { importProcessApi } from '../Services/apiConfig';
function ProgressDiy(props) { function ProgressDiy(props) {
const { const {
importProcessUrl = '',
fileCacheKey, fileCacheKey,
changeOpenProgress = () => { changeOpenProgress = () => {
}, },
...@@ -15,7 +16,7 @@ function ProgressDiy(props) { ...@@ -15,7 +16,7 @@ function ProgressDiy(props) {
const [speedData, setData] = useState({ ...props }); const [speedData, setData] = useState({ ...props });
useEffect(() => { useEffect(() => {
interv.current = setInterval(() => { interv.current = setInterval(() => {
getServicesNomal(importProcessApi, { getServicesNomal(importProcessUrl || importProcessApi, {
cacheKey: fileCacheKey, cacheKey: fileCacheKey,
}).then(res => { }).then(res => {
setData(res); setData(res);
......
...@@ -34,6 +34,15 @@ export const importExecute = (params) => { ...@@ -34,6 +34,15 @@ export const importExecute = (params) => {
}); });
}; };
export const importExecute2 = (params) => {
return apiRequest('/UnifiedAppFormApi/importExecute', {
...params,
customErrMsg:
'导入的文件中可能存在字段不一致、字段类型不匹配、唯一性字段冲突,请检查或联系系统管理员',// 自定义errMsg
});
};
export const decodeObjKey = (code) => { export const decodeObjKey = (code) => {
return apiRequest('/SnowflakeUtilApi/decode', { return apiRequest('/SnowflakeUtilApi/decode', {
code, code,
......
/** /**
* 2019年9月22日 * 2019年9月22日
* TODO 钟是志 2021年10月20日 * 钟是志 2021年10月20日
* 动态表格组件返回对应的组件 * 动态表格组件返回对应的组件
*/ */
import React, { Component, lazy, Suspense } from 'react'; import React, { Component, lazy, Suspense } from 'react';
......
...@@ -339,7 +339,7 @@ export default class ViewPrint extends Component { ...@@ -339,7 +339,7 @@ export default class ViewPrint extends Component {
name={'字段位置设置(实施)'} name={'字段位置设置(实施)'}
handleClick={() => { handleClick={() => {
router.push({ router.push({
//pathname: '/xg/xg_hard/AwardSet/printSetting', // 中医大这里也要改 TODO //pathname: '/xg/xg_hard/AwardSet/printSetting', // 中医大这里也要改
pathname: '/jc/setting/printSetting', pathname: '/jc/setting/printSetting',
state: { code: templateInfo.code }, state: { code: templateInfo.code },
}); });
......
...@@ -53,7 +53,7 @@ function EditDrawer(props) { ...@@ -53,7 +53,7 @@ function EditDrawer(props) {
setLowCodeEdit(newCodeEdit); setLowCodeEdit(newCodeEdit);
}; };
// TODO localStorage 事件中获取的state 不是最新的. // localStorage 事件中获取的state 不是最新的.
const handleLocalStorageSave = (e) => { const handleLocalStorageSave = (e) => {
if (e.key === 'save-low-code-local') { if (e.key === 'save-low-code-local') {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论