feat: 文件下载
This commit is contained in:
@@ -17,7 +17,7 @@ export default {
|
||||
// http://192.168.1.231:48080 伟强
|
||||
// http://192.168.1.89:48086 子杰
|
||||
// https://petshy.tashowz.com/
|
||||
target: 'http://192.168.1.89:48086',
|
||||
target: 'http://192.168.1.89:48080',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -32,6 +32,7 @@ const GroupTagCore: React.FC<GroupTagCoreProps> = (props) => {
|
||||
const [type, setType] = useState<'group' | 'tag'>('group');
|
||||
const [visible, setVisible] = useState<boolean>(false);
|
||||
const [name, setName] = useState<string>('');
|
||||
const [tagName, setTagName] = useState<string>('');
|
||||
const [total, setTotal] = useState<number>(0);
|
||||
const [currentId, setCurrentId] = useState<number>();
|
||||
const [tagsModalValue, setTagsModalValue] = useState<{
|
||||
@@ -56,7 +57,11 @@ const GroupTagCore: React.FC<GroupTagCoreProps> = (props) => {
|
||||
const fetchTagsApi = useCallback(async () => {
|
||||
try {
|
||||
setLoadingTags(true);
|
||||
const res = await tagsApi.get({ groupId: currentId, pageNo: 1 });
|
||||
const res = await tagsApi.get({
|
||||
groupId: currentId,
|
||||
pageNo: 1,
|
||||
tagName: tagName,
|
||||
});
|
||||
const newGroup = { ...currentGroup, tags: res.list };
|
||||
const newData = groups.map((g) => (g.id === currentId ? newGroup : g));
|
||||
setGroups(newData as GroupItem[]);
|
||||
@@ -238,6 +243,7 @@ const GroupTagCore: React.FC<GroupTagCoreProps> = (props) => {
|
||||
|
||||
const onSearchTags = async (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const searchValue = (e.target as HTMLInputElement).value;
|
||||
setTagName(searchValue);
|
||||
const res = await tagsApi.get({
|
||||
groupId: currentId,
|
||||
pageNo: 1,
|
||||
@@ -247,11 +253,15 @@ const GroupTagCore: React.FC<GroupTagCoreProps> = (props) => {
|
||||
...currentGroup,
|
||||
tags: res.list,
|
||||
};
|
||||
setTotal(res.total);
|
||||
document.getElementById('scrollableDiv')?.scrollTo(0, 0);
|
||||
setCurrentGroup(newGroup as GroupItem);
|
||||
setPageNo(1);
|
||||
};
|
||||
|
||||
const onSearchTagsClear = async () => {
|
||||
setTagName('');
|
||||
fetchTagsApi();
|
||||
};
|
||||
return (
|
||||
<div className={`group-tag-core`}>
|
||||
<div className="search-wrapper">
|
||||
@@ -260,6 +270,7 @@ const GroupTagCore: React.FC<GroupTagCoreProps> = (props) => {
|
||||
placeholder="搜索"
|
||||
onPressEnter={onSearchTags}
|
||||
allowClear
|
||||
onClear={onSearchTagsClear}
|
||||
disabled={isInEditMode}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -116,7 +116,7 @@ export const renderTags = (data: GroupTagProps) => {
|
||||
<Empty description="暂无分组" image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
);
|
||||
}
|
||||
console.log(list.length);
|
||||
console.log(list, total);
|
||||
return (
|
||||
<InfiniteScroll
|
||||
dataLength={list.length}
|
||||
|
||||
@@ -32,7 +32,7 @@ const ModelPage = () => {
|
||||
};
|
||||
|
||||
const onFetch = async (params: { pageSize?: number; current?: number }) => {
|
||||
const data = await getModelList(params);
|
||||
const data = await getModelList({ ...params, pageNo: params.current });
|
||||
return {
|
||||
data: data.list,
|
||||
success: true,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { ProColumns } from '@ant-design/pro-components';
|
||||
import { Tag } from 'antd';
|
||||
import GroupTagSelect from '@/components/GroupTag/GroupTagSelect';
|
||||
import {
|
||||
type AiSampleRespVO,
|
||||
@@ -15,13 +16,32 @@ export const baseTenantColumns: ProColumns<AiSampleRespVO>[] = [
|
||||
{
|
||||
title: '样本名称',
|
||||
dataIndex: 'sampleName',
|
||||
// width: 500,
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '文件格式',
|
||||
width: 100,
|
||||
dataIndex: 'sampleMineType',
|
||||
},
|
||||
{
|
||||
title: '标签',
|
||||
dataIndex: 'tags',
|
||||
width: 200,
|
||||
hideInSearch: true,
|
||||
render: (_, record) => {
|
||||
return record.tags?.map((tag) => {
|
||||
return <Tag key={tag.id}>{tag.tagName}</Tag>;
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '注释',
|
||||
width: 100,
|
||||
dataIndex: 'remark',
|
||||
hideInSearch: true,
|
||||
},
|
||||
|
||||
{
|
||||
title: '标签',
|
||||
hideInTable: true,
|
||||
@@ -57,11 +77,6 @@ export const baseTenantColumns: ProColumns<AiSampleRespVO>[] = [
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '样本格式',
|
||||
hideInTable: true,
|
||||
dataIndex: 'sample_mine_type',
|
||||
},
|
||||
];
|
||||
|
||||
// export const formColumns = (data: {
|
||||
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
deleteSampleTag,
|
||||
deleteSampleTagGroup,
|
||||
deleteSampleTagRelate,
|
||||
downloadSample,
|
||||
downloadZipFile,
|
||||
getSampleTagGroup,
|
||||
getSampleTagPage,
|
||||
relateSample,
|
||||
@@ -123,7 +125,22 @@ const SampleTagDetail = <T extends Record<string, any>>(
|
||||
};
|
||||
|
||||
// 下载
|
||||
const handleDownloadAll = () => {};
|
||||
const handleDownloadAll = async () => {
|
||||
const ids = data?.map((sample) => sample.id) as number[];
|
||||
downloadZipFile(ids);
|
||||
// const res = await downloadSample(ids);
|
||||
// console.log(res);
|
||||
// const downloadUrl = window.URL.createObjectURL(res);
|
||||
// const link = document.createElement("a");
|
||||
// link.href = downloadUrl;
|
||||
// link.download = downloadUrl; // 设置下载的文件名
|
||||
// link.style.display = "none";
|
||||
// document.body.appendChild(link);
|
||||
// link.click();
|
||||
// document.body.removeChild(link);
|
||||
// // const blob = new Blob([response.data], { type: 'application/pdf' });
|
||||
// // const url = window.URL.createObjectURL(blob);
|
||||
};
|
||||
|
||||
const handleTagManager = () => {
|
||||
setTagManagerVisible(true);
|
||||
@@ -158,6 +175,16 @@ const SampleTagDetail = <T extends Record<string, any>>(
|
||||
setTagManagerVisible(false);
|
||||
};
|
||||
|
||||
const onDownload = () => {
|
||||
const item = data?.[0];
|
||||
const link = document.createElement('a');
|
||||
link.href = item?.sampleFilePath;
|
||||
link.download = item?.sampleName; // 设置下载的文件名
|
||||
link.style.display = 'none';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<ProForm name="validate_other" formRef={formRef} submitter={false}>
|
||||
@@ -312,7 +339,7 @@ const SampleTagDetail = <T extends Record<string, any>>(
|
||||
onCancel={() => setTagManagerVisible(false)}
|
||||
></TagManager>
|
||||
<Space style={{ width: '100%', justifyContent: 'center', padding: 12 }}>
|
||||
<Button color="danger" onClick={() => {}}>
|
||||
<Button color="danger" onClick={onDownload}>
|
||||
下载
|
||||
</Button>
|
||||
<Button color="danger" variant="solid" onClick={handleDeleteAll}>
|
||||
|
||||
@@ -58,6 +58,7 @@ const SampleTag: React.FC = () => {
|
||||
const onFetch = async (params: SampleReqVo) => {
|
||||
const data = await getSamplePage({
|
||||
...params,
|
||||
pageNo: params.current,
|
||||
});
|
||||
return {
|
||||
data: data.list,
|
||||
@@ -86,7 +87,7 @@ const SampleTag: React.FC = () => {
|
||||
headerTitle="样本列表"
|
||||
showIndex={false}
|
||||
enableRowClick={true}
|
||||
scroll={{ x: 'max-content' }}
|
||||
scroll={{ x: 400 }}
|
||||
rowSelection={{
|
||||
type: selectTableType,
|
||||
selectedRowKeys: selectedRows.map((item) => item.id) as React.Key[],
|
||||
|
||||
@@ -134,23 +134,20 @@ export const errorConfig: RequestConfig = {
|
||||
const { data } = response as unknown as ResponseStructure;
|
||||
const config = response.config;
|
||||
const { code } = data;
|
||||
// if (!data) {
|
||||
// // 返回“[HTTP]请求没有返回值”;
|
||||
// throw new Error();
|
||||
// }
|
||||
// 未设置状态码则默认成功状态
|
||||
// 二进制数据则直接返回,例如说 Excel 导出
|
||||
// if (
|
||||
// response.request.responseType === "blob" ||
|
||||
// response.request.responseType === "arraybuffer"
|
||||
// ) {
|
||||
// // 注意:如果导出的响应为 json,说明可能失败了,不直接返回进行下载
|
||||
// // if (response.data.type !== "application/json") {
|
||||
// // return response.data;
|
||||
// // }
|
||||
// data = await new Response(data).json();
|
||||
// }
|
||||
// // 获取错误信息
|
||||
|
||||
if (!data) {
|
||||
// 返回“[HTTP]请求没有返回值”;
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (
|
||||
response.request.responseType === 'blob' ||
|
||||
response.request.responseType === 'arraybuffer'
|
||||
) {
|
||||
return response;
|
||||
// data = await new Response(data).json();
|
||||
}
|
||||
// 获取错误信息
|
||||
// const msg = data.msg || errorCode[code] || errorCode["default"];
|
||||
// if (ignoreMsgs.indexOf(msg) !== -1) {
|
||||
// // 如果是忽略的错误码,直接返回 msg 异常
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { request } from "@umijs/max";
|
||||
import { message } from "antd";
|
||||
|
||||
export interface SampleVo {
|
||||
/**
|
||||
@@ -85,9 +86,11 @@ export interface AiSampleRespVO {
|
||||
* 样本时长
|
||||
*/
|
||||
sampleTime?: string;
|
||||
tags?: { tagName?: string; id?: number }[];
|
||||
}
|
||||
|
||||
export interface SampleReqVo extends PageParam {
|
||||
current: number | undefined;
|
||||
name?: string;
|
||||
status?: number;
|
||||
}
|
||||
@@ -244,3 +247,73 @@ export const updateSampleTag = async (params: {
|
||||
data: params,
|
||||
});
|
||||
};
|
||||
|
||||
// 下载
|
||||
export const downloadSample = async (ids: number[]) => {
|
||||
return request("/ai/sample/download", {
|
||||
method: "GET",
|
||||
params: { ids },
|
||||
responseType: "blob",
|
||||
});
|
||||
};
|
||||
|
||||
export async function downloadZipFile(ids: number[]) {
|
||||
try {
|
||||
const response = await downloadSample(ids);
|
||||
|
||||
const blob = response; // Blob {size: 3164203, type: 'application/zip'}
|
||||
|
||||
// 验证文件类型
|
||||
if (blob.type !== "application/zip" && !blob.type.includes("zip")) {
|
||||
console.warn("返回的可能不是 ZIP 文件:", blob.type);
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadUrl;
|
||||
link.download = `音频文件_${new Date().getTime()}.wav`; // 设置文件名和后缀
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
// 从响应头获取文件名
|
||||
let fileName = "音频文件";
|
||||
const contentDisposition =
|
||||
response.response?.headers?.["content-disposition"];
|
||||
if (!fileName && contentDisposition) {
|
||||
const match = contentDisposition.match(
|
||||
/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
|
||||
);
|
||||
if (match?.[1]) {
|
||||
fileName = decodeURIComponent(match[1].replace(/['"]/g, ""));
|
||||
}
|
||||
}
|
||||
|
||||
// 默认文件名
|
||||
fileName = fileName || `archive_${new Date().getTime()}.zip`;
|
||||
|
||||
// 创建下载链接
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = downloadUrl;
|
||||
link.download = fileName;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// 清理
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
|
||||
message.success(
|
||||
`下载成功,文件大小:${(blob.size / 1024 / 1024).toFixed(2)} MB`
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("下载失败:", error);
|
||||
message.error("下载失败,请稍后重试");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user