feat: 导入投放账户修改为异步逻辑
This commit is contained in:
@ -1,6 +1,18 @@
|
|||||||
import { Notification } from '@arco-design/web-vue';
|
import { Notification } from '@arco-design/web-vue';
|
||||||
|
import { downloadByUrl } from '@/utils/tools';
|
||||||
import { IconLoading } from '@arco-design/web-vue/es/icon';
|
import { IconLoading } from '@arco-design/web-vue/es/icon';
|
||||||
|
|
||||||
|
|
||||||
|
import icon1 from '@/assets/img/media-account/icon-warn.png';
|
||||||
|
import icon2 from '@/assets/img/media-account/icon-close.png';
|
||||||
|
|
||||||
|
interface RenderNotificationData {
|
||||||
|
total_number: number;
|
||||||
|
success_number: number;
|
||||||
|
fail_number: number;
|
||||||
|
file?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export function showExportNotification(label: string, id: '') {
|
export function showExportNotification(label: string, id: '') {
|
||||||
Notification.warning({
|
Notification.warning({
|
||||||
id,
|
id,
|
||||||
@ -15,4 +27,43 @@ export function showExportNotification(label: string, id: '') {
|
|||||||
duration: 3000,
|
duration: 3000,
|
||||||
class: 'px-16px py-9px w-400px rounded-2px bg-#F0EDFF',
|
class: 'px-16px py-9px w-400px rounded-2px bg-#F0EDFF',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const showImportResultNotification = (data: RenderNotificationData) => {
|
||||||
|
const { total_number, success_number, fail_number, file } = data;
|
||||||
|
const hasError = fail_number > 0;
|
||||||
|
const handleDownloadError = (file?: string) => {
|
||||||
|
file && downloadByUrl(file);
|
||||||
|
};
|
||||||
|
|
||||||
|
Notification.warning({
|
||||||
|
showIcon: false,
|
||||||
|
closable: true,
|
||||||
|
content: () => (
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center mb-4px">
|
||||||
|
<img src={hasError ? icon1 : icon2} width="16" height="16" class="mr-8px" />
|
||||||
|
<span class="text-16px lh-24px font-400 color-#211F24">导入完成</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-14px lh-22px font-400 color-#211F24">
|
||||||
|
共导入 {total_number} 个账号,导入成功 {success_number} 个
|
||||||
|
{hasError && (
|
||||||
|
<span>
|
||||||
|
,失败 <span class="color-#F64B31">{fail_number}</span> 个
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
{hasError && (
|
||||||
|
<div
|
||||||
|
class="mt-8px text-14px lh-22px font-400 color-#6D4CFE cursor-pointer"
|
||||||
|
onClick={() => handleDownloadError(file)}
|
||||||
|
>
|
||||||
|
下载问题表格
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
duration: 3000,
|
||||||
|
class: `px-16px py-16px w-400px rounded-2px ${hasError ? 'bg-#FFF7E5' : 'bg-#EBF7F2'}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -42,8 +42,8 @@ import icon1 from '@/assets/img/media-account/icon-download.png';
|
|||||||
import icon2 from '@/assets/img/media-account/icon-delete.png';
|
import icon2 from '@/assets/img/media-account/icon-delete.png';
|
||||||
import icon3 from '@/assets/img/media-account/icon-dy.png';
|
import icon3 from '@/assets/img/media-account/icon-dy.png';
|
||||||
import icon4 from '@/assets/img/media-account/icon-xhs.png';
|
import icon4 from '@/assets/img/media-account/icon-xhs.png';
|
||||||
import icon5 from '@/assets/img/media-account/icon-warn-1.png';
|
// import icon5 from '@/assets/img/media-account/icon-warn-1.png';
|
||||||
import icon6 from '@/assets/img/media-account/icon-success.png';
|
// import icon6 from '@/assets/img/media-account/icon-success.png';
|
||||||
|
|
||||||
const UploadStatus = {
|
const UploadStatus = {
|
||||||
DEFAULT: 'default',
|
DEFAULT: 'default',
|
||||||
@ -74,10 +74,10 @@ export default {
|
|||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const file = ref(null);
|
const file = ref(null);
|
||||||
const authorizedAccountModalRef = ref(null);
|
const authorizedAccountModalRef = ref(null);
|
||||||
const importPromptModalRef = ref(null);
|
// const importPromptModalRef = ref(null);
|
||||||
const uploadRef = ref(null);
|
const uploadRef = ref(null);
|
||||||
const isCustomCookie = ref(false);
|
const isCustomCookie = ref(false);
|
||||||
const form = ref({ ...INITIAL_FORM });
|
const form = ref(cloneDeep(INITIAL_FORM));
|
||||||
const syncDataModalRef = ref(null);
|
const syncDataModalRef = ref(null);
|
||||||
const importLoading = ref(false);
|
const importLoading = ref(false);
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ export default {
|
|||||||
const reset = () => {
|
const reset = () => {
|
||||||
formRef.value?.resetFields();
|
formRef.value?.resetFields();
|
||||||
formRef.value?.clearValidate();
|
formRef.value?.clearValidate();
|
||||||
form.value = { ...INITIAL_FORM };
|
form.value = cloneDeep(INITIAL_FORM);
|
||||||
fileName.value = '';
|
fileName.value = '';
|
||||||
file.value = null;
|
file.value = null;
|
||||||
isEdit.value = false;
|
isEdit.value = false;
|
||||||
@ -197,6 +197,8 @@ export default {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uploadStatus.value = UploadStatus.ERROR;
|
uploadStatus.value = UploadStatus.ERROR;
|
||||||
|
} finally {
|
||||||
|
importLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleAddAccount = async () => {
|
const handleAddAccount = async () => {
|
||||||
|
|||||||
@ -130,7 +130,7 @@ import BatchTagModal from './components/batch-tag-modal';
|
|||||||
import BatchGroupModal from './components/batch-group-modal';
|
import BatchGroupModal from './components/batch-group-modal';
|
||||||
|
|
||||||
import { INITIAL_QUERY, INITIAL_PAGE_INFO } from './constants';
|
import { INITIAL_QUERY, INITIAL_PAGE_INFO } from './constants';
|
||||||
import {renderNotification} from "./renderComp"
|
import { showImportResultNotification } from '@/utils/arcoD';
|
||||||
import { EnumStatus } from '@/views/property-marketing/media-account/components/status-select/constants';
|
import { EnumStatus } from '@/views/property-marketing/media-account/components/status-select/constants';
|
||||||
import { getTaskStatus } from '@/api/all/common';
|
import { getTaskStatus } from '@/api/all/common';
|
||||||
import {
|
import {
|
||||||
@ -350,7 +350,7 @@ const getSyncTaskStatus = async (id, notificationId) => {
|
|||||||
if (data?.status !== 0) {
|
if (data?.status !== 0) {
|
||||||
clearQueryTaskTimer();
|
clearQueryTaskTimer();
|
||||||
notificationId && Notification.remove(notificationId);
|
notificationId && Notification.remove(notificationId);
|
||||||
renderNotification(data)
|
showImportResultNotification(data)
|
||||||
getData();
|
getData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
import { downloadByUrl } from '@/utils/tools';
|
|
||||||
|
|
||||||
const handleDownloadError = (file) => {
|
|
||||||
file && downloadByUrl(file);
|
|
||||||
};
|
|
||||||
export const renderNotification = (data) => {
|
|
||||||
const { total_number, success_number, fail_number, file } = data;
|
|
||||||
const hasError = fail_number > 0;
|
|
||||||
Notification.warning({
|
|
||||||
id,
|
|
||||||
showIcon: false,
|
|
||||||
closable: true,
|
|
||||||
content: (
|
|
||||||
<div>
|
|
||||||
<div class="flex items-center mb-4px">
|
|
||||||
<img src={hasError ? icon5 : icon6} width="16" height="16" class="mr-8px" />
|
|
||||||
<span class="text-16px lh-24px font-400 color-#211F24">导入完成</span>
|
|
||||||
</div>
|
|
||||||
<p class="text-14px lh-22px font-400 color-#211F24">
|
|
||||||
共导入 {total_number} 个账号,导入成功 {success_number} 个
|
|
||||||
{hasError && (
|
|
||||||
<span>
|
|
||||||
,失败 <span class="color-#F64B31">{fail_number}</span> 个
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
{hasError && (
|
|
||||||
<div
|
|
||||||
class="mt-8px text-14px lh-22px font-400 color-#6D4CFE cursor-pointer"
|
|
||||||
onClick={() => handleDownloadError(file)}
|
|
||||||
>
|
|
||||||
下载问题表格
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
duration: 3000,
|
|
||||||
class: `px-16px py-16px w-400px rounded-2px ${hasError ? 'bg-#FFF7E5' : 'bg-#EBF7F2'}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@ -132,7 +132,7 @@
|
|||||||
</a-form>
|
</a-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<a-button size="large" class="cancel-btn" @click="onClose">取消</a-button>
|
<a-button size="large" class="cancel-btn" @click="onClose">取消</a-button>
|
||||||
<a-button type="primary" size="large" @click="onSubmit">
|
<a-button type="primary" size="large" @click="onSubmit" :loading="importLoading">
|
||||||
{{ confirmBtnText }}
|
{{ confirmBtnText }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
@ -150,6 +150,7 @@ import AuthorizedAccountModal from '../authorized-account-modal';
|
|||||||
import StatusBox from '../status-box';
|
import StatusBox from '../status-box';
|
||||||
import { PLATFORM_LIST, ENUM_PLATFORM } from '@/views/property-marketing/put-account/common_constants';
|
import { PLATFORM_LIST, ENUM_PLATFORM } from '@/views/property-marketing/put-account/common_constants';
|
||||||
|
|
||||||
|
import { showExportNotification } from '@/utils/arcoD';
|
||||||
import {
|
import {
|
||||||
postPlacementAccounts,
|
postPlacementAccounts,
|
||||||
getPlacementAccountsDetail,
|
getPlacementAccountsDetail,
|
||||||
@ -162,6 +163,7 @@ import icon1 from '@/assets/img/media-account/icon-download.png';
|
|||||||
import icon2 from '@/assets/img/media-account/icon-delete.png';
|
import icon2 from '@/assets/img/media-account/icon-delete.png';
|
||||||
|
|
||||||
const update = inject('update');
|
const update = inject('update');
|
||||||
|
const emits = defineEmits(['startQueryTaskStatus']);
|
||||||
|
|
||||||
const UploadStatus = {
|
const UploadStatus = {
|
||||||
DEFAULT: 'default',
|
DEFAULT: 'default',
|
||||||
@ -188,6 +190,7 @@ const authorizedAccountModalRef = ref(null);
|
|||||||
const uploadRef = ref(null);
|
const uploadRef = ref(null);
|
||||||
const file = ref(null);
|
const file = ref(null);
|
||||||
const form = ref(cloneDeep(INITIAL_FORM));
|
const form = ref(cloneDeep(INITIAL_FORM));
|
||||||
|
const importLoading = ref(false);
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
mobile: [
|
mobile: [
|
||||||
@ -213,7 +216,7 @@ const rules = {
|
|||||||
|
|
||||||
const isBatchImport = computed(() => uploadType.value === 'batch');
|
const isBatchImport = computed(() => uploadType.value === 'batch');
|
||||||
const confirmBtnText = computed(() => {
|
const confirmBtnText = computed(() => {
|
||||||
if (isBatchImport.value) return '确定导入';
|
if (isBatchImport.value) return importLoading.value ? '导入中' : '确定导入';
|
||||||
return isEdit.value ? '确定' : '下一步';
|
return isEdit.value ? '确定' : '下一步';
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -229,6 +232,7 @@ const handleUpload = async (option) => {
|
|||||||
function removeFile() {
|
function removeFile() {
|
||||||
fileName.value = '';
|
fileName.value = '';
|
||||||
file.value = null;
|
file.value = null;
|
||||||
|
importLoading.value = false;
|
||||||
uploadStatus.value = UploadStatus.DEFAULT;
|
uploadStatus.value = UploadStatus.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,6 +244,7 @@ const reset = () => {
|
|||||||
fileName.value = '';
|
fileName.value = '';
|
||||||
file.value = null;
|
file.value = null;
|
||||||
isEdit.value = false;
|
isEdit.value = false;
|
||||||
|
importLoading.value = false;
|
||||||
uploadStatus.value = UploadStatus.DEFAULT;
|
uploadStatus.value = UploadStatus.DEFAULT;
|
||||||
uploadType.value = 'manual';
|
uploadType.value = 'manual';
|
||||||
};
|
};
|
||||||
@ -273,23 +278,28 @@ const handleBatchImport = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
importLoading.value = true;
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file.value);
|
formData.append('file', file.value);
|
||||||
|
|
||||||
const { code } = await batchPlacementAccounts(formData, {
|
const { code, data } = await batchPlacementAccounts(formData, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'multipart/form-data',
|
'Content-Type': 'multipart/form-data',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
AMessage.success('导入成功');
|
const ID = 'IMPORT-PUT-ACCOUNT';
|
||||||
update();
|
showExportNotification(`正在导入“${file.value.name}”,请稍后...`, ID);
|
||||||
|
emits('startQueryTaskStatus', data.id, ID);
|
||||||
onClose();
|
onClose();
|
||||||
} else {
|
} else {
|
||||||
uploadStatus.value = UploadStatus.ERROR;
|
uploadStatus.value = UploadStatus.ERROR;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uploadStatus.value = UploadStatus.ERROR;
|
uploadStatus.value = UploadStatus.ERROR;
|
||||||
|
} finally {
|
||||||
|
importLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// importPromptModalRef.value.open();
|
// importPromptModalRef.value.open();
|
||||||
|
|||||||
@ -86,7 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AddAccountModal ref="addAccountModalRef" />
|
<AddPutAccountModal ref="addAccountModalRef" @startQueryTaskStatus="handleGetImportTaskStatus" />
|
||||||
<DeleteAccountModal ref="deleteAccountRef" @update="onDeleteSuccess" />
|
<DeleteAccountModal ref="deleteAccountRef" @update="onDeleteSuccess" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -96,11 +96,13 @@ import { ref } from 'vue';
|
|||||||
|
|
||||||
import FilterBlock from './components/filter-block';
|
import FilterBlock from './components/filter-block';
|
||||||
import AccountTable from './components/account-table';
|
import AccountTable from './components/account-table';
|
||||||
import AddAccountModal from './components/add-account-modal';
|
import AddPutAccountModal from './components/add-account-modal';
|
||||||
import DeleteAccountModal from './components/account-table/delete-account';
|
import DeleteAccountModal from './components/account-table/delete-account';
|
||||||
|
|
||||||
import { INITIAL_QUERY } from './constants';
|
import { INITIAL_QUERY } from './constants';
|
||||||
import { getPlacementAccounts, getPlacementAccountsHealth } from '@/api/all/propertyMarketing';
|
import { getPlacementAccounts, getPlacementAccountsHealth } from '@/api/all/propertyMarketing';
|
||||||
|
import { getTaskStatus } from '@/api/all/common';
|
||||||
|
import { showImportResultNotification } from '@/utils/arcoD';
|
||||||
|
|
||||||
import icon1 from '@/assets/img/media-account/icon-add.png';
|
import icon1 from '@/assets/img/media-account/icon-add.png';
|
||||||
import icon4 from '@/assets/img/media-account/icon-success.png';
|
import icon4 from '@/assets/img/media-account/icon-success.png';
|
||||||
@ -111,6 +113,8 @@ const groupManageModalRef = ref(null);
|
|||||||
const tagsManageModalRef = ref(null);
|
const tagsManageModalRef = ref(null);
|
||||||
const addAccountModalRef = ref(null);
|
const addAccountModalRef = ref(null);
|
||||||
const deleteAccountRef = ref(null);
|
const deleteAccountRef = ref(null);
|
||||||
|
let queryTaskTimer = null;
|
||||||
|
|
||||||
|
|
||||||
const pageInfo = ref({
|
const pageInfo = ref({
|
||||||
page: 1,
|
page: 1,
|
||||||
@ -158,10 +162,6 @@ const tipLabel = computed(() => {
|
|||||||
return `共有 ${total_abnormal_number} 个账号存在授权异常,其中:${abnormalLabels.join(',')}。`;
|
return `共有 ${total_abnormal_number} 个账号存在授权异常,其中:${abnormalLabels.join(',')}。`;
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getData();
|
|
||||||
});
|
|
||||||
|
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
getHealthData();
|
getHealthData();
|
||||||
getAccountData();
|
getAccountData();
|
||||||
@ -257,6 +257,37 @@ const handleOpenAbnormalAccount = () => {
|
|||||||
reload();
|
reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 查询导入账号任务状态
|
||||||
|
const getSyncTaskStatus = async (id, notificationId) => {
|
||||||
|
const { code, data } = await getTaskStatus(id);
|
||||||
|
if (code === 200) {
|
||||||
|
if (data?.status !== 0) {
|
||||||
|
clearQueryTaskTimer();
|
||||||
|
notificationId && Notification.remove(notificationId);
|
||||||
|
showImportResultNotification(data);
|
||||||
|
getData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleGetImportTaskStatus = (id, notificationId) => {
|
||||||
|
clearQueryTaskTimer();
|
||||||
|
getSyncTaskStatus(id, notificationId);
|
||||||
|
queryTaskTimer = setInterval(getSyncTaskStatus, 3000);
|
||||||
|
};
|
||||||
|
const clearQueryTaskTimer = () => {
|
||||||
|
if (queryTaskTimer) {
|
||||||
|
clearInterval(queryTaskTimer);
|
||||||
|
queryTaskTimer = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getData();
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearQueryTaskTimer();
|
||||||
|
});
|
||||||
|
|
||||||
provide('update', getData);
|
provide('update', getData);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user