feat(property-marketing): 重构月度数据展示组件并优化AI分析交互流程
This commit is contained in:
@ -11,20 +11,11 @@
|
||||
</div>
|
||||
<div class="month-data-div">
|
||||
<div style="align-self: stretch">
|
||||
<a-space direction="vertical" v-for="(item, index) in overview">
|
||||
<span :style="{ color: getColor(item?.highlight) }">{{ item.text }}</span>
|
||||
<br />
|
||||
<a-space direction="vertical">
|
||||
<span v-for="(line, index) in formattedText" :key="index" :class="getCss(line.highlight)" >
|
||||
{{ line.text }}
|
||||
</span>
|
||||
</a-space>
|
||||
<!-- <span class="month-text-black">总消耗:</span>-->
|
||||
<!-- <span class="month-text-blue">¥52,382.16</span>-->
|
||||
<!-- <span class="month-normal-span">,较上周期</span><span class="month-text-red">↑12.6%</span>-->
|
||||
<!-- <span class="month-normal-span">;<br />整体ROI:</span><span class="month-text-blue">2.84</span>-->
|
||||
<!-- <span class="month-normal-span">,属于</span><span class="month-text-red">中等偏高水平</span>-->
|
||||
<!-- <span class="month-text-black">,较上周期 </span><span class="month-text-red">+0.45</span>-->
|
||||
<!-- <span class="month-normal-span">;<br />主要转化来源:</span><span class="month-text-blue">抖音 46.3%</span>-->
|
||||
<!-- <span class="month-normal-span">,CTR 2.91%;<br />优质素材表现:</span>-->
|
||||
<!-- <span class="month-text-blue">美团酒店爆款横版1号</span>-->
|
||||
<!-- <span class="month-normal-spanw">。CTR 3.47%,CVR 5.92%。</span>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -34,20 +25,48 @@
|
||||
import { IconQuestionCircle } from '@arco-design/web-vue/es/icon';
|
||||
import { defineProps } from 'vue';
|
||||
|
||||
const colorMap = {
|
||||
purple: 'purple',
|
||||
orange: 'orange',
|
||||
};
|
||||
const props = defineProps({
|
||||
overview: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
type: Object,
|
||||
default: () => ({
|
||||
text: '',
|
||||
parts: [],
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const getColor = (highlight?: string) => {
|
||||
return highlight ? colorMap[highlight] : undefined;
|
||||
const classMap = {
|
||||
purple: 'month-text-blue',
|
||||
black: 'month-text-black',
|
||||
orange: 'orange',
|
||||
red: 'month-text-red',
|
||||
};
|
||||
|
||||
const formattedText = computed(() => {
|
||||
console.log(props.overview, 'props.overview');
|
||||
const { text, parts } = props.overview;
|
||||
if (!text || !parts) return [];
|
||||
|
||||
// 替换占位符
|
||||
let resultText = text;
|
||||
parts.forEach((part) => {
|
||||
const key = Object.keys(part)[0];
|
||||
resultText = resultText.replace(`{${key}}`, part[key]);
|
||||
});
|
||||
|
||||
// 按分号拆分并保留颜色信息
|
||||
return resultText.split(';').map((line) => {
|
||||
const matchedPart = parts.find((part) => line.includes(part[Object.keys(part)[0]]));
|
||||
return {
|
||||
text: line.trim(),
|
||||
highlight: matchedPart?.highlight || 'black',
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const getCss = (highlight?: string) => {
|
||||
return highlight ? classMap[highlight] : undefined;
|
||||
};
|
||||
|
||||
console.log(props.overview, 'overvie333');
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
@ -33,14 +33,7 @@
|
||||
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">平台</span>
|
||||
<a-select
|
||||
v-model="query.platform"
|
||||
class="w-150"
|
||||
size="medium"
|
||||
placeholder="全部"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-select v-model="query.platform" class="w-150" size="medium" placeholder="全部" allow-clear>
|
||||
<a-option v-for="(item, index) in PLATFORM_LIST" :key="index" :value="item.value" :label="item.label"
|
||||
>{{ item.label }}
|
||||
</a-option>
|
||||
@ -83,6 +76,10 @@ const props = defineProps({
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
||||
// 获取最近7天的日期
|
||||
@ -100,6 +97,10 @@ const localQuery = computed({
|
||||
get: () => props.query,
|
||||
set: (value) => emits('update:query', value),
|
||||
});
|
||||
|
||||
const handleReset = () => {
|
||||
emits('onReset');
|
||||
};
|
||||
onMounted(() => {
|
||||
localQuery.value.data_time = getLast7Days();
|
||||
});
|
||||
|
||||
@ -61,15 +61,15 @@
|
||||
|
||||
<template #weekConsumptionRate="{ record }">
|
||||
<a-statistic
|
||||
:value="record.week_consumption_rate * 100"
|
||||
:value="record.pre_total_use_amount_chain * 100"
|
||||
:value-style="{
|
||||
color: record.week_consumption_rate > 0 ? '#F64B31' : '#25C883',
|
||||
color: record.pre_total_use_amount_chain > 0 ? '#F64B31' : '#25C883',
|
||||
fontStyle: 'normal',
|
||||
fontSize: '14px',
|
||||
}"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-arrow-rise v-if="record.week_consumption_rate > 0" />
|
||||
<icon-arrow-rise v-if="record.pre_total_use_amount_chain > 0" />
|
||||
<icon-arrow-down v-else />
|
||||
</template>
|
||||
<template #suffix>%</template>
|
||||
@ -91,7 +91,7 @@ const props = defineProps({
|
||||
default: () => {
|
||||
data: [];
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['updateQuery']);
|
||||
@ -99,13 +99,7 @@ const emit = defineEmits(['updateQuery']);
|
||||
const handleSorterChange = (column, order) => {
|
||||
emit('updateQuery', { column, order });
|
||||
};
|
||||
const listQuery = reactive({
|
||||
project_id: ref(''),
|
||||
platform: ref(''),
|
||||
page: ref(1),
|
||||
name: ref(''),
|
||||
page_size: ref('10'),
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '账户名称',
|
||||
@ -139,7 +133,7 @@ const columns = [
|
||||
{
|
||||
title: '本周总消耗环比',
|
||||
titleSlotName: 'weekConsumptionRateTitle',
|
||||
dataIndex: 'week_consumption_rate',
|
||||
dataIndex: 'pre_total_use_amount_chain',
|
||||
width: 120,
|
||||
minWidth: 120,
|
||||
slotName: 'weekConsumptionRate',
|
||||
|
||||
@ -15,7 +15,12 @@
|
||||
</a-tabs>
|
||||
</div>
|
||||
<!--表单组件搜索-->
|
||||
<listSearchForm v-model:query="query" @onSearch="onSearch"></listSearchForm>
|
||||
<listSearchForm
|
||||
@onReset="handleReset"
|
||||
v-model:query="query"
|
||||
@onSearch="onSearch"
|
||||
:disabled="loading"
|
||||
></listSearchForm>
|
||||
|
||||
<component
|
||||
:is="currentComponent"
|
||||
@ -38,14 +43,17 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<a-spin v-if="tabData === 'placement_guide'" :loading="loading" tip="AI分析中...." wrapperClassName="custom-spin-wrapper">
|
||||
<div >
|
||||
|
||||
<div v-if="tabData === 'placement_guide'">
|
||||
<MonthData :overview="aiResult.overview"></MonthData>
|
||||
<!-- 投放建议-->
|
||||
<PlacementSuggestions :optimization="aiResult.optimization"></PlacementSuggestions>
|
||||
<!-- 投放行动指南-->
|
||||
<ActionGuideDistribution :action_guide="aiResult.action_guide"></ActionGuideDistribution>
|
||||
</div>
|
||||
|
||||
</a-spin>
|
||||
<div v-if="tabData == 'placement_guide'">
|
||||
<a-space class="down-btn">
|
||||
<a-button type="outline" @click="downPage">
|
||||
@ -87,7 +95,9 @@ const tabData = ref('placement_guide');
|
||||
|
||||
const query = reactive({
|
||||
platform: '',
|
||||
date_time: '',
|
||||
account_name: '',
|
||||
plan: '',
|
||||
date_time: [],
|
||||
sort_column: '',
|
||||
sort_order: '',
|
||||
page_size: 20,
|
||||
@ -105,11 +115,12 @@ const onPageSizeChange = (pageSize) => {
|
||||
query.page_size = pageSize;
|
||||
onSearch();
|
||||
};
|
||||
|
||||
const isGetAi = ref(true); // 是否获取AI数据
|
||||
const handleUpdateQuery = (payload) => {
|
||||
payload.order = payload.order === 'ascend' ? 'asc' : 'desc';
|
||||
query.sort_column = payload.column;
|
||||
query.sort_order = payload.order;
|
||||
isGetAi.value = false;
|
||||
onSearch();
|
||||
};
|
||||
|
||||
@ -134,8 +145,11 @@ const onSearch = async () => {
|
||||
listData.total = result.data.total;
|
||||
if (placementGuideList.value.length > 0) {
|
||||
loading.value = true;
|
||||
if (isGetAi.value) {
|
||||
startTask();
|
||||
}
|
||||
}
|
||||
isGetAi.value = true;
|
||||
};
|
||||
const aiResult = reactive({
|
||||
optimization: [], // 投放建议优化
|
||||
@ -144,7 +158,6 @@ const aiResult = reactive({
|
||||
});
|
||||
|
||||
// 下载当前页面
|
||||
|
||||
const downPage = async () => {
|
||||
await nextTick(); // 确保 DOM 更新完成
|
||||
html2canvas(document.querySelector('.guidelines-data-wrap')).then((canvas) => {
|
||||
@ -164,10 +177,7 @@ const saveForm = reactive({
|
||||
code: '',
|
||||
});
|
||||
const timerRef = ref<number | null>(null);
|
||||
|
||||
const startTask = () => {
|
||||
//todo 暂时注释
|
||||
return;
|
||||
if (timerRef.value !== null) return;
|
||||
timerRef.value = setInterval(async () => {
|
||||
try {
|
||||
@ -181,7 +191,7 @@ const startTask = () => {
|
||||
loading.value = false;
|
||||
aiResult.optimization = data.result?.optimization?.modules || [];
|
||||
aiResult.action_guide = data.result?.action_guide?.modules || [];
|
||||
aiResult.overview = data.result?.overview || [];
|
||||
aiResult.overview = data.result?.overview?.content_blocks[0] || [];
|
||||
}
|
||||
saveForm.code = data?.code;
|
||||
console.log(aiResult, 'aiResult');
|
||||
@ -191,7 +201,21 @@ const startTask = () => {
|
||||
}
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
console.log('handleReset');
|
||||
query.page = 1;
|
||||
query.page_size = 20;
|
||||
query.account_name = '';
|
||||
query.platform = '';
|
||||
query.sort_column = '';
|
||||
query.sort_order = '';
|
||||
query.platform = '';
|
||||
query.date_time = [];
|
||||
onSearch();
|
||||
};
|
||||
const stopTask = () => {
|
||||
loading.value = false;
|
||||
if (timerRef.value !== null) {
|
||||
clearInterval(timerRef.value); // 清除定时器
|
||||
timerRef.value = null; // 重置引用
|
||||
@ -218,4 +242,8 @@ onMounted(() => {
|
||||
|
||||
<style lang="scss">
|
||||
@import './style.scss';
|
||||
.custom-spin-wrapper {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user