前端兼容处理接口返回的文件流或json数据

news/2025/2/27 17:19:27/

参考文档:JavaScript | MDN

参考链接:Blob格式转json格式,拿到后端返回的json数据_blob转json-CSDN博客

参考链接:https://juejin.cn/post/7117939029567340557

场景:导入上传文件,导入成功,返回json数据显示列表,导入失败后端返回二进制文件流。

一、代码实现

1、接口请求

/*** @description 导入*/
export const postCustGroupImport = (params?: any) => {return request(`${prefixPath}/custGroupManages/custGroupListImport`, {method: 'POST',data: params,responseType: 'blob',// headers: {//   'Content-Type': 'multipart/form-data',// },});
};

2、操作步骤

(1)点击要上传的文件

(2)上传文件

(3)导入正确的文件

请求参数:file为二进制文件流

返回格式

打印结果:

(4)导入失败的文件,返回结果

(5)代码:

    const handleUpload = async () => {// 请求接口中去除,直接用下面的// headers: {//   'Content-Type': 'multipart/form-data',// },// 设置'multipart/form-data'const formData = new FormData();formData.append('channelCode', channelCode);formData.append('file', fileList[0]);setUploading(true);// 1、导入文件上传const res = await postCustGroupImport(formData);console.log('res', res);setUploading(false);if (res.failed) {message.error(res.message, undefined, undefined, 'top');return;}/** 检查返回的 Blob 是否是 JSON 格式 */if (res.type === 'application/json') {const text = await res.text(); // 将 Blob 转换为文本const json = JSON.parse(text); // 将文本解析为 JSONconsole.log('JSON response:', json);// 上传成功if (Array.isArray(json) && json?.length > 0) {setStatus('success');message.success('上传成功', undefined, undefined, 'top');tableDs.loadData(json);return;}} else {// 上传失败console.error('返回的 Blob 类型不是 JSON:(错误文件)', res.type);setStatus('error');setErrorFile(res); // 把错误文件存储到本地,手动点击下载}};/** 下载错误文件 */const handleDown = () => {// 确保 errorFile 是一个有效的 Blob 对象if (!(errorFile instanceof Blob)) {console.error('errorFile 不是一个有效的 Blob 对象');return;}// 创建 Blob 对象const blob = new Blob([errorFile], {type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',});// 创建一个可访问的 URLconst downloadUrl = URL.createObjectURL(blob);// 使用 window.open 触发下载window.open(downloadUrl, '_blank');// 释放资源URL.revokeObjectURL(downloadUrl);};

三、完整代码

1、引用模块代码

2、导入模块代码

import { Button, Icon, message, Modal, Table } from 'choerodon-ui/pro';
import DataSet from 'choerodon-ui/dataset/data-set/DataSet';
import React, { useEffect, useMemo, useState } from 'react';
import formatterCollections from 'hzero-front/lib/utils/intl/formatterCollections';
import { ColumnProps } from 'choerodon-ui/pro/lib/table/Column';
import {commonModelPrompt,languageConfig,prmPrTemCode,TABLE_COLUMN_NUM,
} from '@/language/language';
import { CoverModelChooseProps } from '@/interface/customerBase/main';
import { handleSerialNum } from '@/utils/utils';
import { ColumnAlign } from 'choerodon-ui/dataset/enum';
import { ButtonColor, FuncType } from 'choerodon-ui/pro/lib/button/enum';
import { Upload } from 'choerodon-ui';
import { postCustGroupImport } from '@/api/customerBase/main';
import { importTableList } from './store';
import {SelectionMode,TableAutoHeightType,
} from 'choerodon-ui/pro/lib/table/enum';
import { Title } from '@ino/ltc-component-paas';
import moment from 'moment';
import { ErrorMessage, handleTotal } from '../../../hook';const Index: React.FC<CoverModelChooseProps> = ({/** 控制弹框显示/隐藏 */visible,/** 设置弹框显示/隐藏的回调函数 */setVisible,/** 弹框关闭后回调函数 */onSelect,/** 渠道编码 */channelCode = '',infoData,
}) => {const { chooseList = [] } = infoData;/** ds */const tableDs = useMemo(() => new DataSet(importTableList(chooseList)), []);const columns: ColumnProps[] = useMemo(() => {return [{header: TABLE_COLUMN_NUM,width: 60,align: ColumnAlign.left,renderer: ({ record }) => {return handleSerialNum(record);},},{ name: 'custCode' },{ name: 'custName' },{ name: 'productAuthCategoryId' },{ name: 'categoryCapacity' },{ name: 'custManager' },{name: 'disableMessage',renderer: ({ value, record }) => {const { custCode, productAuthCategoryId } = record?.toData();const arr = chooseList.filter((item: any) =>item.custCode === custCode &&productAuthCategoryId === item.productAuthCategoryId,);/** 列表中添加过的数据,手动设置文案:'列表中已添加' */return (<div style={{ color: 'red' }}>{arr.length === 0? value: languageConfig('customerBase.relevantInfo.tip.hasDisableMessage','列表中已添加该条数据。',)}</div>);},},];}, []);useEffect(() => {if (visible) {openModal();}}, [visible]);/** 弹框打开 */const openModal = () => {Modal.open({title: languageConfig('btn.add.importReleaseCustToList','导入关联客户列表',),style: { width: '70vw' },closable: true,maskClosable: false,keyboardClosable: false,onClose: () => {setVisible(false);},children: <Box />,onOk: async () => {if (tableDs?.selected.length === 0) {message.error(languageConfig('customerBase.relevantInfo.tip.pleaseChooseOne','请至少选择一条数据',),undefined,undefined,'top',);return false;}/** 1、导入的数据:处理 */const choose = tableDs.selected?.map((item: Record<any, any>) => {return {...item.toData(),joinDate: moment().format('YYYY-MM-DD HH:mm:ss'), // 入团时间(默认'当前')status: 'TO_BE_ACTIVE', // 状态(默认'待生效')};});/** 2、'已选数据'中存在的提示 */const matchingItems = choose.filter(itemChoose =>chooseList.some(itemChooseList => itemChooseList.custCode === itemChoose.custCode,),);if (matchingItems.length > 0) {message.error(languageConfig('customerBase.coverModel.tip.alreadySelected','已选数据中存在重复数据',),undefined,undefined,'top',);return false;}/** 3、总价超5k 校验 */const list = chooseList.concat(choose);if (handleTotal(list, 'categoryCapacity') > 5000) {ErrorMessage(languageConfig('customerBase.relevantInfo.tips.categoryCapacityPass','客户团总容量已超上限5000万,不可提交!',),);return false;}onSelect(choose);},});};/** 内容 */const Box = () => {const [fileList, setFileList] = useState<any>([]); // 文件列表const [uploading, setUploading] = useState(false); // 是否正在上传const [status, setStatus] = useState<any>(''); // 导入状态const [errorFile, setErrorFile] = useState<any>(''); // 导入失败,错误文件存储/** 上传文件 */const handleUpload = async () => {// 请求接口中去除,直接用下面的// headers: {//   'Content-Type': 'multipart/form-data',// },// 设置'multipart/form-data'const formData = new FormData();formData.append('channelCode', channelCode);formData.append('file', fileList[0]);setUploading(true);// 1、导入文件上传const res = await postCustGroupImport(formData);console.log('res', res);setUploading(false);if (res.failed) {message.error(res.message, undefined, undefined, 'top');return;}/** 检查返回的 Blob 是否是 JSON 格式,是json格式为'上传成功',否则为'上传失败' */if (res.type === 'application/json') {const text = await res.text(); // 将 Blob 转换为文本const json = JSON.parse(text); // 将文本解析为 JSONconsole.log('JSON response:', json);// 上传成功if (Array.isArray(json) && json?.length > 0) {setStatus('success');message.success('上传成功', undefined, undefined, 'top');tableDs.loadData(json);return;}} else {// 上传失败console.error('返回的 Blob 类型不是 JSON:(错误文件)', res.type);setStatus('error');setErrorFile(res);}};/** 下载错误文件 */const handleDown = () => {// 确保 errorFile 是一个有效的 Blob 对象if (!(errorFile instanceof Blob)) {console.error('errorFile 不是一个有效的 Blob 对象');return;}// 创建 Blob 对象const blob = new Blob([errorFile], {type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',});// 创建一个可访问的 URLconst downloadUrl = URL.createObjectURL(blob);// 使用 window.open 触发下载window.open(downloadUrl, '_blank');// 释放资源URL.revokeObjectURL(downloadUrl);};const handleRemove = file => {const index = fileList.indexOf(file);const newFileList = [...fileList];newFileList.splice(index, 1);setFileList(newFileList);};const beforeUpload = file => {setFileList([...fileList, file]);return false; // 返回 false 阻止自动上传};return (<>{/* 导入文件 */}<div style={{ display: 'flex' }}><Upload beforeUpload={beforeUpload} onRemove={handleRemove}><Button><Icon type="file_upload" />{languageConfig('customerBase.btn.chooseTheFileToImport','选择要导入的文件',)}</Button></Upload><ButtonfuncType={FuncType.raised}color={ButtonColor.primary}onClick={handleUpload}disabled={fileList.length === 0}loading={uploading}style={{ marginLeft: '12px' }}>{uploading? languageConfig('customerBase.label.Importing', '导入中'): languageConfig('customerBase.label.startImport', '开始导入')}</Button></div>{/* 导入成功的数据 */}{status === 'success' && (<><div style={{ marginTop: '12px' }}><Titletitle={languageConfig('customerBase.title.importSuccessData','导入成功的数据',)}/><TabledataSet={tableDs}columns={columns}pagination={false}alwaysShowRowBoxselectionMode={SelectionMode.click}selectedHighLightRow// autoHeight={{ type: TableAutoHeightType.maxHeight, diff: 100 }}renderEmpty={() => {return <div>暂无数据</div>;}}/></div></>)}{/* 导入失败 */}{status === 'error' && (<><div style={{ marginTop: '12px' }}><Titletitle={languageConfig('customerBase.title.importFailedData','导入失败的数据',)}/></div><div><a onClick={handleDown}><Icon type="file_download_black-o" />{languageConfig('customerBase.download.errorFile','下载错误文件',)}</a></div></>)}</>);};return <></>;
};export default formatterCollections({code: [prmPrTemCode, commonModelPrompt],
})(Index);


http://www.ppmy.cn/news/1575288.html

相关文章

【NLP 23、预训练语言模型】

人类发明后悔&#xff0c;来证明拥有的珍贵 —— 25.1.15 Bert的优势&#xff1a;① 预训练思想 ② Transformer模型结构 一、传统方法 VS 预训练方式 Pre-train&#xff1a; ① 收集海量无标注文本数据 ② 进行模型预训练&#xff0c;并在任务模型中使用 Fine-tune&#xff1a…

vmware:新装ubuntu无法使用ssh连接或者复制粘连

前言 如标题所示&#xff0c;我在使用vmware-workstation安装ubuntu22.04LTS桌面版虚拟机后&#xff0c;发现没办法使用ssh远程连接&#xff0c;或者与宿主机之间的复制粘连功能。 解决方案 卡了一天&#xff0c;以为是网络通讯问题&#xff0c;没想到是内部服务的问题。 远程连…

uniapp-X 对象动态取值

有个对象&#xff0c;例如 const data{age:12,list:[1,2,3,4]} 有个函数如下 export function getValueByPath(obj:UTSJSONObject, path:string):any {const current obj.getAny(path) as any;// 返回最终的值return current; } 期待 通过执行getValueByPath("xx.xx…

C++ Primer 泛型算法定制操作

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

MySQL---存储过程详解

目录 一、介绍 二、基础语法 三、变量 四、流程控制 五、参数 六、游标 七、条件处理程序 八、存储函数 一、介绍 存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合&#xff0c;调用存储过程可以简化应用开发人员的很多工作&#xff0c;减少数据在数据库…

实现Python+Django+Transformers库中的BertTokenizer和BertModel来进行BERT预训练,并将其应用于商品推荐功能

一、环境安装准备 #git拉取 bert-base-chinese 文件#创建 虚拟运行环境python -m venv myicrplatenv#刷新source myicrplatenv/bin/activate#python Django 集成nacospip install nacos-sdk-python#安装 Djangopip3 install Django5.1#安装 pymysql settings.py 里面需要 # 强制…

Docker01 - docker快速入门

Docker快速入门 文章目录 Docker快速入门一&#xff1a;Docker概述1&#xff1a;虚拟机技术和容器化技术2&#xff1a;Docker名词解释2.1&#xff1a;Docker镜像(images)2.2&#xff1a;Docker容器(containers)2.3&#xff1a;Docker仓库(registry) 3&#xff1a;Docker下载安装…

Kubernetes集群状态检查与告警整合的自动化

将Kubernetes集群状态检查与告警整合的自动化方案&#xff0c;包含脚本实现、定时任务配置及异常通知机制&#xff1a; 1. 创建监控脚本 保存为 /opt/k8s-monitor/cluster-check.sh&#xff1a; #!/bin/bash# 基础配置 LOG_DIR"/var/log/k8s-monitor" REPORT_FILE&…