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

@ -2,7 +2,7 @@
* @Author: qinzhenpen qzp1807@126.com * @Author: qinzhenpen qzp1807@126.com
* @Date: 2024-08-16 10:14:59 * @Date: 2024-08-16 10:14:59
* @LastEditors: qinzhenpen qzp1807@126.com * @LastEditors: qinzhenpen qzp1807@126.com
* @LastEditTime: 2024-08-17 16:57:01 * @LastEditTime: 2024-08-19 15:07:27
* @FilePath: \vue3\src\api\marketing-algorithm.js * @FilePath: \vue3\src\api\marketing-algorithm.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/ */
@ -55,3 +55,21 @@ export function getMarketingAlgorithmKnowledgeImport(data) {
data, data,
}); });
} }
//描述性统计分析下载
export function getMarketingAlgorithmDownload(data) {
return request({
url: "/api/analysis/dSExport",
//下载
responseType: "blob",
method: "post",
data,
});
}
// 情感分析
export function getMarketingAlgorithmSentiment(data) {
return request({
url: "/api/model/emotionalAnalysis",
method: "POST",
data,
});
}

@ -175,7 +175,7 @@
<p>支持度是一个度量,用于表示一个项集在整个数据集中出现的频率。<br />!file</p><p style="font-size:19px;font-weight:600">置信度(Confidence)</p><p>置信度表示在包含项集X的所有事务中,也包含项集Y的事务的概率。</p><img src="@/assets/images/f2001.png" alt=""><p style="font-size:19px;font-weight:600">提升度(Lift)</p><p>提升度用于衡量项集X和Y的出现是否相互独立。</p><img src="@/assets/images/f2002.png" alt=""><p style="font-size:19px;font-weight:600">Apriori原理</p><p>Apriori原理是Apriori算法的核心,它基于一个简单但重要的观察:一个项集是频繁的,那么它的所有子集也必须是频繁的。<br />例子: 如果{"牛奶", "面包", "啤酒"}是一个频繁项集,那么{"牛奶", "面包"}、{"牛奶", "啤酒"}和{"面包", "啤酒"}也必须是频繁项集。<br />通过以上的概念和例子,我们应该对关联规则挖掘的基础理论有了更深入的了解。这为我们后续详解Apriori算法以及实际应用提供了坚实的基础。</p><p style="font-weight: 700;font-size:22px">三、Apriori算法概述</p><p>Apriori算法是由Agrawal和Srikant于1994年提出的,用于高效地挖掘频繁项集和生成关联规则。其名字“Apriori”来源于拉丁语,意为“从先验知识”。这很好地反映了算法的核心思想:利用已知的频繁项集(即先验知识)来更有效地找到更大的频繁项集。</p><p style="font-size:19px;font-weight:600">算法步骤</p><img src="@/assets/images/f2004.png" alt=""><p>Apriori算法的执行流程主要包含两个步骤:<br />&nbsp;&nbsp;1.频繁项集生成(Frequent Itemset Generation): 找出满足最小支持度阈值的所有频繁项集。<br />&nbsp;&nbsp;2.关联规则生成(Association Rule Generation): 从频繁项集中生成高置信度的关联规则。</p> <p>支持度是一个度量,用于表示一个项集在整个数据集中出现的频率。<br />!file</p><p style="font-size:19px;font-weight:600">置信度(Confidence)</p><p>置信度表示在包含项集X的所有事务中,也包含项集Y的事务的概率。</p><img src="@/assets/images/f2001.png" alt=""><p style="font-size:19px;font-weight:600">提升度(Lift)</p><p>提升度用于衡量项集X和Y的出现是否相互独立。</p><img src="@/assets/images/f2002.png" alt=""><p style="font-size:19px;font-weight:600">Apriori原理</p><p>Apriori原理是Apriori算法的核心,它基于一个简单但重要的观察:一个项集是频繁的,那么它的所有子集也必须是频繁的。<br />例子: 如果{"牛奶", "面包", "啤酒"}是一个频繁项集,那么{"牛奶", "面包"}、{"牛奶", "啤酒"}和{"面包", "啤酒"}也必须是频繁项集。<br />通过以上的概念和例子,我们应该对关联规则挖掘的基础理论有了更深入的了解。这为我们后续详解Apriori算法以及实际应用提供了坚实的基础。</p><p style="font-weight: 700;font-size:22px">三、Apriori算法概述</p><p>Apriori算法是由Agrawal和Srikant于1994年提出的,用于高效地挖掘频繁项集和生成关联规则。其名字“Apriori”来源于拉丁语,意为“从先验知识”。这很好地反映了算法的核心思想:利用已知的频繁项集(即先验知识)来更有效地找到更大的频繁项集。</p><p style="font-size:19px;font-weight:600">算法步骤</p><img src="@/assets/images/f2004.png" alt=""><p>Apriori算法的执行流程主要包含两个步骤:<br />&nbsp;&nbsp;1.频繁项集生成(Frequent Itemset Generation): 找出满足最小支持度阈值的所有频繁项集。<br />&nbsp;&nbsp;2.关联规则生成(Association Rule Generation): 从频繁项集中生成高置信度的关联规则。</p>
<p style="font-size:19px;font-weight:600">频繁项集生成</p><p>&nbsp;&nbsp;1.扫描数据集,找出所有单一项的支持度,并筛选出满足最小支持度的项。<br />&nbsp;&nbsp;2.使用满足最小支持度的项生成新的候选项集。<br />&nbsp;&nbsp;3.计算新生成的候选项集的支持度,并再次筛选。<br />&nbsp;&nbsp;4.重复上述步骤,直到不能生成新的频繁项集。<br />例子: 假设有一个购物交易数据集,其中包括5笔交易。第一步是计算所有单一商品(如“牛奶”,“面包”等)在这5笔交易中的出现次数,并筛选出那些出现次数达到最小支持度的商品。</p><p style="font-size:19px;font-weight:600">关联规则生成</p><p>&nbsp;&nbsp;1.对于每一个频繁项集,生成所有可能的非空子集。<br />&nbsp;&nbsp;2.对每一条生成的规则 ( A \Rightarrow B ),计算其置信度。<br />&nbsp;&nbsp;3.如果规则的置信度满足最小置信度要求,则该规则为有效关联规则。</p><p>例子: 对于频繁项集 {"牛奶", "面包", "黄油"},可能的规则有 "牛奶, 面包 -> 黄油", "牛奶, 黄油 -> 面包" 等。计算这些规则的置信度,并筛选出满足最小置信度的规则。</p><p style="font-size:19px;font-weight:600">优缺点</p><p style="font-size:19px;font-weight:600">优点</p><li>简单易懂: Apriori算法基于直观的原理,并且计算过程简单。</li><li>可扩展性强: 算法可以应用于大规模的数据集。</li><p style="font-size:19px;font-weight:600">缺点</p><li>计算量大: 在大数据集上,可能需要生成大量的候选项集。</li><li>多次扫描数据: 算法需要多次扫描数据集以计算项集的支持度,这在数据集很大时可能是低效的。</li><p>例子: 在一个包含百万级交易数据的电子商务网站中,使用Apriori算法可能需要消耗大量计算资源和时间。<br />通过以上的详细描述和例子,我们应该对Apriori算法有了全面而深入的理解。这为我们后续的技术解析和实战应用奠定了基础。</p> <p style="font-size:19px;font-weight:600">频繁项集生成</p><p>&nbsp;&nbsp;1.扫描数据集,找出所有单一项的支持度,并筛选出满足最小支持度的项。<br />&nbsp;&nbsp;2.使用满足最小支持度的项生成新的候选项集。<br />&nbsp;&nbsp;3.计算新生成的候选项集的支持度,并再次筛选。<br />&nbsp;&nbsp;4.重复上述步骤,直到不能生成新的频繁项集。<br />例子: 假设有一个购物交易数据集,其中包括5笔交易。第一步是计算所有单一商品(如“牛奶”,“面包”等)在这5笔交易中的出现次数,并筛选出那些出现次数达到最小支持度的商品。</p><p style="font-size:19px;font-weight:600">关联规则生成</p><p>&nbsp;&nbsp;1.对于每一个频繁项集,生成所有可能的非空子集。<br />&nbsp;&nbsp;2.对每一条生成的规则 ( A \Rightarrow B ),计算其置信度。<br />&nbsp;&nbsp;3.如果规则的置信度满足最小置信度要求,则该规则为有效关联规则。</p><p>例子: 对于频繁项集 {"牛奶", "面包", "黄油"},可能的规则有 "牛奶, 面包 -> 黄油", "牛奶, 黄油 -> 面包" 等。计算这些规则的置信度,并筛选出满足最小置信度的规则。</p><p style="font-size:19px;font-weight:600">优缺点</p><p style="font-size:19px;font-weight:600">优点</p><li>简单易懂: Apriori算法基于直观的原理,并且计算过程简单。</li><li>可扩展性强: 算法可以应用于大规模的数据集。</li><p style="font-size:19px;font-weight:600">缺点</p><li>计算量大: 在大数据集上,可能需要生成大量的候选项集。</li><li>多次扫描数据: 算法需要多次扫描数据集以计算项集的支持度,这在数据集很大时可能是低效的。</li><p>例子: 在一个包含百万级交易数据的电子商务网站中,使用Apriori算法可能需要消耗大量计算资源和时间。<br />通过以上的详细描述和例子,我们应该对Apriori算法有了全面而深入的理解。这为我们后续的技术解析和实战应用奠定了基础。</p>
<p style="font-weight: 700;font-size:22px">四、实战应用</p><p>在理解了Apriori算法的理论基础和工作原理之后,现在我们将进一步探讨其在实际场景中的应用。特别是在购物篮分析和推荐系统中,Apriori算法被广泛应用。<br />为了更好地说明这一点,下面将通过Python展示如何实现Apriori算法,并用一个简单的购物数据集进行演示。</p><p style="font-size:19px;font-weight:600">购物篮分析</p><p>购物篮分析(Market Basket Analysis)是一种在零售业非常流行的技术,用于发现顾客购买产品之间的关联规则。</p><p style="font-size:19px;font-weight:600">输入和输出</p><li>输入: 一组交易数据,每一笔交易包含多个购买的商品。</li><li>输出: 满足最小支持度和最小置信度的关联规则。</li><p style="font-size:19px;font-weight:600">Python实现代码</p> <p style="font-weight: 700;font-size:22px">四、实战应用</p><p>在理解了Apriori算法的理论基础和工作原理之后,现在我们将进一步探讨其在实际场景中的应用。特别是在购物篮分析和推荐系统中,Apriori算法被广泛应用。<br />为了更好地说明这一点,下面将通过Python展示如何实现Apriori算法,并用一个简单的购物数据集进行演示。</p><p style="font-size:19px;font-weight:600">购物篮分析</p><p>购物篮分析(Market Basket Analysis)是一种在零售业非常流行的技术,用于发现顾客购买产品之间的关联规则。</p><p style="font-size:19px;font-weight:600">输入和输出</p><li>输入: 一组交易数据,每一笔交易包含多个购买的商品。</li><li>输出: 满足最小支持度和最小置信度的关联规则。</li><p style="font-size:19px;font-weight:600">Python实现代码</p>
<MdPreview editorId="id2" :modelValue="message" :codeFoldable="false" theme="dark" /> <MdPreview v-model="text" />
</div> </div>
</template> </template>
</pop-model> </pop-model>
@ -183,12 +183,12 @@
<script setup> <script setup>
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { MdPreview } from "md-editor-v3"; import { MdEditor,MdPreview } from 'md-editor-v3';
import "md-editor-v3/lib/preview.css"; import 'md-editor-v3/lib/style.css';
import ecStat from 'echarts-stat'; import ecStat from 'echarts-stat';
import * as API from '@/api/AI.js' import * as API from '@/api/AI.js'
import { getUserInfo } from "@/utils/auth"; import { getUserInfo } from "@/utils/auth";
import { onMounted } from 'vue'; import { onMounted, reactive } from 'vue';
import popModel from "@/views/components/popModal.vue"; import popModel from "@/views/components/popModal.vue";
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const dialogVisible=ref(false) const dialogVisible=ref(false)
@ -199,7 +199,7 @@ const tableLabel=reactive([
const tableLabel2=reactive([ const tableLabel2=reactive([
{prop:'date',label:''}, {prop:'date',label:''},
]) ])
const message=ref('') const text = ref('Hello Editor!');
const getList=()=>{ const getList=()=>{
API.selectionMetrics({userId:JSON.parse(getUserInfo()).userId}).then((res)=>{ API.selectionMetrics({userId:JSON.parse(getUserInfo()).userId}).then((res)=>{
res.data.forEach(element => { res.data.forEach(element => {

@ -481,27 +481,26 @@ const nowData=ref([])
const upLoad=()=>{ const upLoad=()=>{
let formData=[ let formData=[
{ {
field:tableLabel.map(item=>item.label).join(','),
camexports:[]
} }
] ]
nowData.value.forEach(item=>{ nowData.value.forEach(item=>{
item.forEach((item2,index)=>{ item.forEach((item2,index)=>{
item2.forEach((item3,index2)=>{ item2.forEach((item3,index2)=>{
if (!formData[0].camexports[index]) { if (!formData[index]) {
formData[0].camexports[index] = {}; // 如果不存在,则初始化为一个空对象 formData[index] = {}; // 如果不存在,则初始化为一个空对象
} }
if(index2===0){ if(index2===0){
formData[0].camexports[index].fieldOne=item3 formData[index].fieldOne=item3
}else if(index2===1){ }else if(index2===1){
formData[0].camexports[index].fieldTow=item3 formData[index].fieldTow=item3
}else if(index2===2){ }else if(index2===2){
formData[0].camexports[index].fieldThree=item3 formData[index].fieldThree=item3
} }
}) })
}) })
}) })
API.downloadClusterAnalysisForm(formData).then((response)=>{ API.downloadClusterAnalysisForm([formData]).then((response)=>{
// 创建一个 Blob 对象 // 创建一个 Blob 对象
const blob = new Blob([response.data], { type: 'application/octet-stream' }); const blob = new Blob([response.data], { type: 'application/octet-stream' });

@ -74,7 +74,7 @@
</div> </div>
<div class="analysisResults" style="margin-top: 20px"> <div class="analysisResults" style="margin-top: 20px">
<span style="font-weight: bold; font-size: 18px; color: #3596eb; display: block">分析结果:</span> <span style="font-weight: bold; font-size: 18px; color: #3596eb; display: block">分析结果:</span>
<el-button>下载</el-button> <el-button @click="download">下载</el-button>
<el-table :data="tableData" style="width: 100%; margin-top: 10px" :header-cell-style="headerCellStyle" height="350"> <el-table :data="tableData" style="width: 100%; margin-top: 10px" :header-cell-style="headerCellStyle" height="350">
<el-table-column v-for="column in tableLabel" :key="column.label" :prop="column.prop" :label="column.label" align="center"></el-table-column> <el-table-column v-for="column in tableLabel" :key="column.label" :prop="column.prop" :label="column.label" align="center"></el-table-column>
</el-table> </el-table>
@ -138,7 +138,6 @@
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog v-model="b_introductionOfAlgorithmKnowledge" title="算法知识导入" width="60%" :show-close="false"> <el-dialog v-model="b_introductionOfAlgorithmKnowledge" title="算法知识导入" width="60%" :show-close="false">
<template #header="{ close, titleId, titleClass }"> <template #header="{ close, titleId, titleClass }">
<div class="my-header"> <div class="my-header">
@ -147,9 +146,7 @@
</div> </div>
<img class="xtImg" src="../../../assets/images/线条.png" alt="" /> <img class="xtImg" src="../../../assets/images/线条.png" alt="" />
</template> </template>
<div class="from-item"> <div class="from-item"></div>
</div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button @click="submitTask">确定</el-button> <el-button @click="submitTask">确定</el-button>
@ -160,7 +157,7 @@
</template> </template>
<script setup> <script setup>
import * as portraitModel from "@/api/portraitModel"; import * as portraitModel from "@/api/portraitModel";
import {paginate} from '@/utils/index.js' import { paginate } from "@/utils/index.js";
import * as API from "@/api/AI.js"; import * as API from "@/api/AI.js";
import * as marketingAlgorithmApi from "@/api/marketing-algorithm.js"; import * as marketingAlgorithmApi from "@/api/marketing-algorithm.js";
import useAlgorithmStore from "@/store/modules/algorithm.js"; import useAlgorithmStore from "@/store/modules/algorithm.js";
@ -182,7 +179,7 @@ const n_dataTableQuery = ref({
const gAnalysisResults = ref({ const gAnalysisResults = ref({
index: 1, index: 1,
size: 5, size: 5,
}) });
const dialogVisible = ref(false); const dialogVisible = ref(false);
// 模型参数 // 模型参数
const modelParams = reactive([ const modelParams = reactive([
@ -253,7 +250,6 @@ const formInline = ref({
summation: "", summation: "",
observations: "", observations: "",
}); });
const input = ref();
const g_indicatorData = ref([]); const g_indicatorData = ref([]);
const preProcessText = ref({ const preProcessText = ref({
text1: "数据去重", text1: "数据去重",
@ -263,8 +259,9 @@ const preProcessText = ref({
const n_analyzeTheNumberOfDataItems = ref(0); const n_analyzeTheNumberOfDataItems = ref(0);
const aAnalyzeTheRawData = ref([]); const aAnalyzeTheRawData = ref([]);
//分析结果 //分析结果
const nNumberOfAnalysisResults=ref(0) const nNumberOfAnalysisResults = ref(0);
const aOriginalDataOfAnalysisResults=ref([]) const aOriginalDataOfAnalysisResults = ref([]);
const aOriginalDataOfAnalysisResults2 = ref({});
// 模型参数 // 模型参数
const g_modelParameter = ref([]); const g_modelParameter = ref([]);
@ -329,11 +326,12 @@ const modelCalculation = () => {
} }
const processedData = processArrayData(analysisHanderKry.value, analysisData.value); const processedData = processArrayData(analysisHanderKry.value, analysisData.value);
marketingAlgorithmApi.getMarketingAlgorithmPreprocessing(JSON.stringify({ map: processedData, statistic: g_modelParameter.value, userId: n_dataTableQuery.value.userId })).then((res) => { marketingAlgorithmApi.getMarketingAlgorithmPreprocessing(JSON.stringify({ map: processedData, statistic: g_modelParameter.value, userId: n_dataTableQuery.value.userId })).then((res) => {
aOriginalDataOfAnalysisResults2.value = res.data;
tableData.value = res.data.map((item) => item.statistics); tableData.value = res.data.map((item) => item.statistics);
if (res.data.length > 5) { if (res.data.length > 5) {
nNumberOfAnalysisResults.value=res.data.length nNumberOfAnalysisResults.value = res.data.length;
aOriginalDataOfAnalysisResults.value = res.data.map((item) => item.statistics) aOriginalDataOfAnalysisResults.value = res.data.map((item) => item.statistics);
tableData.value = res.data.map((item) => item.statistics).slice(0,5) tableData.value = res.data.map((item) => item.statistics).slice(0, 5);
} }
}); });
}; };
@ -360,7 +358,7 @@ const getIndicator = () => {
}; };
// 算法知识导入 // 算法知识导入
const knowledgeImport = () => { const knowledgeImport = () => {
b_introductionOfAlgorithmKnowledge.value=true b_introductionOfAlgorithmKnowledge.value = true;
}; };
// 实训任务提交 // 实训任务提交
const submitTask = () => { const submitTask = () => {
@ -412,11 +410,33 @@ const restart = () => {
}; };
// //
const analyzeDataNext = () => { const analyzeDataNext = () => {
analysisData.value =paginate(aAnalyzeTheRawData.value,n_dataTableQuery.value.index,n_dataTableQuery.value.size).data analysisData.value = paginate(aAnalyzeTheRawData.value, n_dataTableQuery.value.index, n_dataTableQuery.value.size).data;
}; };
const updatePageAnalysisResults = () => { const updatePageAnalysisResults = () => {
tableData.value =paginate(aOriginalDataOfAnalysisResults.value,gAnalysisResults.value.index,gAnalysisResults.value.size).data tableData.value = paginate(aOriginalDataOfAnalysisResults.value, gAnalysisResults.value.index, gAnalysisResults.value.size).data;
};
// 下载
const download = () => {
aOriginalDataOfAnalysisResults2.value.forEach((item) => {
item.statistics.field = item.field;
for (let key in item.statistics) {
item.statistics[key] = item.statistics[key] ?? 0;
} }
});
marketingAlgorithmApi.getMarketingAlgorithmDownload(aOriginalDataOfAnalysisResults2.value).then((res) => {
const blob = new Blob([res], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "描述性统计.xlsx";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
proxy.$modal.msgSuccess("下载成功");
});
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

@ -0,0 +1,593 @@
<template>
<div class="main-top">
<span style="font-weight: bold; font-size: 18px; color: #3596eb">任务描述</span>
<p style="font-weight: 400; font-size: 12px; color: #e6e6e6">(给出任务清单参考,做哪些数据的统计分析)Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar sic tempor. Sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis tellus mollis orci, sed rhoncus pronin sapien nunc accuan eget.</p>
</div>
<div class="main-but">
<el-button @click="knowledgeImport">
<img src="../../../assets/images/导入.png" alt="" />
算法知识导入
</el-button>
<el-button @click="taskSubmit">
<img src="../../../assets/images/提交.png" alt="" />
实训任务提交
</el-button>
</div>
<div class="app-main">
<div class="main-left">
<div>
<div class="left-top">
<span>一、选择指标</span>
</div>
<div class="metrics">
<el-select v-model="n_dataTableQuery.tableName" placeholder="请选择数据" style="width: 180px" @change="selectType">
<el-option v-for="item in algorithmStore.userDataLabel" :key="item" :label="item" :value="item" />
</el-select>
</div>
<div class="metrics-table" style="margin-top: 10px">
<el-table border ref="multipleTableRef" :data="algorithmStore.indexLibrary" style="width: 100%" :header-cell-style="headerCellStyle" @selection-change="handleSelectionChange">
<el-table-column type="selection" prop="date" label="Date" align="center" />
<el-table-column label="指标" align="center" prop="label" />
</el-table>
<el-button @click="submit">确定</el-button>
</div>
<div class="left-top">
<span>二、数据预处理</span>
</div>
<div class="metrics">
<el-select v-model="preProcessText.text1" placeholder="请选择数据" style="width: 180px">
<el-option label="数据去重" value="数据去重" />
</el-select>
</div>
<div class="metrics" style="margin-top: 15px">
<el-select v-model="preProcessText.text2" placeholder="请选择数据" style="width: 180px" @change="preProcess">
<el-option label="缺失值处理-剔除数据" value="缺失值处理-剔除数据" />
<el-option label="缺失值处理一均值替代" value="缺失值处理一均值替代" />
</el-select>
</div>
<div class="left-top" style="margin-top: 10px">
<span>三、模型参数设置</span>
</div>
<div class="metrics-table" style="margin-top: 10px">
<el-select v-model="preProcessText.text3" placeholder="请选择模型" style="width: 180px" @change="preProcess">
<el-option label="评论观点抽取" value="评论观点抽取" />
<el-option label="情感倾向分析" value="情感倾向分析" />
<el-option label="词频分析" value="词频分析" />
<el-option label="词云生成" value="词云生成" />
</el-select>
<el-button @click="modelCalculation">计算</el-button>
</div>
</div>
<div style="margin-top: auto">
<div class="startOver" @click="restart">
<img src="../../../assets/images/重新开始.png" alt="" />
<span>重新开始</span>
</div>
</div>
</div>
<div class="main-right">
<div>
<span style="font-weight: bold; font-size: 18px; color: #3596eb">分析数据:</span>
<div class="text-type" v-show="preProcessText.text3 == '评论观点抽取'">
<el-button v-for="text in textType" :key="text" type="primary" plain>{{ text }}</el-button>
</div>
<div class="analysis">
<el-input v-model="g_analyzeTheNumberOfDataItems" :rows="2" type="textarea" placeholder="" />
</div>
<div class="footer">
<el-button type="primary" plain @click="sentimentAnalysis">情感分析</el-button>
<el-button type="primary" plain>清空</el-button>
</div>
</div>
<div class="analysisResults" style="margin-top: 20px">
<span style="font-weight: bold; font-size: 18px; color: #3596eb; display: block">分析结果:</span>
<el-button @click="download">下载</el-button>
<h4>词频列表</h4>
<p>你可以对词频词语进行修改删除以及增加,频次数越大,显示越大,最多200关键词。</p>
<div class="conditions">
<label>显示条件:</label>
<div>
<span>频次>=</span>
<el-input v-model="input" style="width: 120px" placeholder="" />
</div>
<div>
<span>词语长度>=</span>
<el-input v-model="input" style="width: 120px" placeholder="" />
</div>
</div>
<el-table border :data="aWordFrequency" style="width: 80%" :header-cell-style="headerCellStyle">
<el-table-column label="内容(5)" align="center" prop="keyword" width="747"/>
<el-table-column label="频次" align="center" prop="frequency" />
</el-table>
</div>
</div>
</div>
<!-- </el-scrollbar> -->
<el-dialog v-model="dialogVisible" title="实训任务提交" width="565" custom-class="dialogClass" :show-close="false">
<template #header="{ close, titleId, titleClass }">
<div class="my-header">
<span :id="titleId" :class="titleClass">实训任务提交</span>
<img class="gbImg" src="../../../assets/images/关闭.png" @click="close" alt="" />
</div>
<img class="xtImg" src="../../../assets/images/线条.png" alt="" />
</template>
<div class="from-item">
<el-form :inline="true" label-position="right" label-width="84px" :model="form" class="demo-form-inline">
<el-form-item label="平均数:">
<el-input style="width: 120px" v-model="formInline.average" clearable />
</el-form-item>
<el-form-item label="众数:">
<el-input style="width: 120px" v-model="formInline.mode" clearable />
</el-form-item>
<el-form-item label="中位数:">
<el-input style="width: 120px" v-model="formInline.median" clearable />
</el-form-item>
<el-form-item label="标准差:">
<el-input style="width: 120px" v-model="formInline.standardDeviation" clearable />
</el-form-item>
<el-form-item label="方差:">
<el-input style="width: 120px" v-model="formInline.variance" clearable />
</el-form-item>
<el-form-item label="峰度:">
<el-input style="width: 120px" v-model="formInline.kurtosis" clearable />
</el-form-item>
<el-form-item label="标准误差:">
<el-input style="width: 120px" v-model="formInline.standardError" clearable />
</el-form-item>
<el-form-item label="偏度:">
<el-input style="width: 120px" v-model="formInline.skewness" clearable />
</el-form-item>
<el-form-item label="最大值:">
<el-input style="width: 120px" v-model="formInline.max" clearable />
</el-form-item>
<el-form-item label="最小值:">
<el-input style="width: 120px" v-model="formInline.min" clearable />
</el-form-item>
<el-form-item label="求和:">
<el-input style="width: 120px" v-model="formInline.summation" clearable />
</el-form-item>
<el-form-item label="观测数:">
<el-input style="width: 120px" v-model="formInline.observations" clearable />
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="submitTask">确定</el-button>
<el-button type="primary" @click="dialogVisible = false">返回</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import * as portraitModel from "@/api/portraitModel";
import * as API from "@/api/AI.js";
import * as marketingAlgorithmApi from "@/api/marketing-algorithm.js";
import useAlgorithmStore from "@/store/modules/algorithm.js";
import useUserStore from "@/store/modules/user";
import { getUserInfo } from "@/utils/auth";
const userInfo = JSON.parse(getUserInfo());
const loading = ref(false);
const { proxy } = getCurrentInstance();
const algorithmStore = useAlgorithmStore();
const multipleTableRef = ref(null);
const b_introductionOfAlgorithmKnowledge = ref(false);
const n_dataTableQuery = ref({
index: 1,
size: 5,
tableName: "用户属性表",
userId: userInfo.userId,
});
const textType = ["酒店", "KTV", "丽人", "关食", "旅游", "健束", "教育", "商业", "房产", "汽车", "生活", "购物", "3C"];
const dialogVisible = ref(false);
const analysisData = ref([]);
const analysisHanderKry = ref([]);
//
const aWordFrequency=ref([])
const tableLabel = reactive([
{ prop: "average", label: "平均数" },
{ prop: "median", label: "中位数" },
{ prop: "mode", label: "众数" },
{ prop: "standardDeviation", label: "标准差" },
{ prop: "variance", label: "方差" },
{ prop: "standardError", label: "标准误差" },
{ prop: "kurtosis", label: "峰度" },
{ prop: "skewness", label: "偏度" },
{ prop: "max", label: "最大值" },
{ prop: "min", label: "最小值" },
{ prop: "summation", label: "求和" },
{ prop: "observations", label: "观测数" },
]);
const formInline = ref({
average: "",
median: "",
mode: "",
standardDeviation: "",
variance: "",
standardError: "",
kurtosis: "",
skewness: "",
max: "",
min: "",
summation: "",
observations: "",
});
const g_indicatorData = ref([]);
const preProcessText = ref({
text1: "数据去重",
text2: "",
text3: "",
});
const aOriginalDataOfAnalysisResults2 = ref({});
// 分析变量
const g_analyzeTheNumberOfDataItems = ref("");
// 模型参数
const g_modelParameter = ref([]);
// 预处理
const preProcess = (tetx) => {
if (analysisData.value.length == 0) {
proxy.$modal.msgWarning("请先选择指标进行数据分析!");
preProcessText.value.text2 = "";
}
API.dataPreprocessing({
mapList: analysisData.value,
method: preProcessText.value.text2,
userId: n_dataTableQuery.value.userId,
}).then((res) => {
proxy.$modal.msgSuccess("预处理成功");
analysisData.value = res.data;
g_analyzeTheNumberOfDataItems.value = res.data.map((item) => (item ? item.text : "")).join(",");
});
};
// 提交
const taskSubmit = () => {
dialogVisible.value = true;
};
const tableData = ref([]);
const headerCellStyle = () => {
return {
backgroundColor: "#1882DE !important", // 设置表头背景颜色
color: "#ffffff !important",
};
};
// 选择指标
const selectType = (type) => {
n_dataTableQuery.value.tableName = type;
getIndicator();
};
// 选择数据
const handleSelectionChange = (type) => {
g_indicatorData.value = type.map((item) => item.label);
};
// 提交指標
const submit = () => {
if (g_indicatorData.value.length == 0) return proxy.$modal.msgWarning("请选择指标");
marketingAlgorithmApi.getMarketingAlgorithm({ userId: n_dataTableQuery.value.userId, tableName: n_dataTableQuery.value.tableName, fieldList: g_indicatorData.value }).then((res) => {
g_analyzeTheNumberOfDataItems.value = res.data.map((item) => (item ? item.text : "")).join(",");
analysisData.value = res.data.filter((item) => item !== null);
proxy.$modal.msgSuccess("分析数据成功");
});
};
// 选择模型
const handlemodelSelectionChange = (type) => {
g_modelParameter.value = type.map((item) => item.name);
};
//计算
const modelCalculation = () => {
if (analysisData.value.length == 0 && g_modelParameter.value.length == 0) {
proxy.$modal.msgWarning("请先分析数据/未选择模型参数!");
return;
}
const processedData = processArrayData(analysisHanderKry.value, analysisData.value);
marketingAlgorithmApi.getMarketingAlgorithmPreprocessing(JSON.stringify({ map: processedData, statistic: g_modelParameter.value, userId: n_dataTableQuery.value.userId })).then((res) => {
aOriginalDataOfAnalysisResults2.value = res.data;
tableData.value = res.data.map((item) => item.statistics);
if (res.data.length > 5) {
nNumberOfAnalysisResults.value = res.data.length;
aOriginalDataOfAnalysisResults.value = res.data.map((item) => item.statistics);
tableData.value = res.data.map((item) => item.statistics).slice(0, 5);
}
});
};
function processArrayData(keys, data) {
// 创建结果对象
const result = {};
// 遍历每个键
keys.forEach((key) => {
// 为每个键创建一个数组,包含 data 数组中该键的所有值
const values = data.map((item) => item[key]);
// 将键和对应的值数组添加到结果对象中
result[key] = values;
});
return result;
}
onMounted(() => {
getIndicator();
});
// 获取指标
const getIndicator = () => {
algorithmStore.getUserDatabase({ userId: n_dataTableQuery.value.userId, tableName: n_dataTableQuery.value.tableName, algorithmName: "情感分析" });
};
// 算法知识导入
const knowledgeImport = () => {
b_introductionOfAlgorithmKnowledge.value = true;
};
// 实训任务提交
const submitTask = () => {
for (let key in formInline.value) {
if (formInline.value[key] == "") {
const label = tableLabel.find((item) => item.prop == key);
proxy.$modal.msgWarning(`${label.label}不能为空`);
return;
}
}
portraitModel
.submit({
userId: n_dataTableQuery.value.userId,
taskName: "描述性统计",
numberOfErrors: 0,
})
.then((res) => {
dialogVisible.value = false;
proxy.$modal.msgSuccess("提交成功");
});
};
// 重新开始
const restart = () => {
// 清空
formInline.value = {
average: "",
median: "",
mode: "",
standardDeviation: "",
variance: "",
standardError: "",
kurtosis: "",
skewness: "",
max: "",
min: "",
summation: "",
observations: "",
};
analysisData.value = [];
analysisHanderKry.value = [];
tableData.value = [];
g_indicatorData.value = [];
g_modelParameter.value = [];
preProcessText.value.text2 = "";
n_dataTableQuery.value.tableName = "用户属性表";
getIndicator();
proxy.$modal.msgSuccess("重新开始成功");
multipleTableRef.value.clearSelection();
};
// 下载
const download = () => {
aOriginalDataOfAnalysisResults2.value.forEach((item) => {
item.statistics.field = item.field;
for (let key in item.statistics) {
item.statistics[key] = item.statistics[key] ?? 0;
}
});
marketingAlgorithmApi.getMarketingAlgorithmDownload(aOriginalDataOfAnalysisResults2.value).then((res) => {
const blob = new Blob([res], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "描述性统计.xlsx";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
proxy.$modal.msgSuccess("下载成功");
});
};
// 情感分析
const sentimentAnalysis = () => {
marketingAlgorithmApi.getMarketingAlgorithmSentiment({ userId: n_dataTableQuery.value.userId, content: g_analyzeTheNumberOfDataItems.value, modelType: preProcessText.value.text3 }).then(res=>{
aWordFrequency.value=res.data
})
};
</script>
<style lang="scss" scoped>
.main-top {
margin: 20px 20px 0;
margin-top: 10px;
height: 85px;
background: #001d40;
border: 1px solid #0452c6;
padding: 5px 20px;
}
.main-but {
margin: 5px 20px 0;
display: flex;
.el-button:nth-child(1) {
width: 180px;
height: 56px;
background: url("../../../assets/images/011.png");
color: #ffffff;
border-color: #ffffff00;
}
.el-button:nth-child(2) {
width: 180px;
height: 56px;
background: url("../../../assets/images/022.png");
color: #ffffff;
border-color: #ffffff00;
}
}
.app-main {
// background-color: #f5f5f5;
min-height: 965px;
margin: 5px 20px 0;
height: 100%;
display: flex;
overflow: auto;
.main-left {
//水平居中
flex-direction: column;
min-height: 965px;
display: flex;
width: 205px;
height: 100%;
background: #041c49;
padding: 0px 10px;
.left-top {
padding: 10px;
span {
font-weight: bold;
font-size: 18px;
color: #3596eb;
}
}
.metrics-table {
.el-button {
width: 149px;
height: 48px;
background: url("../../../assets/images/确定.png");
color: #ffffff;
border-color: #ffffff00;
background-size: 100% 100%;
margin: 15px;
}
}
.startOver {
margin-left: -10px;
width: 205px;
height: 55px;
background: #00f4ff;
//水平居中
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
:deep(.el-table) {
--el-table-row-hover-bg-color: #002651 !important;
--el-table-border-color: #7ac1ff;
.el-table__row {
background-color: #002652 !important;
color: #e6e6e6;
}
}
}
.main-right {
width: 1639px;
// height: 100%;
padding: 20px;
border: 1px solid #0452c6;
.text-type {
margin: 29px 0 20px 0px;
transition: all 3s;
.el-button {
width: 90px;
height: 28px;
--el-button-bg-color: #041d3b;
--el-button-border-color: #1983dd;
}
}
.analysis {
.el-textarea {
height: 343px;
background: #002652;
border-radius: 10px;
:deep(.el-textarea__inner) {
min-height: 343px !important;
background: transparent;
box-shadow: 0 0 0 1px #1983dd;
color: #ffffff;
}
}
}
.footer {
padding-top: 20px;
text-align: center;
}
}
.metrics,
.metrics-table {
:deep(.el-input) {
.el-input__wrapper {
background-color: #ffffff00;
background-image: url("../../../assets/images/下拉框.png");
background-size: 100% 100%;
}
--el-input-text-color: #ffffff;
--el-input-border-color: #ffffff00;
--el-input-hover-border-color: #ffffff00;
--el-input-hover-border: #ffffff00;
--el-select-border-color-hover: #ffffff00;
--el-select-input-focus-border-color: #ffffff00;
--el-input-placeholder-color: #ffffff;
.el-input__inner {
color: #ffffff;
}
}
}
}
.analysisResults {
.el-button {
width: 89px;
height: 31px;
background: url("../../../assets/images/下载.png");
color: black;
border-color: #ffffff00;
// background-size: 100% 100%;
margin: 15px 0px 5px;
}
.conditions {
display: flex;
align-items: center;
color: #ffffff;
font-size: 14px;
margin: 16px 0;
label {
width: 80px;
color: #ffffff;
}
div {
span {
display: inline-block;
color: #ffffff;
margin-right: 10px;
}
:deep(.el-input) {
.el-input__wrapper {
background-color: #002651 !important;
box-shadow: 0 0 0 1px #67b3d6;
border: radius 0px;
.el-input__inner {
color: #ffffff;
caret-color: #ffffff;
cursor: pointer;
}
}
}
margin-right: 55px;
}
}
}
:deep(.el-form-item__label) {
color: #ffffff;
}
.from-item {
padding: 20px;
.el-input {
--el-input-text-color: #ffffff;
--el-input-bg-color: #002651;
--el-input-border-color: #67b3d6;
}
}
.dialog-footer {
margin-bottom: 20px;
}
h4,
p {
color: #ffffff !important;
font-size: 14px;
}
</style>

@ -1,13 +1,13 @@
<template> <template>
<div class="rgzn_top app-container"> <div class="rgzn_top app-container">
<div class="top_item"> <div class="top_item">
<el-button :class="{'active':isActive===1}" @click="activeIndex(1)">用户数据库</el-button> <el-button :class="{ active: isActive === 1 }" @click="activeIndex(1)">用户数据库</el-button>
<el-button :class="{'active':isActive===2}" @click="activeIndex(2)">描述性统计</el-button> <el-button :class="{ active: isActive === 2 }" @click="activeIndex(2)">描述性统计</el-button>
<el-button :class="{'active':isActive===3}" @click="activeIndex(3)">聚类分析</el-button> <el-button :class="{ active: isActive === 3 }" @click="activeIndex(3)">聚类分析</el-button>
<el-button :class="{'active':isActive===4}" @click="activeIndex(4)">关联规则挖掘</el-button> <el-button :class="{ active: isActive === 4 }" @click="activeIndex(4)">关联规则挖掘</el-button>
<el-button :class="{'active':isActive===5}" @click="activeIndex(5)">回归分析</el-button> <el-button :class="{ active: isActive === 5 }" @click="activeIndex(5)">回归分析</el-button>
<el-button :class="{'active':isActive===6}" @click="activeIndex(6)">情感分析/文本挖掘</el-button> <el-button :class="{ active: isActive === 6 }" @click="activeIndex(6)">情感分析/文本挖掘</el-button>
<el-button :class="{'active':isActive===7}" @click="activeIndex(7)">决策树分析</el-button> <!-- <el-button :class="{'active':isActive===7}" @click="activeIndex(7)">决策树分析</el-button> -->
</div> </div>
<div> <div>
<component :is="component"></component> <component :is="component"></component>
@ -17,18 +17,19 @@
<script setup> <script setup>
// import AIGC from './AIGCLargeModel/index.vue' // import AIGC from './AIGCLargeModel/index.vue'
import big from './components/bigData.vue' import big from "./components/bigData.vue";
import descriptiveStatistics from './components/descriptiveStatistics.vue' import descriptiveStatistics from "./components/descriptiveStatistics.vue";
import clusterAnalysis from './components/clusterAnalysis.vue' import clusterAnalysis from "./components/clusterAnalysis.vue";
import associationRuleMining from './components/associationRuleMining.vue' import associationRuleMining from "./components/associationRuleMining.vue";
import regressionAnalysis from './components/regressionAnalysis.vue' import regressionAnalysis from "./components/regressionAnalysis.vue";
const component=ref(big) import emotionAnalysis from "./components/emotion-analysis.vue";
const pageData=[big,descriptiveStatistics,clusterAnalysis,associationRuleMining,regressionAnalysis] const component = ref(emotionAnalysis);
const isActive=ref(1) const pageData = [big, descriptiveStatistics, clusterAnalysis, associationRuleMining, regressionAnalysis, emotionAnalysis];
const isActive = ref(1);
const activeIndex = (index) => { const activeIndex = (index) => {
isActive.value=index isActive.value = index;
component.value=pageData[index-1] component.value = pageData[index - 1];
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -47,65 +48,64 @@
.el-button:nth-child(1) { .el-button:nth-child(1) {
width: 170px; width: 170px;
height: 50px; height: 50px;
background: url('../../assets/images/11.png'); background: url("../../assets/images/11.png");
color:#FFFFFF; color: #ffffff;
border-color:#FFFFFF00; border-color: #ffffff00;
padding: 8px 5px 8px 47px; padding: 8px 5px 8px 47px;
} }
.el-button:nth-child(2) { .el-button:nth-child(2) {
width: 170px; width: 170px;
height: 50px; height: 50px;
background: url('../../assets/images/22.png'); background: url("../../assets/images/22.png");
color:#FFFFFF; color: #ffffff;
border-color:#FFFFFF00; border-color: #ffffff00;
padding: 8px 5px 8px 47px; padding: 8px 5px 8px 47px;
} }
.el-button:nth-child(3) { .el-button:nth-child(3) {
width: 170px; width: 170px;
height: 50px; height: 50px;
background: url('../../assets/images/33.png'); background: url("../../assets/images/33.png");
color:#FFFFFF; color: #ffffff;
border-color:#FFFFFF00; border-color: #ffffff00;
padding: 8px 5px 8px 47px; padding: 8px 5px 8px 47px;
} }
.el-button:nth-child(4) { .el-button:nth-child(4) {
width: 170px; width: 170px;
height: 50px; height: 50px;
background: url('../../assets/images/44.png'); background: url("../../assets/images/44.png");
color:#FFFFFF; color: #ffffff;
border-color:#FFFFFF00; border-color: #ffffff00;
padding: 8px 5px 8px 30px; padding: 8px 5px 8px 30px;
} }
.el-button:nth-child(5) { .el-button:nth-child(5) {
width: 170px; width: 170px;
height: 50px; height: 50px;
background: url('../../assets/images/55.png'); background: url("../../assets/images/55.png");
color:#FFFFFF; color: #ffffff;
border-color:#FFFFFF00; border-color: #ffffff00;
padding: 8px 5px 8px 25px; padding: 8px 5px 8px 25px;
} }
.el-button:nth-child(6) { .el-button:nth-child(6) {
width: 190px; width: 190px;
height: 50px; height: 50px;
background: url('../../assets/images/66.png'); background: url("../../assets/images/66.png");
color:#FFFFFF; color: #ffffff;
border-color:#FFFFFF00; border-color: #ffffff00;
padding:8px 21px 8px 25px; padding: 8px 5px 8px 30px;
background-size: 100% 100%; background-size: 100% 100%;
} }
.el-button:nth-child(7) { .el-button:nth-child(7) {
width: 170px; width: 170px;
height: 50px; height: 50px;
background: url('../../assets/images/77.png'); background: url("../../assets/images/77.png");
color:#FFFFFF; color: #ffffff;
border-color:#FFFFFF00; border-color: #ffffff00;
padding: 8px 5px 8px 20px; padding: 8px 5px 8px 20px;
} }
.active { .active {
background: url('../../assets/images/亮(钮).png'); transform: scale(1.1);
transition: all 0.3s;
} }
} }
} }
</style> </style>

@ -8,7 +8,7 @@
<div class="zs"> <div class="zs">
<div class="el_top"> <div class="el_top">
<a target="_blank" @click="showResource(i.resourcesUrl)"> <a target="_blank" @click="showResource(i.resourcesUrl)">
<span style="color:#FFFFFF">{{i.resourcesName}}</span> <span>{{ i.resourcesName }}</span>
</a> </a>
</div> </div>
@ -25,40 +25,39 @@
<!-- </div> --> <!-- </div> -->
</el-scrollbar> </el-scrollbar>
</div> </div>
</template> </template>
<script setup> <script setup>
import * as API from "@/api/prtrait/prtrait.js" import * as API from "@/api/prtrait/prtrait.js";
import { getAssetsFile } from '@/utils'; import { getAssetsFile } from "@/utils";
import { getUserInfo } from '@/utils/auth' import { getUserInfo } from "@/utils/auth";
import { onMounted } from "vue"; import { onMounted } from "vue";
const getImg = (i) => { const getImg = (i) => {
return getAssetsFile(i) return getAssetsFile(i);
} };
const getImgLink = (i) => { const getImgLink = (i) => {
return i return i;
} };
const data = ref({ const data = ref({
"stuScoreDetailsDTO":{ stuScoreDetailsDTO: {
"learningProjects":"资源学习", learningProjects: "资源学习",
"assessmentItems":"观看资源", assessmentItems: "观看资源",
"viewingTime":0, viewingTime: 0,
"userId":JSON.parse(getUserInfo()).userId, userId: JSON.parse(getUserInfo()).userId,
} },
}) });
const item=ref({}) const item = ref({});
onMounted(() => { onMounted(() => {
API.learningResourcesView({ module: data.value.stuScoreDetailsDTO.module }).then((res) => { API.learningResourcesView({ module: data.value.stuScoreDetailsDTO.module }).then((res) => {
item.value=res.data item.value = res.data;
}) });
}) });
const showResource = async (i) => { const showResource = async (i) => {
// const newWindow=window.open(`http://192.168.2.4:8800/api/stu/concept/block/getResource?`+`module=${data2.module}`+`&name=${i}`) // const newWindow=window.open(`http://192.168.2.4:8800/api/stu/concept/block/getResource?`+`module=${data2.module}`+`&name=${i}`)
// window.open(`http://qkljr.sztzjy.com:90/api/stu/concept/block/getResource?`+`module=${data2.module}`+`&name=${i}`) // window.open(`http://qkljr.sztzjy.com:90/api/stu/concept/block/getResource?`+`module=${data2.module}`+`&name=${i}`)
if(i.includes('mp4')){ if (i.includes("mp4")) {
const newWindow=window.open('','_blank') const newWindow = window.open("", "_blank");
newWindow.document.write(` newWindow.document.write(`
<html> <html>
<head> <head>
@ -86,33 +85,29 @@
</html> </html>
`); `);
} }
if(i.includes('pdf')){ if (i.includes("pdf")) {
// window.open(`http://qkljr.sztzjy.com:90/api/stu/concept/block/getResource?`+`module=${data2.module}`+`&name=${i}#toolbar=0`) // window.open(`http://qkljr.sztzjy.com:90/api/stu/concept/block/getResource?`+`module=${data2.module}`+`&name=${i}#toolbar=0`)
window.open(`http://118.31.7.2:8042/file/${i}#toolbar=0`) window.open(`http://118.31.7.2:8042/file/${i}#toolbar=0`);
// window.open(`http://202.199.90.115:8800/api/stu/concept/block/getResource?`+`module=${data2.module}`+`&name=${i}`) // window.open(`http://202.199.90.115:8800/api/stu/concept/block/getResource?`+`module=${data2.module}`+`&name=${i}`)
} }
};
} const timer = ref(null);
const timer=ref(null) let seconds = 0;
let seconds=0
onMounted(() => { onMounted(() => {
timer.value = setInterval(() => { timer.value = setInterval(() => {
seconds++ seconds++;
},1000) }, 1000);
}) });
onBeforeUnmount(() => { onBeforeUnmount(() => {
item.value={} item.value = {};
if (timer.value) { if (timer.value) {
clearInterval(timer.value) clearInterval(timer.value);
} }
data.value.stuScoreDetailsDTO.viewingTime=seconds data.value.stuScoreDetailsDTO.viewingTime = seconds;
API.resourcesLearningScoreStatistics(data.value) API.resourcesLearningScoreStatistics(data.value);
}) });
const taskTime = async () => {};
const taskTime=async()=>{
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.app-container { .app-container {
@ -148,9 +143,11 @@
font-size: 12px; font-size: 12px;
font-family: Source Han Sans CN; font-family: Source Han Sans CN;
font-weight: 550; font-weight: 550;
color: #333333; // color: #333333;
padding: 7px; padding: 7px;
text-align: center; text-align: center;
background: #ffffff;
border-radius: 6px 6px 0 0;
} }
.el_bon { .el_bon {
display: flex; display: flex;
@ -181,4 +178,3 @@
} }
} }
</style> </style>

File diff suppressed because one or more lines are too long

@ -24,9 +24,7 @@
<img src="@/assets/images/caseIcon.png" alt="" /> <img src="@/assets/images/caseIcon.png" alt="" />
<span>案例背景:</span> <span>案例背景:</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">现有以下某商店的交易原始数据,需要采用帕累托分析方法,对商品进行分类:</span>
现有以下某商店的交易原始数据,需要采用帕累托分析方法,对商品进行分类:
</span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<el-table <el-table
:data="fileTable1" :data="fileTable1"
@ -38,12 +36,9 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column label="交易单号" align="center" prop="id"> <el-table-column label="交易单号" align="center" prop="id"></el-table-column>
</el-table-column> <el-table-column label="商品名称" align="center" prop="name"></el-table-column>
<el-table-column label="商品名称" align="center" prop="name"> <el-table-column label="销售额" align="center" prop="amount"></el-table-column>
</el-table-column>
<el-table-column label="销售额" align="center" prop="amount">
</el-table-column>
</el-table> </el-table>
<div class="download" @click="downloadData">下载数据</div> <div class="download" @click="downloadData">下载数据</div>
</div> </div>
@ -54,9 +49,7 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第一步,统计各类商品累计销售额</span> <span>第一步,统计各类商品累计销售额</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">以商品为统计单元,计算各类商品的销售额。</span>
以商品为统计单元,计算各类商品的销售额。
</span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<el-table <el-table
:data="step1Data" :data="step1Data"
@ -68,16 +61,10 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column label="商品名称" align="center" prop="name"> <el-table-column label="商品名称" align="center" prop="name"></el-table-column>
</el-table-column>
<el-table-column label="销售额" align="center" prop="amount"> <el-table-column label="销售额" align="center" prop="amount">
<template #default="scope"> <template #default="scope">
<el-input <el-input v-model="scope.row.params" placeholder="请输入" style="width: 130px"></el-input>
v-model="scope.row.params"
placeholder="请输入"
style="width: 130px"
>
</el-input>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -90,9 +77,7 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第二步,排序</span> <span>第二步,排序</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">以累计销售额为排序基准,按照倒序进行排序。</span>
以累计销售额为排序基准,按照倒序进行排序。
</span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<el-table <el-table
:data="step2Data" :data="step2Data"
@ -104,31 +89,13 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column label="商品名称" align="center" prop="name"> <el-table-column label="商品名称" align="center" prop="name"></el-table-column>
</el-table-column> <el-table-column label="销售额" align="center" prop="amount"></el-table-column>
<el-table-column label="销售额" align="center" prop="amount">
</el-table-column>
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center">
<template #default="scope"> <template #default="scope">
<div <div style="display: flex; align-items: center; justify-content: center">
style=" <img src="@/assets/images/上.png" alt="" style="margin-right: 10px; cursor: pointer" @click="moveUp(scope.$index, scope.row)" />
display: flex; <img src="@/assets/images/下.png" alt="" style="cursor: pointer" @click="moveDown(scope.$index, scope.row)" />
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> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -142,9 +109,7 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第三步,计算累计销售额占比</span> <span>第三步,计算累计销售额占比</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">计算各个商品的销售额占比,并以此通过累加计算累计销售额占比。</span>
计算各个商品的销售额占比,并以此通过累加计算累计销售额占比。
</span>
<div style="margin-top: 10px; display: flex" v-if="step2AnswerFlag"> <div style="margin-top: 10px; display: flex" v-if="step2AnswerFlag">
<el-table <el-table
:data="step3Data" :data="step3Data"
@ -156,38 +121,18 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column label="商品名称" align="center" prop="data1"> <el-table-column label="商品名称" align="center" prop="data1"></el-table-column>
</el-table-column> <el-table-column label="销售额" align="center" prop="data2"></el-table-column>
<el-table-column label="销售额" align="center" prop="data2"> <el-table-column label="销售额占比(%)" align="center" prop="data3">
</el-table-column>
<el-table-column
label="销售额占比(%)"
align="center"
prop="data3"
>
<template #default="scope"> <template #default="scope">
<el-input <el-input v-model="scope.row.params1" placeholder="请输入" style="width: 110px"></el-input>
v-model="scope.row.params1" %
placeholder="请输入"
style="width: 110px"
>
</el-input
>%
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column label="累计销售额占比(%)" align="center" prop="data4">
label="累计销售额占比(%)"
align="center"
prop="data4"
>
<template #default="scope"> <template #default="scope">
<el-input <el-input v-model="scope.row.params2" placeholder="请输入" style="width: 110px"></el-input>
v-model="scope.row.params2" %
placeholder="请输入"
style="width: 110px"
>
</el-input
>%
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -200,9 +145,7 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第四步,划分商品类型</span> <span>第四步,划分商品类型</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">我们按照0-80%,80%-90%,90%-100%将商品分成ABC3个类别,然后对于这3个类别的产品做区别管理,以提高效益。</span>
我们按照0-80%,80%-90%,90%-100%将商品分成ABC3个类别,然后对于这3个类别的产品做区别管理,以提高效益。
</span>
<el-table <el-table
:show-header="false" :show-header="false"
:data="typeData" :data="typeData"
@ -214,15 +157,8 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column <el-table-column label="用户ID" align="center" prop="data1" width="160"></el-table-column>
label="用户ID" <el-table-column label="用户名称" align="center" prop="data2"></el-table-column>
align="center"
prop="data1"
width="160"
>
</el-table-column>
<el-table-column label="用户名称" align="center" prop="data2">
</el-table-column>
</el-table> </el-table>
<div style="margin-top: 10px; display: flex" v-if="step3AnswerFlag"> <div style="margin-top: 10px; display: flex" v-if="step3AnswerFlag">
<el-table <el-table
@ -235,23 +171,12 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column label="商品名称" align="center" prop="data1"> <el-table-column label="商品名称" align="center" prop="data1"></el-table-column>
</el-table-column> <el-table-column label="销售额" align="center" prop="data2"></el-table-column>
<el-table-column label="销售额" align="center" prop="data2"> <el-table-column label="累计销售额占比(%)" align="center" prop="data3"></el-table-column>
</el-table-column>
<el-table-column
label="累计销售额占比(%)"
align="center"
prop="data3"
>
</el-table-column>
<el-table-column label="划分商品类型" align="center" prop="data4"> <el-table-column label="划分商品类型" align="center" prop="data4">
<template #default="scope"> <template #default="scope">
<el-select <el-select v-model="scope.row.params" placeholder="请选择" style="width: 100px">
v-model="scope.row.params"
placeholder="请选择"
style="width: 100px"
>
<el-option :label="'A类商品'" :value="'A类商品'" /> <el-option :label="'A类商品'" :value="'A类商品'" />
<el-option :label="'B类商品'" :value="'B类商品'" /> <el-option :label="'B类商品'" :value="'B类商品'" />
<el-option :label="'C类商品'" :value="'C类商品'" /> <el-option :label="'C类商品'" :value="'C类商品'" />
@ -268,53 +193,36 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第五步,绘制帕累托图</span> <span>第五步,绘制帕累托图</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">以分析表的商品名称为X轴,销售额为左侧Y轴,累计销售额占比为右侧Y轴绘制帕累托图。</span>
以分析表的商品名称为X轴,销售额为左侧Y轴,累计销售额占比为右侧Y轴绘制帕累托图。
</span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<el-table <div id="echarts" style="width: 500px; height: 400px"></div>
:data="step5Data" <div class="submit" @click="step5Submit" v-if="step3AnswerFlag">提交</div>
style="width: 680px" </div>
border <div class="chartXData" v-if="step3AnswerFlag">
:header-cell-style="{ <el-select v-model="chartParam1" placeholder="请选择" style="width: 85px" class="XdataItem" size="small">
color: '#fff', <el-option :label="'男士配饰'" :value="'男士配饰'" />
fontSize: '14px', <el-option :label="'床上用品'" :value="'床上用品'" />
backgroundColor: '#6A7DE9!important', <el-option :label="'婴儿用品'" :value="'婴儿用品'" />
}" <el-option :label="'儿童服装'" :value="'儿童服装'" />
> </el-select>
<el-table-column label="" align="center" prop="title" /> <el-select v-model="chartParam2" placeholder="请选择" style="width: 85px" class="XdataItem" size="small">
<el-table-column label="R值打分" align="center"> <el-option :label="'男士配饰'" :value="'男士配饰'" />
<template #default="scope"> <el-option :label="'床上用品'" :value="'床上用品'" />
<el-input <el-option :label="'婴儿用品'" :value="'婴儿用品'" />
v-model="scope.row.params1" <el-option :label="'儿童服装'" :value="'儿童服装'" />
placeholder="请输入" </el-select>
style="width: 100px" <el-select v-model="chartParam3" placeholder="请选择" style="width: 85px" class="XdataItem" size="small">
> <el-option :label="'男士配饰'" :value="'男士配饰'" />
</el-input> <el-option :label="'床上用品'" :value="'床上用品'" />
</template> <el-option :label="'婴儿用品'" :value="'婴儿用品'" />
</el-table-column> <el-option :label="'儿童服装'" :value="'儿童服装'" />
<el-table-column label="F值打分" align="center"> </el-select>
<template #default="scope"> <el-select v-model="chartParam4" placeholder="请选择" style="width: 85px" class="XdataItem" size="small" @change="selectChange">
<el-input <el-option :label="'男士配饰'" :value="'男士配饰'" />
v-model="scope.row.params2" <el-option :label="'床上用品'" :value="'床上用品'" />
placeholder="请输入" <el-option :label="'婴儿用品'" :value="'婴儿用品'" />
style="width: 100px" <el-option :label="'儿童服装'" :value="'儿童服装'" />
> </el-select>
</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> </div>
<div class="line"></div> <div class="line"></div>
@ -323,14 +231,10 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第六步,针对不同类别的商品,制定不同的库存策略</span> <span>第六步,针对不同类别的商品,制定不同的库存策略</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">一般来说,在商品的库存管理策略中:</span>
一般来说,在商品的库存管理策略中:
</span>
<div class="customerType" style="width: 1115px"> <div class="customerType" style="width: 1115px">
<img src="@/assets/images/商品a.png" alt="" /> <img src="@/assets/images/商品a.png" alt="" />
<span <span>A类商品对公司销售额贡献最大,这种商品备货周期短,在保证安全库存的情况下,应该小批量多批次按需储存,尽可能降低库存总量,减少仓储管理成本,但如果控制不好库存,很容易出现断货风险。</span>
>A类商品对公司销售额贡献最大,这种商品备货周期短,在保证安全库存的情况下,应该小批量多批次按需储存,尽可能降低库存总量,减少仓储管理成本,但如果控制不好库存,很容易出现断货风险。</span
>
</div> </div>
<div class="customerType" style="width: 1115px"> <div class="customerType" style="width: 1115px">
<img src="@/assets/images/商品b.png" alt="" /> <img src="@/assets/images/商品b.png" alt="" />
@ -338,25 +242,30 @@
</div> </div>
<div class="customerType" style="width: 1115px"> <div class="customerType" style="width: 1115px">
<img src="@/assets/images/商品c.png" alt="" /> <img src="@/assets/images/商品c.png" alt="" />
<span <span>C类商品属于长尾商品,备货周期更长,最好是集中采购,并适当增大库存量,相应减少订货次数。</span>
>C类商品属于长尾商品,备货周期更长,最好是集中采购,并适当增大库存量,相应减少订货次数。</span
>
</div> </div>
</div> </div>
</div> </div>
<pop-modal :showModel="dialogVisible" @closePop="dialogVisible = false"> <pop-modal :showModel="dialogVisible" @closePop="dialogVisible = false">
<template v-slot:content> <template v-slot:content>
<p> <p>
帕累托分析法源于经典的二八法则。意大利经济学家维尔弗雷多·帕累托于1906年提出了著名的关于意大利社会财务分配的研究结论:20%的人口掌握了80%的社会财富。这个结论对大多数国家的社会财富分配情况都成立。因此帕累托法则又被称为80/20法则。<br /><br /> 帕累托分析法源于经典的二八法则。意大利经济学家维尔弗雷多·帕累托于1906年提出了著名的关于意大利社会财务分配的研究结论:20%的人口掌握了80%的社会财富。这个结论对大多数国家的社会财富分配情况都成立。因此帕累托法则又被称为80/20法则。
帕累托分析的核心观点是:在许多情况下,大部分的问题、效益或成本都来自于少数的要素。换句话说,少数关键要素占据了绝大多数的结果。这一规律在许多领域都具有普适性,例如:<br /><br /> <br />
在企业中,80%的利润可能来自于20%的产品或客户。<br /> <br />
在销售中,80%的销售额可能来自于20%的销售员或产品。<br /> 帕累托分析的核心观点是:在许多情况下,大部分的问题、效益或成本都来自于少数的要素。换句话说,少数关键要素占据了绝大多数的结果。这一规律在许多领域都具有普适性,例如:
在质量控制中,80%的缺陷可能来自于20%的原因或工序。<br /><br /> <br />
ABC 分类法全称应为 ABC 分类库存控制法。 <br />
又称帕累托分析法或巴雷托分析法、柏拉图分析、主次因分析法 在企业中,80%的利润可能来自于20%的产品或客户。
、ABC分析法、ABC 管理法,平常也称之为「80 对 20」规则。 <br />
在销售中,80%的销售额可能来自于20%的销售员或产品。
<br />
在质量控制中,80%的缺陷可能来自于20%的原因或工序。
<br />
<br />
ABC 分类法全称应为 ABC 分类库存控制法。 又称帕累托分析法或巴雷托分析法、柏拉图分析、主次因分析法 、ABC分析法、ABC 管理法,平常也称之为「80 对 20」规则。
</p> </p>
<img src="@/assets/images/u3323.png" alt="" /><br /> <img src="@/assets/images/u3323.png" alt="" />
<br />
<img src="@/assets/images/u3324.png" alt="" /> <img src="@/assets/images/u3324.png" alt="" />
</template> </template>
</pop-modal> </pop-modal>
@ -364,11 +273,13 @@
</template> </template>
<script setup> <script setup>
import * as echarts from "echarts";
import popModal from "@/views/components/popModal.vue"; import popModal from "@/views/components/popModal.vue";
import { getUserInfo } from "@/utils/auth"; import { getUserInfo } from "@/utils/auth";
import * as portraitModel from "@/api/portraitModel"; import * as portraitModel from "@/api/portraitModel";
import { downBlobFile } from "@/utils/index.js"; import { downBlobFile } from "@/utils/index.js";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const dialogVisible = ref(false); const dialogVisible = ref(false);
const knowledgeFlag = ref(false); const knowledgeFlag = ref(false);
const errorNum = ref(0); const errorNum = ref(0);
@ -376,10 +287,16 @@ const step1Error = ref(0);
const step2Error = ref(0); const step2Error = ref(0);
const step3Error = ref(0); const step3Error = ref(0);
const step4Error = ref(0); const step4Error = ref(0);
const step5Error = ref(0);
const step1AnswerFlag = ref(false); const step1AnswerFlag = ref(false);
const step2AnswerFlag = ref(false); const step2AnswerFlag = ref(false);
const step3AnswerFlag = ref(false); const step3AnswerFlag = ref(false);
const step4AnswerFlag = ref(false); const step4AnswerFlag = ref(false);
const step5AnswerFlag = ref(false);
const chartParam1 = ref("");
const chartParam2 = ref("");
const chartParam3 = ref("");
const chartParam4 = ref("");
const step1Data = ref([ const step1Data = ref([
{ {
name: "男士配饰", name: "男士配饰",
@ -601,7 +518,98 @@ onBeforeUnmount(() => {
}); });
onMounted(() => { onMounted(() => {
getData(); getData();
// initCharts();
}); });
const initCharts = () => {
var chartDom = document.getElementById("echarts");
var myChart = echarts.init(chartDom, "dark");
var option;
option = {
title: {
text: "帕累托图",
left: "center",
top: "10px",
textStyle: {
color: "#fff",
// fontSize:16
},
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "cross",
crossStyle: {
color: "#999",
},
},
},
legend: {
data: ["销售额", "累计销售占比"],
bottom: 5,
},
xAxis: [
{
show: false,
type: "category",
data: ["", "", "", ""],
axisPointer: {
type: "shadow",
},
},
],
yAxis: [
{
type: "value",
name: "销售额",
// min: 0,
// max: 250,
// interval: 50,
axisLabel: {
formatter: "{value}",
},
},
{
type: "value",
name: "累计销售占比",
min: 0,
max: 120,
interval: 20,
axisLabel: {
formatter: "{value} %",
},
},
],
series: [
{
name: "销售额",
type: "bar",
tooltip: {
valueFormatter: function (value) {
return value + " 元";
},
},
// data: [5900, 2400, 1100, 600],
data: [step3Data.value[0].data2, step3Data.value[1].data2, step3Data.value[2].data2, step3Data.value[3].data2],
},
{
name: "累计销售占比",
type: "line",
yAxisIndex: 1,
tooltip: {
valueFormatter: function (value) {
return value + " %";
},
},
// data: [59, 83, 94, 100],
data: [step3Data.value[0].params2, step3Data.value[1].params2, step3Data.value[2].params2, step3Data.value[3].params2],
},
],
};
option && myChart.setOption(option);
};
const moveUp = (index, row) => { const moveUp = (index, row) => {
console.log("上移", index, row); console.log("上移", index, row);
if (index > 0) { if (index > 0) {
@ -624,14 +632,15 @@ const moveDown = (index, row) => {
}; };
const downloadData = () => { const downloadData = () => {
// console.log(666); // console.log(666);
portraitModel // portraitModel
.downloadDataByABC({}) // .downloadDataByABC({})
.then((res) => { // .then((res) => {
// console.log(res,'--'); // // console.log(res,'--');
const blob = new Blob([res], { type: "application/vnd.ms-excel" }); // const blob = new Blob([res], { type: "application/vnd.ms-excel" });
downBlobFile(`案例数据-帕累托分析`, blob); // downBlobFile(`案例数据-帕累托分析`, blob);
}) // })
.catch((error) => {}); // .catch((error) => {});
window.open(baseUrl + "/api/downDataByUserPortrait/analysisByPareto");
}; };
const step1Submit = () => { const step1Submit = () => {
step1Error.value = 0; step1Error.value = 0;
@ -665,11 +674,7 @@ const step1Submit = () => {
}; };
const step2Submit = () => { const step2Submit = () => {
step2Error.value = 0; step2Error.value = 0;
if ( 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)) {
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; step2Error.value = 0;
} else { } else {
step2Error.value = 1; step2Error.value = 1;
@ -726,6 +731,7 @@ const step3Submit = () => {
step4Data.value[2].data3 = step3Data.value[2].params2; step4Data.value[2].data3 = step3Data.value[2].params2;
step4Data.value[3].data3 = step3Data.value[3].params2; step4Data.value[3].data3 = step3Data.value[3].params2;
step3AnswerFlag.value = true; step3AnswerFlag.value = true;
initCharts();
}; };
const step4Submit = () => { const step4Submit = () => {
step4Error.value = 0; step4Error.value = 0;
@ -753,6 +759,28 @@ const step4Submit = () => {
proxy.$modal.msgSuccess("提交成功"); proxy.$modal.msgSuccess("提交成功");
step4AnswerFlag.value = true; step4AnswerFlag.value = true;
}; };
const step5Submit = () => {
step5Error.value = 0;
if (chartParam1.value == "" || chartParam2.value == "" || chartParam3.value == "" || chartParam4.value == "") {
proxy.$modal.msgError("请先完成所有填空");
return;
}
if (chartParam1.value != "男士配饰") {
step5Error.value++;
}
if (chartParam2.value != "床上用品") {
step5Error.value++;
}
if (chartParam3.value != "婴儿用品") {
step5Error.value++;
}
if (chartParam4.value != "儿童服装") {
step5Error.value++;
}
console.log("错误数", step5Error.value);
proxy.$modal.msgSuccess("提交成功");
step5AnswerFlag.value = true;
};
const saveData = () => { const saveData = () => {
const params = { const params = {
stepFiveA: step1Data.value[0].params, stepFiveA: step1Data.value[0].params,
@ -855,19 +883,17 @@ const getData = () => {
}) })
.catch((error) => {}); .catch((error) => {});
}; };
const selectChange = (item) => {
// console.log(22);
// initCharts();
};
const submitData = () => { const submitData = () => {
console.log("tj"); console.log("tj");
if ( if (!step1AnswerFlag.value || !step2AnswerFlag.value || !step3AnswerFlag.value || !step4AnswerFlag.value) {
!step1AnswerFlag.value ||
!step2AnswerFlag.value ||
!step3AnswerFlag.value ||
!step4AnswerFlag.value
) {
proxy.$modal.msgError("请先完成所有步骤!"); proxy.$modal.msgError("请先完成所有步骤!");
return; return;
} }
errorNum.value = errorNum.value = step1Error.value + step2Error.value + step3Error.value + step4Error.value + step5Error.value;
step1Error.value + step2Error.value + step3Error.value + step4Error.value;
console.log(errorNum.value, "总错误次数"); console.log(errorNum.value, "总错误次数");
portraitModel portraitModel
.submit({ .submit({
@ -987,6 +1013,14 @@ defineExpose({
margin-right: 10px; margin-right: 10px;
} }
} }
.chartXData {
position: relative;
top: -58px;
left: 60px;
.XdataItem {
margin-right: 15px;
}
}
} }
.line { .line {
width: 1400px; width: 1400px;
@ -1001,4 +1035,8 @@ defineExpose({
background-color: #002652 !important; background-color: #002652 !important;
color: #fff; color: #fff;
} }
::v-deep .el-table td {
padding-top: 4px;
padding-bottom: 4px;
}
</style> </style>

File diff suppressed because one or more lines are too long

@ -28,9 +28,7 @@
<img src="@/assets/images/caseIcon.png" alt="" /> <img src="@/assets/images/caseIcon.png" alt="" />
<span>案例背景:</span> <span>案例背景:</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">现有以下某商店的客户消费原始数据,需要采用波士顿矩阵分析方法,对客户进行分类:</span>
现有以下某商店的客户消费原始数据,需要采用波士顿矩阵分析方法,对客户进行分类:
</span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<el-table <el-table
:data="fileTable1" :data="fileTable1"
@ -42,12 +40,9 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column label="客户ID" align="center" prop="id"> <el-table-column label="客户ID" align="center" prop="id"></el-table-column>
</el-table-column> <el-table-column label="消费金额" align="center" prop="amount"></el-table-column>
<el-table-column label="消费金额" align="center" prop="amount"> <el-table-column label="消费时间" align="center" prop="time"></el-table-column>
</el-table-column>
<el-table-column label="消费时间" align="center" prop="time">
</el-table-column>
</el-table> </el-table>
<div class="download" @click="downloadData">下载数据</div> <div class="download" @click="downloadData">下载数据</div>
</div> </div>
@ -58,9 +53,7 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第一步,统计各个客户的消费次数和消费金额</span> <span>第一步,统计各个客户的消费次数和消费金额</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">以客户ID为统计单元,分别计算各个客户累计的消费次数、消费金额。</span>
以客户ID为统计单元,分别计算各个客户累计的消费次数、消费金额。
</span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<el-table <el-table
:data="step1Data" :data="step1Data"
@ -72,26 +65,15 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column label="客户ID" align="center" prop="name"> <el-table-column label="客户ID" align="center" prop="name"></el-table-column>
</el-table-column>
<el-table-column label="消费次数" align="center" prop="amount"> <el-table-column label="消费次数" align="center" prop="amount">
<template #default="scope"> <template #default="scope">
<el-input <el-input v-model="scope.row.params1" placeholder="请输入" style="width: 130px"></el-input>
v-model="scope.row.params1"
placeholder="请输入"
style="width: 130px"
>
</el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="消费金额" align="center" prop="amount"> <el-table-column label="消费金额" align="center" prop="amount">
<template #default="scope"> <template #default="scope">
<el-input <el-input v-model="scope.row.params2" placeholder="请输入" style="width: 130px"></el-input>
v-model="scope.row.params2"
placeholder="请输入"
style="width: 130px"
>
</el-input>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -104,10 +86,8 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第二步,确定象限测度划分标准</span> <span>第二步,确定象限测度划分标准</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">以客户ID为统计单元,分别计算各个客户的平均消费次数、平均消费金额。</span>
以客户ID为统计单元,分别计算各个客户的平均消费次数、平均消费金额。 <div style="margin-top: 10px; display: flex" v-if="step1AnswerFlag">
</span>
<div style="margin-top: 10px; display: flex">
<el-table <el-table
:data="step2Data" :data="step2Data"
style="width: 650px" style="width: 650px"
@ -118,28 +98,15 @@
backgroundColor: '#6A7DE9!important', backgroundColor: '#6A7DE9!important',
}" }"
> >
<el-table-column label="客户ID" align="center" prop="name"> <el-table-column label="客户ID" align="center" prop="name"></el-table-column>
</el-table-column>
<el-table-column label="消费次数" align="center" prop="amount"> <el-table-column label="消费次数" align="center" prop="amount">
<template #default="scope"> <template #default="scope">
<el-input <el-input v-model="scope.row.params1" placeholder="请输入" style="width: 130px" v-if="scope.$index == 4"></el-input>
v-model="scope.row.params1"
placeholder="请输入"
style="width: 130px"
v-if="scope.$index == 4"
>
</el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="消费金额" align="center" prop="account"> <el-table-column label="消费金额" align="center" prop="account">
<template #default="scope"> <template #default="scope">
<el-input <el-input v-model="scope.row.params2" placeholder="请输入" style="width: 130px" v-if="scope.$index == 4"></el-input>
v-model="scope.row.params2"
placeholder="请输入"
style="width: 130px"
v-if="scope.$index == 4"
>
</el-input>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -152,36 +119,26 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第三步,绘制散点图</span> <span>第三步,绘制散点图</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">以消费金额为纵轴,消费次数为横轴,将第一步的客户数据绘制于坐标轴中</span>
以消费金额为纵轴,消费次数为横轴,将第一步的客户数据绘制于坐标轴中
</span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<div id="charts1" style="width: 500px; height: 400px"></div> <div id="charts1" style="width: 500px; height: 400px"></div>
<div> <div>
<div class="submit" @click="step3Submit">提交</div> <div class="submit" @click="step3Submit">提交</div>
<div class="drawPoint"> <div class="drawPoint">
<div class="point"> <div class="point">
<div class="pointItem" @click="drawPoint('A', '#009FF1')"> <div class="pointItem" @click="drawPoint('A', '#009FF1')">绘制A</div>
绘制A
</div>
<span>(3,800)</span> <span>(3,800)</span>
</div> </div>
<div class="point"> <div class="point">
<div class="pointItem" @click="drawPoint('B', '#FB54A1')"> <div class="pointItem" @click="drawPoint('B', '#FB54A1')">绘制B</div>
绘制B
</div>
<span>(4,1200)</span> <span>(4,1200)</span>
</div> </div>
<div class="point"> <div class="point">
<div class="pointItem" @click="drawPoint('C', '#FE8D2A')"> <div class="pointItem" @click="drawPoint('C', '#FE8D2A')">绘制C</div>
绘制C
</div>
<span>(6,600)</span> <span>(6,600)</span>
</div> </div>
<div class="point"> <div class="point">
<div class="pointItem" @click="drawPoint('D', '#6E70F0')"> <div class="pointItem" @click="drawPoint('D', '#6E70F0')">绘制D</div>
绘制D
</div>
<span>(7,1400)</span> <span>(7,1400)</span>
</div> </div>
</div> </div>
@ -194,18 +151,14 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第四步,坐标轴区域绘制象限测度划分标准</span> <span>第四步,坐标轴区域绘制象限测度划分标准</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">将计算出的客户的平均消费次数、平均消费金额,绘制在坐标轴中。</span>
将计算出的客户的平均消费次数、平均消费金额,绘制在坐标轴中。
</span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<div id="charts2" style="width: 500px; height: 400px"></div> <div id="charts2" style="width: 500px; height: 400px"></div>
<div> <div>
<div class="submit" @click="step4Submit">提交</div> <div class="submit" @click="step4Submit">提交</div>
<div class="drawPoint"> <div class="drawPoint">
<div class="point"> <div class="point">
<div class="pointItem" @click="drawPointStep4('A', '#009FF1')"> <div class="pointItem" @click="drawPointStep4('A', '#009FF1')">绘制平均消费次数X,平均消费金额Y</div>
绘制平均消费次数X,平均消费金额Y
</div>
<span>(5,1000)</span> <span>(5,1000)</span>
</div> </div>
<!-- <div class="point"> <!-- <div class="point">
@ -225,10 +178,14 @@
<span>第五步,划分客户类型</span> <span>第五步,划分客户类型</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">
按照客户标准,划分A、B、C、D各属于哪类客户。<br /> 按照客户标准,划分A、B、C、D各属于哪类客户。
1、消费次数超过平均值,每次消费力度也超过平均水平的客户:判定为明星客户<br /> <br />
2、消费次数超过平均值,但每次消费力度未达到平均水平的客户:被判定为现金流客户<br /> 1、消费次数超过平均值,每次消费力度也超过平均水平的客户:判定为明星客户
3、消费未达到平均值,但每次消费力度超过平均水平的客户:是问题客户<br /> <br />
2、消费次数超过平均值,但每次消费力度未达到平均水平的客户:被判定为现金流客户
<br />
3、消费未达到平均值,但每次消费力度超过平均水平的客户:是问题客户
<br />
4、消费未达到平均值,消费力度也未达到平均水平的客户:属于瘦狗客户 4、消费未达到平均值,消费力度也未达到平均水平的客户:属于瘦狗客户
</span> </span>
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
@ -237,36 +194,16 @@
<div class="submit" @click="step5Submit">提交</div> <div class="submit" @click="step5Submit">提交</div>
<div class="drawPoint"> <div class="drawPoint">
<div class="point"> <div class="point">
<div <div class="pointItem" @click="drawQuadrant('明星客户', 'rgba(52, 134, 207, 0.8)')">明星客户</div>
class="pointItem"
@click="drawQuadrant('明星客户', 'rgba(52, 134, 207, 0.8)')"
>
明星客户
</div>
</div> </div>
<div class="point"> <div class="point">
<div <div class="pointItem" @click="drawQuadrant('现金流客户', 'rgba(0, 184, 105, 0.8)')">现金流客户</div>
class="pointItem"
@click="drawQuadrant('现金流客户', 'rgba(0, 184, 105, 0.8)')"
>
现金流客户
</div>
</div> </div>
<div class="point"> <div class="point">
<div <div class="pointItem" @click="drawQuadrant('问题客户', 'rgba(177, 130, 192, 0.8)')">问题客户</div>
class="pointItem"
@click="drawQuadrant('问题客户', 'rgba(177, 130, 192, 0.8)')"
>
问题客户
</div>
</div> </div>
<div class="point"> <div class="point">
<div <div class="pointItem" @click="drawQuadrant('瘦狗客户', 'rgba(254, 141, 42, 0.8)')">瘦狗客户</div>
class="pointItem"
@click="drawQuadrant('瘦狗客户', 'rgba(254, 141, 42, 0.8)')"
>
瘦狗客户
</div>
</div> </div>
</div> </div>
</div> </div>
@ -278,57 +215,63 @@
<img src="@/assets/images/步骤.png" alt="" /> <img src="@/assets/images/步骤.png" alt="" />
<span>第六步,针对不同的客户类型,制定不同的营销策略</span> <span>第六步,针对不同的客户类型,制定不同的营销策略</span>
</div> </div>
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">当波士顿矩阵应用于客户画像时候,可以大致分析出不同用户的客户画像:</span>
当波士顿矩阵应用于客户画像时候,可以大致分析出不同用户的客户画像:
</span>
<div class="customerType" style="width: 887px"> <div class="customerType" style="width: 887px">
<img src="@/assets/images/客户1.png" alt="" /> <img src="@/assets/images/客户1.png" alt="" />
<span>明星客户,这类客户需要重点关注,并给予最高的礼遇;</span> <span>明星客户,这类客户需要重点关注,并给予最高的礼遇;</span>
</div> </div>
<div class="customerType" style="width: 887px"> <div class="customerType" style="width: 887px">
<img src="@/assets/images/客户2.png" alt="" /> <img src="@/assets/images/客户2.png" alt="" />
<span <span>现金流客户,这类客户通常消费频次比较频繁,能给企业带来较为稳定的现金流,这类客户是企业利润基石;</span>
>现金流客户,这类客户通常消费频次比较频繁,能给企业带来较为稳定的现金流,这类客户是企业利润基石;</span
>
</div> </div>
<div class="customerType" style="width: 887px"> <div class="customerType" style="width: 887px">
<img src="@/assets/images/客户3.png" alt="" /> <img src="@/assets/images/客户3.png" alt="" />
<span <span>问题客户,这类客户最有希望转化为明星客户,但是因为客户存在一定的潜在问题,导致消费频次不高,这类客户需要利用客服进行重点跟进和长期跟踪;</span>
>问题客户,这类客户最有希望转化为明星客户,但是因为客户存在一定的潜在问题,导致消费频次不高,这类客户需要利用客服进行重点跟进和长期跟踪;</span
>
</div> </div>
<div class="customerType" style="width: 887px"> <div class="customerType" style="width: 887px">
<img src="@/assets/images/客户1.png" alt="" /> <img src="@/assets/images/客户1.png" alt="" />
<span <span>瘦狗客户,这类客户通常占企业客户的大多数,只需要一般性维护,不需要投入重点维系。</span>
>瘦狗客户,这类客户通常占企业客户的大多数,只需要一般性维护,不需要投入重点维系。</span
>
</div> </div>
</div> </div>
</div> </div>
<pop-modal :showModel="dialogVisible" @closePop="dialogVisible = false"> <pop-modal :showModel="dialogVisible" @closePop="dialogVisible = false">
<template v-slot:content> <template v-slot:content>
<p style="line-height: 25px; font-size: 14px"> <p style="line-height: 25px; font-size: 14px">
波士顿矩阵(BCG 波士顿矩阵(BCG Matrix),又称市场增长率-相对市场份额矩阵,由美国著名的管理学家、波士顿咨询公司创始人布鲁斯·亨德森于1970年首创,它是通过销售增长率(反应市场引力的指标)和市场占有率(反应企业实力的指标)来分析决定企业的产品结构。
Matrix),又称市场增长率-相对市场份额矩阵,由美国著名的管理学家、波士顿咨询公司创始人布鲁斯·亨德森于1970年首创,它是通过销售增长率(反应市场引力的指标)和市场占有率(反应企业实力的指标)来分析决定企业的产品结构。<br /> <br />
市场吸引力包括企业销售量增长率、目标市场容量、竞争对手强弱、利润高低等。其中最重要的是反映市场引力的综合指标——销售增长率,这是决定企业产品结构是否合理的外在因素。<br /> 市场吸引力包括企业销售量增长率、目标市场容量、竞争对手强弱、利润高低等。其中最重要的是反映市场引力的综合指标——销售增长率,这是决定企业产品结构是否合理的外在因素。
<br />
企业实力包括市场占有率、技术、设备、资金利用能力等,其中市场占有率是决定企业产品结构的内在因素,他直接显示出企业的竞争实力。 企业实力包括市场占有率、技术、设备、资金利用能力等,其中市场占有率是决定企业产品结构的内在因素,他直接显示出企业的竞争实力。
</p> </p>
<img src="@/assets/images/u3678.png" alt="" /><br /> <img src="@/assets/images/u3678.png" alt="" />
<br />
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">
波士顿矩阵将产品类型分为四种:<br /> 波士顿矩阵将产品类型分为四种:
1,明星类产品:高增长且高市占,发展前景好,竞争力强,需加大投资以支持其发展;<br /> <br />
2,问题类产品:高增长但低市占,发展前景好但市场开拓不足,需谨慎投资;<br /> 1,明星类产品:高增长且高市占,发展前景好,竞争力强,需加大投资以支持其发展;
3,现金牛产品:低增长但高市占,成熟市场的领导者,应降低投资,维持市占并延缓衰退;<br /> <br />
4,瘦狗类产品:低增长且低市占,理论率低甚至亏损,应采取撤退战略。 </span 2,问题类产品:高增长但低市占,发展前景好但市场开拓不足,需谨慎投资;
><br /><br /> <br />
3,现金牛产品:低增长但高市占,成熟市场的领导者,应降低投资,维持市占并延缓衰退;
<br />
4,瘦狗类产品:低增长且低市占,理论率低甚至亏损,应采取撤退战略。
</span>
<br />
<br />
<span style="line-height: 25px; font-size: 14px"> <span style="line-height: 25px; font-size: 14px">
当波士顿矩阵应用于客户画像时候,可以大致分析出不同用户的客户画像:<br /> 当波士顿矩阵应用于客户画像时候,可以大致分析出不同用户的客户画像:
1、消费次数超过平均值,每次消费力度也超过平均水平的客户:判定为明星客户,这类客户需要重点关注,并给予最高的礼遇;<br /> <br />
2、消费次数超过平均值,但每次消费力度未达到平均水平的客户:被判定为现金流客户,这类客户通常消费频次比较频繁,能给企业带来较为稳定的现金流,这类客户是企业利润基石;<br /> 1、消费次数超过平均值,每次消费力度也超过平均水平的客户:判定为明星客户,这类客户需要重点关注,并给予最高的礼遇;
3、消费未达到平均值,但每次消费力度超过平均水平的客户:是问题客户,这类客户最有希望转化为明星客户,但是因为客户存在一定的潜在问题,导致消费频次不高,这类客户需要利用客服进行重点跟进和长期跟踪;<br /> <br />
4、消费未达到平均值,消费力度也未达到平均水平的客户:属于瘦狗客户,这类客户通常占企业客户的大多数,只需要一般性维护,不需要投入重点维系。<br /> </span 2、消费次数超过平均值,但每次消费力度未达到平均水平的客户:被判定为现金流客户,这类客户通常消费频次比较频繁,能给企业带来较为稳定的现金流,这类客户是企业利润基石;
><br /> <br />
3、消费未达到平均值,但每次消费力度超过平均水平的客户:是问题客户,这类客户最有希望转化为明星客户,但是因为客户存在一定的潜在问题,导致消费频次不高,这类客户需要利用客服进行重点跟进和长期跟踪;
<br />
4、消费未达到平均值,消费力度也未达到平均水平的客户:属于瘦狗客户,这类客户通常占企业客户的大多数,只需要一般性维护,不需要投入重点维系。
<br />
</span>
<br />
<img src="@/assets/images/u3682.png" alt="" /> <img src="@/assets/images/u3682.png" alt="" />
</template> </template>
</pop-modal> </pop-modal>
@ -344,6 +287,7 @@ import * as portraitModel from "@/api/portraitModel";
import { downBlobFile } from "@/utils/index.js"; import { downBlobFile } from "@/utils/index.js";
import { onMounted } from "vue"; import { onMounted } from "vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const dialogVisible = ref(false); const dialogVisible = ref(false);
const knowledgeFlag = ref(false); const knowledgeFlag = ref(false);
const step1Data = ref([ const step1Data = ref([
@ -746,10 +690,7 @@ const step3EchartInit = () => {
// { seriesIndex: 0 }, // { seriesIndex: 0 },
// pointInPixel // pointInPixel
// ); // );
pointInGrid.value = myChart.convertFromPixel( pointInGrid.value = myChart.convertFromPixel({ seriesIndex: 0 }, pointInPixel);
{ seriesIndex: 0 },
pointInPixel
);
// 转换Y轴坐标 // 转换Y轴坐标
// let pointInGrid2 = myChart.convertFromPixel({ seriesIndex: 1 }, pointInPixel); // let pointInGrid2 = myChart.convertFromPixel({ seriesIndex: 1 }, pointInPixel);
// x轴数据的索引值 // x轴数据的索引值
@ -851,10 +792,7 @@ const step4EchartInit = () => {
const pointInPixel = [param.offsetX, param.offsetY]; const pointInPixel = [param.offsetX, param.offsetY];
console.log("pointInPixel4", pointInPixel); console.log("pointInPixel4", pointInPixel);
//将偏移值转化为坐标值 //将偏移值转化为坐标值
pointInGridStep4.value = myChart.convertFromPixel( pointInGridStep4.value = myChart.convertFromPixel({ seriesIndex: 0 }, pointInPixel);
{ seriesIndex: 0 },
pointInPixel
);
console.log("pointInGrid4", pointInGridStep4.value); console.log("pointInGrid4", pointInGridStep4.value);
option2.value.series[0].data.push({ option2.value.series[0].data.push({
value: pointInGridStep4.value, value: pointInGridStep4.value,
@ -1136,37 +1074,26 @@ const step5EchartInit = () => {
const pointInPixel = [param.offsetX, param.offsetY]; const pointInPixel = [param.offsetX, param.offsetY];
console.log("pointInPixel5", pointInPixel); console.log("pointInPixel5", pointInPixel);
//将偏移值转化为坐标值 //将偏移值转化为坐标值
pointInGridStep5.value = myChart.convertFromPixel( pointInGridStep5.value = myChart.convertFromPixel({ seriesIndex: 0 }, pointInPixel);
{ seriesIndex: 0 },
pointInPixel
);
console.log("pointInGrid5", pointInGridStep5.value); console.log("pointInGrid5", pointInGridStep5.value);
if (pointInGridStep5.value[0] > 5 && pointInGridStep5.value[1] > 1000) { if (pointInGridStep5.value[0] > 5 && pointInGridStep5.value[1] > 1000) {
optionStep5.value.series[0].markArea.data[0][0].itemStyle.color = optionStep5.value.series[0].markArea.data[0][0].itemStyle.color = drawPointColorStep5.value;
drawPointColorStep5.value; optionStep5.value.series[0].markArea.data[0][0].name = drawPointNameStep5.value;
optionStep5.value.series[0].markArea.data[0][0].name =
drawPointNameStep5.value;
console.log(optionStep5.value); console.log(optionStep5.value);
} }
if (pointInGridStep5.value[0] < 5 && pointInGridStep5.value[1] > 1000) { if (pointInGridStep5.value[0] < 5 && pointInGridStep5.value[1] > 1000) {
optionStep5.value.series[0].markArea.data[1][0].itemStyle.color = optionStep5.value.series[0].markArea.data[1][0].itemStyle.color = drawPointColorStep5.value;
drawPointColorStep5.value; optionStep5.value.series[0].markArea.data[1][0].name = drawPointNameStep5.value;
optionStep5.value.series[0].markArea.data[1][0].name =
drawPointNameStep5.value;
console.log(optionStep5.value); console.log(optionStep5.value);
} }
if (pointInGridStep5.value[0] < 5 && pointInGridStep5.value[1] < 1000) { if (pointInGridStep5.value[0] < 5 && pointInGridStep5.value[1] < 1000) {
optionStep5.value.series[0].markArea.data[2][0].itemStyle.color = optionStep5.value.series[0].markArea.data[2][0].itemStyle.color = drawPointColorStep5.value;
drawPointColorStep5.value; optionStep5.value.series[0].markArea.data[2][0].name = drawPointNameStep5.value;
optionStep5.value.series[0].markArea.data[2][0].name =
drawPointNameStep5.value;
console.log(optionStep5.value); console.log(optionStep5.value);
} }
if (pointInGridStep5.value[0] > 5 && pointInGridStep5.value[1] < 1000) { if (pointInGridStep5.value[0] > 5 && pointInGridStep5.value[1] < 1000) {
optionStep5.value.series[0].markArea.data[3][0].itemStyle.color = optionStep5.value.series[0].markArea.data[3][0].itemStyle.color = drawPointColorStep5.value;
drawPointColorStep5.value; optionStep5.value.series[0].markArea.data[3][0].name = drawPointNameStep5.value;
optionStep5.value.series[0].markArea.data[3][0].name =
drawPointNameStep5.value;
console.log(optionStep5.value); console.log(optionStep5.value);
} }
optionStep5.value && myChart.setOption(optionStep5.value); optionStep5.value && myChart.setOption(optionStep5.value);
@ -1212,6 +1139,10 @@ const step1Submit = () => {
console.log(step1Error.value, "错误数"); console.log(step1Error.value, "错误数");
proxy.$modal.msgSuccess("提交成功"); proxy.$modal.msgSuccess("提交成功");
step1AnswerFlag.value = true; step1AnswerFlag.value = true;
for (let k in step1Data.value) {
step2Data.value[k].amount = step1Data.value[k].params1;
step2Data.value[k].account = step1Data.value[k].params2;
}
}; };
const step2Submit = () => { const step2Submit = () => {
step2Error.value = 0; step2Error.value = 0;
@ -1234,34 +1165,22 @@ const step3Submit = () => {
for (let i in option.value.series[0].data) { for (let i in option.value.series[0].data) {
console.log(option.value.series[0].data[i]); console.log(option.value.series[0].data[i]);
if (option.value.series[0].data[i].name == "A") { if (option.value.series[0].data[i].name == "A") {
if ( if (Math.round(option.value.series[0].data[i].value[0]) != 3 || Math.round(option.value.series[0].data[i].value[1]) != 800) {
Math.round(option.value.series[0].data[i].value[0]) != 3 ||
Math.round(option.value.series[0].data[i].value[1]) != 800
) {
step3Error.value++; step3Error.value++;
} }
} }
if (option.value.series[0].data[i].name == "B") { if (option.value.series[0].data[i].name == "B") {
if ( if (Math.round(option.value.series[0].data[i].value[0]) != 4 || Math.round(option.value.series[0].data[i].value[1]) != 1200) {
Math.round(option.value.series[0].data[i].value[0]) != 4 ||
Math.round(option.value.series[0].data[i].value[1]) != 1200
) {
step3Error.value++; step3Error.value++;
} }
} }
if (option.value.series[0].data[i].name == "C") { if (option.value.series[0].data[i].name == "C") {
if ( if (Math.round(option.value.series[0].data[i].value[0]) != 6 || Math.round(option.value.series[0].data[i].value[1]) != 600) {
Math.round(option.value.series[0].data[i].value[0]) != 6 ||
Math.round(option.value.series[0].data[i].value[1]) != 600
) {
step3Error.value++; step3Error.value++;
} }
} }
if (option.value.series[0].data[i].name == "D") { if (option.value.series[0].data[i].name == "D") {
if ( if (Math.round(option.value.series[0].data[i].value[0]) != 7 || Math.round(option.value.series[0].data[i].value[1]) != 1400) {
Math.round(option.value.series[0].data[i].value[0]) != 7 ||
Math.round(option.value.series[0].data[i].value[1]) != 1400
) {
step3Error.value++; step3Error.value++;
} }
} }
@ -1275,10 +1194,7 @@ const step4Submit = () => {
for (let i in option2.value.series[0].data) { for (let i in option2.value.series[0].data) {
console.log(option2.value.series[0].data[i]); console.log(option2.value.series[0].data[i]);
if (option2.value.series[0].data[i].name == "A") { if (option2.value.series[0].data[i].name == "A") {
if ( if (Math.round(option2.value.series[0].data[i].value[0]) != 5 || Math.round(option2.value.series[0].data[i].value[1]) != 1000) {
Math.round(option2.value.series[0].data[i].value[0]) != 5 ||
Math.round(option2.value.series[0].data[i].value[1]) != 1000
) {
step4Error.value++; step4Error.value++;
} }
} }
@ -1307,32 +1223,22 @@ const step5Submit = () => {
}; };
const downloadData = () => { const downloadData = () => {
// console.log(666); // console.log(666);
portraitModel // portraitModel
.downloadDataByBoston({}) // .downloadDataByBoston({})
.then((res) => { // .then((res) => {
// console.log(res,'--'); // // console.log(res,'--');
const blob = new Blob([res], { type: "application/vnd.ms-excel" }); // const blob = new Blob([res], { type: "application/vnd.ms-excel" });
downBlobFile(`案例数据-波士顿矩阵分析`, blob); // downBlobFile(`案例数据-波士顿矩阵分析`, blob);
}) // })
.catch((error) => {}); // .catch((error) => {});
window.open(baseUrl + "/api/downDataByUserPortrait/bostonMatrixAnalysisData");
}; };
const submitData = () => { const submitData = () => {
if ( if (!step1AnswerFlag.value || !step2AnswerFlag.value || !step3AnswerFlag.value || !step4AnswerFlag.value || !step5AnswerFlag.value) {
!step1AnswerFlag.value ||
!step2AnswerFlag.value ||
!step3AnswerFlag.value ||
!step4AnswerFlag.value ||
!step5AnswerFlag.value
) {
proxy.$modal.msgError("请先完成所有步骤!"); proxy.$modal.msgError("请先完成所有步骤!");
return; return;
} }
errorNum.value = errorNum.value = step1Error.value + step2Error.value + step3Error.value + step4Error.value + step5Error.value;
step1Error.value +
step2Error.value +
step3Error.value +
step4Error.value +
step5Error.value;
console.log(errorNum.value, "总错误次数"); console.log(errorNum.value, "总错误次数");
portraitModel portraitModel
.submit({ .submit({
@ -1597,4 +1503,8 @@ defineExpose({
background-color: #002652 !important; background-color: #002652 !important;
color: #fff; color: #fff;
} }
::v-deep .el-table td {
padding-top: 4px;
padding-bottom: 4px;
}
</style> </style>

@ -603,6 +603,7 @@ const step1AnswerFlag = ref(false);
const step2AnswerFlag = ref(false); const step2AnswerFlag = ref(false);
const step3AnswerFlag = ref(false); const step3AnswerFlag = ref(false);
const errorNum = ref(0); const errorNum = ref(0);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
onBeforeUnmount(() => { onBeforeUnmount(() => {
saveData(); saveData();
}); });
@ -755,14 +756,15 @@ const step3Submit = () => {
step3AnswerFlag.value = true; step3AnswerFlag.value = true;
}; };
const downloadData = () => { const downloadData = () => {
portraitModel // portraitModel
.downloadDataByFunnel({}) // .downloadDataByFunnel({})
.then((res) => { // .then((res) => {
// console.log(res,'--'); // // console.log(res,'--');
const blob = new Blob([res], { type: "application/vnd.ms-excel" }); // const blob = new Blob([res], { type: "application/vnd.ms-excel" });
downBlobFile(`案例数据-漏斗模型`, blob); // downBlobFile(`案例数据-漏斗模型`, blob);
}) // })
.catch((error) => {}); // .catch((error) => {});
window.open(baseUrl + "/api/downDataByUserPortrait/analysisByFunnelModel");
}; };
const saveData = () => { const saveData = () => {
const params = { const params = {
@ -1009,4 +1011,8 @@ defineExpose({
background-color: #002652 !important; background-color: #002652 !important;
color: #fff; color: #fff;
} }
::v-deep .el-table td {
padding-top: 4px;
padding-bottom: 4px;
}
</style> </style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -17,7 +17,7 @@
<div style="margin-top: 10px; display: flex"> <div style="margin-top: 10px; display: flex">
<el-table <el-table
:data="fileTable1" :data="fileTable1"
style="width: 650px" style="width: 550px"
border border
:header-cell-style="{ :header-cell-style="{
color: '#fff', color: '#fff',
@ -105,7 +105,11 @@
</el-table-column> </el-table-column>
<el-table-column label="用户名称" align="center" prop="userName"> <el-table-column label="用户名称" align="center" prop="userName">
</el-table-column> </el-table-column>
<el-table-column label="最近一次消费时间间隔(R)" align="center" width="210"> <el-table-column
label="最近一次消费时间间隔(R)"
align="center"
width="210"
>
<template #default="scope"> <template #default="scope">
<el-input <el-input
v-model="scope.row.params1" v-model="scope.row.params1"
@ -532,11 +536,16 @@
</div> </div>
<img class="xtImg" src="../../../assets/images/线条.png" alt="" /> <img class="xtImg" src="../../../assets/images/线条.png" alt="" />
</template> </template>
<div style="color:#fff;margin-top:-35px;padding:10px;padding-left:20px"> <div
style="
color: #fff;
margin-top: -35px;
padding: 10px;
padding-left: 20px;
"
>
<el-scrollbar height="650px"> <el-scrollbar height="650px">
<div v-html="knowledge"> <div v-html="knowledge"></div>
</div>
</el-scrollbar> </el-scrollbar>
</div> </div>
<!-- <template #footer> <!-- <template #footer>
@ -556,6 +565,8 @@ import { getUserInfo } from "@/utils/auth";
import * as portraitModel from "@/api/portraitModel"; import * as portraitModel from "@/api/portraitModel";
import { downBlobFile } from "@/utils/index.js"; import { downBlobFile } from "@/utils/index.js";
import { onBeforeUnmount, onMounted } from "vue"; import { onBeforeUnmount, onMounted } from "vue";
// const baseURL = "http://192.168.2.16:9868/";
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const dialogVisible = ref(false); const dialogVisible = ref(false);
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const errorNum = ref(0); //总错误次数 const errorNum = ref(0); //总错误次数
@ -834,14 +845,17 @@ onMounted(() => {
getData(); getData();
}); });
const downloadData = () => { const downloadData = () => {
portraitModel // portraitModel
.downloadDataByRFM({}) // .downloadDataByRFM({})
.then((res) => { // .then((res) => {
// console.log(res,'--'); // // console.log(res,'--');
const blob = new Blob([res], { type: "application/vnd.ms-excel" }); // const blob = new Blob([res], {
downBlobFile(`案例数据-RFM分析`, blob); // type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
}) // });
.catch((error) => {}); // downBlobFile(`案例数据-RFM分析`, blob);
// })
// .catch((error) => {});
window.open(baseUrl + "/api/downDataByUserPortrait/analysisByRfmDown");
}; };
const step1Submit = () => { const step1Submit = () => {
// errorNum.value = 0; // errorNum.value = 0;
@ -1392,4 +1406,8 @@ const tableSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
margin-left: 20px; margin-left: 20px;
} }
} }
::v-deep .el-table td {
padding-top: 4px;
padding-bottom: 4px;
}
</style> </style>

File diff suppressed because one or more lines are too long

@ -275,7 +275,7 @@ import { onMounted } from "vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const currentComponent = ref(null); const currentComponent = ref(null);
const contentRef = ref(null); const contentRef = ref(null);
const menuIndex = ref(1); const menuIndex = ref(0);
const tabIndex = ref(0); const tabIndex = ref(0);
const fileTable = ref([]); const fileTable = ref([]);
const tabList = ref([ const tabList = ref([
@ -342,7 +342,8 @@ const tabList = ref([
]); ]);
// defineExpose({ submitMethod }); // defineExpose({ submitMethod });
onMounted(() => { onMounted(() => {
getTableData("用户属性表"); // getTableData("用户属性表");
currentComponent.value = tabList.value[0].key
}); });
const getTableData = (name) => { const getTableData = (name) => {
fileTable.value = []; fileTable.value = [];
@ -399,8 +400,8 @@ const retrain = () => {
// width: 1060px; // width: 1060px;
.tabs { .tabs {
cursor: pointer; cursor: pointer;
font-size: 12px; font-size: 13px;
margin-right: 4px; margin-right: 9px;
margin-bottom: 20px; margin-bottom: 20px;
width: 159px; width: 159px;
height: 56px; height: 56px;
@ -420,9 +421,6 @@ const retrain = () => {
.tabs:nth-of-type(9) { .tabs:nth-of-type(9) {
background-image: url("@/assets/images/itembg2.png"); background-image: url("@/assets/images/itembg2.png");
} }
.tabs:nth-of-type(9) {
font-size: 11px;
}
.tabs:nth-of-type(3), .tabs:nth-of-type(3),
.tabs:nth-of-type(10) { .tabs:nth-of-type(10) {
background-image: url("@/assets/images/itembg3.png"); background-image: url("@/assets/images/itembg3.png");
@ -445,6 +443,51 @@ const retrain = () => {
margin-right: 5px; margin-right: 5px;
} }
} }
.tabs:nth-of-type(1) {
// background-image: url("@/assets/images/itembg1.png");
width: 130px;
background-size: 130px 56px;
}
.tabs:nth-of-type(2) {
// background-image: url("@/assets/images/itembg1.png");
width: 153px;
background-size: 153px 56px;
}
.tabs:nth-of-type(3) {
// background-image: url("@/assets/images/itembg1.png");
width: 150px;
background-size: 150px 56px;
}
.tabs:nth-of-type(4) {
// background-image: url("@/assets/images/itembg1.png");
width: 172px;
background-size: 172px 56px;
}
.tabs:nth-of-type(6),.tabs:nth-of-type(7) {
// background-image: url("@/assets/images/itembg1.png");
width: 133px;
background-size: 133px 56px;
}
.tabs:nth-of-type(5) {
// background-image: url("@/assets/images/itembg1.png");
width: 133px;
background-size: 133px 56px;
}
.tabs:nth-of-type(8) {
// background-image: url("@/assets/images/itembg1.png");
width: 135px;
background-size: 135px 56px;
}
.tabs:nth-of-type(9) {
// background-image: url("@/assets/images/itembg1.png");
width: 185px;
background-size: 185px 56px;
}
.tabs:nth-of-type(10) {
// background-image: url("@/assets/images/itembg1.png");
width: 138px;
background-size: 138px 56px;
}
} }
.btn { .btn {
width: 220px; width: 220px;

Loading…
Cancel
Save