Merge remote-tracking branch 'origin/feature/v1.3_营销资产中台' into feature/0707_产品权限
This commit is contained in:
@ -20,6 +20,7 @@
|
|||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"echarts": "^5.6.0",
|
"echarts": "^5.6.0",
|
||||||
"html2canvas": "^1.4.1",
|
"html2canvas": "^1.4.1",
|
||||||
|
"jspdf": "^3.0.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
|
|||||||
@ -140,6 +140,11 @@ export const fetchImageUploadFile = (params: any) => {
|
|||||||
return Http.get(`/v1/oss/image-pre-signed-url`, params);
|
return Http.get(`/v1/oss/image-pre-signed-url`, params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取预上传文件后缀
|
||||||
|
export const fetchUploadFile = (params: any) => {
|
||||||
|
return Http.get(`/v1/oss/file-pre-signed-url`, params);
|
||||||
|
};
|
||||||
|
|
||||||
// 移除企业子账号
|
// 移除企业子账号
|
||||||
export const removeEnterpriseAccount = (userId: number) => {
|
export const removeEnterpriseAccount = (userId: number) => {
|
||||||
return Http.delete(`/v1/enterprises/users/${userId}`);
|
return Http.delete(`/v1/enterprises/users/${userId}`);
|
||||||
|
|||||||
@ -7,7 +7,8 @@
|
|||||||
border-color: #d7d7d9;
|
border-color: #d7d7d9;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
&:focus-within,
|
&:focus-within,
|
||||||
&.arco-input-focus {
|
&.arco-input-focus,
|
||||||
|
&.arco-textarea-focus {
|
||||||
background-color: var(--color-bg-2);
|
background-color: var(--color-bg-2);
|
||||||
border-color: rgb(var(--primary-6));
|
border-color: rgb(var(--primary-6));
|
||||||
box-shadow: 0 0 0 0 var(--color-primary-light-2);
|
box-shadow: 0 0 0 0 var(--color-primary-light-2);
|
||||||
|
|||||||
@ -36,7 +36,7 @@ export const getAccountInfoFields = (dateType: string, showMore: boolean) => {
|
|||||||
{ title: '账号名称', dataIndex: 'name' },
|
{ title: '账号名称', dataIndex: 'name' },
|
||||||
{ title: '项目分组', dataIndex: 'group.name' },
|
{ title: '项目分组', dataIndex: 'group.name' },
|
||||||
{ title: '状态', dataIndex: 'status', type: 'status' },
|
{ title: '状态', dataIndex: 'status', type: 'status' },
|
||||||
{ title: '运营人员', dataIndex: 'operator_name' },
|
{ title: '运营人员', dataIndex: 'operator.name' },
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{ title: 'AI评价', dataIndex: 'ai_evaluation' },
|
{ title: 'AI评价', dataIndex: 'ai_evaluation' },
|
||||||
|
|||||||
@ -53,7 +53,7 @@ const open = (record) => {
|
|||||||
|
|
||||||
async function onDelete() {
|
async function onDelete() {
|
||||||
const _fn = isBatch.value ? batchDeleteMediaAccounts : deleteMediaAccount;
|
const _fn = isBatch.value ? batchDeleteMediaAccounts : deleteMediaAccount;
|
||||||
const _params = isBatch.value ? { ids: accountId.value } : { id: accountId.value };
|
const _params = isBatch.value ? { ids: accountId.value } : accountId.value;
|
||||||
const { code } = await _fn(_params);
|
const { code } = await _fn(_params);
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
AMessage.success('删除成功');
|
AMessage.success('删除成功');
|
||||||
|
|||||||
@ -115,6 +115,21 @@
|
|||||||
<a-form-item label="选择标签">
|
<a-form-item label="选择标签">
|
||||||
<TagSelect v-model="form.tag_ids" :options="tagOptions" placeholder="请选择…" size="large" />
|
<TagSelect v-model="form.tag_ids" :options="tagOptions" placeholder="请选择…" size="large" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="笔记链接" field="end_work_link">
|
||||||
|
<template #label>
|
||||||
|
<span class="label">笔记链接</span>
|
||||||
|
<a-tooltip content="平台将从该笔记“之后”的内容开始同步,该笔记及更早的数据均不采集">
|
||||||
|
<icon-question-circle size="14" class="ml-4px color-#737478" />
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-textarea
|
||||||
|
v-model="form.end_work_link"
|
||||||
|
placeholder="请输入..."
|
||||||
|
size="large"
|
||||||
|
max-length="72"
|
||||||
|
:auto-size="{ minRows: 3, maxRows: 5 }"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
</template>
|
</template>
|
||||||
</a-form>
|
</a-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -166,6 +181,7 @@ const INITIAL_FORM = {
|
|||||||
platform: 0,
|
platform: 0,
|
||||||
group_id: undefined,
|
group_id: undefined,
|
||||||
tag_ids: [],
|
tag_ids: [],
|
||||||
|
end_work_link: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupOptions = ref([]);
|
const groupOptions = ref([]);
|
||||||
@ -318,10 +334,8 @@ async function onSubmit() {
|
|||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
isEdit.value && AMessage.success('修改成功');
|
isEdit.value && AMessage.success('修改成功');
|
||||||
emits('update');
|
emits('update');
|
||||||
|
onClose();
|
||||||
if (isEdit.value) {
|
if (!isEdit.value) {
|
||||||
onClose();
|
|
||||||
} else {
|
|
||||||
startAuthorized(data?.id, data?.platform);
|
startAuthorized(data?.id, data?.platform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,7 +57,7 @@ const open = (record) => {
|
|||||||
|
|
||||||
async function onDelete() {
|
async function onDelete() {
|
||||||
const _fn = isBatch.value ? batchDeletePlacementAccounts : deletePlacementAccount;
|
const _fn = isBatch.value ? batchDeletePlacementAccounts : deletePlacementAccount;
|
||||||
const _params = isBatch.value ? { ids: accountId.value } : { id: accountId.value };
|
const _params = isBatch.value ? { ids: accountId.value } : accountId.value;
|
||||||
const { code } = await _fn(_params);
|
const { code } = await _fn(_params);
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
AMessage.success('删除成功');
|
AMessage.success('删除成功');
|
||||||
|
|||||||
@ -164,10 +164,9 @@ const getData = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getHealthData = async () => {
|
const getHealthData = async () => {
|
||||||
const { code, data } = await getMediaAccountsHealth();
|
const { code, data } = await getPlacementAccountsHealth();
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
healthData.value = data;
|
healthData.value = data;
|
||||||
console.log(healthData.value);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const getAccountData = async () => {
|
const getAccountData = async () => {
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
</a-space>
|
</a-space>
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="outline" @click="downloadDetailAsImage(record.id)" class="operation-btn">下载</a-button>
|
<a-button type="outline" @click="downLoad(record.file_url)" class="operation-btn">下载</a-button>
|
||||||
<a-button type="outline" @click="goDetail(record.id)" class="operation-btn">详情</a-button>
|
<a-button type="outline" @click="goDetail(record.id)" class="operation-btn">详情</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</a-space>
|
</a-space>
|
||||||
@ -82,32 +82,24 @@ const goDetail = async (id) => {
|
|||||||
router.push(`/put-account/detail/${id}`);
|
router.push(`/put-account/detail/${id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadDetailAsImage = (id) => {
|
const downLoad = (fileUrl) => {
|
||||||
const url = `/put-account/detail/${id}`;
|
if (isEmpty(fileUrl)) {
|
||||||
const win = window.open(url, '_blank');
|
Message.error('下载失败,文件不存在');
|
||||||
|
return;
|
||||||
win.onload = () => {
|
}
|
||||||
setTimeout(() => {
|
const link = document.createElement('a');
|
||||||
html2canvas(win.document.body, {
|
link.href = fileUrl;
|
||||||
useCORS: true,
|
link.download = '投放指南.pdf';
|
||||||
scale: 2,
|
document.body.appendChild(link);
|
||||||
}).then((canvas) => {
|
link.click();
|
||||||
const imgData = canvas.toDataURL('image/png');
|
document.body.removeChild(link);
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = imgData;
|
|
||||||
link.download = `详情页面_${Date.now()}.png`;
|
|
||||||
link.click();
|
|
||||||
win.close(); // 关闭新窗口
|
|
||||||
});
|
|
||||||
}, 2000); // 等待页面加载
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
const deleteData = async (id) => {
|
const deleteData = async (id) => {
|
||||||
const { code, message } = await deleteHistorylog(id);
|
const { code, message } = await deleteHistorylog(id);
|
||||||
if (code == 200) {
|
if (code == 200) {
|
||||||
Message.success(message);
|
Message.success(message);
|
||||||
emits('onSearch');
|
emits('onSearch');
|
||||||
console.log('onsearch')
|
console.log('onsearch');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -50,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="filter-row-item flex items-center">
|
<div class="filter-row-item flex items-center">
|
||||||
<a-button class="w-84px search-btn mr-12px" size="medium" @click="handleSearch">
|
<a-button class="w-84px search-btn mr-12px" :disabled="disabled" size="medium" @click="handleSearch">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<icon-search />
|
<icon-search />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -54,8 +54,7 @@
|
|||||||
|
|
||||||
<template #platform="{ record }">
|
<template #platform="{ record }">
|
||||||
<a-space size="medium" v-if="record.platform">
|
<a-space size="medium" v-if="record.platform">
|
||||||
<img :src="PLATFORM_LIST[record.platform]?.icon" width="19" class="mr-4px" />
|
|
||||||
<span>{{ PLATFORM_LIST[record.platform].label }}</span>
|
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<a-tabs
|
<a-tabs
|
||||||
v-model:activeKey="tabData"
|
v-model:activeKey="tabData"
|
||||||
@tab-click="onSearch"
|
@tab-click="onSearch"
|
||||||
class="a-tab-class"
|
class="a-tab-class ignore-export"
|
||||||
default-active-key="placement_guide"
|
default-active-key="placement_guide"
|
||||||
>
|
>
|
||||||
<a-tab-pane key="placement_guide" title="投放指南"></a-tab-pane>
|
<a-tab-pane key="placement_guide" title="投放指南"></a-tab-pane>
|
||||||
@ -16,6 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!--表单组件搜索-->
|
<!--表单组件搜索-->
|
||||||
<listSearchForm
|
<listSearchForm
|
||||||
|
class="ignore-export"
|
||||||
@onReset="handleReset"
|
@onReset="handleReset"
|
||||||
v-model:query="query"
|
v-model:query="query"
|
||||||
@onSearch="onSearch"
|
@onSearch="onSearch"
|
||||||
@ -43,18 +44,21 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-spin v-if="tabData === 'placement_guide'" :loading="loading" tip="AI分析中...." wrapperClassName="custom-spin-wrapper">
|
<a-spin
|
||||||
<div >
|
v-show="tabData === 'placement_guide'"
|
||||||
|
:loading="loading"
|
||||||
|
tip="AI分析中...."
|
||||||
|
wrapperClassName="custom-spin-wrapper"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
<MonthData :overview="aiResult.overview"></MonthData>
|
<MonthData :overview="aiResult.overview"></MonthData>
|
||||||
<!-- 投放建议-->
|
<!-- 投放建议-->
|
||||||
<PlacementSuggestions :optimization="aiResult.optimization"></PlacementSuggestions>
|
<PlacementSuggestions :optimization="aiResult.optimization"></PlacementSuggestions>
|
||||||
<!-- 投放行动指南-->
|
<!-- 投放行动指南-->
|
||||||
<ActionGuideDistribution :action_guide="aiResult.action_guide"></ActionGuideDistribution>
|
<!-- <ActionGuideDistribution :action_guide="aiResult.action_guide"></ActionGuideDistribution>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</a-spin>
|
</a-spin>
|
||||||
<div v-if="tabData == 'placement_guide'">
|
<div v-if="tabData == 'placement_guide'" class="ignore-export">
|
||||||
<a-space class="down-btn">
|
<a-space class="down-btn">
|
||||||
<a-button type="outline" @click="downPage">
|
<a-button type="outline" @click="downPage">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
@ -89,7 +93,10 @@ import {
|
|||||||
} from '@/api/all/propertyMarketing';
|
} from '@/api/all/propertyMarketing';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import html2canvas from 'html2canvas';
|
import html2canvas from 'html2canvas';
|
||||||
|
import { jsPDF } from 'jspdf';
|
||||||
import { AiResultStatus } from '@/views/property-marketing/put-account/investment-guidelines/constants';
|
import { AiResultStatus } from '@/views/property-marketing/put-account/investment-guidelines/constants';
|
||||||
|
import { fetchUploadFile } from '@/api/all';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
const tabData = ref('placement_guide');
|
const tabData = ref('placement_guide');
|
||||||
|
|
||||||
@ -121,6 +128,7 @@ const handleUpdateQuery = (payload) => {
|
|||||||
query.sort_column = payload.column;
|
query.sort_column = payload.column;
|
||||||
query.sort_order = payload.order;
|
query.sort_order = payload.order;
|
||||||
isGetAi.value = false;
|
isGetAi.value = false;
|
||||||
|
loading.value = false;
|
||||||
onSearch();
|
onSearch();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -143,11 +151,10 @@ const onSearch = async () => {
|
|||||||
guideHistoryList.value = result?.data?.data || [];
|
guideHistoryList.value = result?.data?.data || [];
|
||||||
}
|
}
|
||||||
listData.total = result.data.total;
|
listData.total = result.data.total;
|
||||||
if (placementGuideList.value.length > 0) {
|
if (placementGuideList.value.length > 0 && isGetAi.value) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
if (isGetAi.value) {
|
syncGetAiResult();
|
||||||
startTask();
|
startTask();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
isGetAi.value = true;
|
isGetAi.value = true;
|
||||||
};
|
};
|
||||||
@ -159,15 +166,14 @@ const aiResult = reactive({
|
|||||||
|
|
||||||
// 下载当前页面
|
// 下载当前页面
|
||||||
const downPage = async () => {
|
const downPage = async () => {
|
||||||
await nextTick(); // 确保 DOM 更新完成
|
await nextTick();
|
||||||
html2canvas(document.querySelector('.guidelines-data-wrap')).then((canvas) => {
|
const fileUrl = await uploadPdf();
|
||||||
const imgData = canvas.toDataURL('image/png');
|
const link = document.createElement('a');
|
||||||
const link = document.createElement('a');
|
link.href = fileUrl;
|
||||||
link.href = imgData;
|
link.download = '投放指南.pdf';
|
||||||
const timestamp = new Date().getTime();
|
document.body.appendChild(link);
|
||||||
link.download = `投放指南-${timestamp}.png`;
|
link.click();
|
||||||
link.click();
|
document.body.removeChild(link);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
const saveForm = reactive({
|
const saveForm = reactive({
|
||||||
account: [],
|
account: [],
|
||||||
@ -175,33 +181,48 @@ const saveForm = reactive({
|
|||||||
platform: [],
|
platform: [],
|
||||||
aiResult: [],
|
aiResult: [],
|
||||||
code: '',
|
code: '',
|
||||||
|
file_url: '',
|
||||||
});
|
});
|
||||||
const timerRef = ref<number | null>(null);
|
const timerRef = ref<number | null>(null);
|
||||||
const startTask = () => {
|
const startTask = () => {
|
||||||
if (timerRef.value !== null) return;
|
if (timerRef.value !== null) return;
|
||||||
timerRef.value = setInterval(async () => {
|
timerRef.value = setInterval(async () => {
|
||||||
try {
|
syncGetAiResult();
|
||||||
const { code, data } = await getAiResult(query);
|
|
||||||
console.log('定时任务执行结果:', data);
|
|
||||||
if (data.ai_result_status === AiResultStatus.SUCCESS || data.ai_result_status === AiResultStatus.FAILED) {
|
|
||||||
stopTask();
|
|
||||||
console.log('任务已完成,定时器已关闭');
|
|
||||||
}
|
|
||||||
if (data.ai_result_status === AiResultStatus.SUCCESS) {
|
|
||||||
loading.value = false;
|
|
||||||
aiResult.optimization = data.result?.optimization?.modules || [];
|
|
||||||
aiResult.action_guide = data.result?.action_guide?.modules || [];
|
|
||||||
aiResult.overview = data.result?.overview?.content_blocks[0] || [];
|
|
||||||
}
|
|
||||||
saveForm.code = data?.code;
|
|
||||||
console.log(aiResult, 'aiResult');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('定时任务执行出错:', error);
|
|
||||||
stopTask();
|
|
||||||
}
|
|
||||||
}, 5000);
|
}, 5000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const syncGetAiResult = async () => {
|
||||||
|
try {
|
||||||
|
const { code, data } = await getAiResult(query);
|
||||||
|
saveForm.file_url = '';
|
||||||
|
console.log('定时任务执行结果:', data);
|
||||||
|
if (data.ai_result_status === AiResultStatus.SUCCESS || data.ai_result_status === AiResultStatus.FAILED) {
|
||||||
|
stopTask();
|
||||||
|
console.log('任务已完成,定时器已关闭');
|
||||||
|
}
|
||||||
|
if (data.ai_result_status === AiResultStatus.SUCCESS) {
|
||||||
|
loading.value = false;
|
||||||
|
aiResult.optimization = data.result?.optimization?.modules || [];
|
||||||
|
aiResult.action_guide = data.result?.action_guide?.modules || [];
|
||||||
|
aiResult.overview = data.result?.overview?.content_blocks[0] || [];
|
||||||
|
} else if (data.ai_result_status === AiResultStatus.FAILED) {
|
||||||
|
Message.error('AI分析失败');
|
||||||
|
aiError();
|
||||||
|
}
|
||||||
|
saveForm.code = data?.code;
|
||||||
|
} catch (error) {
|
||||||
|
aiError();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ai 检测失败执行方法
|
||||||
|
const aiError = () => {
|
||||||
|
aiResult.optimization = [];
|
||||||
|
aiResult.action_guide = [];
|
||||||
|
aiResult.overview = [];
|
||||||
|
stopTask();
|
||||||
|
};
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
console.log('handleReset');
|
console.log('handleReset');
|
||||||
query.page = 1;
|
query.page = 1;
|
||||||
@ -226,6 +247,7 @@ onUnmounted(() => {
|
|||||||
stopTask();
|
stopTask();
|
||||||
});
|
});
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
|
await uploadPdf();
|
||||||
const updatedSaveForm = {
|
const updatedSaveForm = {
|
||||||
...saveForm,
|
...saveForm,
|
||||||
ai_result: aiResult,
|
ai_result: aiResult,
|
||||||
@ -235,6 +257,52 @@ const handleSave = async () => {
|
|||||||
Message.success(message);
|
Message.success(message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 上传pdf文件
|
||||||
|
const uploadPdf = async () => {
|
||||||
|
if (saveForm.file_url !== '') {
|
||||||
|
return saveForm.file_url;
|
||||||
|
}
|
||||||
|
const response = await fetchUploadFile({ suffix: 'pdf' });
|
||||||
|
const preSignedUrl = response?.data?.upload_url;
|
||||||
|
const fileUrl = response?.data?.file_url;
|
||||||
|
if (!preSignedUrl) {
|
||||||
|
throw new Error('未能获取有效的预签名上传地址');
|
||||||
|
}
|
||||||
|
saveForm.file_url = fileUrl;
|
||||||
|
const pdfBlob = await generatePDF(); // 生成 PDF Blob
|
||||||
|
console.log('pdfBlob', pdfBlob);
|
||||||
|
await axios.put(preSignedUrl, pdfBlob, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': pdfBlob.type,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return fileUrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generatePDF = async (): Promise<Blob> => {
|
||||||
|
await nextTick();
|
||||||
|
const sections = document.querySelectorAll('.guidelines-data-wrap');
|
||||||
|
const pdf = new jsPDF('p', 'mm', 'a4');
|
||||||
|
let position = 0;
|
||||||
|
for (const section of sections) {
|
||||||
|
if (section.children.length === 0) continue; // 跳过空内容区域
|
||||||
|
const canvas = await html2canvas(section as HTMLElement, {
|
||||||
|
ignoreElements: (element) => {
|
||||||
|
return element.classList.contains('ignore-export'); // 例如:忽略 class 为 ignore-export 的元素
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const imgData = canvas.toDataURL('image/png');
|
||||||
|
const imgProps = pdf.getImageProperties(imgData);
|
||||||
|
const pdfWidth = pdf.internal.pageSize.getWidth();
|
||||||
|
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
|
||||||
|
pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pdfHeight);
|
||||||
|
position += pdfHeight + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdf.output('blob');
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
onSearch();
|
onSearch();
|
||||||
});
|
});
|
||||||
@ -242,6 +310,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import './style.scss';
|
@import './style.scss';
|
||||||
|
|
||||||
.custom-spin-wrapper {
|
.custom-spin-wrapper {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
Reference in New Issue
Block a user