2025-06-27 16:26:03 +08:00
|
|
|
<template>
|
2025-07-07 20:59:54 +08:00
|
|
|
<div class="guidelines-data-wrap">
|
2025-06-27 16:26:03 +08:00
|
|
|
<div class="part-div">
|
|
|
|
|
<div>
|
2025-09-04 16:10:44 +08:00
|
|
|
<Tabs
|
2025-07-07 20:59:54 +08:00
|
|
|
v-model:activeKey="tabData"
|
2025-09-04 16:10:44 +08:00
|
|
|
@change="onSearch"
|
2025-07-09 14:24:09 +08:00
|
|
|
class="a-tab-class ignore-export"
|
2025-09-04 16:10:44 +08:00
|
|
|
defaultActiveKey="placement_guide"
|
|
|
|
|
size="large"
|
2025-07-07 20:59:54 +08:00
|
|
|
>
|
2025-09-04 16:10:44 +08:00
|
|
|
<TabPane key="placement_guide" tab="投放指南"></TabPane>
|
|
|
|
|
<TabPane key="guide_history" tab="历史指南列表"></TabPane>
|
|
|
|
|
</Tabs>
|
2025-06-27 16:26:03 +08:00
|
|
|
</div>
|
2025-07-10 15:35:58 +08:00
|
|
|
<!--表单组件搜索-->
|
2025-07-08 20:05:26 +08:00
|
|
|
<listSearchForm
|
2025-07-09 14:24:09 +08:00
|
|
|
class="ignore-export"
|
2025-07-08 20:05:26 +08:00
|
|
|
@onReset="handleReset"
|
|
|
|
|
v-model:query="query"
|
2025-07-17 10:00:00 +08:00
|
|
|
@onSearch="handleSearch"
|
2025-07-08 20:05:26 +08:00
|
|
|
:disabled="loading"
|
|
|
|
|
></listSearchForm>
|
2025-07-08 16:55:03 +08:00
|
|
|
|
|
|
|
|
<component
|
|
|
|
|
:is="currentComponent"
|
|
|
|
|
:listData="tabData === 'placement_guide' ? placementGuideList : guideHistoryList"
|
|
|
|
|
@onSearch="onSearch"
|
2025-07-07 20:59:54 +08:00
|
|
|
@updateQuery="handleUpdateQuery"
|
2025-07-08 16:55:03 +08:00
|
|
|
/>
|
2025-07-17 10:00:00 +08:00
|
|
|
<a-spin v-if="loading" tip="AI分析中" />
|
2025-07-07 20:59:54 +08:00
|
|
|
|
2025-07-09 15:15:16 +08:00
|
|
|
<div v-if="listData.total > 0" class="pagination-box flex justify-end ignore-export">
|
2025-09-04 23:30:41 +08:00
|
|
|
<Pagination
|
2025-07-07 20:59:54 +08:00
|
|
|
:total="listData.total"
|
2025-09-04 23:30:41 +08:00
|
|
|
size="small"
|
|
|
|
|
:showTotal="(total: number) => `共 ${total} 条`"
|
|
|
|
|
showSizeChanger
|
|
|
|
|
showQuickJumper
|
2025-07-07 20:59:54 +08:00
|
|
|
:current="query.page"
|
2025-09-04 23:30:41 +08:00
|
|
|
:pageSize="query.page_size"
|
2025-07-07 20:59:54 +08:00
|
|
|
@change="onPageChange"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2025-06-27 16:26:03 +08:00
|
|
|
</div>
|
2025-07-17 10:00:00 +08:00
|
|
|
|
2025-07-10 16:49:33 +08:00
|
|
|
<!-- 投放建议-->
|
2025-07-10 17:16:44 +08:00
|
|
|
<MonthData v-if="tabData == 'placement_guide'" :overview="aiResult.overview"></MonthData>
|
2025-07-17 10:00:00 +08:00
|
|
|
<PlacementSuggestions
|
|
|
|
|
v-if="tabData == 'placement_guide'"
|
|
|
|
|
:optimization="aiResult.optimization"
|
|
|
|
|
></PlacementSuggestions>
|
2025-07-10 16:49:33 +08:00
|
|
|
|
2025-07-09 14:24:09 +08:00
|
|
|
<div v-if="tabData == 'placement_guide'" class="ignore-export">
|
2025-09-04 16:50:20 +08:00
|
|
|
<Space class="down-btn">
|
2025-09-03 11:15:37 +08:00
|
|
|
<Button type="primary" ghost :loading="exportLoading" @click="downPage">
|
2025-06-27 16:26:03 +08:00
|
|
|
<template #icon>
|
2025-09-03 11:15:37 +08:00
|
|
|
<icon-download class="mr-8px"/>
|
2025-06-27 16:26:03 +08:00
|
|
|
</template>
|
|
|
|
|
<template #default>下载</template>
|
2025-09-03 11:15:37 +08:00
|
|
|
</Button>
|
|
|
|
|
<Button type="primary" @click="handleSave">
|
2025-06-27 16:26:03 +08:00
|
|
|
<template #icon>
|
2025-09-03 11:15:37 +08:00
|
|
|
<icon-drive-file class="mr-8px"/>
|
2025-06-27 16:26:03 +08:00
|
|
|
</template>
|
|
|
|
|
<template #default>保存</template>
|
2025-09-03 11:15:37 +08:00
|
|
|
</Button>
|
2025-09-04 16:50:20 +08:00
|
|
|
</Space>
|
2025-06-27 16:26:03 +08:00
|
|
|
</div>
|
2025-07-07 20:59:54 +08:00
|
|
|
</div>
|
2025-06-27 16:26:03 +08:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { reactive, ref } from 'vue';
|
2025-09-04 23:30:41 +08:00
|
|
|
import { Button, Tabs, Space, Pagination } from 'ant-design-vue';
|
2025-09-04 16:10:44 +08:00
|
|
|
const { TabPane } = Tabs;
|
2025-06-27 16:26:03 +08:00
|
|
|
import PlacementGuideList from './components/table-data/placementGuideList.vue';
|
|
|
|
|
import listSearchForm from './components/table-data/listSearchForm.vue';
|
|
|
|
|
import GuideListHistory from './components/table-data/guideListHistory.vue';
|
|
|
|
|
import MonthData from './components/month-data/index.vue';
|
|
|
|
|
import PlacementSuggestions from './components/placement-suggestions/index.vue';
|
2025-07-04 10:35:16 +08:00
|
|
|
import {
|
|
|
|
|
getAiResult,
|
|
|
|
|
getPlacementGuide,
|
2025-07-07 20:59:54 +08:00
|
|
|
getPlacementGuideHistory,
|
|
|
|
|
savePlacementGuide,
|
2025-07-04 10:35:16 +08:00
|
|
|
} from '@/api/all/propertyMarketing';
|
2025-07-07 21:37:27 +08:00
|
|
|
import { Message } from '@arco-design/web-vue';
|
2025-07-10 16:49:33 +08:00
|
|
|
import { AiResultStatus, generatePDF } from '@/views/property-marketing/put-account/investment-guidelines/constants';
|
2025-07-09 15:15:16 +08:00
|
|
|
import { uploadPdf } from '@/views/property-marketing/put-account/investment-guidelines/constants';
|
2025-06-27 16:26:03 +08:00
|
|
|
|
|
|
|
|
const tabData = ref('placement_guide');
|
|
|
|
|
|
2025-07-04 10:35:16 +08:00
|
|
|
const query = reactive({
|
2025-09-04 12:07:18 +08:00
|
|
|
platform: undefined,
|
2025-07-08 20:05:26 +08:00
|
|
|
date_time: [],
|
2025-07-10 15:24:11 +08:00
|
|
|
placement_account_id: [],
|
|
|
|
|
placement_account_project_id: [],
|
2025-07-07 20:59:54 +08:00
|
|
|
sort_column: '',
|
|
|
|
|
sort_order: '',
|
|
|
|
|
page_size: 20,
|
|
|
|
|
page: 1,
|
2025-06-27 16:26:03 +08:00
|
|
|
});
|
2025-07-04 10:35:16 +08:00
|
|
|
|
2025-07-08 16:55:03 +08:00
|
|
|
const currentComponent = computed(() => {
|
|
|
|
|
return tabData.value === 'placement_guide' ? PlacementGuideList : GuideListHistory;
|
|
|
|
|
});
|
2025-09-04 23:30:41 +08:00
|
|
|
const onPageChange = (current: number, pageSize: number) => {
|
2025-07-07 20:59:54 +08:00
|
|
|
query.page = current;
|
2025-09-04 23:30:41 +08:00
|
|
|
query.page_size = pageSize;
|
2025-07-07 20:59:54 +08:00
|
|
|
onSearch();
|
|
|
|
|
};
|
|
|
|
|
const onPageSizeChange = (pageSize) => {
|
|
|
|
|
query.page_size = pageSize;
|
|
|
|
|
onSearch();
|
|
|
|
|
};
|
2025-07-08 20:05:26 +08:00
|
|
|
const isGetAi = ref(true); // 是否获取AI数据
|
2025-07-07 20:59:54 +08:00
|
|
|
const handleUpdateQuery = (payload) => {
|
|
|
|
|
payload.order = payload.order === 'ascend' ? 'asc' : 'desc';
|
|
|
|
|
query.sort_column = payload.column;
|
|
|
|
|
query.sort_order = payload.order;
|
2025-07-08 20:05:26 +08:00
|
|
|
isGetAi.value = false;
|
2025-07-09 14:24:09 +08:00
|
|
|
loading.value = false;
|
2025-07-07 20:59:54 +08:00
|
|
|
onSearch();
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-08 16:55:03 +08:00
|
|
|
const loading = ref(false);
|
2025-07-09 15:15:16 +08:00
|
|
|
const exportLoading = ref(false);
|
2025-07-07 20:59:54 +08:00
|
|
|
const listData = reactive({
|
2025-07-06 18:27:51 +08:00
|
|
|
total: 0,
|
2025-07-08 16:55:03 +08:00
|
|
|
list: [],
|
2025-07-04 10:35:16 +08:00
|
|
|
});
|
2025-07-08 16:55:03 +08:00
|
|
|
const placementGuideList = ref([]); // 投放指南数据
|
|
|
|
|
const guideHistoryList = ref([]); // 历史投放指南数据
|
2025-07-04 10:35:16 +08:00
|
|
|
|
2025-07-06 18:27:51 +08:00
|
|
|
const onSearch = async () => {
|
2025-07-07 20:59:54 +08:00
|
|
|
let result;
|
|
|
|
|
if (tabData.value === 'placement_guide') {
|
|
|
|
|
result = await getPlacementGuide(query);
|
2025-07-17 10:00:00 +08:00
|
|
|
console.log(1);
|
|
|
|
|
|
2025-07-08 16:55:03 +08:00
|
|
|
placementGuideList.value = result?.data?.data || [];
|
2025-07-07 20:59:54 +08:00
|
|
|
} else {
|
|
|
|
|
result = await getPlacementGuideHistory(query);
|
2025-07-08 16:55:03 +08:00
|
|
|
guideHistoryList.value = result?.data?.data || [];
|
2025-07-07 20:59:54 +08:00
|
|
|
}
|
2025-07-08 16:55:03 +08:00
|
|
|
listData.total = result.data.total;
|
2025-07-08 20:05:26 +08:00
|
|
|
isGetAi.value = true;
|
2025-07-04 10:35:16 +08:00
|
|
|
};
|
2025-07-17 10:00:00 +08:00
|
|
|
|
|
|
|
|
const handleSearch = async () => {
|
|
|
|
|
await onSearch();
|
|
|
|
|
if (placementGuideList.value.length > 0 && isGetAi.value) {
|
|
|
|
|
loading.value = true;
|
|
|
|
|
syncGetAiResult();
|
|
|
|
|
startTask();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-07-06 18:27:51 +08:00
|
|
|
const aiResult = reactive({
|
2025-07-08 16:55:03 +08:00
|
|
|
optimization: [], // 投放建议优化
|
|
|
|
|
action_guide: [], // 新投放建议生成
|
|
|
|
|
overview: [], // 新投放建议生成
|
2025-07-06 18:27:51 +08:00
|
|
|
});
|
|
|
|
|
|
2025-07-07 21:37:27 +08:00
|
|
|
// 下载当前页面
|
|
|
|
|
const downPage = async () => {
|
2025-07-09 15:15:16 +08:00
|
|
|
try {
|
|
|
|
|
let fileUrl = saveForm.file_url;
|
|
|
|
|
exportLoading.value = true;
|
|
|
|
|
if (saveForm.file_url === '') {
|
2025-07-10 16:49:33 +08:00
|
|
|
fileUrl = await uploadPdf('投放指南.pdf', '.guidelines-data-wrap');
|
2025-07-09 15:15:16 +08:00
|
|
|
}
|
|
|
|
|
console.log(fileUrl, 'fileUrl');
|
|
|
|
|
const link = document.createElement('a');
|
|
|
|
|
link.href = fileUrl;
|
|
|
|
|
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;
|
|
|
|
|
}
|
2025-07-07 21:37:27 +08:00
|
|
|
};
|
2025-07-09 15:15:16 +08:00
|
|
|
|
2025-07-07 20:59:54 +08:00
|
|
|
const saveForm = reactive({
|
|
|
|
|
account: [],
|
|
|
|
|
plan: [],
|
|
|
|
|
platform: [],
|
|
|
|
|
aiResult: [],
|
2025-07-08 16:55:03 +08:00
|
|
|
code: '',
|
2025-07-09 14:24:09 +08:00
|
|
|
file_url: '',
|
2025-07-07 20:59:54 +08:00
|
|
|
});
|
2025-07-08 16:55:03 +08:00
|
|
|
const timerRef = ref<number | null>(null);
|
|
|
|
|
const startTask = () => {
|
|
|
|
|
if (timerRef.value !== null) return;
|
|
|
|
|
timerRef.value = setInterval(async () => {
|
2025-07-09 14:24:09 +08:00
|
|
|
syncGetAiResult();
|
|
|
|
|
}, 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) {
|
2025-07-08 16:55:03 +08:00
|
|
|
stopTask();
|
2025-07-04 10:35:16 +08:00
|
|
|
}
|
2025-07-09 14:24:09 +08:00
|
|
|
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();
|
2025-07-08 16:55:03 +08:00
|
|
|
};
|
2025-07-08 20:05:26 +08:00
|
|
|
|
|
|
|
|
const handleReset = () => {
|
|
|
|
|
console.log('handleReset');
|
|
|
|
|
query.page = 1;
|
|
|
|
|
query.page_size = 20;
|
|
|
|
|
query.platform = '';
|
|
|
|
|
query.sort_column = '';
|
|
|
|
|
query.sort_order = '';
|
2025-09-04 12:07:18 +08:00
|
|
|
query.platform = undefined;
|
2025-07-08 20:05:26 +08:00
|
|
|
query.date_time = [];
|
|
|
|
|
onSearch();
|
|
|
|
|
};
|
2025-07-08 16:55:03 +08:00
|
|
|
const stopTask = () => {
|
2025-07-08 20:05:26 +08:00
|
|
|
loading.value = false;
|
2025-07-08 16:55:03 +08:00
|
|
|
if (timerRef.value !== null) {
|
|
|
|
|
clearInterval(timerRef.value); // 清除定时器
|
|
|
|
|
timerRef.value = null; // 重置引用
|
|
|
|
|
console.log('定时器已停止');
|
2025-07-07 20:59:54 +08:00
|
|
|
}
|
|
|
|
|
};
|
2025-07-08 16:55:03 +08:00
|
|
|
onUnmounted(() => {
|
|
|
|
|
stopTask();
|
|
|
|
|
});
|
2025-07-07 20:59:54 +08:00
|
|
|
const handleSave = async () => {
|
2025-07-09 14:24:09 +08:00
|
|
|
await uploadPdf();
|
2025-07-07 20:59:54 +08:00
|
|
|
const updatedSaveForm = {
|
|
|
|
|
...saveForm,
|
|
|
|
|
ai_result: aiResult,
|
|
|
|
|
};
|
2025-07-07 21:37:27 +08:00
|
|
|
const { code, message, data } = await savePlacementGuide(updatedSaveForm);
|
2025-07-07 20:59:54 +08:00
|
|
|
if (code === 200) {
|
2025-07-07 21:37:27 +08:00
|
|
|
Message.success(message);
|
2025-07-04 10:35:16 +08:00
|
|
|
}
|
|
|
|
|
};
|
2025-07-09 14:24:09 +08:00
|
|
|
|
2025-07-07 20:59:54 +08:00
|
|
|
onMounted(() => {
|
|
|
|
|
onSearch();
|
|
|
|
|
});
|
2025-06-27 16:26:03 +08:00
|
|
|
</script>
|
|
|
|
|
|
2025-06-30 11:36:11 +08:00
|
|
|
<style lang="scss">
|
|
|
|
|
@import './style.scss';
|
|
|
|
|
</style>
|