no message

main
HUOJIN\霍先森 2025-05-10 14:43:49 +08:00
parent 316d40908d
commit efb8bc00f8
7 changed files with 454 additions and 364 deletions

View File

@ -14,7 +14,8 @@
:theme="{ :theme="{
algorithm: compactFlag ? theme.compactAlgorithm : theme.defaultAlgorithm, algorithm: compactFlag ? theme.compactAlgorithm : theme.defaultAlgorithm,
token: { token: {
fontFamily: '微软雅黑, Arial, sans-serif', fontFamily:'-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji',
fontsize: '14px',
colorPrimary: themeColors[colorIndex].primaryColor, colorPrimary: themeColors[colorIndex].primaryColor,
colorLink: themeColors[colorIndex].primaryColor, colorLink: themeColors[colorIndex].primaryColor,
colorLinkActive: themeColors[colorIndex].activeColor, colorLinkActive: themeColors[colorIndex].activeColor,
@ -45,7 +46,7 @@
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { computed, h, useSlots } from 'vue'; import {computed, h, useSlots, watch} from 'vue';
import {messages} from '/@/i18n'; import {messages} from '/@/i18n';
import {useAppConfigStore} from '/@/store/modules/system/app-config'; import {useAppConfigStore} from '/@/store/modules/system/app-config';
import {useSpinStore} from '/@/store/modules/system/spin'; import {useSpinStore} from '/@/store/modules/system/spin';
@ -73,6 +74,7 @@
const borderRadius = computed(() => { const borderRadius = computed(() => {
return useAppConfigStore().borderRadius; return useAppConfigStore().borderRadius;
}); });
function transformCellText({text, column, record, index}) { function transformCellText({text, column, record, index}) {
if (column && column.textEllipsisFlag === true) { if (column && column.textEllipsisFlag === true) {
return h( return h(
@ -80,7 +82,10 @@
{placement: 'bottom'}, {placement: 'bottom'},
{ {
default: () => default: () =>
h('div', { style: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }, id: `${column.dataIndex}${index}` }, text), h('div', {
style: {whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'},
id: `${column.dataIndex}${index}`
}, text),
content: () => content: () =>
h('div', {style: {display: 'flex'}}, [ h('div', {style: {display: 'flex'}}, [
h('div', text), h('div', text),
@ -92,9 +97,23 @@
return text; return text;
} }
} }
// CSS
/*watch(() => colorIndex.value, (newVal) => {
document.documentElement.style.setProperty('--primary-color', themeColors[newVal].primaryColor);
}, { immediate: true });*/
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
:deep(.ant-table-column-sorters) { /*:deep(.ant-table-column-sorters) {
align-items: flex-start !important; align-items: flex-start !important;
}*/
/*:deep(.ant-table-thead > tr > th) {
background-color: var(--primary-color) !important;
color: black !important;
}*/
:deep(.ant-table-thead > tr > th) {
background-color: #FAFAFA !important;
} }
</style> </style>

View File

@ -5,7 +5,7 @@
* @Date: 2024-12-26 15:35:23 * @Date: 2024-12-26 15:35:23
* @Copyright * @Copyright
*/ */
import {postRequest, getRequest, getDownload} from '/@/lib/axios'; import {postRequest, getRequest, getDownload2} from '/@/lib/axios';
export const addressApi = { export const addressApi = {
@ -71,8 +71,8 @@ export const addressApi = {
/** /**
* @author hj * @author hj
*/ */
exportAddress: (taskId: string) => { exportAddress: (taskId: string,signal?: AbortSignal) => {
return getDownload(`/address/exportAddress/${taskId}`, {}); return getDownload2(`/address/exportAddress/${taskId}`, {},signal);
} }
}; };

View File

@ -5,7 +5,7 @@
* @Date: 2024-11-25 17:08:18 * @Date: 2024-11-25 17:08:18
* @Copyright * @Copyright
*/ */
import {postRequest, getRequest, getDownload} from '/@/lib/axios'; import {postRequest, getRequest, getDownload2} from '/@/lib/axios';
export const itemApi = { export const itemApi = {
@ -62,8 +62,8 @@ export const itemApi = {
/** /**
* @author hj * @author hj
*/ */
exportItems: (taskId: string) => { exportItems: (taskId: string,signal?: AbortSignal) => {
return getDownload(`/item/exportItems/${taskId}`,{}); return getDownload2(`/item/exportItems/${taskId}`,{},signal);
} },
}; };

View File

@ -202,6 +202,22 @@ export const getDownload = function (url, params) {
}); });
}; };
export const getDownload2 = function (url: string, params: any, signal?: AbortSignal) {
request({
method: 'get',
url,
params,
responseType: 'blob',
signal // 注入取消信号
})
.then((data) => {
handleDownloadData(data);
})
.catch((error) => {
message.success('取消成功');
});
};
function handleDownloadError(error) { function handleDownloadError(error) {
if (error instanceof Blob) { if (error instanceof Blob) {
const fileReader = new FileReader(); const fileReader = new FileReader();

View File

@ -59,7 +59,7 @@
<a-modal <a-modal
v-model:open="open" v-model:open="open"
@cancel="onClose" @cancel="onCancel"
:closable="false" :closable="false"
:maskClosable="false" :maskClosable="false"
:destroyOnClose="true"> :destroyOnClose="true">
@ -75,7 +75,7 @@
</template> </template>
<template #footer> <template #footer>
<a-space> <a-space>
<a-button @click="onClose"></a-button> <a-button @click="onCancel"></a-button>
</a-space> </a-space>
</template> </template>
</a-modal> </a-modal>
@ -101,7 +101,7 @@
bordered bordered
:loading="tableLoading" :loading="tableLoading"
:pagination="false" :pagination="false"
:scroll="{ x: 1500, y: 350 }" :scroll="{ x: 1500, y: 450 }"
:row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }" :row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
> >
<template #bodyCell="{ text, record, column }"> <template #bodyCell="{ text, record, column }">
@ -443,53 +443,102 @@ async function onImportAddress() {
} }
// //
const progressTitle = ref('文件下载中,请稍等...'); const progressTitle = ref('文件下载中,请稍等...');//
const progressPercent = ref(0);// const progressPercent = ref(0);//
const progressStatus = ref('active');// const progressStatus = ref('active');
const currentTaskId = ref('');//ID const currentTaskId = ref('');//ID
const open = ref<boolean>(false);// const open = ref(false);//
const timerId = ref<NodeJS.Timeout | null>(null); //
const isExporting = ref(false); //
const abortController = ref<AbortController | null>(null);//
const onExportAddress = async () => { const onExportAddress = async () => {
if (isExporting.value) return;
try { try {
isExporting.value = true;
abortController.value = new AbortController(); //
open.value = true; open.value = true;
//ID resetProgressState(); //
//
const {data: taskId} = await addressApi.createExportTask(); const {data: taskId} = await addressApi.createExportTask();
currentTaskId.value = taskId; currentTaskId.value = taskId;
progressStatus.value = 'active';
// //
await addressApi.exportAddress(currentTaskId.value);
//
const timer = setInterval(async () => {
try { try {
// addressApi.exportAddress(taskId, abortController.value.signal)
const {data: progress} = await addressApi.getExportProgress(currentTaskId.value);
progressPercent.value = progress;
if (progress >= 100) {
clearInterval(timer);
progressStatus.value = 'success';
progressTitle.value = '文件下载完成';
// 2
setTimeout(() => {
open.value = false;
progressPercent.value = 0;
progressTitle.value = '文件下载中,请稍等...';
}, 2000);
}
} catch (error) { } catch (error) {
clearInterval(timer); handleExportError();
progressStatus.value = 'exception'; }
progressPercent.value = 0;
//
if (timerId.value) {
clearInterval(timerId.value);
}
//
timerId.value = setInterval(async () => {
try {
const {data: progress} = await addressApi.getExportProgress(currentTaskId.value);
progressPercent.value = progress;
if (progress >= 100) {
handleExportSuccess();
} }
}, 1000); //
} catch (error) { } catch (error) {
message.error('导出失败'); handleExportError();
}
}, 1000);
} catch (error) {
handleExportError();
} finally {
isExporting.value = false;
} }
}; };
const onClose = () => { //
const handleExportSuccess = () => {
if (timerId.value) {
clearInterval(timerId.value);
}
progressStatus.value = 'success';
progressTitle.value = '文件下载完成';
setTimeout(() => {
open.value = false; open.value = false;
resetProgressState();
}, 1000);
};
//
const handleExportError = () => {
if (timerId.value) clearInterval(timerId.value);
progressStatus.value = 'exception';
progressPercent.value = 0;
open.value = false;
resetProgressState();
};
//
const resetProgressState = () => {
progressPercent.value = 0;
progressStatus.value = 'active';
progressTitle.value = '文件下载中,请稍等...';
currentTaskId.value = '';
};
//
const onCancel = () => {
//
open.value = false;
if (abortController.value) {
abortController.value.abort();
abortController.value = null;
}
}; };
onMounted(queryData); onMounted(queryData);

View File

@ -65,7 +65,7 @@
<a-modal <a-modal
v-model:open="open" v-model:open="open"
@cancel="onClose" @cancel="onCancel"
:closable="false" :closable="false"
:maskClosable="false" :maskClosable="false"
:destroyOnClose="true"> :destroyOnClose="true">
@ -81,7 +81,7 @@
</template> </template>
<template #footer> <template #footer>
<a-space> <a-space>
<a-button @click="onClose"></a-button> <a-button @click="onCancel"></a-button>
</a-space> </a-space>
</template> </template>
</a-modal> </a-modal>
@ -498,96 +498,102 @@ async function onImportItems() {
} }
// //
const progressTitle = ref('文件下载中,请稍等...'); const progressTitle = ref('文件下载中,请稍等...');//
const progressPercent = ref(0); const progressPercent = ref(0);//
const progressStatus = ref('active'); const progressStatus = ref('active');
const currentTaskId = ref(''); const currentTaskId = ref('');//ID
const open = ref(false); const open = ref(false);//
const pollTimer = ref<NodeJS.Timeout>(); // 使ref const timerId = ref<NodeJS.Timeout | null>(null); //
const isExporting = ref(false); //
// const abortController = ref<AbortController | null>(null);//
const resetProgress = () => {
progressPercent.value = 0;
progressStatus.value = 'active';
progressTitle.value = '文件下载中,请稍等...';
};
//
const startProgressPolling = async (taskId: string) => {
try {
// 1
pollTimer.value = setInterval(async () => {
try {
const { data: progress } = await addressApi.getExportProgress(taskId);
progressPercent.value = progress;
if (progress >= 100) {
handleComplete();
clearInterval(pollTimer.value);
}
} catch (error) {
handlePollingError();
clearInterval(pollTimer.value);
}
}, 200); // 1
} catch (error) {
handlePollingError();
}
};
//
const handleComplete = () => {
progressStatus.value = 'success';
progressTitle.value = '文件下载完成';
// 使
open.value = false;
resetProgress();
};
//
const handlePollingError = () => {
progressStatus.value = 'exception';
progressPercent.value = 0;
progressTitle.value = '获取进度失败';
};
const onExportItems = async () => { const onExportItems = async () => {
if (isExporting.value) return;
try { try {
// isExporting.value = true;
if (pollTimer.value) clearInterval(pollTimer.value); abortController.value = new AbortController(); //
// ID
resetProgress();
currentTaskId.value = '';
open.value = true; open.value = true;
resetProgressState(); //
// ID //
const {data: taskId} = await addressApi.createExportTask(); const {data: taskId} = await addressApi.createExportTask();
currentTaskId.value = taskId; currentTaskId.value = taskId;
// //
await Promise.race([ try {
itemApi.exportItems(taskId), itemApi.exportItems(taskId, abortController.value.signal)
new Promise((_, reject) => } catch (error) {
setTimeout(() => reject(new Error('导出超时')), 30_000) handleExportError();
) }
]);
// //
await startProgressPolling(taskId); if (timerId.value) {
} catch (error: any) { clearInterval(timerId.value);
open.value = false; }
message.error('导出失败: ' + error.message);
// //
if (pollTimer.value) clearInterval(pollTimer.value); timerId.value = setInterval(async () => {
resetProgress(); try {
const {data: progress} = await addressApi.getExportProgress(currentTaskId.value);
progressPercent.value = progress;
if (progress >= 100) {
handleExportSuccess();
}
} catch (error) {
handleExportError();
}
}, 1000);
} catch (error) {
handleExportError();
} finally {
isExporting.value = false;
} }
}; };
const onClose = () => { //
resetProgress(); const handleExportSuccess = () => {
if (timerId.value) {
clearInterval(timerId.value);
}
progressStatus.value = 'success';
progressTitle.value = '文件下载完成';
setTimeout(() => {
open.value = false;
resetProgressState();
}, 1000);
};
//
const handleExportError = () => {
if (timerId.value) clearInterval(timerId.value);
progressStatus.value = 'exception';
progressPercent.value = 0;
open.value = false;
resetProgressState();
};
//
const resetProgressState = () => {
progressPercent.value = 0;
progressStatus.value = 'active';
progressTitle.value = '文件下载中,请稍等...';
currentTaskId.value = '';
};
//
const onCancel = () => {
//
open.value = false;
if (abortController.value) {
abortController.value.abort();
abortController.value = null;
}
}; };
onMounted(queryData); onMounted(queryData);