|
|
|
|
|
<!--
|
|
|
|
|
|
* @Author: qinzhenpen qzp1807@126.com
|
|
|
|
|
|
* @Date: 2025-05-02 16:34:29
|
|
|
|
|
|
* @LastEditors: qinzhenpen qzp1807@126.com
|
|
|
|
|
|
* @LastEditTime: 2025-05-21 11:14:05
|
|
|
|
|
|
* @FilePath: \e-commerce-internet\src\views\test\marketing.vue
|
|
|
|
|
|
* @Description: 四象限图展示广告版本的点击率和转化率,支持动态选择横轴和纵轴
|
|
|
|
|
|
-->
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="marketing app-container student-training-shell legacy-training-page">
|
|
|
|
|
|
<TrainingIntro title="四象限法则">
|
|
|
|
|
|
<template #background>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
营销定位在电商领域具有极其重要的意义。它有助于企业明确产品的目标消费群体、差异化特点和市场优势,从而制定更有效的营销策略。一个准确的营销定位能够提高产品的市场竞争力,吸引更多潜在客户,并促进销售增长。
|
|
|
|
|
|
<br />
|
|
|
|
|
|
<br />
|
|
|
|
|
|
|
|
|
|
|
|
营销定位的关键因素
|
|
|
|
|
|
<br />
|
|
|
|
|
|
|
|
|
|
|
|
目标消费者:了解目标消费者的需求、偏好和行为特征是营销定位的基础。企业需要深入分析目标消费者的年龄、性别、收入水平、教育程度、消费习惯等因素,以便为他们提供符合其需求的产品和服务。
|
|
|
|
|
|
<br />
|
|
|
|
|
|
|
|
|
|
|
|
差异化特点:在竞争激烈的市场中,企业需要明确产品的差异化特点,以便与竞争对手区分开来。这些差异化特点可以体现在产品质量、功能、设计、价格、服务等方面。通过强调产品的独特之处,企业能够吸引更多消费者的关注。
|
|
|
|
|
|
<br />
|
|
|
|
|
|
|
|
|
|
|
|
市场定位策略:市场定位策略包括针锋相对式定位、另辟蹊径式定位和心理定位等。企业需要根据自身实力和市场环境选择合适的定位策略。例如,对于实力雄厚的企业,可以选择针锋相对式定位,与竞争对手展开正面竞争;而对于实力较弱的企业,则可以选择另辟蹊径式定位,寻找市场上的空白领域或细分领域进行发展。
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template #goal>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
使用四象限法则,分析用户点击率和转化率数据,定位产品在哪个象限,为下一步营销决策提供依据。
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</TrainingIntro>
|
|
|
|
|
|
<div class="training-step-area">
|
|
|
|
|
|
|
|
|
|
|
|
<p>在产品投放测试时,我们主要是评估投放产品广告的点击率、转化率等用户行为数据,高点击率高转化率往往意味着产品被用户看好,具有很大潜力。</p>
|
|
|
|
|
|
<div class="caseBacktitle">
|
|
|
|
|
|
<img src="@/assets/images/步骤.png" alt="" />
|
|
|
|
|
|
<span>实验实训</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p>假设某品牌在电商平台上投放了三个女装产品广告(广告A、广告B、广告C),收集了以下数据:</p>
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
:data="advertisementList"
|
|
|
|
|
|
border
|
|
|
|
|
|
style="width: 60%"
|
|
|
|
|
|
:header-cell-style="{
|
|
|
|
|
|
color: '#fff',
|
|
|
|
|
|
fontSize: '14px',
|
|
|
|
|
|
backgroundColor: '#1e88e5!important',
|
|
|
|
|
|
}"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column label="广告" align="center" prop="channel"></el-table-column>
|
|
|
|
|
|
<el-table-column label="点击率" align="center" prop="clickData"></el-table-column>
|
|
|
|
|
|
<el-table-column label="转化率" align="center" prop="conversions"></el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
<p>1、选择评估维度</p>
|
|
|
|
|
|
<div style="display: flex; gap: 70px">
|
|
|
|
|
|
<div class="online">
|
|
|
|
|
|
<span>横轴:</span>
|
|
|
|
|
|
<el-select v-model="gHorizontalAxis" placeholder="请选择" class="ml10">
|
|
|
|
|
|
<el-option v-for="item in optionOptions" :key="item" :value="item" :label="item"></el-option>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="online">
|
|
|
|
|
|
<span>纵轴:</span>
|
|
|
|
|
|
<el-select v-model="longitudinalAxis" placeholder="请选择" class="ml10">
|
|
|
|
|
|
<el-option v-for="item in optionOptions" :key="item" :value="item" :label="item"></el-option>
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p>2、绘制四象限图</p>
|
|
|
|
|
|
<div id="quadrantChart" ref="quadrantChart" style="width: 50%; height: 400px"></div>
|
|
|
|
|
|
<p>请根据上述四象限图分析上述三种女装产品的营销定位及下一步策略优化。</p>
|
|
|
|
|
|
<el-input :autosize="{ minRows: 11, maxRows: 11 }" type="textarea" v-model="textarea" placeholder="" />
|
|
|
|
|
|
<p>
|
|
|
|
|
|
广告A:转化率高但点击率低,需优化广告创意或投放策略,提高点击率。
|
|
|
|
|
|
<br />
|
|
|
|
|
|
广告B:点击率高但转化率低,可能是广告内容与实际产品不符,需优化产品页面或广告内容。
|
|
|
|
|
|
<br />
|
|
|
|
|
|
广告C:点击率和转化率都低,需重新评估广告策略或优化广告内容。
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="taskfooter">
|
|
|
|
|
|
<el-button @click="submitTask">提交任务</el-button>
|
|
|
|
|
|
<el-button @click="resetTask">重新实训</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<TrainingLegacyActions />
|
|
|
|
|
|
<TrainingAiSidebar />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import TrainingLegacyActions from "@/views/components/TrainingLegacyActions.vue";
|
|
|
|
|
|
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
|
|
|
|
|
|
import TrainingIntro from '@/views/components/TrainingIntro.vue';
|
|
|
|
|
|
import useUserStore from "@/store/modules/user";
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
|
|
|
import popModel from "@/views/components/popModal.vue";
|
|
|
|
|
|
import * as analysisAPI from "@/api/market-demand-mining.js";
|
|
|
|
|
|
import * as echarts from "echarts";
|
|
|
|
|
|
import { onMounted } from "vue";
|
|
|
|
|
|
const textarea = ref("");
|
|
|
|
|
|
const dialogVisible = ref(false);
|
|
|
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
|
|
|
// 状态变量
|
|
|
|
|
|
const gHorizontalAxis = ref("点击率"); // 默认横轴为点击率
|
|
|
|
|
|
const longitudinalAxis = ref("转化率"); // 默认纵轴为转化率
|
|
|
|
|
|
const advertisementList = ref([
|
|
|
|
|
|
{ channel: "广告A", clickData: "1%", conversions: "5%" },
|
|
|
|
|
|
{ channel: "广告B", clickData: "4%", conversions: "2%" },
|
|
|
|
|
|
{ channel: "广告C", clickData: "1%", conversions: "2%" },
|
|
|
|
|
|
]);
|
|
|
|
|
|
const optionOptions = ["点击率", "转化率"];
|
|
|
|
|
|
// 绘制四象限图
|
|
|
|
|
|
const drawQuadrantChart = () => {
|
|
|
|
|
|
let myChart = echarts.init(proxy.$refs.quadrantChart);
|
|
|
|
|
|
// 解析数据:将百分比字符串转换为数字
|
|
|
|
|
|
const parsedData = advertisementList.value.map((item) => ({
|
|
|
|
|
|
name: item.channel,
|
|
|
|
|
|
clickRate: parseFloat(item.clickData.replace("%", "")),
|
|
|
|
|
|
conversionRate: parseFloat(item.conversions.replace("%", "")),
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
// 计算平均值
|
|
|
|
|
|
const avgClickRate = parsedData.reduce((sum, item) => sum + item.clickRate, 0) / parsedData.length; // 2%
|
|
|
|
|
|
const avgConversionRate = parsedData.reduce((sum, item) => sum + item.conversionRate, 0) / parsedData.length; // 3%
|
|
|
|
|
|
|
|
|
|
|
|
// 根据用户选择确定横轴和纵轴数据
|
|
|
|
|
|
const xAxisType = gHorizontalAxis.value === "点击率" ? "clickRate" : "conversionRate";
|
|
|
|
|
|
const yAxisType = longitudinalAxis.value === "点击率" ? "clickRate" : "conversionRate";
|
|
|
|
|
|
const xAxisName = gHorizontalAxis.value + " (%)";
|
|
|
|
|
|
const yAxisName = longitudinalAxis.value + " (%)";
|
|
|
|
|
|
|
|
|
|
|
|
// 确定范围和平均值
|
|
|
|
|
|
const xMax = xAxisType === "clickRate" ? 5 : 6;
|
|
|
|
|
|
const yMax = yAxisType === "clickRate" ? 5 : 6;
|
|
|
|
|
|
const xAvg = xAxisType === "clickRate" ? avgClickRate : avgConversionRate;
|
|
|
|
|
|
const yAvg = yAxisType === "clickRate" ? avgClickRate : avgConversionRate;
|
|
|
|
|
|
const xAvgLabel = xAxisType === "clickRate" ? `平均点击率 (${xAvg}%)` : `平均转化率 (${xAvg}%)`;
|
|
|
|
|
|
const yAvgLabel = yAxisType === "clickRate" ? `平均点击率 (${yAvg}%)` : `平均转化率 (${yAvg}%)`;
|
|
|
|
|
|
|
|
|
|
|
|
// 准备散点图数据
|
|
|
|
|
|
const scatterData = parsedData.map((item) => ({
|
|
|
|
|
|
name: item.name,
|
|
|
|
|
|
value: [item[xAxisType], item[yAxisType]],
|
|
|
|
|
|
}));
|
|
|
|
|
|
console.log(scatterData, "scatterData");
|
|
|
|
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
|
|
title: {
|
|
|
|
|
|
text: "广告版本四象限图",
|
|
|
|
|
|
left: "center",
|
|
|
|
|
|
textStyle: { fontSize: 16 },
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
formatter: function (params) {
|
|
|
|
|
|
return `${params.name}: (${params.value[0]}%, ${params.value[1]}%)`;
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
name: xAxisName,
|
|
|
|
|
|
nameLocation: "middle",
|
|
|
|
|
|
nameGap: 30,
|
|
|
|
|
|
min: 0,
|
|
|
|
|
|
max: xMax,
|
|
|
|
|
|
splitLine: { show: false },
|
|
|
|
|
|
axisLabel: { formatter: "{value}%" },
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
name: yAxisName,
|
|
|
|
|
|
nameLocation: "middle",
|
|
|
|
|
|
nameGap: 40,
|
|
|
|
|
|
min: 0,
|
|
|
|
|
|
max: yMax,
|
|
|
|
|
|
splitLine: { show: false },
|
|
|
|
|
|
axisLabel: { formatter: "{value}%" },
|
|
|
|
|
|
},
|
|
|
|
|
|
visualMap: {
|
|
|
|
|
|
show: false,
|
|
|
|
|
|
dimension: 0,
|
|
|
|
|
|
pieces: [
|
|
|
|
|
|
{ lte: xAvg, color: "rgba(75, 192, 192, 0.6)" }, // 低值
|
|
|
|
|
|
{ gt: xAvg, color: "rgba(255, 159, 64, 0.6)" }, // 高值
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "广告数据",
|
|
|
|
|
|
type: "scatter",
|
|
|
|
|
|
data: scatterData,
|
|
|
|
|
|
symbolSize: 15,
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
position: "top",
|
|
|
|
|
|
formatter: "{b}",
|
|
|
|
|
|
},
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
borderColor: "#000",
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "象限分割线",
|
|
|
|
|
|
type: "line",
|
|
|
|
|
|
markLine: {
|
|
|
|
|
|
silent: true,
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: "rgba(255, 0, 0, 0.5)",
|
|
|
|
|
|
width: 2,
|
|
|
|
|
|
type: "dashed",
|
|
|
|
|
|
},
|
|
|
|
|
|
label: {
|
|
|
|
|
|
position: "middle",
|
|
|
|
|
|
formatter: "{b}",
|
|
|
|
|
|
},
|
|
|
|
|
|
data: [
|
|
|
|
|
|
{ xAxis: xAvg, name: xAvgLabel },
|
|
|
|
|
|
{ yAxis: yAvg, name: yAvgLabel },
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
};
|
|
|
|
|
|
myChart.setOption(option, true);
|
|
|
|
|
|
// 响应式调整
|
|
|
|
|
|
window.addEventListener("resize", () => myChart.resize());
|
|
|
|
|
|
};
|
|
|
|
|
|
const submitTask = () => {
|
|
|
|
|
|
if (textarea.value == "") {
|
|
|
|
|
|
proxy.$message.error("请输入实训内容");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
analysisAPI
|
|
|
|
|
|
.productMarketingPositioningSubmit({
|
|
|
|
|
|
analysis: textarea.value,
|
|
|
|
|
|
positionData: JSON.stringify(advertisementList.value),
|
|
|
|
|
|
userId: userStore.userInfo.userId,
|
|
|
|
|
|
xAxis: gHorizontalAxis.value,
|
|
|
|
|
|
yAxis: longitudinalAxis.value,
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((res) => {
|
|
|
|
|
|
if (res.code == 200) {
|
|
|
|
|
|
proxy.$message.success("实训成功");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
proxy.$message.error(res.msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
const resetTask = () => {
|
|
|
|
|
|
analysisAPI.productReleaseReTrain({ userId: userStore.userInfo.userId, module: "产品营销定位" }).then((res) => {
|
|
|
|
|
|
textarea.value = "";
|
|
|
|
|
|
proxy.$message.success("实训已重置");
|
|
|
|
|
|
})
|
|
|
|
|
|
};
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
drawQuadrantChart();
|
|
|
|
|
|
});
|
|
|
|
|
|
// 回显
|
|
|
|
|
|
const getTask = () => {
|
|
|
|
|
|
analysisAPI
|
|
|
|
|
|
.productMarketingPositioningEcho({
|
|
|
|
|
|
userId: userStore.userInfo.userId,
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((res) => {
|
|
|
|
|
|
if (res.code == 200) {
|
|
|
|
|
|
textarea.value = res.data.analysis;
|
|
|
|
|
|
advertisementList.value = JSON.parse(res.data.positionData);
|
|
|
|
|
|
gHorizontalAxis.value = res.data.xAxis;
|
|
|
|
|
|
longitudinalAxis.value = res.data.yAxis;
|
|
|
|
|
|
drawQuadrantChart();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 监听横轴和纵轴的选择变化,重新绘制图表
|
|
|
|
|
|
watch([gHorizontalAxis, longitudinalAxis], () => {
|
|
|
|
|
|
drawQuadrantChart();
|
|
|
|
|
|
});
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
getTask();
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang='scss' scoped>
|
|
|
|
|
|
.marketing {
|
|
|
|
|
|
background: #ffffff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mt10 {
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ml10 {
|
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.online {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|