diff --git a/config/unplugin/auto-import.ts b/config/unplugin/auto-import.ts
index 1036483..a6244c8 100644
--- a/config/unplugin/auto-import.ts
+++ b/config/unplugin/auto-import.ts
@@ -21,7 +21,7 @@ export function configAutoImport() {
'@vueuse/core',
{
dayjs: [['default', 'dayjs']],
- 'lodash-es': ['cloneDeep', 'omit', 'pick', 'union', 'isNumber'],
+ 'lodash-es': ['cloneDeep', 'omit', 'pick', 'union', 'isNumber', 'isEmpty'],
'@/hooks': ['useModal'],
},
],
diff --git a/src/components/upload/ImageUpload.vue b/src/components/upload/ImageUpload.vue
index 0054575..9a0be66 100644
--- a/src/components/upload/ImageUpload.vue
+++ b/src/components/upload/ImageUpload.vue
@@ -75,7 +75,6 @@ let previousFileListLength = 0;
//删除图片
const onChange = (fileList) => {
if (fileList.length < previousFileListLength) {
- // 在这里执行你需要的操作
if (props.limit === 1) {
if (fileList.length === 0) {
emit('update:modelValue', '');
@@ -90,7 +89,6 @@ const onChange = (fileList) => {
}
}
- // 更新上一次的文件列表长度
previousFileListLength = fileList.length;
};
diff --git a/src/views/property-marketing/put-account/investment-guidelines/components/month-data/index.vue b/src/views/property-marketing/put-account/investment-guidelines/components/month-data/index.vue
index b99e439..6a2e1ed 100644
--- a/src/views/property-marketing/put-account/investment-guidelines/components/month-data/index.vue
+++ b/src/views/property-marketing/put-account/investment-guidelines/components/month-data/index.vue
@@ -1,11 +1,11 @@
diff --git a/src/views/property-marketing/put-account/investment-guidelines/components/placement-suggestions/index.vue b/src/views/property-marketing/put-account/investment-guidelines/components/placement-suggestions/index.vue
index 4798c52..515cefe 100644
--- a/src/views/property-marketing/put-account/investment-guidelines/components/placement-suggestions/index.vue
+++ b/src/views/property-marketing/put-account/investment-guidelines/components/placement-suggestions/index.vue
@@ -6,7 +6,7 @@
- 投放建议优化。
+ 基于筛选出来的投流账户/计划的情况生成的优化建议。
@@ -15,7 +15,15 @@
-
总体策略
+
总体策略
+
+
+
+ 优化建议的整体调整概述。
+
+
+
{{ props.optimization?.[0]?.['content'] }}
@@ -23,13 +31,29 @@
-
预算分配
+
预算分配
+
+
+
+ 优化建议在预算分配部分的详细描述。
+
+
+
{{ props.optimization?.[1]?.['content'] }}
-
时段优化
+
时段优化
+
+
+
+ 优化建议在时段优化部分的详细描述。
+
+
+
{{ props.optimization?.[2]?.['content'] }}
@@ -37,13 +61,29 @@
-
人群包优化
+
人群包优化
+
+
+
+ 优化建议在人群包优化部分的详细描述。
+
+
+
{{ props?.optimization?.[3]?.['content'] }}
-
素材优化
+
素材优化
+
+
+
+ 优化建议在素材优化部分的详细描述。
+
+
+
{{ props?.optimization?.[4]?.['content'] }}
diff --git a/src/views/property-marketing/put-account/investment-guidelines/components/table-data/placementGuideList.vue b/src/views/property-marketing/put-account/investment-guidelines/components/table-data/placementGuideList.vue
index ebd2c5b..12db503 100644
--- a/src/views/property-marketing/put-account/investment-guidelines/components/table-data/placementGuideList.vue
+++ b/src/views/property-marketing/put-account/investment-guidelines/components/table-data/placementGuideList.vue
@@ -13,7 +13,7 @@
- 本周总消耗
+ 当前周内所有投流账户的累计广告花费,反映整体投放规模。
@@ -24,7 +24,7 @@
- 本周总消耗环比
+ 本周消耗金额与上周对比的变化百分比,用于衡量预算投放趋势。
@@ -35,7 +35,7 @@
- ROI
+ 投资回报率(ROI)= 收益 ÷ 投入成本,反映整体投流账户的收益效率。
@@ -46,7 +46,7 @@
- CTR
+ 点击率(CTR)= 点击量 ÷ 展示量,是衡量广告素材吸引力的关键指标。
diff --git a/src/views/property-marketing/put-account/investment-guidelines/constants.ts b/src/views/property-marketing/put-account/investment-guidelines/constants.ts
index 2a33f99..cbec9c3 100644
--- a/src/views/property-marketing/put-account/investment-guidelines/constants.ts
+++ b/src/views/property-marketing/put-account/investment-guidelines/constants.ts
@@ -1,6 +1,10 @@
import top1 from '@/assets/img/captcha/top1.svg';
import top2 from '@/assets/img/captcha/top2.svg';
import top3 from '@/assets/img/captcha/top3.svg';
+import { fetchUploadFile } from '@/api/all';
+import { jsPDF } from 'jspdf';
+import html2canvas from 'html2canvas';
+import axios from 'axios';
/**
* 根据评分获取对应的星星图标路径
@@ -27,3 +31,49 @@ export enum AiResultStatus {
FAILED = 2, // 失败
SUCCESS = 3, // 成功
}
+
+/**
+ * 将指定 DOM 元素导出为 PDF Blob
+ * @param elementSelector - 要导出的 DOM 元素选择器
+ */
+export const generatePDF = async (elementSelector: string): Promise => {
+ const sections = document.querySelectorAll(elementSelector);
+ const pdf = new jsPDF('p', 'mm', 'a4');
+ let position = 0;
+ for (const section of sections) {
+ if ((section as HTMLElement).children.length === 0) continue;
+ const canvas = await html2canvas(section as HTMLElement, {
+ ignoreElements: (element) => element.classList.contains('ignore-export'),
+ scale: 2,
+ useCORS: true,
+ });
+ 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');
+};
+
+/**
+ * 上传 PDF 并返回文件 URL
+ * @param fileName - PDF 文件名
+ * @param elementSelector - 要导出的 DOM 元素选择器
+ */
+export const uploadPdf = async (fileName: string, elementSelector: string): Promise => {
+ const response = await fetchUploadFile({ suffix: 'pdf' });
+ const preSignedUrl = response?.data?.upload_url;
+ const fileUrl = response?.data?.file_url;
+ if (!preSignedUrl) {
+ throw new Error('未能获取有效的预签名上传地址');
+ }
+ const pdfBlob = await generatePDF(elementSelector);
+ await axios.put(preSignedUrl, pdfBlob, {
+ headers: {
+ 'Content-Type': pdfBlob.type,
+ },
+ });
+ return fileUrl;
+};
diff --git a/src/views/property-marketing/put-account/investment-guidelines/detail.vue b/src/views/property-marketing/put-account/investment-guidelines/detail.vue
index 010355f..152e111 100644
--- a/src/views/property-marketing/put-account/investment-guidelines/detail.vue
+++ b/src/views/property-marketing/put-account/investment-guidelines/detail.vue
@@ -54,8 +54,16 @@
-
-
+
+
@@ -65,17 +73,18 @@ import { reactive, ref } from 'vue';
import MonthData from './components/month-data/index.vue';
import PlacementSuggestions from './components/placement-suggestions/index.vue';
-import ActionGuideDistribution from './components/action-guide-distribution';
import { PLATFORM_LIST } from '@/views/property-marketing/put-account/common_constants.ts';
import { getPlacementGuideDetail } from '@/api/all/propertyMarketing';
import { useRoute } from 'vue-router';
+import { uploadPdf } from '@/views/property-marketing/put-account/investment-guidelines/constants';
+import { Message } from '@arco-design/web-vue';
const aiResult = reactive({
optimization: [], // 投放建议优化
action_guide: [], // 新投放建议生成
overview: [], // 新投放建议生成
});
-
+const fileUrl = ref('');
const detailData = reactive({
created_at: '',
account: '',
@@ -92,6 +101,27 @@ const getDetail = async () => {
}
};
+const exportLoading = ref(false);
+const downPage = async () => {
+ try {
+ let downFileUrl = fileUrl.value;
+ exportLoading.value = true;
+ if (downFileUrl === '') {
+ downFileUrl = await uploadPdf('投放指南.pdf', '.guidelines-data-wrap');
+ fileUrl.value = downFileUrl;
+ }
+ const link = document.createElement('a');
+ link.href = downFileUrl;
+ link.download = '投放指南.pdf';
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ exportLoading.value = false;
+ } catch (error) {
+ Message.error(error.message);
+ exportLoading.value = false;
+ }
+};
onMounted(() => {
getDetail();
});
diff --git a/src/views/property-marketing/put-account/investment-guidelines/index.vue b/src/views/property-marketing/put-account/investment-guidelines/index.vue
index a1f079a..709f2d9 100644
--- a/src/views/property-marketing/put-account/investment-guidelines/index.vue
+++ b/src/views/property-marketing/put-account/investment-guidelines/index.vue
@@ -10,7 +10,7 @@
>
- 历史投放指南
+ 历史指南列表
@@ -30,7 +30,7 @@
@updateQuery="handleUpdateQuery"
/>
-