fix/non-blocking-route-navigation
方佳 博 2 years ago
commit 2d9c97bc24

@ -0,0 +1,115 @@
import request from "@/utils/request";
//条件查询用户表信息
export function getUserTableData(data) {
return request({
url: "/api/userprofile/getBaseInfoBySelect",
method: "get",
params: data,
});
}
//数据下载-RFM分析
export function downloadDataByRFM(data) {
return request({
url: "/api/downDataByUserPortrait/analysisByRfmDown",
method: "get",
params: data,
responseType: "blob",
});
}
//数据下载-ABC分析
export function downloadDataByABC(data) {
return request({
url: "/api/downDataByUserPortrait/analysisByPareto",
method: "get",
params: data,
});
}
//数据下载-波士顿矩阵分析
export function downloadDataByBoston(data) {
return request({
url: "/api/downDataByUserPortrait/bostonMatrixAnalysisData",
method: "get",
responseType: "blob",
params: data,
});
}
//数据下载-漏斗分析
export function downloadDataByFunnel(data) {
return request({
url: "/api/downDataByUserPortrait/analysisByFunnelModel",
method: "get",
params: data,
});
}
//数据下载-购物篮分析
export function downloadDataByBasket(data) {
return request({
url: "/api/downDataByUserPortrait/analysisByShopBasket",
method: "get",
params: data,
});
}
//数据下载-复购分析
export function downloadDataByRepurchase(data) {
return request({
url: "/api/downDataByUserPortrait/analysisByRepurchase",
method: "get",
params: data,
});
}
//数据下载-留存分析
export function downloadDataByRetain(data) {
return request({
url: "/api/downDataByUserPortrait/analysisByRetention",
method: "get",
params: data,
});
}
//数据下载-用户粘性分析
export function downloadDataByViscosity(data) {
return request({
url: "/api/downDataByUserPortrait/analysisByStickiness",
method: "get",
params: data,
});
}
//筛选出统计样本
export function filterOutStatisSample(data) {
return request({
url: "/api/userBehaviorByRFM/filterOutStatisSample",
method: "post",
data: data,
});
}
//保存数据接口
export function saveData(data) {
return request({
url: "/api/userBehavior/analysisByAutoSave",
method: "post",
data: data,
});
}
//页面回显
export function getData(data) {
return request({
url: "/api/userBehavior/readTrainInfo",
method: "get",
params: data,
});
}
//重新实训
export function retrain(data) {
return request({
url: "/api/userBehavior/restartByTraining",
method: "get",
params: data,
});
}
//实训任务提交
export function submit(data) {
return request({
url: "/api/userBehavior/practicalTrainingSubmission",
method: "post",
params: data,
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

@ -96,6 +96,19 @@ export const constantRoutes = [
},
],
},
{
path: "",
component: Layout,
redirect: "/portraitModel",
children: [
{
path: "/portraitModel",
component: () => import("@/views/portraitModel/index"),
name: "portraitModel",
meta: { title: "用户画像模型", icon: "dashboard", affix: true },
},
],
},
{
path: "",
component: Layout,

@ -389,4 +389,22 @@ export function camelCase(str) {
export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}
//文件下载
export function downBlobFile(fileName, fileBlob) {
const link = document.createElement('a')
try {
// let blob = new Blob([res.data],{type: 'application/vnd.ms-excel'}); //如果后台返回的不是blob对象类型,先定义成blob对象格式,type格式根据返回文件不同修改
const blob = fileBlob
const _fileName = fileName // 拆解获取文件名,如果后端没返回文件格式,则需要自己拼接文件后缀
link.style.display = 'none'
// 兼容浏览器
const url = window.URL || window.webkitURL || window.moxURL
link.href = url.createObjectURL(blob) // 如果没设置axios请求reponseType为‘blob’的话,则参数应为new Blob(文件流),否则报错
link.download = _fileName // 下载的文件名称
link.click()
window.URL.revokeObjectURL(url) // #URL.revokeObjectURL()方法会释放一个通过URL.createObjectURL()创建的对象URL. 当你要已经用过了这个对象URL,然后要让浏览器知道这个URL已经不再需要指向对应的文件的时候,就需要调用这个方法.
} catch (error) {
console.error(error.message)
}
}

@ -15,7 +15,9 @@ axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL: import.meta.env.VITE_APP_BASE_API,
// baseURL: import.meta.env.VITE_APP_BASE_API,
// baseURL:'http://192.168.2.28:9868/',
baseURL:'http://192.168.2.16:9868/',
// 超时
timeout: 10000
})

@ -0,0 +1,47 @@
<template>
<div class="main-content">
<el-scrollbar height="680px">
<component :is="currentComponent" ref="content"></component>
</el-scrollbar>
</div>
</template>
<script setup>
import { defineExpose } from "vue";
const props = defineProps({
currentComponent: {
type: Object,
required: true,
},
});
const content = ref(null);
// const consumerLeft = () => {
// content.value.consumer();
// };
// const resLeft = () => {
// content.value.practicalTraining();
// };
// const submitDataLeft = () => {
// content.value.submitData();
// };
// const submitMethod = () => {
// console.log(666);
// // content.value.submitData();
// };
const submitMethod = () => {
// console.log(666);
content.value.submitData();
};
const retrainMethod = () => {
// console.log(666);
content.value.retrain();
};
defineExpose({
submitMethod,
retrainMethod,
});
</script>
<style lang="scss" scoped>
.main-content {
width: calc(100% - 60px);
}
</style>

