import { useNamespace } from '@ibiz-template/vue-util'; import { defineComponent, ref } from 'vue'; import '@ibiz-template/theme/style/components/common/data-import/data-import.scss'; import { HttpError } from '@ibiz-template/core'; export const DataImport = defineComponent({ name: 'DataImport', props: { templateUrl: { type: String, required: true, }, importUrl: { type: String, required: true, }, }, setup(props, { emit }) { const ns = useNamespace('data-import'); const inputUpLoad = ref(); const message = ref<{ state: 'ready' | 'success' | 'fail'; message: string; rowError: Array<{ index: number; info: string }>; }>({ state: 'ready', message: '', rowError: [], }); // 上传数据 const uploadFile = async (file: Blob) => { const data = new FormData(); data.append('file', file); try { const res = await ibiz.net.request(props.importUrl, { method: 'post', data, headers: { 'Content-Type': 'multipart/form-data' }, }); message.value.state = 'success'; message.value.message = '导入成功'; const { errorinfo, success, total } = res.data; const totalNum = total ? Number(total) : 0; const successNum = success ? Number(success) : 0; const errorNum = total - success; message.value.message = `共计导入数据 ${totalNum} 条,错误[${errorNum}],成功[${successNum}]`; if (errorinfo && Object.keys(errorinfo).length > 0) { message.value.rowError = []; Object.keys(errorinfo).forEach((key: string) => { message.value.rowError.push({ index: Number(key) + 1, info: errorinfo[key].errorInfo, }); }); } } catch (error) { message.value.state = 'fail'; message.value.message = `导入失败!${(error as HttpError).message}`; } }; // 文件选择变更事件 const onFileChange = ($event: Event) => { const obj = $event.target as IData; if (!obj.files) { return; } const selectedFile = obj.files[0]; obj.value = null; // 置空不然下次文件不变不触发 uploadFile(selectedFile); }; // 下载模板文件 const onLinkClick = async () => { const res = await ibiz.net.request(props.templateUrl, { responseType: 'blob', }); if (res.status === 200) { let fileName = res.headers['content-disposition']!.split(';') .find((str: string) => str.indexOf('filename=') !== -1) ?.slice(9) || ''; fileName = decodeURIComponent(fileName); const blob = new Blob([res.data as Blob], { type: 'application/vnd.ms-excel', }); const elink = document.createElement('a'); elink.download = fileName; elink.style.display = 'none'; elink.href = URL.createObjectURL(blob); document.body.appendChild(elink); elink.click(); URL.revokeObjectURL(elink.href); // 释放URL 对象 document.body.removeChild(elink); } }; const selectFile = () => { inputUpLoad.value.click(); }; const onCancelButtonClick = () => { emit('close', { ok: false, data: {} }); }; return { ns, onLinkClick, selectFile, onCancelButtonClick, onFileChange, inputUpLoad, message, }; }, render() { return ( <div class={this.ns.b()}> <input ref='inputUpLoad' type='file' style='display: none' accept='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' onChange={this.onFileChange} /> <div class={this.ns.e('caption')}>导入数据</div> {this.message.state === 'ready' ? ( <div class={this.ns.b('upload')} onClick={this.selectFile}> <img class={this.ns.be('upload', 'img')} src='./assets/img/icon-import.svg' ></img> <span class={this.ns.be('upload', 'text')}>单击此区域进行上传</span> </div> ) : ( <div class={this.ns.b('message')}> <div class={this.ns.be('message', 'title')}>导入结果</div> <div class={this.ns.be('message', 'content')}> {this.message.message} </div> {this.message.rowError.length > 0 && [ <div class={this.ns.be('message', 'title')}>错误信息</div>, <div class={this.ns.be('message', 'content')}> {this.message.rowError.map(item => { return <div>{`第 ${item.index} 行:${item.info}`}</div>; })} </div>, ]} </div> )} <div class={this.ns.e('template-container')}> <div class={this.ns.e('template-description')}> 下载导入模版,并按要求填写: </div> <div class={this.ns.e('template-link')} onClick={this.onLinkClick}> <i-icon type='ios-link' /> 数据导入模板文件 </div> </div> <div class={this.ns.e('button-bar')}> <i-button onClick={this.onCancelButtonClick}>取消</i-button> {this.message.state !== 'ready' && ( <i-button onClick={this.selectFile}>重新上传</i-button> )} </div> </div> ); }, });