Signed-off-by: chy <chy@163.com>

This commit is contained in:
chy
2026-02-02 23:17:44 +08:00
parent e10f2f058c
commit a49878384e
774 changed files with 249821 additions and 0 deletions

432
src/views/Home/Index8.vue Normal file
View File

@@ -0,0 +1,432 @@
<template>
<div class="w-100%">
<div class="w-100% flex gap-y-20px home-top">
<div class="el-card top-card flex items-center" v-for="(item, index) in tabList" :key="index">
<div class="left">
<span class="text-value">
<avue-count-up :end="item.countUp"></avue-count-up>
</span>
<div class="text mt-10px">
<span class="mr-5px">{{ item.title }}</span>
</div>
</div>
<div>
<el-image :src="item.imgUrl" fit="contain"></el-image>
</div>
</div>
</div>
<div class="w-100% flex gap-x-20px mt-30px ml-10px mr-10px">
<div class="w-35%">
<el-calendar v-model="value">
<template #header>
<span>{{ calendarDate }}</span>
</template>
</el-calendar>
</div>
<div class="echart-util bold bg-white .dark:bg-#1D1E1F">
<Echart :options="visitor_option" width="100%" height="314px" />
</div>
</div>
<div class="w-100% flex gap-x-20px mt-30px ml-10px mr-10px">
<div class="echart-util bold bg-white .dark:bg-#1D1E1F">
<Echart :options="salesVolume_option" width="100%" height="314px" />
</div>
<div class="echart-util reverse bg-white .dark:bg-#1D1E1F">
<Echart :options="cyclic_annular_option" width="100%" height="314px" />
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { formatDate } from '@/utils/formatTime'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import { useAppStore } from '@/store/modules/app'
import { batchGetTableList } from '@/api/design/report'
defineOptions({ name: 'Home8' })
interface CyclicAnnular {
name: string
dictionary: string
value?: number
}
const tabList = ref([
{ countUp: 0, title: '今日访客数(人)', imgUrl: '/img/sjhy1.png', dictionary: 'today_visitors' },
{
countUp: 0,
title: '今日会员访问数(人)',
imgUrl: '/img/sjhy2.png',
dictionary: 'today_member_visitors'
},
{
countUp: 0,
title: '今日会员付费数(人)',
imgUrl: '/img/sjhy3.png',
dictionary: 'today_paid_member'
},
{ countUp: 0, title: '新增会员数(人)', imgUrl: '/img/sjhy4.png', dictionary: 'today_new_member' }
])
const value = ref(new Date())
const calendarDate = formatDate(new Date(), 'YYYY-MM-DD')
// 实时访客量
const visitorXAxis = ref<string[]>([])
const visitorSeries = ref<number[]>([])
const visitor_option = ref({
tooltip: {
trigger: 'axis'
},
title: {
text: '实时访客量',
textStyle: {
fontSize: 20,
color: 'black'
},
left: 25
},
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: '#EDE8FE' // 0% 处的颜色
},
{
offset: 1,
color: '#F8F7FC' // 100% 处的颜色
}
],
global: false // 缺省为 false
},
grid: {
left: '4%',
right: '4%',
bottom: 20,
top: '16%',
containLabel: true
},
xAxis: {
data: visitorXAxis.value,
type: 'category',
boundaryGap: false,
axisLine: {
symbol: 'none',
lineStyle: {
color: '#EBEBEB'
}
},
axisTick: {
show: false
},
axisLabel: {
interval: 0,
color: 'black',
fontSize: 12,
padding: [10, 0, 0, 0],
align: 'center'
}
},
yAxis: {
type: 'value',
axisLabel: {
color: '#6071A9',
fontSize: 12
},
splitLine: {
lineStyle: {
color: '#EBEBEB',
type: 'solid'
}
},
offset: 10
},
series: [
{
name: '访客量',
type: 'line',
data: visitorSeries.value,
smooth: true,
lineStyle: {
width: 5,
color: '#5D77FF'
},
areaStyle: {
opacity: 0.7
},
emphasis: { disabled: true },
symbol: 'none'
}
]
})
// 销售额
const salesVolumeXAxis = ref<string[]>([])
const salesVolumeSeries = ref<number[]>([])
const salesVolume_option = ref({
tooltip: {
trigger: 'axis'
},
title: {
text: '销售额(元)',
textStyle: {
fontSize: 20,
color: 'black'
},
left: 25
},
color: ['#6F7EFD'],
grid: {
left: '4%',
right: '4%',
bottom: 20,
top: '16%',
containLabel: true
},
xAxis: {
data: salesVolumeXAxis.value,
type: 'category',
boundaryGap: false,
axisLine: {
symbol: 'none',
lineStyle: {
color: '#EBEBEB'
}
},
axisTick: {
show: false
},
axisLabel: {
interval: 0,
color: 'black',
fontSize: 12,
padding: [10, 0, 0, 0],
align: 'center'
}
},
yAxis: {
type: 'value',
axisLabel: {
color: '#6071A9',
fontSize: 12
},
splitLine: {
lineStyle: {
width: 0
}
},
offset: 10
},
series: [
{
type: 'line',
data: salesVolumeSeries.value,
smooth: true,
lineStyle: {
width: 0
},
areaStyle: {
opacity: 1
},
emphasis: { disabled: true },
symbol: 'none'
}
]
})
// 环状图
const cyclic_annular_option_data = ref<CyclicAnnular[]>([
{ name: '男装', dictionary: 'nz' },
{ name: '鞋包', dictionary: 'xb' },
{ name: '母婴', dictionary: 'my' },
{ name: '数码', dictionary: 'sm' }
])
const cyclic_annular_option = ref({
title: {
text: '',
left: 'center',
top: 'center',
textStyle: {
fontSize: 24,
fontWeight: 'bold',
color: '#5E78FD'
},
subtext: '',
subtextStyle: {
color: '#999999',
fontWeight: '600'
},
itemGap: 0
},
color: ['#5E78FD', '#6E86FD', '#8DA0FF', '#AEBBFF'],
series: [
{
type: 'pie',
radius: ['35%', '55%'],
label: {
formatter: (parms) => {
return [`{str|${parms.percent}% ${parms.data.name}}`].join('\n')
},
rich: {
str: {
fontWeight: 'bold',
align: 'center'
}
}
},
data: cyclic_annular_option_data.value
}
]
})
const appStore = useAppStore()
watch(
() => appStore.isDark,
(val) => {
if (val) {
visitor_option.value.title.textStyle.color = 'white'
salesVolume_option.value.title.textStyle.color = 'white'
} else {
visitor_option.value.title.textStyle.color = 'black'
salesVolume_option.value.title.textStyle.color = 'black'
}
}
)
const init = async () => {
let oneres = await batchGetTableList('example_member_count_data,example_member_realtime_visits')
let countData = oneres.example_member_count_data.records[0]
let realtimeVisits = oneres.example_member_realtime_visits.records
tabList.value = tabList.value.map((item) => {
return (item = {
...item,
countUp: countData[item.dictionary]
})
})
realtimeVisits.forEach((ele) => {
visitorXAxis.value?.push(ele.sj)
visitorSeries.value?.push(ele.ssfkl)
})
let endres = await batchGetTableList('example_member_sale,example_member_product_percentage')
let sale = endres.example_member_sale.records
let productPercentage = endres.example_member_product_percentage.records[0]
sale.forEach((ele) => {
salesVolumeXAxis.value?.push(ele.sj)
salesVolumeSeries.value?.push(ele.xse)
})
cyclic_annular_option_data.value = cyclic_annular_option_data.value.map((item) => {
return (item = {
...item,
value: productPercentage[item.dictionary]
})
})
cyclic_annular_option.value.series[0].data = cyclic_annular_option_data.value
cyclic_annular_option.value.title.text = '¥' + productPercentage.je
cyclic_annular_option.value.title.subtext = productPercentage.sj
}
onMounted(async () => {
// 判断是否为暗色模式
const { wsCache } = useCache()
if (wsCache.get(CACHE_KEY.IS_DARK)) {
visitor_option.value.title.textStyle.color = 'white'
salesVolume_option.value.title.textStyle.color = 'white'
}
await init()
})
</script>
<style lang="scss" scoped>
.home-top {
flex-wrap: wrap;
.top-card {
width: calc(25% - 50px);
height: 85px;
padding: 15px;
margin: 0 10px;
margin-top: 0 !important;
border: none;
border-radius: inherit;
flex-shrink: 0;
justify-content: space-around;
box-shadow: 0 0 20px rgb(204 204 204 / 34.9%);
.left {
font-weight: bold;
.text-value {
margin-bottom: 45px;
font-size: 28px;
}
.text {
font-size: 13px;
}
}
}
}
.echart-util {
padding: 20px;
box-shadow: 0 0 20px rgb(204 204 204 / 34.9%);
}
.echart-util.bold {
width: calc(65% - 80px);
}
.echart-util.reverse {
width: calc(35% - 40px);
}
::v-deep(.el-calendar) {
box-shadow: 0 0 20px rgb(204 204 204 / 34.9%);
.el-calendar__header {
font-size: 18px;
font-weight: bold;
border-bottom: none;
}
.el-calendar__body {
th {
font-size: 15px;
font-weight: bold;
}
.el-calendar-table__row {
.is-selected {
background-color: rgb(0 255 255 / 0%);
}
.current,
.next,
.prev {
border: none;
.el-calendar-day {
display: flex;
height: 43px;
font-size: 14px;
font-weight: 700;
justify-content: center;
align-items: center;
}
}
}
td {
// border: none;
}
}
}
</style>