@ -259,7 +259,7 @@ const modelTags = ref([
// background-color: #02112e;
background-color: rgba(2, 17, 46, 0.3);
// padding: 20px;
padding-left: 20px;
padding-left: 45px;
padding-right: 20px;
padding-top: 15px;
padding-bottom: 15px;

File diff suppressed because it is too large Load Diff

@ -0,0 +1,985 @@
<template>
<div class="content">
<div class="import" @click="knowledgeFlag = !knowledgeFlag">
<img src="@/assets/images/导入.png" alt="" />
<span>任务知识导入</span>
</div>
<div v-if="knowledgeFlag">
<p>
帕累托分析法源于经典的二八法则。意大利经济学家维尔弗雷多·帕累托于1906年提出了著名的关于意大利社会财务分配的研究结论:20%的人口掌握了80%的社会财富。这个结论对大多数国家的社会财富分配情况都成立。因此帕累托法则又被称为80/20法则。<br /><br />
帕累托分析的核心观点是:在许多情况下,大部分的问题、效益或成本都来自于少数的要素。换句话说,少数关键要素占据了绝大多数的结果。这一规律在许多领域都具有普适性,例如:<br /><br />
在企业中,80%的利润可能来自于20%的产品或客户。<br />
在销售中,80%的销售额可能来自于20%的销售员或产品。<br />
在质量控制中,80%的缺陷可能来自于20%的原因或工序。<br /><br />
ABC 分类法全称应为 ABC 分类库存控制法。
又称帕累托分析法或巴雷托分析法、柏拉图分析、主次因分析法
、ABC分析法、ABC 管理法,平常也称之为「80 对 20」规则。
</p>
<img src="@/assets/images/u3323.png" alt="" /><br />
<img src="@/assets/images/u3324.png" alt="" />
</div>
<div v-if="!knowledgeFlag">
<div class="caseBack">
<div class="title">
<img src="@/assets/images/caseIcon.png" alt="" />
<span>案例背景:</span>
</div>
<span style="line-height: 25px; font-size: 14px">
现有以下某商店的交易原始数据,需要采用帕累托分析方法,对商品进行分类:
</span>
<div style="margin-top: 10px; display: flex">
<el-table
:data="fileTable1"
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="交易单号" align="center" prop="id">
</el-table-column>
<el-table-column label="商品名称" align="center" prop="name">
</el-table-column>
<el-table-column label="销售额" align="center" prop="amount">
</el-table-column>
</el-table>
<div class="download" @click="downloadData">下载数据</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第一步,统计各类商品累计销售额</span>
</div>
<span style="line-height: 25px; font-size: 14px">
以商品为统计单元,计算各类商品的销售额。
</span>
<div style="margin-top: 10px; display: flex">
<el-table
:data="step1Data"
style="width: 450px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="商品名称" align="center" prop="name">
</el-table-column>
<el-table-column label="销售额" align="center" prop="amount">
<template #default="scope">
<el-input
v-model="scope.row.params"
placeholder="请输入"
style="width: 130px"
>
</el-input>
</template>
</el-table-column>
</el-table>
<div class="submit" @click="step1Submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第二步,排序</span>
</div>
<span style="line-height: 25px; font-size: 14px">
以累计销售额为排序基准,按照倒序进行排序。
</span>
<div style="margin-top: 10px; display: flex">
<el-table
:data="step2Data"
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="商品名称" align="center" prop="name">
</el-table-column>
<el-table-column label="销售额" align="center" prop="amount">
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<div
style="
display: flex;
align-items: center;
justify-content: center;
"
>
<img
src="@/assets/images/上.png"
alt=""
style="margin-right: 10px; cursor: pointer"
@click="moveUp(scope.$index, scope.row)"
/>
<img
src="@/assets/images/下.png"
alt=""
style="cursor: pointer"
@click="moveDown(scope.$index, scope.row)"
/>
</div>
</template>
</el-table-column>
</el-table>
<div class="submit" @click="step2Submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第三步,计算累计销售额占比</span>
</div>
<span style="line-height: 25px; font-size: 14px">
计算各个商品的销售额占比,并以此通过累加计算累计销售额占比。
</span>
<div style="margin-top: 10px; display: flex" v-if="step2AnswerFlag">
<el-table
:data="step3Data"
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="商品名称" align="center" prop="data1">
</el-table-column>
<el-table-column label="销售额" align="center" prop="data2">
</el-table-column>
<el-table-column
label="销售额占比(%)"
align="center"
prop="data3"
>
<template #default="scope">
<el-input
v-model="scope.row.params1"
placeholder="请输入"
style="width: 110px"
>
</el-input
>%
</template>
</el-table-column>
<el-table-column
label="累计销售额占比(%)"
align="center"
prop="data4"
>
<template #default="scope">
<el-input
v-model="scope.row.params2"
placeholder="请输入"
style="width: 110px"
>
</el-input
>%
</template>
</el-table-column>
</el-table>
<div class="submit" @click="step3Submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第四步,划分商品类型</span>
</div>
<span style="line-height: 25px; font-size: 14px">
我们按照0-80%,80%-90%,90%-100%将商品分成ABC3个类别,然后对于这3个类别的产品做区别管理,以提高效益。
</span>
<el-table
:show-header="false"
:data="typeData"
style="width: 580px; margin-top: 10px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column
label="用户ID"
align="center"
prop="data1"
width="160"
>
</el-table-column>
<el-table-column label="用户名称" align="center" prop="data2">
</el-table-column>
</el-table>
<div style="margin-top: 10px; display: flex" v-if="step3AnswerFlag">
<el-table
:data="step4Data"
style="width: 680px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="商品名称" align="center" prop="data1">
</el-table-column>
<el-table-column label="销售额" align="center" prop="data2">
</el-table-column>
<el-table-column
label="累计销售额占比(%)"
align="center"
prop="data3"
>
</el-table-column>
<el-table-column label="划分商品类型" align="center" prop="data4">
<template #default="scope">
<el-select
v-model="scope.row.params"
placeholder="请选择"
style="width: 100px"
>
<el-option :label="'A类商品'" :value="'A类商品'" />
<el-option :label="'B类商品'" :value="'B类商品'" />
<el-option :label="'C类商品'" :value="'C类商品'" />
</el-select>
</template>
</el-table-column>
</el-table>
<div class="submit" @click="step4Submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第五步,绘制帕累托图</span>
</div>
<span style="line-height: 25px; font-size: 14px">
以分析表的商品名称为X轴,销售额为左侧Y轴,累计销售额占比为右侧Y轴绘制帕累托图。
</span>
<div style="margin-top: 10px; display: flex">
<el-table
:data="step5Data"
style="width: 680px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="" align="center" prop="title" />
<el-table-column label="R值打分" align="center">
<template #default="scope">
<el-input
v-model="scope.row.params1"
placeholder="请输入"
style="width: 100px"
>
</el-input>
</template>
</el-table-column>
<el-table-column label="F值打分" align="center">
<template #default="scope">
<el-input
v-model="scope.row.params2"
placeholder="请输入"
style="width: 100px"
>
</el-input>
</template>
</el-table-column>
<el-table-column label="M值打分" align="center">
<template #default="scope">
<el-input
v-model="scope.row.params3"
placeholder="请输入"
style="width: 100px"
>
</el-input>
</template>
</el-table-column>
</el-table>
<div class="submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第六步,针对不同类别的商品,制定不同的库存策略</span>
</div>
<span style="line-height: 25px; font-size: 14px">
一般来说,在商品的库存管理策略中:
</span>
<div class="customerType" style="width: 1115px">
<img src="@/assets/images/商品a.png" alt="" />
<span
>A类商品对公司销售额贡献最大,这种商品备货周期短,在保证安全库存的情况下,应该小批量多批次按需储存,尽可能降低库存总量,减少仓储管理成本,但如果控制不好库存,很容易出现断货风险。</span
>
</div>
<div class="customerType" style="width: 1115px">
<img src="@/assets/images/商品b.png" alt="" />
<span>B类商品销售额贡献次之,这种商品备货周期可以适当延长。</span>
</div>
<div class="customerType" style="width: 1115px">
<img src="@/assets/images/商品c.png" alt="" />
<span
>C类商品属于长尾商品,备货周期更长,最好是集中采购,并适当增大库存量,相应减少订货次数。</span
>
</div>
</div>
</div>
</div>
</template>
<script setup>
import * as portraitModel from "@/api/portraitModel";
import { downBlobFile } from "@/utils/index.js";
const { proxy } = getCurrentInstance();
const knowledgeFlag = ref(false);
const errorNum = ref(0);
const step1Error = ref(0);
const step2Error = ref(0);
const step3Error = ref(0);
const step4Error = ref(0);
const step1AnswerFlag = ref(false);
const step2AnswerFlag = ref(false);
const step3AnswerFlag = ref(false);
const step4AnswerFlag = ref(false);
const step1Data = ref([
{
name: "男士配饰",
amount: "2300",
},
{
name: "儿童服装",
amount: "2300",
},
{
name: "婴儿用品",
amount: "2300",
},
{
name: "床上用品",
amount: "2300",
},
]);
const fileTable1 = ref([
{
id: "20250101",
name: "男士配饰",
amount: "2300",
},
{
id: "20250102",
name: "儿童服装",
amount: "300",
},
{
id: "20250103",
name: "婴儿用品",
amount: "400",
},
{
id: "20250104",
name: "床上用品",
amount: "1200",
},
{
id: "20250105",
name: "男士配饰",
amount: "1800",
},
{
id: "20250106",
name: "婴儿用品",
amount: "300",
},
{
id: "20250107",
name: "男士配饰",
amount: "1800",
},
{
id: "20250108",
name: "儿童服装",
amount: "300",
},
{
id: "20250109",
name: "床上用品",
amount: "1200",
},
{
id: "20250110",
name: "婴儿用品",
amount: "400",
},
]);
const step2Data = ref([
{
name: "男士配饰",
amount: "",
},
{ name: "儿童服装", amount: "" },
{ name: "婴儿用品", amount: "" },
{ name: "床上用品", amount: "" },
]);
const step3Data = ref([
{
data1: "男士配饰",
data2: "5900",
},
{
data1: "床上用品",
data2: "2400",
},
{
data1: "婴儿用品",
data2: "1100",
},
{
data1: "儿童服装",
data2: "600",
},
]);
const step4Data = ref([
{
data1: "男士配饰",
data2: "5900",
data3: "59%",
data4: "2",
},
{
data1: "床上用品",
data2: "2400",
data3: "83%",
data4: "3",
},
{
data1: "婴儿用品",
data2: "1100",
data3: "94%",
data4: "1",
},
{
data1: "儿童服装",
data2: "600",
data3: "100%",
data4: "1",
},
]);
const step5Data = ref([
{
title: "平均值",
},
]);
const step6Data = ref([
{
data1: "1",
data2: "小明",
data3: "4",
data4: "2",
data5: "4",
},
{
data1: "2",
data2: "小红",
data3: "5",
data4: "2",
data5: "2",
},
{
data1: "3",
data2: "小李",
data3: "5",
data4: "1",
data5: "1",
},
]);
const rulesTable = ref([
{
data1: "1.重要价值用户",
data2: "高",
data3: "高",
data4: "高",
},
{
data1: "2.重要发展用户",
data2: "高",
data3: "低",
data4: "高",
},
{
data1: "3.重要保持用户",
data2: "低",
data3: "高",
data4: "高",
},
{
data1: "4.重要挽留用户",
data2: "低",
data3: "低",
data4: "高",
},
{
data1: "5.一般价值用户",
data2: "高",
data3: "高",
data4: "低",
},
{
data1: "6.一般发展用户",
data2: "高",
data3: "低",
data4: "低",
},
{
data1: "7.一般保持用户",
data2: "低",
data3: "高",
data4: "低",
},
{
data1: "6.一般挽留用户",
data2: "低",
data3: "低",
data4: "低",
},
]);
const typeData = ref([
{
data1: "A类商品",
data2: "占总销售额的80%,需要重点关注",
},
{
data1: "B类商品",
data2: "占总销售额的10%,给予次要关注",
},
{
data1: "C类商品",
data2: "占总销售额的10%,给予一般关注",
},
]);
onBeforeUnmount(() => {
saveData();
});
onMounted(() => {
getData();
});
const moveUp = (index, row) => {
console.log("上移", index, row);
if (index > 0) {
const upDate = step2Data.value[index - 1];
step2Data.value.splice(index - 1, 1);
step2Data.value.splice(index, 0, upDate);
} else {
alert("已经是第一条,不可上移");
}
};
const moveDown = (index, row) => {
console.log("下移", index, row);
if (index + 1 === step2Data.value.length) {
alert("已经是最后一条,不可下移");
} else {
const downDate = step2Data.value[index + 1];
step2Data.value.splice(index + 1, 1);
step2Data.value.splice(index, 0, downDate);
}
};
const downloadData = () => {
// console.log(666);
portraitModel
.downloadDataByABC({})
.then((res) => {
// console.log(res,'--');
const blob = new Blob([res], { type: "application/vnd.ms-excel" });
downBlobFile(`案例数据-帕累托分析`, blob);
})
.catch((error) => {});
};
const step1Submit = () => {
step1Error.value = 0;
for (let i in step1Data.value) {
// console.log(fileTable1.value[i]);
if (!step1Data.value[i].params) {
proxy.$modal.msgError("请先完成所有填空");
return;
}
}
if (step1Data.value[0].params && step1Data.value[0].params !== "5900") {
step1Error.value++;
}
if (step1Data.value[1].params && step1Data.value[1].params !== "600") {
step1Error.value++;
}
if (step1Data.value[2].params && step1Data.value[2].params !== "1100") {
step1Error.value++;
}
if (step1Data.value[3].params && step1Data.value[3].params !== "2400") {
step1Error.value++;
}
console.log(step1Error.value, "错误数");
proxy.$modal.msgSuccess("提交成功");
step1AnswerFlag.value = true;
//将所填值同步到第二步表格
step2Data.value[0].amount = step1Data.value[0].params;
step2Data.value[1].amount = step1Data.value[1].params;
step2Data.value[2].amount = step1Data.value[2].params;
step2Data.value[3].amount = step1Data.value[3].params;
};
const step2Submit = () => {
step2Error.value = 0;
if (
Number(step2Data.value[0].amount) > Number(step2Data.value[1].amount) &&
Number(step2Data.value[1].amount) > Number(step2Data.value[2].amount) &&
Number(step2Data.value[2].amount) > Number(step2Data.value[3].amount)
) {
step2Error.value = 0;
} else {
step2Error.value = 1;
}
console.log("错误数", step2Error.value);
proxy.$modal.msgSuccess("提交成功");
step3Data.value[0].data2 = step2Data.value[0].amount;
step3Data.value[1].data2 = step2Data.value[1].amount;
step3Data.value[2].data2 = step2Data.value[2].amount;
step3Data.value[3].data2 = step2Data.value[3].amount;
step2AnswerFlag.value = true;
};
const step3Submit = () => {
step3Error.value = 0;
for (let i in step3Data.value) {
// console.log(fileTable1.value[i]);
if (!step3Data.value[i].params1 || !step3Data.value[i].params2) {
proxy.$modal.msgError("请先完成所有填空");
return;
}
}
if (step3Data.value[0].params1 && step3Data.value[0].params1 !== "59") {
step3Error.value++;
}
if (step3Data.value[0].params2 && step3Data.value[0].params2 !== "59") {
step3Error.value++;
}
if (step3Data.value[1].params1 && step3Data.value[1].params1 !== "24") {
step3Error.value++;
}
if (step3Data.value[1].params2 && step3Data.value[1].params2 !== "83") {
step3Error.value++;
}
if (step3Data.value[2].params1 && step3Data.value[2].params1 !== "11") {
step3Error.value++;
}
if (step3Data.value[2].params2 && step3Data.value[2].params2 !== "94") {
step3Error.value++;
}
if (step3Data.value[3].params1 && step3Data.value[3].params1 !== "6") {
step3Error.value++;
}
if (step3Data.value[3].params2 && step3Data.value[3].params2 !== "100") {
step3Error.value++;
}
console.log("错误数", step3Error.value);
proxy.$modal.msgSuccess("提交成功");
step4Data.value[0].data2 = step3Data.value[0].data2;
step4Data.value[1].data2 = step3Data.value[1].data2;
step4Data.value[2].data2 = step3Data.value[2].data2;
step4Data.value[3].data2 = step3Data.value[3].data2;
step4Data.value[0].data3 = step3Data.value[0].params2;
step4Data.value[1].data3 = step3Data.value[1].params2;
step4Data.value[2].data3 = step3Data.value[2].params2;
step4Data.value[3].data3 = step3Data.value[3].params2;
step3AnswerFlag.value = true;
};
const step4Submit = () => {
step4Error.value = 0;
// console.log('asd1112');
for (let i in step4Data.value) {
// console.log(fileTable1.value[i]);
if (!step4Data.value[i].params || !step4Data.value[i].params) {
proxy.$modal.msgError("请先完成所有填空");
return;
}
}
if (step4Data.value[0].params && step4Data.value[0].params !== "A类商品") {
step4Error.value++;
}
if (step4Data.value[1].params && step4Data.value[1].params !== "B类商品") {
step4Error.value++;
}
if (step4Data.value[2].params && step4Data.value[2].params !== "C类商品") {
step4Error.value++;
}
if (step4Data.value[3].params && step4Data.value[3].params !== "C类商品") {
step4Error.value++;
}
console.log("错误数", step4Error.value);
proxy.$modal.msgSuccess("提交成功");
step4AnswerFlag.value = true;
};
const saveData = () => {
const params = {
stepFiveA: step1Data.value[0].params,
stepFiveB: step1Data.value[1].params,
stepFiveC: step1Data.value[2].params,
stepFiveD: step1Data.value[3].params,
stepSixA: step3Data.value[0].params1,
stepSixB: step3Data.value[0].params2,
stepSixC: step3Data.value[1].params1,
stepSixD: step3Data.value[1].params2,
stepSevenA: step3Data.value[2].params1,
stepSevenB: step3Data.value[2].params2,
stepSevenC: step3Data.value[3].params1,
stepSevenD: step3Data.value[3].params2,
stepEightA: step4Data.value[0].params,
stepEightB: step4Data.value[1].params,
stepEightC: step4Data.value[2].params,
stepEightD: step4Data.value[3].params,
// stepNineA: step4Data.value[0].params1,
// stepNineB: step4Data.value[0].params2,
// stepNineC: step4Data.value[0].params3,
// stepNineD: step4Data.value[1].params1,
// stepTenA: step4Data.value[1].params2,
// stepTenB: step4Data.value[1].params3,
// stepTenC: step4Data.value[2].params1,
// stepTenD: step4Data.value[2].params2,
// stepElevenA: step4Data.value[2].params3,
// stepOneA: step5Data.value[0].params1,
// stepOneB: step5Data.value[0].params2,
// stepOneC: step5Data.value[0].params3,
// stepOneD: step6Data.value[0].params1,
// stepTwoA: step6Data.value[0].params2,
// stepTwoB: step6Data.value[0].params3,
// stepTwoC: step6Data.value[1].params1,
// stepThreeA: step6Data.value[1].params2,
// stepThreeB: step6Data.value[1].params3,
// stepThreeC: step6Data.value[2].params1,
// stepThreeD: step6Data.value[2].params2,
// stepFourA: step6Data.value[2].params3,
// stepFourB: step7Data.value[0].params,
// stepFourC: step7Data.value[1].params,
// stepFourD: step7Data.value[2].params,
};
portraitModel
.saveData({
userId: 492,
module: "帕累托/ABC分析",
...params,
})
.then((res) => {})
.catch((error) => {});
};
const getData = () => {
portraitModel
.getData({
userId: 492,
module: "帕累托/ABC分析",
})
.then((res) => {
step1Data.value[0].params = res.data.stepFiveA;
step1Data.value[1].params = res.data.stepFiveB;
step1Data.value[2].params = res.data.stepFiveC;
step1Data.value[3].params = res.data.stepFiveD;
step3Data.value[0].params1 = res.data.stepSixA;
step3Data.value[0].params2 = res.data.stepSixB;
step3Data.value[1].params1 = res.data.stepSixC;
step3Data.value[1].params2 = res.data.stepSixD;
step3Data.value[2].params1 = res.data.stepSevenA;
step3Data.value[2].params2 = res.data.stepSevenB;
step3Data.value[3].params1 = res.data.stepSevenC;
step3Data.value[3].params2 = res.data.stepSevenD;
step4Data.value[0].params = res.data.stepEightA;
step4Data.value[1].params = res.data.stepEightB;
step4Data.value[2].params = res.data.stepEightC;
step4Data.value[3].params = res.data.stepEightD;
// step4Data.value[0].params1 = res.data.stepNineA;
// step4Data.value[0].params2 = res.data.stepNineB;
// step4Data.value[0].params3 = res.data.stepNineC;
// step4Data.value[1].params1 = res.data.stepNineD;
// step4Data.value[1].params2 = res.data.stepTenA;
// step4Data.value[1].params3 = res.data.stepTenB;
// step4Data.value[2].params1 = res.data.stepTenC;
// step4Data.value[2].params2 = res.data.stepTenD;
// step4Data.value[2].params3 = res.data.stepElevenA;
// step5Data.value[0].params1 = res.data.stepOneA;
// step5Data.value[0].params2 = res.data.stepOneB;
// step5Data.value[0].params3 = res.data.stepOneC;
// step6Data.value[0].params1 = res.data.stepOneD;
// step6Data.value[0].params2 = res.data.stepTwoA;
// step6Data.value[0].params3 = res.data.stepTwoB;
// step6Data.value[1].params1 = res.data.stepTwoC;
// step6Data.value[1].params2 = res.data.stepThreeA;
// step6Data.value[1].params3 = res.data.stepThreeB;
// step6Data.value[2].params1 = res.data.stepThreeC;
// step6Data.value[2].params2 = res.data.stepThreeD;
// step6Data.value[2].params3 = res.data.stepFourA;
// step7Data.value[0].params = res.data.stepFourB;
// step7Data.value[1].params = res.data.stepFourC;
// step7Data.value[2].params = res.data.stepFourD;
})
.catch((error) => {});
};
const submitData = () => {
console.log("tj");
if (
!step1AnswerFlag.value ||
!step2AnswerFlag.value ||
!step3AnswerFlag.value ||
!step4AnswerFlag.value
) {
proxy.$modal.msgError("请先完成所有步骤!");
return;
}
errorNum.value =
step1Error.value + step2Error.value + step3Error.value + step4Error.value;
console.log(errorNum.value, "总错误次数");
portraitModel
.submit({
userId: 492,
taskName: "帕累托/ABC分析",
numberOfErrors: errorNum.value,
})
.then((res) => {
proxy.$modal.msgSuccess("提交成功");
})
.catch((error) => {});
};
const retrain = () => {
portraitModel
.retrain({
userId: 492,
module: "帕累托/ABC分析",
})
.then((res) => {
proxy.$modal.msgSuccess("重新实训成功");
for (let i in step1Data.value) {
step1Data.value[i].params = "";
}
for (let i in step3Data.value) {
step3Data.value[i].params1 = "";
step3Data.value[i].params2 = "";
}
for (let i in step4Data.value) {
step4Data.value[i].params = "";
}
// for (let i in step5Data.value) {
// step5Data.value[i].params1 = "";
// step5Data.value[i].params2 = "";
// step5Data.value[i].params3 = "";
// }
})
.catch((error) => {});
};
defineExpose({
submitData,
retrain,
// practicalTraining,
});
</script>
<style scoped lang="scss">
.content {
width: 100%;
background: rgba(0, 29, 64, 0.5);
border: 1px solid #0452c6;
padding: 10px;
// opacity: 0.5;
.import {
display: flex;
font-size: 15px;
font-weight: bold;
width: 180px;
height: 56px;
background-image: url("@/assets/images/01.png");
background-size: 180px 56px;
text-align: center;
align-items: center;
line-height: 56px;
cursor: pointer;
img {
margin-left: 20px;
margin-right: 15px;
}
}
.caseBack {
.title {
font-weight: bold;
margin-top: 10px;
display: flex;
align-items: center;
span {
margin-left: 10px;
}
}
.download {
cursor: pointer;
margin-left: 20px;
color: #000;
padding-left: 10px;
font-size: 14px;
text-align: center;
line-height: 31px;
width: 89px;
height: 31px;
background: url("@/assets/images/downloadIcon.png");
}
.submit {
cursor: pointer;
margin-left: 20px;
color: #000;
padding-left: 10px;
font-size: 14px;
text-align: center;
line-height: 31px;
width: 99px;
height: 31px;
background: url("@/assets/images/提交任务.png");
}
.customerType {
padding-left: 10px;
display: flex;
align-items: center;
width: 945px;
height: 26px;
background: #003b75;
border-radius: 10px;
border: 1px solid #0052a3;
font-size: 12px;
margin-top: 10px;
img {
margin-right: 10px;
}
}
}
.line {
width: 1400px;
height: 1px;
border: 1px solid #0452c6;
opacity: 0.5;
margin-top: 20px;
margin-bottom: 20px;
}
}
::v-deep .el-table tr {
background-color: #002652 !important;
color: #fff;
}
</style>

File diff suppressed because one or more lines are too long

@ -0,0 +1,637 @@
<template>
<div class="content">
<div class="import" @click="knowledgeFlag = !knowledgeFlag">
<img src="@/assets/images/导入.png" alt="" />
<span>任务知识导入</span>
</div>
<div v-if="knowledgeFlag">
<p style="line-height: 25px; font-size: 14px">
波士顿矩阵(BCG
Matrix),又称市场增长率-相对市场份额矩阵,由美国著名的管理学家、波士顿咨询公司创始人布鲁斯·亨德森于1970年首创,它是通过销售增长率(反应市场引力的指标)和市场占有率(反应企业实力的指标)来分析决定企业的产品结构。<br />
市场吸引力包括企业销售量增长率、目标市场容量、竞争对手强弱、利润高低等。其中最重要的是反映市场引力的综合指标——销售增长率,这是决定企业产品结构是否合理的外在因素。<br />
企业实力包括市场占有率、技术、设备、资金利用能力等,其中市场占有率是决定企业产品结构的内在因素,他直接显示出企业的竞争实力。
</p>
<img src="@/assets/images/u3678.png" alt="" /><br />
<span style="line-height: 25px; font-size: 14px">
波士顿矩阵将产品类型分为四种:<br />
1,明星类产品:高增长且高市占,发展前景好,竞争力强,需加大投资以支持其发展;<br />
2,问题类产品:高增长但低市占,发展前景好但市场开拓不足,需谨慎投资;<br />
3,现金牛产品:低增长但高市占,成熟市场的领导者,应降低投资,维持市占并延缓衰退;<br />
4,瘦狗类产品:低增长且低市占,理论率低甚至亏损,应采取撤退战略。 </span
><br />
<img src="@/assets/images/u3682.png" alt="" />
</div>
<div v-if="!knowledgeFlag">
<div class="caseBack">
<div class="title">
<img src="@/assets/images/caseIcon.png" alt="" />
<span>案例背景:</span>
</div>
<span style="line-height: 25px; font-size: 14px">
现有以下某商店的客户消费原始数据,需要采用波士顿矩阵分析方法,对客户进行分类:
</span>
<div style="margin-top: 10px; display: flex">
<el-table
:data="fileTable1"
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="客户ID" align="center" prop="id">
</el-table-column>
<el-table-column label="消费金额" align="center" prop="amount">
</el-table-column>
<el-table-column label="消费时间" align="center" prop="time">
</el-table-column>
</el-table>
<div class="download" @click="downloadData">下载数据</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第一步,统计各个客户的消费次数和消费金额</span>
</div>
<span style="line-height: 25px; font-size: 14px">
以客户ID为统计单元,分别计算各个客户累计的消费次数、消费金额。
</span>
<div style="margin-top: 10px; display: flex">
<el-table
:data="step1Data"
style="width: 550px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="客户ID" align="center" prop="name">
</el-table-column>
<el-table-column label="消费次数" align="center" prop="amount">
<template #default="scope">
<el-input
v-model="scope.row.params1"
placeholder="请输入"
style="width: 130px"
>
</el-input>
</template>
</el-table-column>
<el-table-column label="消费金额" align="center" prop="amount">
<template #default="scope">
<el-input
v-model="scope.row.params2"
placeholder="请输入"
style="width: 130px"
>
</el-input>
</template>
</el-table-column>
</el-table>
<div class="submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第二步,确定象限测度划分标准</span>
</div>
<span style="line-height: 25px; font-size: 14px">
以客户ID为统计单元,分别计算各个客户的平均消费次数、平均消费金额。
</span>
<div style="margin-top: 10px; display: flex">
<el-table
:data="step2Data"
style="width: 650px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="客户ID" align="center" prop="name">
</el-table-column>
<el-table-column label="消费次数" align="center" prop="amount">
</el-table-column>
<el-table-column label="消费金额" align="center" prop="account">
</el-table-column>
</el-table>
<div class="submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第三步,绘制散点图</span>
</div>
<span style="line-height: 25px; font-size: 14px">
以消费金额为纵轴,消费次数为横轴,将第一步的客户数据绘制于坐标轴中
</span>
<div style="margin-top: 10px; display: flex">
<div class="submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第四步,坐标轴区域绘制象限测度划分标准</span>
</div>
<span style="line-height: 25px; font-size: 14px">
将计算出的客户的平均消费次数、平均消费金额,绘制在坐标轴中。
</span>
<div style="margin-top: 10px; display: flex">
<!-- <el-table
:data="step4Data"
style="width: 680px"
border
:header-cell-style="{
color: '#fff',
fontSize: '14px',
backgroundColor: '#6A7DE9!important',
}"
>
<el-table-column label="商品名称" align="center" prop="data1">
</el-table-column>
<el-table-column label="销售额" align="center" prop="data2">
</el-table-column>
<el-table-column
label="累计销售额占比(%)"
align="center"
prop="data3"
>
</el-table-column>
<el-table-column label="划分商品类型" align="center" prop="data4">
<template #default="scope">
<el-select
v-model="scope.row.params"
placeholder="请选择"
style="width: 100px"
>
<el-option :label="'A类商品'" :value="'A类商品'" />
<el-option :label="'B类商品'" :value="'B类商品'" />
<el-option :label="'C类商品'" :value="'C类商品'" />
</el-select>
</template>
</el-table-column>
</el-table> -->
<div class="submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第五步,划分客户类型</span>
</div>
<span style="line-height: 25px; font-size: 14px">
按照客户标准,划分A、B、C、D各属于哪类客户。<br />
1、消费次数超过平均值,每次消费力度也超过平均水平的客户:判定为明星客户<br />
2、消费次数超过平均值,但每次消费力度未达到平均水平的客户:被判定为现金流客户<br />
3、消费未达到平均值,但每次消费力度超过平均水平的客户:是问题客户<br />
4、消费未达到平均值,消费力度也未达到平均水平的客户:属于瘦狗客户
</span>
<div style="margin-top: 10px; display: flex">
<div class="submit">提交</div>
</div>
</div>
<div class="line"></div>
<div class="caseBack">
<div class="title">
<img src="@/assets/images/步骤.png" alt="" />
<span>第六步,针对不同的客户类型,制定不同的营销策略</span>
</div>
<span style="line-height: 25px; font-size: 14px">
当波士顿矩阵应用于客户画像时候,可以大致分析出不同用户的客户画像:
</span>
<div class="customerType" style="width: 887px">
<img src="@/assets/images/客户1.png" alt="" />
<span>明星客户,这类客户需要重点关注,并给予最高的礼遇;</span>
</div>
<div class="customerType" style="width: 887px">
<img src="@/assets/images/客户2.png" alt="" />
<span
>现金流客户,这类客户通常消费频次比较频繁,能给企业带来较为稳定的现金流,这类客户是企业利润基石;</span
>
</div>
<div class="customerType" style="width: 887px">
<img src="@/assets/images/客户3.png" alt="" />
<span
>问题客户,这类客户最有希望转化为明星客户,但是因为客户存在一定的潜在问题,导致消费频次不高,这类客户需要利用客服进行重点跟进和长期跟踪;</span
>
</div>
<div class="customerType" style="width: 887px">
<img src="@/assets/images/客户1.png" alt="" />
<span
>瘦狗客户,这类客户通常占企业客户的大多数,只需要一般性维护,不需要投入重点维系。</span
>
</div>
</div>
</div>
</div>
</template>
<script setup>
import * as portraitModel from "@/api/portraitModel";
import { downBlobFile } from "@/utils/index.js";
const knowledgeFlag = ref(false);
const step1Data = ref([
{
name: "A",
amount: "2300",
},
{
name: "B",
amount: "2300",
},
{
name: "C",
amount: "2300",
},
{
name: "D",
amount: "2300",
},
]);
const fileTable1 = ref([
{
id: "A",
amount: "200",
time: "2023.02.01",
},
{
id: "B",
amount: "300",
time: "2023.02.02",
},
{
id: "A",
time: "2023.02.03",
amount: "200",
},
{
id: "D",
time: "2023.02.04",
amount: "150",
},
{
id: "C",
time: "2023.02.05",
amount: "100",
},
{
id: "B",
time: "2023.02.06",
amount: "400",
},
{
id: "C",
time: "2023.02.07",
amount: "50",
},
{
id: "D",
time: "2023.02.08",
amount: "250",
},
{
id: "D",
time: "2023.02.09",
amount: "200",
},
{
id: "B",
time: "2023.02.10",
amount: "300",
},
{
id: "D",
time: "2023.02.11",
amount: "200",
},
{
id: "C",
time: "2023.02.12",
amount: "50",
},
{
id: "D",
time: "2023.02.13",
amount: "100",
},
{
id: "A",
time: "2023.02.14",
amount: "400",
},
{
id: "C",
time: "2023.02.15",
amount: "200",
},
{
id: "B",
time: "2023.02.16",
amount: "200",
},
{
id: "C",
time: "2023.02.17",
amount: "150",
},
{
id: "D",
time: "2023.02.18",
amount: "300",
},
{
id: "C",
time: "2023.02.19",
amount: "50",
},
{
id: "D",
time: "2023.02.20",
amount: "200",
},
]);
const step2Data = ref([
{
name: "A",
amount: "3",
account: "800",
},
{ name: "B", amount: "4", account: "1200" },
{ name: "C", amount: "6", account: "600" },
{ name: "D", amount: "7", account: "1400" },
]);
const step3Data = ref([
{
data1: "男士配饰",
data2: "5900",
},
{
data1: "床上用品",
data2: "2400",
},
{
data1: "婴儿用品",
data2: "1100",
},
{
data1: "儿童服装",
data2: "600",
},
]);
const step4Data = ref([
{
data1: "男士配饰",
data2: "5900",
data3: "59%",
data4: "2",
},
{
data1: "床上用品",
data2: "2400",
data3: "83%",
data4: "3",
},
{
data1: "婴儿用品",
data2: "1100",
data3: "94%",
data4: "1",
},
{
data1: "儿童服装",
data2: "600",
data3: "100%",
data4: "1",
},
]);
const step5Data = ref([
{
title: "平均值",
},
]);
const step6Data = ref([
{
data1: "1",
data2: "小明",
data3: "4",
data4: "2",
data5: "4",
},
{
data1: "2",
data2: "小红",
data3: "5",
data4: "2",
data5: "2",
},
{
data1: "3",
data2: "小李",
data3: "5",
data4: "1",
data5: "1",
},
]);
const rulesTable = ref([
{
data1: "1.重要价值用户",
data2: "高",
data3: "高",
data4: "高",
},
{
data1: "2.重要发展用户",
data2: "高",
data3: "低",
data4: "高",
},
{
data1: "3.重要保持用户",
data2: "低",
data3: "高",
data4: "高",
},
{
data1: "4.重要挽留用户",
data2: "低",
data3: "低",
data4: "高",
},
{
data1: "5.一般价值用户",
data2: "高",
data3: "高",
data4: "低",
},
{
data1: "6.一般发展用户",
data2: "高",
data3: "低",
data4: "低",
},
{
data1: "7.一般保持用户",
data2: "低",
data3: "高",
data4: "低",
},
{
data1: "6.一般挽留用户",
data2: "低",
data3: "低",
data4: "低",
},
]);
const typeData = ref([
{
data1: "A类商品",
data2: "占总销售额的80%,需要重点关注",
},
{
data1: "B类商品",
data2: "占总销售额的10%,给予次要关注",
},
{
data1: "C类商品",
data2: "占总销售额的10%,给予一般关注",
},
]);
const moveUp = (index, row) => {
console.log("上移", index, row);
if (index > 0) {
const upDate = step2Data.value[index - 1];
step2Data.value.splice(index - 1, 1);
step2Data.value.splice(index, 0, upDate);
} else {
alert("已经是第一条,不可上移");
}
};
const moveDown = (index, row) => {
console.log("下移", index, row);
if (index + 1 === step2Data.value.length) {
alert("已经是最后一条,不可下移");
} else {
const downDate = step2Data.value[index + 1];
step2Data.value.splice(index + 1, 1);
step2Data.value.splice(index, 0, downDate);
}
};
const downloadData = () => {
// console.log(666);
portraitModel
.downloadDataByBoston({
})
.then((res) => {
// console.log(res,'--');
const blob = new Blob([res], { type: "application/vnd.ms-excel" });
downBlobFile(`案例数据-波士顿矩阵分析`, blob);
})
.catch((error) => {});
}
</script>
<style scoped lang="scss">
.content {
width: 100%;
background: rgba(0, 29, 64, 0.5);
border: 1px solid #0452c6;
padding: 10px;
// opacity: 0.5;
.import {
display: flex;
font-size: 15px;
font-weight: bold;
width: 180px;
height: 56px;
background-image: url("@/assets/images/01.png");
background-size: 180px 56px;
text-align: center;
align-items: center;
line-height: 56px;
cursor: pointer;
img {
margin-left: 20px;
margin-right: 15px;
}
}
.caseBack {
.title {
font-weight: bold;
margin-top: 10px;
display: flex;
align-items: center;
span {
margin-left: 10px;
}
}
.download {
cursor: pointer;
margin-left: 20px;
color: #000;
padding-left: 10px;
font-size: 14px;
text-align: center;
line-height: 31px;
width: 89px;
height: 31px;
background: url("@/assets/images/downloadIcon.png");
}
.submit {
cursor: pointer;
margin-left: 20px;
color: #000;
padding-left: 10px;
font-size: 14px;
text-align: center;
line-height: 31px;
width: 99px;
height: 31px;
background: url("@/assets/images/提交任务.png");
}
.customerType {
padding-left: 10px;
display: flex;
align-items: center;
width: 945px;
height: 26px;
background: #003b75;
border-radius: 10px;
border: 1px solid #0052a3;
font-size: 12px;
margin-top: 10px;
img {
margin-right: 10px;
}
}
}
.line {
width: 1400px;
height: 1px;
border: 1px solid #0452c6;
opacity: 0.5;
margin-top: 20px;
margin-bottom: 20px;
}
}
::v-deep .el-table tr {
background-color: #002652 !important;
color: #fff;
}
</style>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -0,0 +1,527 @@
<template>
<div class="content">
<div class="tabList">
<div
class="tabs"
v-for="item in tabList"
:key="item.id"
@click="changeTab(item)"
>
<div style="display: flex; align-items: center">
<img :src="item.backImg" alt="" />
<span>{{ item.title }}</span>
</div>
</div>
</div>
<div class="btn" v-if="currentComponent">
<div class="submit" @click="submit">提交任务</div>
<div class="retrain" @click="retrain">重新实训</div>
</div>
<div class="container" v-if="menuIndex != 0">
<div class="leftContent">
<div class="title">
<img src="@/assets/images/图标1.png" alt="" />
<span>内置表</span>
</div>
<el-menu
default-active="1"
@open="handleOpen"
@close="handleClose"
@select="handleChange"
background-color="#041C49"
style="border-right: none"
active-text-color="#ffffff"
text-color="#9BD1FF"
>
<el-menu-item index="1">
<span>用户属性表</span>
</el-menu-item>
<el-menu-item index="2">
<span>用户登录活跃表</span>
</el-menu-item>
<el-menu-item index="3">
<span>用户消费能力表</span>
</el-menu-item>
<el-menu-item index="4">
<span>用户行为表</span>
</el-menu-item>
<el-menu-item index="5">
<span>用户评论表</span>
</el-menu-item>
</el-menu>
</div>
<div class="table">
<el-table
v-if="menuIndex == 1"
:data="fileTable"
style="width: 1350px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
background: `linear-gradient(0deg, #002651 0%, #0087F9 100%)`,
}"
>
<el-table-column label="用户ID" align="center" prop="id">
</el-table-column>
<el-table-column label="登录名" align="center" prop="loginName">
</el-table-column>
<el-table-column label="用户姓名" align="center" prop="userName">
</el-table-column>
<el-table-column label="学号" align="center" prop="studentId">
</el-table-column>
<el-table-column label="班级" align="center" prop="stuClass">
</el-table-column>
<el-table-column label="专业" align="center" prop="major">
</el-table-column>
<el-table-column label="学校" align="center" prop="school">
</el-table-column>
<el-table-column label="角色名称" align="center" prop="roleName">
</el-table-column>
<el-table-column label="角色性别" align="center" prop="roleGender">
</el-table-column>
<el-table-column label="角色年龄" align="center" prop="roleAge">
</el-table-column>
<el-table-column label="注册时间" align="center" prop="updateTime">
</el-table-column>
<el-table-column label="所在地" align="center" prop="location">
</el-table-column>
</el-table>
<el-table
v-if="menuIndex == 2"
:data="fileTable"
style="width: 1350px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
background: `linear-gradient(0deg, #002651 0%, #0087F9 100%)`,
}"
>
<el-table-column label="用户ID" align="center" prop="a1">
</el-table-column>
<el-table-column label="登录名" align="center" prop="a1">
</el-table-column>
<el-table-column label="用户姓名" align="center" prop="a1">
</el-table-column>
<el-table-column label="学号" align="center" prop="a1">
</el-table-column>
<el-table-column label="班级" align="center" prop="a1">
</el-table-column>
<el-table-column label="专业" align="center" prop="a1">
</el-table-column>
<el-table-column label="学校" align="center" prop="a1">
</el-table-column>
<el-table-column label="角色名称" align="center" prop="a1">
</el-table-column>
<el-table-column label="常登录地" align="center" prop="a1">
</el-table-column>
<el-table-column label="最近登录日期" align="center" prop="a1">
</el-table-column>
<el-table-column label="登录频次" align="center" prop="a1">
</el-table-column>
<el-table-column label="登录时长" align="center" prop="a1">
</el-table-column>
</el-table>
<el-table
v-if="menuIndex == 3"
:data="fileTable"
style="width: 1350px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
background: `linear-gradient(0deg, #002651 0%, #0087F9 100%)`,
}"
>
<el-table-column label="用户ID" align="center" prop="a1">
</el-table-column>
<el-table-column label="登录名" align="center" prop="a1">
</el-table-column>
<el-table-column label="用户姓名" align="center" prop="a1">
</el-table-column>
<el-table-column label="学号" align="center" prop="a1">
</el-table-column>
<el-table-column label="班级" align="center" prop="a1">
</el-table-column>
<el-table-column label="专业" align="center" prop="a1">
</el-table-column>
<el-table-column label="学校" align="center" prop="a1">
</el-table-column>
<el-table-column label="角色名称" align="center" prop="a1">
</el-table-column>
<el-table-column
label="消费商品小类"
align="center"
prop="a1"
width="110"
>
</el-table-column>
<el-table-column
label="消费商品类型"
align="center"
prop="a1"
width="110"
>
</el-table-column>
<el-table-column
label="累计消费金额"
align="center"
prop="a1"
width="110"
>
</el-table-column>
<el-table-column
label="累计消费次数"
align="center"
prop="a1"
width="110"
>
</el-table-column>
<el-table-column
label="近七天消费金额"
align="center"
prop="a1"
width="130"
>
</el-table-column>
<el-table-column
label="近七天消费次数"
align="center"
prop="a1"
width="130"
>
</el-table-column>
<el-table-column
label="最近消费时间"
align="center"
prop="a1"
width="110"
>
</el-table-column>
</el-table>
<el-table
v-if="menuIndex == 4"
:data="fileTable"
style="width: 1350px"
:header-cell-style="{
color: '#fff',
fontSize: '14px',
background: `linear-gradient(0deg, #002651 0%, #0087F9 100%)`,
}"
>
<el-table-column label="用户ID" align="center" prop="a1">
</el-table-column>
<el-table-column label="登录名" align="center" prop="a1">
</el-table-column>
<el-table-column label="用户姓名" align="center" prop="a1">
</el-table-column>
<el-table-column label="学号" align="center" prop="a1">
</el-table-column>
<el-table-column label="班级" align="center" prop="a1">
</el-table-column>
<el-table-column label="专业" align="center" prop="a1">
</el-table-column>
<el-table-column label="学校" align="center" prop="a1">
</el-table-column>
<el-table-column label="角色名称" align="center" prop="a1">
</el-table-column>
<el-table-column
label="商品名称"
align="center"
prop="a1"
width="110"
>
</el-table-column>
<el-table-column
label="商品小类"
align="center"
prop="a1"
width="110"
>
</el-table-column>
<el-table-column
label="商品类型"
align="center"
prop="a1"
width="110"
>
</el-table-column>
<el-table-column
label="用户行为类型"
align="center"
prop="a1"
width="110"
>
</el-table-column>
<el-table-column
label="行为日期"
align="center"
prop="a1"
width="130"
>
</el-table-column>
</el-table>
</div>
</div>
<main-content
v-if="menuIndex == 0"
:currentComponent="currentComponent"
ref="contentRef"
></main-content>
</div>
</template>
<script setup>
import { ref } from "vue";
import { defineExpose } from "vue";
import * as portraitModel from "@/api/portraitModel";
import mainContent from "@/views/components/mainContent.vue";
import rfmAnalysis from "./components/rfmAnalysis.vue";
import abcAnalysis from "./components/abcAnalysis.vue";
import bostonAnalysis from "./components/bostonAnalysis.vue";
import funnelAnalysis from "./components/funnelAnalysis.vue";
import basketAnalysis from "./components/basketAnalysis.vue";
import repurchaseAnalysis from "./components/repurchaseAnalysis.vue";
import retainAnalysis from "./components/retainAnalysis.vue";
import viscosityAnalysis from "./components/viscosityAnalysis.vue";
import AARRRAnalysis from "./components/AARRRAnalysis.vue";
import portraitAnalysis from "./components/portraitAnalysis.vue";
import { onMounted } from "vue";
const { proxy } = getCurrentInstance();
const currentComponent = ref(null);
const contentRef = ref(null);
const menuIndex = ref(1);
const tabIndex = ref(0);
const fileTable = ref([]);
const tabList = ref([
{
id: "1",
key: rfmAnalysis,
title: "RFM分析",
backImg: "src/assets/images/icon1.png",
},
{
id: "2",
key: abcAnalysis,
title: "帕累托/ABC分析",
backImg: "src/assets/images/icon2.png",
},
{
id: "3",
key: bostonAnalysis,
title: "波士顿矩阵分析",
backImg: "src/assets/images/icon3.png",
},
{
id: "4",
key: funnelAnalysis,
title: "转化分析-漏斗模型",
backImg: "src/assets/images/icon4.png",
},
{
id: "5",
key: basketAnalysis,
title: "购物篮分析",
backImg: "src/assets/images/icon5.png",
},
{
id: "6",
key: repurchaseAnalysis,
title: "复购分析",
backImg: "src/assets/images/icon6.png",
},
{
id: "7",
key: retainAnalysis,
title: "留存分析",
backImg: "src/assets/images/icon7.png",
},
{
id: "8",
key: viscosityAnalysis,
title: "用户粘性分析",
backImg: "src/assets/images/icon8.png",
},
{
id: "9",
key: AARRRAnalysis,
title: "AARRR用户运营分析",
backImg: "src/assets/images/icon9.png",
},
{
id: "10",
key: portraitAnalysis,
title: "用户画像分析",
backImg: "src/assets/images/icon10.png",
},
]);
// defineExpose({ submitMethod });
onMounted(() => {
getTableData("用户属性表");
});
const getTableData = (name) => {
fileTable.value = [];
portraitModel
.getUserTableData({
userId: 492,
tableName: name,
size:10,
index:1
})
.then((res) => {
// fileTable.value.push(res.data.list);
fileTable.value = res.data.list
// console.log(res,'--');
})
.catch((error) => {});
};
const handleChange = (index) => {
console.log(index);
menuIndex.value = index;
if (index == 1) {
getTableData("用户属性表");
} else if (index == 2) {
getTableData("用户登录活跃表");
} else if (index == 3) {
getTableData("用户消费能力表");
} else if (index == 4) {
getTableData("用户行为表");
} else {
getTableData("用户评论表");
}
};
const changeTab = (item) => {
currentComponent.value = item.key;
menuIndex.value = 0;
// tabIndex = item.id;
};
const submit = () => {
contentRef.value.submitMethod();
};
const retrain = () => {
contentRef.value.retrainMethod();
}
// defineExpose({
// submit,
// });
</script>
<style lang="scss" scoped>
.content {
color: #fff;
.tabList {
// display: flex;
width: 1060px;
.tabs {
cursor: pointer;
font-size: 14px;
margin-right: 20px;
margin-bottom: 20px;
width: 188px;
height: 61px;
background-image: url("@/assets/images/itembg1.png");
// display: flex;
// justify-content: center;
// align-items: center;
padding-left: 30px;
line-height: 60px;
display: inline-block;
img {
margin-right: 15px;
}
}
.tabs:nth-of-type(2),
.tabs:nth-of-type(9) {
background-image: url("@/assets/images/itembg2.png");
}
.tabs:nth-of-type(3),
.tabs:nth-of-type(10) {
background-image: url("@/assets/images/itembg3.png");
}
.tabs:nth-of-type(4),
.tabs:nth-of-type(6) {
background-image: url("@/assets/images/itembg4.png");
}
.tabs:nth-of-type(5),
.tabs:nth-of-type(7) {
background-image: url("@/assets/images/itembg5.png");
}
.tabs:nth-of-type(8) {
background-image: url("@/assets/images/itembg1.png");
}
.tabs:nth-of-type(4),
.tabs:nth-of-type(9) {
padding-left: 20px;
img {
margin-right: 5px;
}
}
}
.btn {
display: flex;
position: absolute;
right: 70px;
top: 110px;
.submit {
width: 99px;
height: 31px;
background-image: url("@/assets/images/submit.png");
color: #080138;
font-size: 14px;
line-height: 31px;
padding-left: 30px;
cursor: pointer;
}
.retrain {
width: 99px;
height: 31px;
background-image: url("@/assets/images/retrain.png");
color: #080138;
font-size: 14px;
line-height: 31px;
padding-left: 30px;
margin-left: 20px;
cursor: pointer;
}
}
.container {
display: flex;
.leftContent {
width: 205px;
height: 691px;
background: #041c49;
border: 1px solid #063373;
.title {
padding-left: 10px;
display: flex;
align-items: center;
font-size: 18px;
color: #3596eb;
font-weight: bold;
height: 50px;
border-bottom: 1px solid #063373;
span {
margin-left: 10px;
}
}
.el-menu-item {
padding-left: 40px;
height: 40px;
}
}
.table {
margin-left: 20px;
}
}
}
.el-menu-item.is-active {
// color: var(--el-menu-active-color);
background-color: #1983dd !important;
}
::v-deep .el-table tr {
background-color: #002652 !important;
color: #fff;
}
::v-deep .el-table--enable-row-hover .el-table__body tr:hover > td {
background-color: #0077dd !important;
/* color: #fff; */
}
</style>
Loading…
Cancel
Save