添加热量分析图表

This commit is contained in:
huangdeliang 2021-03-17 17:17:09 +08:00
parent ba372bee26
commit b36cef2948
4 changed files with 336 additions and 30 deletions

View File

@ -6,6 +6,7 @@
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="//at.alicdn.com/t/font_2343184_8rlvxcc41j5.css">
<title><%= webpackConfig.name %></title>
<style>
html,

View File

@ -517,6 +517,10 @@ const getters = {
obj.fHeat = obj.fWeight * 9;
obj.cWeight += (igd.weight / 100) * igd.carbonRatio;
obj.cHeat = obj.cWeight * 4;
obj[`heat${cur.type}`] +=
(igd.weight / 100) * igd.proteinRatio * 4 +
(igd.weight / 100) * igd.fatRatio * 9 +
(igd.weight / 100) * igd.carbonRatio * 4;
});
return obj;
},
@ -527,7 +531,13 @@ const getters = {
cWeight: 0,
pHeat: 0,
fHeat: 0,
cHeat: 0
cHeat: 0,
heat1: 0,
heat2: 0,
heat3: 0,
heat4: 0,
heat5: 0,
heat6: 0,
}
)
);

View File

@ -0,0 +1,171 @@
<template>
<div
:class="`energy_pie_chart_wrapper ${className || ''}`"
:style="{ height: height, width: width }"
>
<div ref="echart" :style="{ height: height, width: '100px' }" />
</div>
</template>
<script>
import echarts from "echarts";
require("@/utils/echarts/myShine");
import resize from "@/views/dashboard/mixins/resize";
import TextInfo from "@/components/TextInfo";
import { createNamespacedHelpers } from "vuex";
const { mapMutations, mapState } = createNamespacedHelpers("recipes");
export default {
mixins: [resize],
components: {
TextInfo,
},
props: {
className: {
type: String,
default: "chart",
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "300px",
},
data: {
type: Array,
default: [],
},
},
data() {
return {
chart: null,
totalHeat: 0,
nameDict: {
p: "蛋白质",
f: "脂肪",
c: "碳水",
},
typeDict: {
Weight: "摄入量",
Rate: "供能比",
},
};
},
computed: {
mData() {
const [data] = this.data;
if (!data) {
this.totalHeat = 0;
return [];
}
this.totalHeat = data.cHeat + data.fHeat + data.pHeat;
const mData = ["Weight", "Rate"].map((t, idx) => ({
type: this.typeDict[t],
...["p", "f", "c"].reduce((obj, cur) => {
obj[cur] = idx
? `${((data[`${cur}Heat`] / this.totalHeat) * 100).toFixed(2)}%`
: `${data[`${cur}Weight`].toFixed(1)}`;
return obj;
}, {}),
}));
// console.log(mData);
return mData;
},
...mapState(["recipesData"]),
},
mounted() {
this.$nextTick(() => {
this.initChart();
});
},
beforeDestroy() {
if (!this.chart) {
return;
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(this.$refs.echart, "myShine");
this.updateChart(this.data.length > 0 ? this.data[0] : {});
},
backToAll() {
this.resetCurrentDay({ currentDay: -1 });
},
updateChart(data) {
this.chart.clear();
this.chart.setOption({
title: {
text: "营养分析",
subtext: data.name,
},
tooltip: {
position: "right",
trigger: "item",
// appendToBody: true,
formatter: (params) => {
const {
name,
marker,
percent,
data: { value, oriData, dim },
} = params;
return [
`${marker} ${name}`,
`摄入量:${oriData[`${dim}Weight`].toFixed(1)}`,
`摄入热量:${value.toFixed(1)}千卡`,
`供能比:${percent}%`,
].join("</br>");
},
},
series: [
{
name: data.name,
type: "pie",
radius: [0, 40],
center: ["50%", "55%"],
data: ["p", "f", "c"].map((dim) => ({
dim,
value: data[`${dim}Heat`],
name: this.nameDict[dim],
oriData: data,
})),
// labelLine: {
// length: 5,
// length2: 5,
// },
label: {
show: true,
position: "inside",
color: "#fff",
fontSize: 10,
fontWeight: "bold",
},
itemStyle: {
borderWidth: 1,
borderColor: "#fff",
},
},
],
});
},
...mapMutations(["resetCurrentDay"]),
},
watch: {
data(newVal, oldVal) {
if (newVal) {
this.$nextTick(() => {
this.updateChart(newVal[0]);
});
}
},
},
};
</script>
<style lang="scss" scoped>
.energy_pie_chart_wrapper {
}
</style>

View File

