feat(property-marketing): 重构AI分析结果处理逻辑并优化页面交互
refactor(property-marketing): 拆分投放指南和历史指南组件逻辑 feat(property-marketing): 添加AI检测结果状态枚举 perf(property-marketing): 优化定时任务处理逻辑和错误处理 style(property-marketing): 调整页面样式和布局结构
This commit is contained in:
@ -147,6 +147,7 @@ const COMPONENTS: AppRouteRecordRaw[] = [
|
|||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
hideInMenu: true,
|
hideInMenu: true,
|
||||||
roles: ['*'],
|
roles: ['*'],
|
||||||
|
activeMenu: 'PutAccountInvestmentGuidelines',
|
||||||
},
|
},
|
||||||
component: () => import('@/views/property-marketing/put-account/investment-guidelines/detail'),
|
component: () => import('@/views/property-marketing/put-account/investment-guidelines/detail'),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -170,7 +170,6 @@ const getSubmoduleContent = (moduleName: string, submoduleName: string) => {
|
|||||||
const content = [];
|
const content = [];
|
||||||
if (module) {
|
if (module) {
|
||||||
const content = Object.values(module.content);
|
const content = Object.values(module.content);
|
||||||
console.log(content, 'content');
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
<a-popover position="tl">
|
<a-popover position="tl">
|
||||||
<icon-question-circle />
|
<icon-question-circle />
|
||||||
<template #content>
|
<template #content>
|
||||||
<p style="margin: 0">本月摘要。</p>
|
<p style="margin: 0">本月摘要2。</p>
|
||||||
</template>
|
</template>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -104,7 +104,7 @@ const downloadDetailAsImage = (id) => {
|
|||||||
};
|
};
|
||||||
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')
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
.container {
|
||||||
|
:deep(.arco-input-wrapper),
|
||||||
|
:deep(.arco-select-view-single),
|
||||||
|
:deep(.arco-select-view-multiple),
|
||||||
|
:deep(.arco-picker) {
|
||||||
|
border-radius: 4px;
|
||||||
|
border-color: #d7d7d9;
|
||||||
|
background-color: #fff;
|
||||||
|
&:focus-within,
|
||||||
|
&.arco-input-focus {
|
||||||
|
background-color: var(--color-bg-2);
|
||||||
|
border-color: rgb(var(--primary-6));
|
||||||
|
box-shadow: 0 0 0 0 var(--color-primary-light-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.search-btn) {
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||||
|
color: #6d4cfe;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.reset-btn) {
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--BG-500, #b1b2b5);
|
||||||
|
background: var(--BG-white, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-row {
|
||||||
|
.filter-row-item {
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-right: 8px;
|
||||||
|
color: #211f24;
|
||||||
|
font-family: 'PuHuiTi-Regular';
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
flex-shrink: 0;
|
||||||
|
line-height: 22px; /* 157.143% */
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-space-item) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,3 +19,11 @@ export function getStarIcon(score: number): string {
|
|||||||
return top1; // 默认返回最高分图标
|
return top1; // 默认返回最高分图标
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ai检测结果状态
|
||||||
|
export enum AiResultStatus {
|
||||||
|
WAIT = 0, // 待执行
|
||||||
|
PENDING = 1, // 处理中
|
||||||
|
FAILED = 2, // 失败
|
||||||
|
SUCCESS = 3, // 成功
|
||||||
|
}
|
||||||
|
|||||||
@ -49,33 +49,13 @@
|
|||||||
</a-row>
|
</a-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a-spin :loading="loading" tip="数据分析中">
|
|
||||||
<div>
|
<div>
|
||||||
<!-- 本月摘要-->
|
<MonthData :overview="aiResult.overview"></MonthData>
|
||||||
<MonthData></MonthData>
|
|
||||||
|
|
||||||
<!-- <!– 投放建议–>-->
|
<!-- 投放建议-->
|
||||||
<PlacementSuggestions :optimization="detailData?.ai_result?.optimization?.modules"></PlacementSuggestions>
|
<PlacementSuggestions :optimization="aiResult.optimization"></PlacementSuggestions>
|
||||||
<!-- <!– 投放行动指南–>-->
|
<!-- 投放行动指南-->
|
||||||
<ActionGuideDistribution :action_guide="detailData?.ai_result.action_guide?.modules"></ActionGuideDistribution>
|
<ActionGuideDistribution :action_guide="aiResult.action_guide"></ActionGuideDistribution>
|
||||||
</div>
|
|
||||||
</a-spin>
|
|
||||||
<div>
|
|
||||||
<a-space class="down-btn">
|
|
||||||
<a-button type="outline" @click="onSearch">
|
|
||||||
<template #icon>
|
|
||||||
<icon-download />
|
|
||||||
</template>
|
|
||||||
<template #default>下载</template>
|
|
||||||
</a-button>
|
|
||||||
<a-button type="primary" @click="handleSave">
|
|
||||||
<template #icon>
|
|
||||||
<icon-drive-file />
|
|
||||||
</template>
|
|
||||||
<template #default>保存</template>
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -90,54 +70,31 @@ import { PLATFORM_LIST } from '@/views/property-marketing/put-account/common_con
|
|||||||
import { getPlacementGuideDetail } from '@/api/all/propertyMarketing';
|
import { getPlacementGuideDetail } from '@/api/all/propertyMarketing';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
const tabData = ref('placement_guide');
|
const aiResult = reactive({
|
||||||
|
optimization: [], // 投放建议优化
|
||||||
const query = reactive({
|
action_guide: [], // 新投放建议生成
|
||||||
platform: '',
|
overview: [], // 新投放建议生成
|
||||||
date_time: '',
|
|
||||||
sort_column: '',
|
|
||||||
sort_order: '',
|
|
||||||
page_size: 20,
|
|
||||||
page: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleUpdateQuery = (payload) => {
|
|
||||||
payload.order = payload.order === 'ascend' ? 'asc' : 'desc';
|
|
||||||
query.sort_column = payload.column;
|
|
||||||
query.sort_order = payload.order;
|
|
||||||
};
|
|
||||||
|
|
||||||
const loading = ref(false);
|
|
||||||
|
|
||||||
const saveForm = reactive({
|
|
||||||
account: [],
|
|
||||||
plan: [],
|
|
||||||
platform: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const detailData = reactive({
|
const detailData = reactive({
|
||||||
|
created_at: '',
|
||||||
|
account: '',
|
||||||
platform: [],
|
platform: [],
|
||||||
ai_result: {},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const id = route.params.id;
|
const id = route.params.id;
|
||||||
const getDetail = async () => {
|
const getDetail = async () => {
|
||||||
const { code, data } = await getPlacementGuideDetail(id);
|
const { code, data } = await getPlacementGuideDetail(id);
|
||||||
console.log(data, 'data');
|
|
||||||
console.log(code, 'code');
|
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
|
Object.assign(aiResult, data.ai_result);
|
||||||
Object.assign(detailData, data);
|
Object.assign(detailData, data);
|
||||||
|
console.log(aiResult, 'aiResult');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getDetail();
|
getDetail();
|
||||||
});
|
});
|
||||||
// 定时任务请求接口
|
|
||||||
// const timer = setInterval(() => {
|
|
||||||
// getSyncAiResult();
|
|
||||||
// }, 5000);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@ -16,14 +16,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<!--表单组件搜索-->
|
<!--表单组件搜索-->
|
||||||
<listSearchForm v-model:query="query" @onSearch="onSearch"></listSearchForm>
|
<listSearchForm v-model:query="query" @onSearch="onSearch"></listSearchForm>
|
||||||
<!-- 投放指南-->
|
|
||||||
<PlacementGuideList
|
<component
|
||||||
v-if="tabData === 'placement_guide'"
|
:is="currentComponent"
|
||||||
:listData="listData.list"
|
:listData="tabData === 'placement_guide' ? placementGuideList : guideHistoryList"
|
||||||
|
@onSearch="onSearch"
|
||||||
@updateQuery="handleUpdateQuery"
|
@updateQuery="handleUpdateQuery"
|
||||||
></PlacementGuideList>
|
/>
|
||||||
<!-- 历史指南列表-->
|
|
||||||
<GuideListHistory v-if="tabData === 'guide_history'" :listData="listData.list"></GuideListHistory>
|
|
||||||
|
|
||||||
<div v-if="listData.total > 0" class="pagination-box flex justify-end">
|
<div v-if="listData.total > 0" class="pagination-box flex justify-end">
|
||||||
<a-pagination
|
<a-pagination
|
||||||
@ -40,14 +39,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="loading === false && tabData === 'placement_guide'">
|
<div v-if="tabData === 'placement_guide'">
|
||||||
|
<a-spin :loading="loading" tip="AI分析中">
|
||||||
<!-- 本月摘要-->
|
<!-- 本月摘要-->
|
||||||
<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" :tmp="tmp"></ActionGuideDistribution>
|
<ActionGuideDistribution :action_guide="aiResult.action_guide"></ActionGuideDistribution>
|
||||||
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="tabData == 'placement_guide'">
|
<div v-if="tabData == 'placement_guide'">
|
||||||
<a-space class="down-btn">
|
<a-space class="down-btn">
|
||||||
@ -84,6 +85,7 @@ 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 { AiResultStatus } from '@/views/property-marketing/put-account/investment-guidelines/constants';
|
||||||
|
|
||||||
const tabData = ref('placement_guide');
|
const tabData = ref('placement_guide');
|
||||||
|
|
||||||
@ -96,8 +98,9 @@ const query = reactive({
|
|||||||
page: 1,
|
page: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tmp = ref(0);
|
const currentComponent = computed(() => {
|
||||||
|
return tabData.value === 'placement_guide' ? PlacementGuideList : GuideListHistory;
|
||||||
|
});
|
||||||
const onPageChange = (current) => {
|
const onPageChange = (current) => {
|
||||||
query.page = current;
|
query.page = current;
|
||||||
onSearch();
|
onSearch();
|
||||||
@ -114,47 +117,41 @@ const handleUpdateQuery = (payload) => {
|
|||||||
onSearch();
|
onSearch();
|
||||||
};
|
};
|
||||||
|
|
||||||
const loading = ref(true);
|
const loading = ref(false);
|
||||||
|
|
||||||
const listData = reactive({
|
const listData = reactive({
|
||||||
list: [],
|
|
||||||
total: 0,
|
total: 0,
|
||||||
|
list: [],
|
||||||
});
|
});
|
||||||
|
const placementGuideList = ref([]); // 投放指南数据
|
||||||
|
const guideHistoryList = ref([]); // 历史投放指南数据
|
||||||
|
|
||||||
const onSearch = async () => {
|
const onSearch = async () => {
|
||||||
let result;
|
let result;
|
||||||
if (tabData.value === 'placement_guide') {
|
if (tabData.value === 'placement_guide') {
|
||||||
result = await getPlacementGuide(query);
|
result = await getPlacementGuide(query);
|
||||||
|
placementGuideList.value = result?.data?.data || [];
|
||||||
} else {
|
} else {
|
||||||
result = await getPlacementGuideHistory(query);
|
result = await getPlacementGuideHistory(query);
|
||||||
|
guideHistoryList.value = result?.data?.data || [];
|
||||||
}
|
}
|
||||||
const { code, data } = result;
|
listData.total = result.data.total;
|
||||||
console.log(data, 'data');
|
if (placementGuideList.value.length > 0) {
|
||||||
if (code === 200) {
|
loading.value = true;
|
||||||
listData.list = data.data;
|
startTask();
|
||||||
listData.total = data.total;
|
|
||||||
if (tabData.value === 'placement_guide') {
|
|
||||||
getSyncAiResult();
|
|
||||||
if (listData.list.length != 0) {
|
|
||||||
// 设置定时器每5秒执行一次
|
|
||||||
timer.value = setInterval(() => {
|
|
||||||
getSyncAiResult();
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const aiResult = reactive({
|
const aiResult = reactive({
|
||||||
optimization: [], //投放建议优化
|
optimization: [], // 投放建议优化
|
||||||
action_guide: [], //新投放建议生成
|
action_guide: [], // 新投放建议生成
|
||||||
overview: [], //新投放建议生成
|
overview: [], // 新投放建议生成
|
||||||
});
|
});
|
||||||
|
|
||||||
// 下载当前页面
|
// 下载当前页面
|
||||||
|
|
||||||
const downPage = async () => {
|
const downPage = async () => {
|
||||||
await nextTick(); // 确保 DOM 更新完成
|
await nextTick(); // 确保 DOM 更新完成
|
||||||
html2canvas(document.querySelector('.guidelines-data-wrap')).then(canvas => {
|
html2canvas(document.querySelector('.guidelines-data-wrap')).then((canvas) => {
|
||||||
const imgData = canvas.toDataURL('image/png');
|
const imgData = canvas.toDataURL('image/png');
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = imgData;
|
link.href = imgData;
|
||||||
@ -168,26 +165,44 @@ const saveForm = reactive({
|
|||||||
plan: [],
|
plan: [],
|
||||||
platform: [],
|
platform: [],
|
||||||
aiResult: [],
|
aiResult: [],
|
||||||
|
code: '',
|
||||||
});
|
});
|
||||||
const timer = ref<number | null>(null); // 定时器引用
|
const timerRef = ref<number | null>(null);
|
||||||
const getSyncAiResult = async () => {
|
|
||||||
if (listData.list.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { code, data } = await getAiResult(query);
|
|
||||||
if (code === 200) {
|
|
||||||
// 成功或者失败清除定时任务
|
|
||||||
if ((data.ai_result_status && data.ai_result_status === 3) || data.ai_result_status === 2) {
|
|
||||||
clearInterval(timer.value);
|
|
||||||
}
|
|
||||||
aiResult.optimization = data.result.optimization.modules;
|
|
||||||
aiResult.action_guide = data.result?.action_guide?.modules;
|
|
||||||
aiResult.overview = data.result?.overview?.content_blocks;
|
|
||||||
Object.assign(saveForm, data);
|
|
||||||
}
|
|
||||||
loading.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const startTask = () => {
|
||||||
|
if (timerRef.value !== null) return;
|
||||||
|
timerRef.value = setInterval(async () => {
|
||||||
|
try {
|
||||||
|
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 || [];
|
||||||
|
}
|
||||||
|
saveForm.code = data?.code;
|
||||||
|
console.log(aiResult, 'aiResult');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('定时任务执行出错:', error);
|
||||||
|
stopTask();
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
};
|
||||||
|
const stopTask = () => {
|
||||||
|
if (timerRef.value !== null) {
|
||||||
|
clearInterval(timerRef.value); // 清除定时器
|
||||||
|
timerRef.value = null; // 重置引用
|
||||||
|
console.log('定时器已停止');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
onUnmounted(() => {
|
||||||
|
stopTask();
|
||||||
|
});
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
const updatedSaveForm = {
|
const updatedSaveForm = {
|
||||||
...saveForm,
|
...saveForm,
|
||||||
|
|||||||
@ -1,3 +1,15 @@
|
|||||||
|
|
||||||
|
.table-wrap {
|
||||||
|
width: 100%;
|
||||||
|
.pagination-box {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px 24px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.part-div {
|
.part-div {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--BG-white, white);
|
background: var(--BG-white, white);
|
||||||
|
|||||||
Reference in New Issue
Block a user