首页
This commit is contained in:
125
components/analytics/AnalyticsAreaChart.uvue
Normal file
125
components/analytics/AnalyticsAreaChart.uvue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<view class="chart-wrap" :style="{ height: heightPx }">
|
||||
<EChartsView :option="chartOption" class="chart" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EChartsView
|
||||
},
|
||||
props: {
|
||||
xLabels: { type: Array, default: () => [] },
|
||||
data: { type: Array, default: () => [] },
|
||||
height: { type: Number, default: 300 }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
heightPx: '300px',
|
||||
chartOption: {} as any
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
xLabels: { handler() { this.updateOption() }, deep: true },
|
||||
data: { handler() { this.updateOption() }, deep: true },
|
||||
height: {
|
||||
handler() {
|
||||
this.heightPx = `${this.height}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.heightPx = `${this.height}px`
|
||||
setTimeout(() => {
|
||||
this.updateOption()
|
||||
}, 150)
|
||||
},
|
||||
methods: {
|
||||
toPlainObject(obj: any): any {
|
||||
if (obj == null) return null
|
||||
if (typeof obj !== 'object') return obj
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => this.toPlainObject(item))
|
||||
}
|
||||
const plain: any = {}
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
const value = obj[key]
|
||||
if (typeof value === 'function' || key.startsWith('_') || key === 'toJSON') {
|
||||
continue
|
||||
}
|
||||
if (value != null && typeof value === 'object' && !Array.isArray(value)) {
|
||||
let isSimple = true
|
||||
for (const k in value) {
|
||||
if (typeof value[k] === 'object' && value[k] !== null) {
|
||||
isSimple = false
|
||||
break
|
||||
}
|
||||
}
|
||||
plain[key] = isSimple ? { ...value } : this.toPlainObject(value)
|
||||
} else {
|
||||
plain[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
return plain
|
||||
},
|
||||
updateOption() {
|
||||
if (!this.xLabels || !this.data || this.xLabels.length === 0 || this.data.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const x = (this.xLabels as Array<any>).map((s) => String(s))
|
||||
const d = (this.data as Array<any>).map((v) => {
|
||||
const n = Number(v)
|
||||
return isFinite(n) ? n : 0
|
||||
})
|
||||
|
||||
const option = {
|
||||
grid: { left: 40, right: 20, top: 20, bottom: 40 },
|
||||
tooltip: { trigger: 'axis' },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: x,
|
||||
axisLine: { lineStyle: { color: 'rgba(0,0,0,0.1)' } },
|
||||
axisLabel: { color: 'rgba(0,0,0,0.45)', fontSize: 10, interval: 'auto' }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: { show: false },
|
||||
splitLine: { lineStyle: { color: 'rgba(0,0,0,0.05)' } },
|
||||
axisLabel: { color: 'rgba(0,0,0,0.45)', fontSize: 10 }
|
||||
},
|
||||
series: [{
|
||||
data: d,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbolSize: 0,
|
||||
lineStyle: { width: 2, color: '#1890ff' },
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0, y: 0, x2: 0, y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: 'rgba(24, 144, 255, 0.2)' },
|
||||
{ offset: 1, color: 'rgba(24, 144, 255, 0.01)' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
this.chartOption = this.toPlainObject(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-wrap { width: 100%; position: relative; overflow: hidden; }
|
||||
.chart { width: 100%; height: 100%; position: absolute; top: 0; left: 0; }
|
||||
</style>
|
||||
|
||||
@@ -129,7 +129,7 @@ export default {
|
||||
let result = params[0].name + '<br/>'
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const p = params[i]
|
||||
if (p.seriesName === 'GMV') {
|
||||
if (p.seriesName === '订单金额' || p.seriesName === 'GMV') {
|
||||
const val = Number(p.value)
|
||||
const formatted = val >= 10000 ? (val / 10000).toFixed(1) + '万' : val.toFixed(0)
|
||||
result += `${p.marker} ${p.seriesName}: ¥${formatted}<br/>`
|
||||
@@ -142,11 +142,11 @@ export default {
|
||||
},
|
||||
legend: {
|
||||
top: 8,
|
||||
left: 8,
|
||||
left: 'center',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
textStyle: { fontSize: 12 },
|
||||
data: ['GMV', '订单数'],
|
||||
data: ['订单金额', '订单数'],
|
||||
bottom: 'auto'
|
||||
},
|
||||
xAxis: {
|
||||
@@ -156,14 +156,14 @@ export default {
|
||||
axisLine: { lineStyle: { color: 'rgba(0,0,0,0.12)' } },
|
||||
axisLabel: {
|
||||
color: 'rgba(0,0,0,0.55)',
|
||||
rotate: x.length > 12 ? 45 : 0,
|
||||
interval: 0
|
||||
rotate: x.length > 20 ? 45 : 0,
|
||||
interval: x.length > 15 ? 1 : 0
|
||||
}
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: 'GMV(元)',
|
||||
name: '金额',
|
||||
position: 'left',
|
||||
axisLine: { show: false },
|
||||
splitLine: { lineStyle: { color: 'rgba(0,0,0,0.06)' } },
|
||||
@@ -171,7 +171,7 @@ export default {
|
||||
color: 'rgba(0,0,0,0.55)',
|
||||
formatter: (value: number) => {
|
||||
if (value >= 10000) {
|
||||
return (value / 10000).toFixed(1) + '万'
|
||||
return (value / 10000).toFixed(0) + '万'
|
||||
}
|
||||
return String(Math.round(value))
|
||||
}
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '订单数',
|
||||
name: '数量',
|
||||
position: 'right',
|
||||
alignTicks: true,
|
||||
axisLine: { show: false },
|
||||
@@ -192,14 +192,14 @@ export default {
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
name: '订单金额',
|
||||
type: 'bar',
|
||||
yAxisIndex: 0,
|
||||
data: bar,
|
||||
barMaxWidth: 14,
|
||||
barCategoryGap: '35%',
|
||||
itemStyle: {
|
||||
borderRadius: [6, 6, 0, 0],
|
||||
borderRadius: [2, 2, 0, 0],
|
||||
color: '#3b82f6'
|
||||
}
|
||||
},
|
||||
@@ -208,7 +208,7 @@ export default {
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
data: line,
|
||||
smooth: true,
|
||||
smooth: false,
|
||||
symbol: 'circle',
|
||||
symbolSize: 6,
|
||||
lineStyle: {
|
||||
|
||||
115
components/analytics/AnalyticsPieChart.uvue
Normal file
115
components/analytics/AnalyticsPieChart.uvue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<view class="chart-wrap" :style="{ height: heightPx }">
|
||||
<EChartsView :option="chartOption" class="chart" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EChartsView
|
||||
},
|
||||
props: {
|
||||
items: { type: Array, default: () => [] },
|
||||
height: { type: Number, default: 300 }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
heightPx: '300px',
|
||||
chartOption: {} as any
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
items: { handler() { this.updateOption() }, deep: true },
|
||||
height: {
|
||||
handler() {
|
||||
this.heightPx = `${this.height}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.heightPx = `${this.height}px`
|
||||
setTimeout(() => {
|
||||
this.updateOption()
|
||||
}, 200)
|
||||
},
|
||||
methods: {
|
||||
toPlainObject(obj: any): any {
|
||||
if (obj == null) return null
|
||||
if (typeof obj !== 'object') return obj
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => this.toPlainObject(item))
|
||||
}
|
||||
const plain: any = {}
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
const value = obj[key]
|
||||
if (typeof value === 'function' || key.startsWith('_') || key === 'toJSON') {
|
||||
continue
|
||||
}
|
||||
if (value != null && typeof value === 'object' && !Array.isArray(value)) {
|
||||
let isSimple = true
|
||||
for (const k in value) {
|
||||
if (typeof value[k] === 'object' && value[k] !== null) {
|
||||
isSimple = false
|
||||
break
|
||||
}
|
||||
}
|
||||
plain[key] = isSimple ? { ...value } : this.toPlainObject(value)
|
||||
} else {
|
||||
plain[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
return plain
|
||||
},
|
||||
updateOption() {
|
||||
if (!this.items || this.items.length === 0) return
|
||||
|
||||
const data = (this.items as Array<any>).map((it) => {
|
||||
return {
|
||||
name: String(it.name),
|
||||
value: Number(it.value),
|
||||
itemStyle: this.toPlainObject(it.itemStyle)
|
||||
}
|
||||
})
|
||||
|
||||
const option = {
|
||||
tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
textStyle: { fontSize: 11, color: '#666' }
|
||||
},
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['45%', '70%'],
|
||||
center: ['35%', '50%'],
|
||||
data: data,
|
||||
avoidLabelOverlap: true,
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
labelLine: { show: false },
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
borderColor: '#fff'
|
||||
}
|
||||
}]
|
||||
}
|
||||
this.chartOption = this.toPlainObject(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-wrap { width: 100%; position: relative; overflow: hidden; }
|
||||
.chart { width: 100%; height: 100%; position: absolute; top: 0; left: 0; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user