@ -3,8 +3,25 @@
:class="`aspect_pie_chart_wrapper ${className || ''}`"
:style="{ height: height, width: width }"
>
<div ref="echart" :style="{ height: height, width: '100px' }" />
<div>
<div
ref="echart"
:style="{ height: height, width: !view ? '100px' : '100%' }"
/>
<div class="icon_btns">
<el-tooltip effect="dark" content="营养分析" placement="top">
<em
:class="['iconfont', 'icon-03', { sel_icon: view === 0 }]"
@click="handleOnViewChange(0)"
/>
</el-tooltip>
<el-tooltip effect="dark" content="热量分析" placement="top">
<em
:class="['iconfont', 'icon-fenxi', { sel_icon: view === 1 }]"
@click="handleOnViewChange(1)"
/>
</el-tooltip>
</div>
<div v-if="view === 0" class="table_zone">
<el-table
:data="mData"
size="mini"
@ -24,16 +41,11 @@
{{ totalHeat.toFixed(1) }}千卡
</div>
</div>
<div
style="text-align: right; margin-top: 4px"
v-if="recipesData.length > 1"
>
<el-button size="mini" type="text" @click="backToAll"
</div>
<el-button size="mini" type="text" @click="backToAll" class="see_all"
>查看全部</el-button
>
</div>
</div>
</div>
</template>
<script>
@ -76,10 +88,19 @@ export default {
f: "脂肪",
c: "碳水",
},
menuDict: {
1: "早餐",
2: "早加餐",
3: "午餐",
4: "午加餐",
5: "晚餐",
6: "晚加餐",
},
typeDict: {
Weight: "摄入量",
Rate: "供能比",
},
view: 1,
};
},
computed: {
@ -119,16 +140,17 @@ export default {
methods: {
initChart() {
this.chart = echarts.init(this.$refs.echart, "myShine");
this.updateChart(this.data.length > 0 ? this.data[0] : {});
this.updateChart(this.data[0] || {});
},
backToAll() {
this.resetCurrentDay({ currentDay: -1 });
},
updateChart(data) {
// console.log(data);
this.chart.clear();
this.chart.setOption({
const option = {
title: {
text: "营养分析",
text: !this.view ? "营养分析" : "热量分析",
subtext: data.name,
},
tooltip: {
@ -142,26 +164,90 @@ export default {
percent,
data: { value, oriData, dim },
} = params;
return [
return !this.view
? [
`${marker} ${name}`,
`摄入量:${oriData[`${dim}Weight`].toFixed(1)}`,
`摄入热量:${value.toFixed(1)}千卡`,
`供能比:${percent}%`,
]
: [
`${marker} ${name}`,
`热量:${data[`heat${dim}`].toFixed(1)}千卡`,
`供能比:${percent}%`,
].join("</br>");
},
},
graphic:
this.view === 1
? [
{
type: "group",
top: 60,
left: 10,
silent: true,
children: [
{
type: "text",
style: {
text: "总热量",
fill: "#606266",
},
},
{
type: "text",
top: 18,
left: 8,
style: {
text: `${this.totalHeat.toFixed(1)}千卡`,
font: '14px "Microsoft YaHei", sans-serif',
},
},
],
},
{
type: "group",
top: 36,
right: 10,
silent: true,
children: Object.keys(this.menuDict).reduce((arr, cur) => {
const tarData = data[`heat${cur}`];
if (tarData) {
arr.push({
type: "text",
top: arr.length * 20,
right: 10,
style: {
text: `${this.menuDict[cur]}${tarData.toFixed(1)}`,
fill: "#606266",
},
});
}
return arr;
}, []),
},
]
: [],
series: [
{
name: data.name,
type: "pie",
radius: [0, 40],
radius: [0, !this.view ? 40 : 60],
center: ["50%", "55%"],
data: ["p", "f", "c"].map((dim) => ({
data: (!this.view
? Object.keys(this.nameDict)
: Object.keys(this.menuDict)
).reduce((arr, dim) => {
if (!this.view || data[`heat${dim}`]) {
arr.push({
dim,
value: data[`${dim}Heat`],
name: this.nameDict[dim],
value: !this.view ? data[`${dim}Heat`] : data[`heat${dim}`],
name: (!this.view ? this.nameDict : this.menuDict)[dim],
oriData: data,
})),
});
}
return arr;
}, []),
// labelLine: {
// length: 5,
// length2: 5,
@ -170,7 +256,7 @@ export default {
show: true,
position: "inside",
color: "#fff",
fontSize: 10,
fontSize: !this.view ? 10 : 12,
fontWeight: "bold",
},
itemStyle: {
@ -179,7 +265,16 @@ export default {
},
},
],
};
console.log(option);
this.chart.setOption(option);
},
handleOnViewChange(view) {
this.view = view;
this.chart.resize({
width: !this.view ? 100 : 364,
});
this.updateChart(this.data[0] || {});
},
...mapMutations(["resetCurrentDay"]),
},
@ -195,21 +290,24 @@ export default {
};
</script>
<style lang="scss" scoped>
/deep/ :focus {
outline: 0;
}
.aspect_pie_chart_wrapper {
width: 100%;
display: flex;
position: relative;
& > div:nth-child(1) {
// width: 200px
}
// & > div:nth-child(2) {
.small_table {
.my_cell {
padding: 2px 0 !important;
}
}
// }
.summary {
padding: 2px;
@ -222,5 +320,31 @@ export default {
text-align: center;
}
}
.see_all {
position: absolute;
bottom: 4px;
left: 4px;
padding: 0;
}
.icon_btns {
position: absolute;
right: 0;
em {
display: inline-block;
padding: 4px;
cursor: pointer;
}
.sel_icon {
color: #1890ff;
}
}
.table_zone {
margin-top: 26px;
}
}
</style>