Browse Source

洞悉首页

test
wzl 1 year ago
parent
commit
fffd26f0a2
1 changed files with 884 additions and 6 deletions
  1. +884
    -6
      src/views/insight/index.vue

+ 884
- 6
src/views/insight/index.vue View File

@@ -5,7 +5,6 @@
<div class="periodItem week" :class="{ active: active == 0 }" @click="active = 0">周</div>
<div class="periodItem month" :class="{ active: active == 1 }" @click="active = 1">月</div>
</div>
<!-- 带有前后箭头的切换器 -->
<div class="periodSwitch">
<div class="arrow arrowLeft" @click="active = active == 0 ? 1 : 0">
<van-icon name="arrow-left"></van-icon>
@@ -15,6 +14,81 @@
<van-icon name="arrow"></van-icon>
</div>
</div>
<div class="label">情绪感知</div>
<div class="periodNav">
<div
class="periodItem minPeriodItem"
:class="{ active: emotionActive == index }"
v-for="(item, index) in emotionList"
:key="index"
@click="onEmotionClick(index)"
>
<span>{{ item.name }}</span>
</div>
</div>
<div class="ChatBox">
<div class="legendBox">
<div class="legend">
<div class="legendItem" :class="item.type" v-for="(item, index) in degreeList" :key="index">
<span>{{ item.name }}{{ emotionList[emotionActive].name }}</span>
<span class="number">{{ 120 }}次({{ 120 }}%)</span>
</div>
</div>
</div>
<div class="Chat emotionChat" id="emotionChart"></div>
</div>
<div class="grid">
<div class="gridItem" :style="`background:${item.color};`" v-for="(item, index) in degreeList" :key="index">
<div class="time">
<span class="number">5</span>
<span>天</span>
</div>
<div class="title">{{ item.name }}{{ emotionList[emotionActive].name }}倾向</div>
</div>
</div>
<div class="label">体征感知</div>
<div class="periodNav">
<div
class="periodItem minPeriodItem"
:class="{ active: signActive == index }"
v-for="(item, index) in signList"
:key="index"
@click="onSignClick(index)"
>
<span>{{ item.name }}</span>
</div>
</div>
<div class="ChatBox" :class="{ hiddenChart: signActive == 2 }">
<div class="legendBox minLegendBox">
<div class="legend">
<div class="legendItem" :class="item.type" v-for="(item, index) in signGrid" :key="index">
<span>{{ item.name }}</span>
</div>
</div>
</div>
<div class="Chat signChart" id="signChart"></div>
</div>
<div class="grid" v-if="signList[signActive].grid">
<div
class="gridItem"
:class="{ minItem: signGrid.length % 3 == 0 }"
:style="`background:${item.color};`"
v-for="(item, index) in signGrid"
:key="index"
>
<div class="time">
<span class="number">5</span>
<span>天</span>
</div>
<div class="title">{{ item.name }}</div>
</div>
</div>
<div class="ChatBox minChartBox" :class="{ hiddenChart: signActive != 2 }">
<div class="Chat stepChart" id="stepChart"></div>
</div>
<div class="ChatBox minChartBox" :class="{ hiddenChart: signActive != 2 }">
<div class="Chat calorieChart" id="calorieChart"></div>
</div>
</div>
</template>

