You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dianshang-qianduan/src/views/assessment/market.vue

489 lines
17 KiB
Vue

4 months ago
<!--
* @Author: qinzhenpen qzp1807@126.com
* @Date: 2025-05-06 11:39:19
* @LastEditors: qinzhenpen qzp1807@126.com
* @LastEditTime: 2025-05-13 15:05:45
* @FilePath: \e-commerce-internet\src\views\assessment\market.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="market">
<el-scrollbar :height="`${height - 100}px`">
<div class="caseBacktitle">
<img src="@/assets/images/步骤.png" alt="" />
<span>任务目标</span>
</div>
<p>市场机会矩阵(波士顿矩阵)‌按市场增长率和市场份额将商品分为“明星、现金牛、问题、瘦狗”四类,制定差异化运营策略(如淘汰低效品、扶持潜力品)。学生需要掌握波士顿矩阵中相关指标的计算公式,准确划分产品类型,并针对不同的产品类型提出可行性建议。‌</p>
<div class="caseBacktitle">
<img src="@/assets/images/步骤.png" alt="" />
<span>任务背景</span>
</div>
<p>某美妆电商平台的商品组合分析,该平台主要销售护肤品、彩妆、个护工具等品类,拥有200+SKU,目标是通过波士顿矩阵优化资源分配,提升整体利润率。</p>
<div class="df">
<div class="left">
<p>1. 销售额数据</p>
<el-table
:data="salesData"
border
style="width: 100%"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="产品类别" align="center" prop="category"></el-table-column>
<el-table-column label="本年度销售额(万元)" align="center" prop="currentYear"></el-table-column>
<el-table-column label="上年度销售额(万元)" align="center" prop="lastYear"></el-table-column>
</el-table>
<p>2. 行业平均增长率</p>
<span>行业整体增长率为 10%(数据来自第三方调研机构)。</span>
</div>
<div class="right">
<p>3. 竞品市场份额</p>
<el-table
:data="competitorMarketShare"
border
style="width: 50%"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="产品类别" align="center" prop="category"></el-table-column>
<el-table-column label="竞品同类产品总销售额(万元)" align="center" prop="totalSales"></el-table-column>
</el-table>
<p>4. 用户行为数据</p>
<el-table
:data="userBehaviorData"
border
style="width: 60%"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="产品类别" align="center" prop="category"></el-table-column>
<el-table-column label="加购率(%)" align="center" prop="addToCartRate"></el-table-column>
<el-table-column label="转化率(%)" align="center" prop="conversionRate"></el-table-column>
<el-table-column label="复购率(%)" align="center" prop="repurchaseRate"></el-table-column>
</el-table>
</div>
</div>
<div class="caseBacktitle">
<img src="@/assets/images/步骤.png" alt="" />
<span>任务要求</span>
</div>
<div class="caseBacktitle">
<span>任务1:计算市场增长率</span>
</div>
<p>市场增长率=(本年度销售额一上年度销售额) / 上年度销售额 x 100%</p>
<el-table
:data="productSalesData"
border
style="width: 80%"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="产品类别" align="center" prop="category" width="180"></el-table-column>
<el-table-column label="本年度销售额(万元)" align="center" prop="currentYear" width="200"></el-table-column>
<el-table-column label="上年度销售额(万元)" align="center" prop="lastYear" width="200"></el-table-column>
<el-table-column label="市场增长率(%)" align="center">
<template #default="scope">
<div class="df" style="align-items: center">
<span>(</span>
<el-input v-model="scope.row.currentYearValue" style="width: 10vw"></el-input>
<span>-</span>
<el-input v-model="scope.row.lastYearValue" style="width: 10vw"></el-input>
<span>)</span>
<span>/</span>
<el-input v-model="scope.row.value" style="width: 10vw"></el-input>
<span>=</span>
<el-input v-model="scope.row.growthValue" style="width: 10vw">
<template #suffix>%</template>
</el-input>
</div>
</template>
</el-table-column>
</el-table>
<div class="caseBacktitle">
<span>任务2:计算相对市场份额</span>
</div>
<p>相对市场份额=本品牌销售额 / 竞品同类产品总销售额 ×100%</p>
<el-table
:data="marketShareData"
border
style="width: 70%"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="产品类别" align="center" prop="category" width="180"></el-table-column>
<el-table-column label="本品牌销售额(万元)" align="center" prop="brandSales" width="200"></el-table-column>
<el-table-column label="竞品同类产品总销售额(万元)" align="center" prop="competitorSales" width="240"></el-table-column>
<el-table-column label="相对市场份额(%)" align="center">
<template #default="scope">
<div class="df" style="align-items: center">
<el-input v-model="scope.row.brandSalesValue" style="width: 10vw"></el-input>
<span>/</span>
<el-input v-model="scope.row.competitorSalesValue" style="width: 10vw"></el-input>
<span>=</span>
<el-input v-model="scope.row.marketShareValue" style="width: 10vw">
<template #suffix>%</template>
</el-input>
</div>
</template>
</el-table-column>
</el-table>
<div class="caseBacktitle">
<span>任务3:汇总计算结果</span>
</div>
<el-table
:data="marketGrowthData"
border
style="width: 70%; margin-top: 10px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column prop="category" label="产品类别" align="center" />
<el-table-column prop="growthRate" label="市场增长率(%)" align="center" />
<el-table-column prop="industryAvgGrowthRate" label="市场增长率行业均值" align="center" />
<el-table-column prop="marketShare" label="相对市场份额(%)" align="center" />
<el-table-column prop="industryAvgMarketShare" label="相对市场份额均值" align="center" />
</el-table>
<div class="caseBacktitle">
<span>任务4:产品分类</span>
</div>
<p>根据 市场增长率 和 相对市场份额 的计算结果,结合波士顿矩阵的标准:</p>
<template v-for="(item, index) in productClassification" :key="index">
<div class="online">
<span style="width: 22vw">{{ index + 1 }}.{{ item.label }}</span>
<el-select placeholder="请选择" @change="onChange" v-model="item.value" class="ml10 mt10">
<el-option v-for="item in option" :key="item" :value="item" :label="item"></el-option>
</el-select>
</div>
</template>
<div class="caseBacktitle">
<span>任务5:产品诊断</span>
</div>
<p>
通过原始数据的计算,明确了各产品的市场定位:
<br />
明星产品(精华液):高增长、高份额,需持续投入资源。
<br />
现金牛产品(面霜):低增长、高份额,需优化成本,支持其他产品。
<br />
问题产品(腮红):高增长、低份额,需评估潜力,精准投放。
<br />
瘦狗产品(口红):低增长、低份额,需快速止损,释放资源。
<br />
</p>
</el-scrollbar>
<div class="taskfooter">
<el-button @click="submitTask">提交任务</el-button>
<el-button @click="resetTask">重新实训</el-button>
</div>
</div>
</template>
<script setup>
import useUserStore from "@/store/modules/user";
const userStore = useUserStore();
import * as analysisAPI from "@/api/market-demand-mining.js";
const { proxy } = getCurrentInstance();
const height = ref(800);
const salesData = [
{ category: "某品牌精华液", currentYear: 500, lastYear: 400 },
{ category: "基础保湿面霜", currentYear: 800, lastYear: 760 },
{ category: "小众矿物腮红", currentYear: 120, lastYear: 92 },
{ category: "传统软管装口红", currentYear: 90, lastYear: 92 },
];
const competitorMarketShare = [
{ category: "某品牌精华液", totalSales: 420 },
{ category: "基础保湿面霜", totalSales: 533 },
{ category: "小众矿物腮红", totalSales: 400 },
{ category: "传统软管装口红", totalSales: 1125 },
];
const userBehaviorData = [
{ category: "某品牌精华液", addToCartRate: 8.5, conversionRate: 3.8, repurchaseRate: 45 },
{ category: "基础保湿面霜", addToCartRate: 6.8, conversionRate: 3.2, repurchaseRate: 28 },
{ category: "小众矿物腮红", addToCartRate: 4.5, conversionRate: 1.8, repurchaseRate: 15 },
{ category: "传统软管装口红", addToCartRate: 1.2, conversionRate: 0.8, repurchaseRate: 5 },
];
const productSalesData = ref([
{
category: "某品牌精华液",
currentYear: 500,
currentYearValue: null,
lastYear: 400,
lastYearValue: null,
value: null,
growthRate: "25%",
growthValue: null,
key1: "mppjhyRw1Two",
key2: "ctrzkhRw1Two",
key3: "mppjhyRw1Three",
key4: "mppjhyRw1Four",
},
{
category: "基础保湿面霜",
currentYear: 800,
currentYearValue: null,
value: null,
lastYear: 760,
lastYearValue: null,
growthRate: "5.26%",
growthValue: null,
key1: "jcbsmsRw1One",
key2: "jcbsmsRw1Two",
key3: "jcbsmsRw1Three",
key4: "jcbsmsRw1Four",
},
{
category: "小众矿物腮红",
currentYear: 120,
currentYearValue: null,
value: null,
lastYear: 92,
lastYearValue: null,
growthRate: "30.43%",
growthValue: null,
key1: "xzkwshRw1One",
key2: "xzkwshRw1Two",
key3: "xzkwshRw1Three",
key4: "xzkwshRw1Four",
},
{
category: "传统软管装口红",
currentYear: 90,
currentYearValue: null,
lastYear: 92,
lastYearValue:null,
value: null,
growthRate: "-2.17%", // 负增长
growthValue: null,
key1: "ctrzkhRw1One",
key2: "ctrzkhRw1Two",
key3: "ctrzkhRw1Three",
key4: "ctrzkhRw1Four",
},
]);
const marketShareData = ref([
{
category: "某品牌精华液",
brandSales: 500,
brandSalesValue: null,
competitorSales: 420,
competitorSalesValue: null,
marketShare: "119.05%",
marketShareValue:null,
key1: "mppjhyRw2One",
key2: "mppjhyRw2Two",
key3: "mppjhyRw2Three",
},
{
category: "基础保湿面霜",
brandSales: 800,
brandSalesValue:null,
competitorSales: 533,
competitorSalesValue: null,
marketShare: "150.09%",
marketShareValue: null,
key1: "jcbsmsRw2One",
key2: "jcbsmsRw2Two",
key3: "jcbsmsRw2Thee",
},
{
category: "小众矿物腮红",
brandSales: 120,
brandSalesValue: null,
competitorSales: 400,
competitorSalesValue: null,
marketShare: "30.00%",
marketShareValue: null,
key1: "xzkwshRw2One",
key2: "xzkwshRw2Two",
key3: "xzkwshRw2Three",
},
{
category: "传统软管装口红",
brandSales: 90,
brandSalesValue:null,
competitorSales: 1125,
competitorSalesValue: null,
marketShare: "8.00%",
marketShareValue:null,
key1: "ctrzkhRw2One",
key2: "ctrzkhRw2Two",
key3: "ctrzkhRw2Three",
},
]);
const marketGrowthData = ref([
{
category: "某品牌精华液",
growthRate: "25%",
industryAvgGrowthRate: "10%",
marketShare: "119.05%",
industryAvgMarketShare: "100%",
},
{
category: "基础保湿面霜",
growthRate: "5.26%",
industryAvgGrowthRate: "10%",
marketShare: "150.09%",
industryAvgMarketShare: "100%",
},
{
category: "小众矿物腮红",
growthRate: "30.43%",
industryAvgGrowthRate: "10%",
marketShare: "30.00%",
industryAvgMarketShare: "100%",
},
{
category: "传统软管装口红",
growthRate: "-2.17%",
industryAvgGrowthRate: "10%",
marketShare: "8.00%",
industryAvgMarketShare: "100%",
},
]);
// 分类描述与绑定值数组
const productClassification = ref([
{
label: "明星产品:市场增长率 > 10%,相对市场份额 > 100%",
value: "", // 绑定的选中值
key1: "rw4One",
},
{
label: "现金牛产品:市场增长率 < 10%,相对市场份额 > 100%",
key1: "rw4Two",
value: "",
},
{
label: "问题产品:市场增长率 > 10%,相对市场份额 < 100%",
key1: "rw4Three",
value: "",
},
{
label: "瘦狗产品:市场增长率 < 0%,相对市场份额 < 10%",
key1: "rw4Four",
value: "",
},
]);
const option = ["某品牌精华液", "基础保湿面霜", "小众矿物腮红", "传统软管装口红"];
function getElementHeight(selector) {
const el = document.querySelector(selector);
if (el) {
// 获取元素的实际高度,包括 padding 但不包括 margin
return el.scrollHeight;
} else {
console.warn(`找不到元素:${selector}`);
return 0;
}
}
const submitTask = () => {
if (productSalesData.value.some((item) => !item.currentYearValue || !item.lastYearValue || !item.value || !item.growthValue)) {
proxy.$modal.msgWarning("请先完成任务1");
return;
}
if (marketShareData.value.some((item) => !item.brandSalesValue || !item.competitorSalesValue || !item.marketShareValue)) {
proxy.$modal.msgWarning("请先完成任务2");
return;
}
if (productClassification.value.some((item) => !item.value)) {
proxy.$modal.msgWarning("请先完成任务4");
return;
}
const answerMap = {};
productSalesData.value.forEach((item, index) => {
answerMap[item.key1] = item.currentYearValue;
answerMap[item.key2] = item.lastYearValue;
answerMap[item.key3] = item.value;
answerMap[item.key4] = Number(item.growthValue).toFixed(2);
});
marketShareData.value.forEach((item, index) => {
answerMap[item.key1] = item.brandSalesValue;
answerMap[item.key2] = item.competitorSalesValue;
answerMap[item.key3] = Number(item.marketShareValue).toFixed(2);
});
productClassification.value.forEach((item, index) => {
answerMap[item.key1] = item.value; // 直接映射 label 作为值
});
answerMap.userId = userStore.userInfo.userId;
analysisAPI.marketOpportunityMatrixSubmit(answerMap).then((res) => {
proxy.$modal.msgSuccess("提交成功");
});
};
const echo = () => {
analysisAPI.marketOpportunityMatrixEcho({ userId: userStore.userInfo.userId }).then((res) => {
const { data } = res;
productSalesData.value.forEach((item, index) => {
item.currentYearValue = data[item.key1];
item.lastYearValue = data[item.key2];
item.value = data[item.key3];
item.growthValue = data[item.key4];
});
marketShareData.value.forEach((item, index) => {
item.brandSalesValue = data[item.key1];
item.competitorSalesValue = data[item.key2];
item.marketShareValue = data[item.key3];
});
productClassification.value.forEach((item, index) => {
item.value = data[item.key1]; // 直接映射 label 作为值
});
});
};
//重新实训
const resetTask = () => {
analysisAPI.marketOpportunityMatrixReTrain({ userId: userStore.userInfo.userId }).then((res) => {
proxy.$modal.msgSuccess("重新实训成功");
productSalesData.value.forEach((item, index) => {
item.currentYear = "";
item.lastYear = "";
item.value = "";
item.growthValue = "";
});
marketShareData.value.forEach((item, index) => {
item.brandSales = "";
item.competitorSales = "";
item.marketShareValue = "";
});
productClassification.value.forEach((item, index) => {
item.value = "";
});
});
};
onMounted(() => {
// 监听窗口大小变化
window.addEventListener("resize", () => {
height.value = getElementHeight(".kano");
});
echo();
});
</script>
<style lang='scss' scoped>
.market {
height: calc(100vh - 230px);
background: #ffffff;
padding: 20px;
border-radius: 8px;
padding-bottom: 0;
.df {
display: flex;
gap: 30px;
.right {
width: 50%;
}
}
}
</style>