@@ -22,12 +96,637 @@
export default {
data() {
return {
active: 0
active: 0,
emotionActive: 0,
signActive: 0,
emotionChart: null,
signChart: null,
stepChart: null,
calorieChart: null,
emotionList: [
{
name: '疲劳'
},
{
name: '压力'
},
{
name: '焦虑'
}
],
degreeList: [
{
name: '无',
type: 'not',
color: '#179B3B'
},
{
name: '轻度',
type: 'mild',
color: '#2EA7E0'
},
{
name: '中度',
type: 'moderate',
color: '#8DC21F'
},
{
name: '重度',
type: 'severe',
color: '#FF5F8B'
}
],
signList: [
{
grid: 'heartRateList',
name: '心率'
},
{
grid: 'temperatureList',
name: '体温'
},
{
grid: null,
name: '运动'
}
],
heartRateList: [
{
name: '正常',
type: 'moderate',
color: '#179B3B'
},
{
name: '偏高',
type: 'severe',
color: '#FF5F8B'
},
{
name: '偏低',
type: 'mild',
color: '#2EA7E0'
}
],
temperatureList: [
{
name: '正常',
type: 'moderate',
color: '#179B3B'
},
{
name: '发烧',
type: 'severe',
color: '#FF5F8B'
}
]
};
},
created() {},
mounted() {},
methods: {}
mounted() {
this.initData();
},
watch: {
active(val) {
console.log(val);
this.emotionActive = 0;
this.signActive = 0;
this.$nextTick(() => {
this.initData();
});
},
emotionActive(val) {
console.log(val);
this.$nextTick(() => {
this.initEmotionChart();
});
},
signActive(val) {
console.log(val);
this.$nextTick(() => {
this.initSignChart();
});
}
},
computed: {
degreeMap() {
let map = new Map();
this.degreeList.forEach(item => {
map.set(item.name, item.color);
});
return map;
},
heartRateMap() {
let map = new Map();
this.heartRateList.forEach(item => {
map.set(item.name, item.color);
});
return map;
},
temperatureMap() {
let map = new Map();
this.temperatureList.forEach(item => {
map.set(item.name, item.color);
});
return map;
},
signGrid() {
let list = [];
if (this.signList[this.signActive].grid) {
let temp = this[`${this.signList[this.signActive].grid}`];
if (temp) {
list = temp;
}
}
return list;
}
},
methods: {
initData() {
//初始化图表
if (!this.emotionChart) {
this.emotionChart = this.$echarts.init(document.getElementById('emotionChart'));
}
if (!this.signChart) {
this.signChart = this.$echarts.init(document.getElementById('signChart'));
}
if (!this.stepChart) {
this.stepChart = this.$echarts.init(document.getElementById('stepChart'));
}
if (!this.calorieChart) {
this.calorieChart = this.$echarts.init(document.getElementById('calorieChart'));
}

//渲染图表
this.initEmotionChart();
this.initSignChart();
},
initEmotionChart() {
let option = this.getOption();

//测试
let data = [
{
time: '5.11',
value: 10
},
{
time: '5.12',
value: 20
},
{
time: '5.13',
value: 40
},
{
time: '5.14',
value: 50
},
{
time: '5.15',
value: 60
},
{
time: '5.16',
value: 70
},
{
time: '5.17',
value: 90
}
];

this.formateEmotionData(option, data);

this.emotionChart.setOption(option);
},
initSignChart() {
let option = this.getOption();

if (this.signActive == 0) {
//测试
let data = [
{
time: '5.11',
value: 50
},
{
time: '5.12',
value: 60
},
{
time: '5.13',
value: 70
},
{
time: '5.14',
value: 80
},
{
time: '5.15',
value: 120
},
{
time: '5.16',
value: 130
},
{
time: '5.17',
value: 150
}
];

this.formateHeartRateData(option, data);
this.signChart.setOption(option);
} else if (this.signActive == 1) {
//测试
let data = [
{
time: '5.11',
value: 36
},
{
time: '5.12',
value: 38
},
{
time: '5.13',
value: 37
},
{
time: '5.14',
value: 36
},
{
time: '5.15',
value: 38
},
{
time: '5.16',
value: 37
},
{
time: '5.17',
value: 39
}
];
this.formateTemperatureData(option, data);
this.signChart.setOption(option);
} else if (this.signActive == 2) {
option = this.getOption(false);
let option2 = this.getOption(false);

//测试
let data = [
{
time: '5.11',
value: 36
},
{
time: '5.12',
value: 38
},
{
time: '5.13',
value: 37
},
{
time: '5.14',
value: 36
},
{
time: '5.15',
value: 38
},
{
time: '5.16',
value: 37
},
{
time: '5.17',
value: 39
}
];
//测试
let data2 = [
{
time: '5.11',
value: 36
},
{
time: '5.12',
value: 38
},
{
time: '5.13',
value: 37
},
{
time: '5.14',
value: 36
},
{
time: '5.15',
value: 38
},
{
time: '5.16',
value: 37
},
{
time: '5.17',
value: 39
}
];

this.formateStepData(option, data);
this.formateCalorieData(option2, data2);

this.stepChart.setOption(option);
this.calorieChart.setOption(option2);
}
},
formateEmotionData(option, data) {
let xdata = [];
let ydata = [];
let fill = [];
let max = 0;
data.forEach(item => {
if (item.value > max) {
max = item.value;
}
});
data.forEach(item => {
xdata.push(item.time);
fill.push({
value: max - item.value,
label: {
show: false
},
itemStyle: {
color: this.formateEmotionColor(item.value)
}
});
ydata.push({
value: item.value,
label: {
show: true
},
itemStyle: {
color: this.formateEmotionColor(item.value)
}
});
});
option.xAxis.data = xdata;
option.series[0].data = ydata;
option.series[1].data = fill;
},
formateEmotionColor(value) {
if (value > 75) {
return this.degreeMap.get('重度');
} else if (value > 50) {
return this.degreeMap.get('中度');
} else if (value > 25) {
return this.degreeMap.get('轻度');
} else {
return this.degreeMap.get('无');
}
},
formateHeartRateData(option, data) {
let xdata = [];
let ydata = [];
let fill = [];
let max = 0;
data.forEach(item => {
if (item.value > max) {
max = item.value;
}
});
data.forEach(item => {
xdata.push(item.time);
fill.push({
value: max - item.value,
label: {
show: false
},
itemStyle: {
color: this.formateHeartRateColor(item.value)
}
});
ydata.push({
value: item.value,
label: {
show: true
},
itemStyle: {
color: this.formateHeartRateColor(item.value)
}
});
});
option.xAxis.data = xdata;
option.series[0].data = ydata;
option.series[1].data = fill;
// 规定最小值
option.yAxis.min = 40;
// 规定最大值
option.yAxis.max = 150;
//设置高压标线
option.series[1].markLine = {
data: [
{
symbol: 'pin',
silent: true,
yAxis: 120,
lineStyle: {
color: '#C1272D'
},
label: {
color: '#C1272D'
}
}
]
};
},
formateHeartRateColor(value) {
if (value > 120) {
return this.heartRateMap.get('偏高');
} else if (value >= 60) {
return this.heartRateMap.get('正常');
} else {
return this.heartRateMap.get('偏低');
}
},
formateTemperatureData(option, data) {
let xdata = [];
let ydata = [];
let fill = [];
let max = 0;
data.forEach(item => {
if (item.value > max) {
max = item.value;
}
});
data.forEach(item => {
xdata.push(item.time);
fill.push({
value: max - item.value,
label: {
show: false
},
itemStyle: {
color: this.formateTemperatureColor(item.value)
}
});
ydata.push({
value: item.value,
label: {
show: true
},
itemStyle: {
color: this.formateTemperatureColor(item.value)
}
});
});
option.xAxis.data = xdata;
option.series[0].data = ydata;
option.series[1].data = fill;
// 规定最小值
option.yAxis.min = 35;
// 规定最大值
option.yAxis.max = max;
},
formateTemperatureColor(value) {
if (value > 38) {
return this.temperatureMap.get('发烧');
} else {
return this.temperatureMap.get('正常');
}
},
formateStepData(option, data) {
let xdata = [];
let ydata = [];
data.forEach(item => {
xdata.push(item.time);
ydata.push({
value: item.value,
label: {
show: true
},
itemStyle: {
color: this.formateTemperatureColor(item.value)
}
});
});
option.xAxis.data = xdata;
option.series[0].data = ydata;
// 隐藏y轴
option.yAxis.show = false;
},
formateCalorieData(option, data) {
let xdata = [];
let ydata = [];
data.forEach(item => {
xdata.push(item.time);
ydata.push({
value: item.value,
label: {
show: true
},
itemStyle: {
color: this.formateTemperatureColor(item.value)
}
});
});
option.xAxis.data = xdata;
option.series[0].data = ydata;
// 隐藏y轴
option.yAxis.show = false;
},
getOption(point = true) {
let option = {
grid: {
top: '10%',
left: '10%',
right: '10%',
bottom: '20%'
},
xAxis: {
type: 'category',
axisLine: {
show: false
},
axisTick: {
show: false
}
},
yAxis: {
type: 'value'
},
series: [
{
type: 'bar',
barMaxWidth: 15,
stack: 'value',
stackStrategy: 'all',
animation: false,
label: {
show: true,
width: 15,
height: 15,
backgroundColor: '#fff',
borderRadius: 50,
borderWidth: 3,
borderColor: 'inherit',
verticalAlign: 'middle',
position: 'insideTop',
formatter: function () {
return '';
}
},
itemStyle: {
borderRadius: [0, 0, 12, 12]
}
},
{
type: 'bar',
barMaxWidth: 15,
stack: 'value',
stackStrategy: 'all',
animation: false,
itemStyle: {
borderRadius: [12, 12, 0, 0]
}
}
]
};

if (!point) {
option.series = [
{
type: 'bar',
barMaxWidth: 15,
label: {
show: true,
color: '#000',
position: 'outside',
},
itemStyle: {
borderRadius: 12
}
},
]
}

return option;
},
onEmotionClick(index) {
this.emotionActive = index;
// 情绪选项变化重新渲染图表
},
onSignClick(index) {
this.signActive = index;
// 体征选项变化重新渲染图表
}
}
};
</script>
<style scoped lang="scss">
@@ -47,12 +746,16 @@ export default {
text-align: center;
padding: 12px;
border-radius: 30px;
background: #E6E6E6;
background: #e6e6e6;
&.active {
color: white;
background: #179B3B;
background: #179b3b;
}
}
.minPeriodItem {
width: 32%;
padding: 8px;
}
}
.periodSwitch {
display: flex;
@@ -60,14 +763,189 @@ export default {
justify-content: space-between;
align-items: center;
padding: 40px 10px;
padding-bottom: 10px;

.timearea {
font-size: 28px;
justify-self: center;
color: gray;
}
.arrow {
font-size: 45px;
}
}
.label {
font-size: 40px;
font-weight: bold;
padding: 30px 0;
}
.ChatBox {
overflow: hidden;
width: calc(100vw - 60px);
height: 600px;
border: 2px solid #cdf348;
border-radius: 70px;
margin-top: 30px;

.legendBox {
width: 100%;
height: 150px;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 0 30px;

.legend {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
align-items: center;
font-size: 20px;

.legendItem {
position: relative;
width: 205px;
margin-top: 10px;
margin-right: 20px;

&:nth-child(2n) {
margin-right: 0;
}
}
.not {
.number {
color: #179b3b;
}
&::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: -20px;
width: 15px;
height: 15px;
background: #179b3b;
border-radius: 50%;
margin: auto;
}
}
.mild {
.number {
color: #2ea7e0;
}
&::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: -20px;
width: 15px;
height: 15px;
background: #2ea7e0;
border-radius: 50%;
margin: auto;
}
}
.moderate {
.number {
color: #8dc21f;
}
&::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: -20px;
width: 15px;
height: 15px;
background: #8dc21f;
border-radius: 50%;
margin: auto;
}
}
.severe {
.number {
color: #ff5f8b;
}
&::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: -20px;
width: 15px;
height: 15px;
background: #ff5f8b;
border-radius: 50%;
margin: auto;
}
}
}
}
.minLegendBox {
.legend {
.legendItem {
width: auto;
margin-right: 50px;

&:nth-child(2n) {
margin-right: 50px;
}
&:last-child {
margin-right: 0;
}
}
}
}
.Chat {
width: calc(100vw - 60px);
height: 450px;
}
}
.minChartBox {
height: 450px;
}
.hiddenChart {
width: 0;
height: 0;
}

.grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
color: white;
font-size: 30px;

.gridItem {
width: calc((100vw - 60px) * 0.48);
height: calc((100vw - 60px) * 0.48);
border-radius: 60px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 30px;

.time {
.number {
font-size: 90px;
font-weight: bold;
}
}
}
.minItem {
width: calc((100vw - 60px) * 0.32);
height: calc((100vw - 60px) * 0.32);
font-size: 28px;

.time {
.number {
font-size: 70px;
font-weight: bold;
}
}
}
}
}
</style>

Loading…
Cancel
Save