220 lines
6.4 KiB
Vue
220 lines
6.4 KiB
Vue
<template>
|
|
<crud-layout title="喜好分析" :bg="filePath(SERVICE_IMAGE.blueBg)">
|
|
<z-paging ref="pageRef" height="100%" :fixed="false" safe-area-inset-bottom :loading-more-enabled="true"
|
|
:show-scrollbar="false" @query="query" :auto-clean-list-when-reload="false"
|
|
:auto-scroll-to-top-when-reload="false" hide-empty-view>
|
|
<tm-sheet :margin="[0, 20]">
|
|
<view class="prefix_title mb-15rpx">菜品分类购买数量占比图</view>
|
|
<view class="w-full h-600rpx">
|
|
<qiun-data-charts type="pie" :opts="pieChartOpts" :chartData="pieChartData"
|
|
tooltipFormat="canteenPieTooltip" />
|
|
</view>
|
|
</tm-sheet>
|
|
|
|
<tm-sheet :margin="[0, 20]">
|
|
<view class="prefix_title mb-15rpx">近一周各食堂购买数量趋势图</view>
|
|
<view class="w-full h-600rpx">
|
|
<!-- tooltipFormat="canteenAreaTooltip" -->
|
|
<qiun-data-charts type="area" :opts="areaChartOpts" :chartData="areaChartData" />
|
|
</view>
|
|
</tm-sheet>
|
|
|
|
<tm-sheet :margin="[0, 20]">
|
|
<view class="prefix_title mb-15rpx">个人菜品喜好排行</view>
|
|
<view v-if="productLikeTopList.length > 0" class="rounded-16rpx bg-white overflow-hidden card">
|
|
<view
|
|
class="bg-gradient-to-r from-blue-100 to-blue-100 px-20rpx py-16rpx flex items-center border-b border-gray-100">
|
|
<view class="w-80rpx text-center text-24rpx font-bold text-gray-600">排名</view>
|
|
<view class="flex-1 px-16rpx text-24rpx font-bold text-gray-600">菜品名称</view>
|
|
<view class="w-120rpx text-center text-24rpx font-bold text-gray-600">分类</view>
|
|
<view class="w-160rpx text-center text-24rpx font-bold text-gray-600">购买数量</view>
|
|
</view>
|
|
|
|
<view v-for="(item, index) in productLikeTopList" :key="item.productId"
|
|
class="flex items-center px-20rpx py-16rpx border-b border-gray-50 hover:bg-gray-50 transition-colors"
|
|
:class="{
|
|
'bg-gradient-to-r from-yellow-50 to-orange-50': index === 0,
|
|
'bg-gradient-to-r from-gray-50 to-gray-100': index === 1,
|
|
'bg-gradient-to-r from-orange-50 to-red-50': index === 2,
|
|
}">
|
|
<view class="w-80rpx flex justify-center items-center">
|
|
<view v-if="Number(index) < 3"
|
|
class="w-40rpx h-40rpx rounded-1 flex items-center justify-center text-20rpx font-bold text-white"
|
|
:class="{
|
|
'bg-gradient-to-r from-yellow-400 to-yellow-500': index === 0,
|
|
'bg-gradient-to-r from-gray-400 to-gray-500': index === 1,
|
|
'bg-gradient-to-r from-orange-400 to-orange-500': index === 2,
|
|
}">
|
|
{{ Number(index) + 1 }}
|
|
</view>
|
|
<view v-else class="text-24rpx font-medium text-gray-500">{{ Number(index) + 1 }}</view>
|
|
</view>
|
|
|
|
<view class="flex-1 px-16rpx">
|
|
<view class="text-26rpx font-medium text-gray-800 truncate">{{ item.productName || "未知菜品" }}
|
|
</view>
|
|
</view>
|
|
|
|
<view class="w-120rpx text-center">
|
|
<view class="text-22rpx text-gray-600 truncate">{{ item.classifyName || "未分类" }}</view>
|
|
</view>
|
|
|
|
<view class="w-160rpx text-center">
|
|
<view
|
|
class="px-12rpx py-6rpx bg-blue-100 text-blue-600 text-22rpx rounded-1 whitespace-nowrap">
|
|
{{ item.payCount }}次</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view v-else class="bg-white rounded-16rpx p-60rpx flex flex-col items-center justify-center">
|
|
<view class="text-28rpx text-gray-500">暂无菜品喜好数据</view>
|
|
</view>
|
|
</tm-sheet>
|
|
|
|
<view class="h-80rpx" />
|
|
</z-paging>
|
|
</crud-layout>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { onLoad } from "@dcloudio/uni-app"
|
|
import { ref } from "vue"
|
|
|
|
import qiunDataCharts from "@/components/qiun-data-charts/qiun-data-charts.vue"
|
|
import { totalApi } from "@/sheep/api"
|
|
import { hooks } from "@/sheep"
|
|
import { SERVICE_IMAGE } from "@@/constant/index"
|
|
import { filePath } from "@@/utils/file"
|
|
|
|
const pieChartData = ref({})
|
|
const areaChartData = ref({})
|
|
const productLikeTopList = ref<any>([])
|
|
const COLORLIST = ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4", "#ea7ccc"]
|
|
|
|
const pieChartOpts = {
|
|
color: COLORLIST,
|
|
padding: [20, 20, 20, 20],
|
|
enableScroll: false,
|
|
legend: {
|
|
float: "center",
|
|
padding: 2,
|
|
margin: 2,
|
|
fontSize: 14,
|
|
lineHeight: 14,
|
|
itemGap: 4,
|
|
},
|
|
extra: {
|
|
pie: {
|
|
activeOpacity: 0.5,
|
|
activeRadius: 10,
|
|
offsetAngle: 0,
|
|
labelWidth: 15,
|
|
border: true,
|
|
borderWidth: 3,
|
|
borderColor: "#FFFFFF",
|
|
linearType: "custom",
|
|
},
|
|
},
|
|
}
|
|
|
|
const areaChartOpts = {
|
|
color: COLORLIST,
|
|
padding: [15, 0, 0, -5],
|
|
enableScroll: false,
|
|
legend: {
|
|
float: "center",
|
|
padding: 10,
|
|
margin: 2,
|
|
fontSize: 12,
|
|
lineHeight: 12,
|
|
itemGap: 4,
|
|
},
|
|
xAxis: {
|
|
disableGrid: true,
|
|
},
|
|
yAxis: {
|
|
gridType: "dash",
|
|
dashLength: 2,
|
|
showTitle: true,
|
|
data: [
|
|
{
|
|
title: "购买数量",
|
|
titleOffsetX: 10,
|
|
titleOffsetY: -6,
|
|
},
|
|
],
|
|
},
|
|
extra: {
|
|
area: {
|
|
type: "curve",
|
|
opacity: 0.6,
|
|
addLine: true,
|
|
width: 2,
|
|
gradient: true,
|
|
activeType: "hollow",
|
|
},
|
|
},
|
|
}
|
|
|
|
onLoad(() => {
|
|
})
|
|
|
|
const pageRef = ref<any>(null)
|
|
const pageHook = hooks.usePage(pageRef, () => [], null, "")
|
|
const query = () => {
|
|
getPieChartData()
|
|
getAreaChartData()
|
|
getProductLikeTop()
|
|
pageHook.startPage()
|
|
}
|
|
|
|
const getPieChartData = async () => {
|
|
const { code, data, msg } = await totalApi.productByClassify({})
|
|
if (code != 0) return uni.showToast({ title: msg || "数据获取失败", icon: "none" })
|
|
const seriesData = data.map((item: any, index: number) => {
|
|
return {
|
|
index,
|
|
name: item.classifyName || "",
|
|
value: Number(item.payCount),
|
|
labelText: `${item.classifyName || ""} ${item.payCount}次`,
|
|
...item,
|
|
}
|
|
})
|
|
|
|
pieChartData.value = {
|
|
series: [
|
|
{
|
|
data: seriesData,
|
|
},
|
|
],
|
|
}
|
|
}
|
|
|
|
const getAreaChartData = async () => {
|
|
const { code, data, msg } = await totalApi.productByCanteen({})
|
|
if (code != 0) return uni.showToast({ title: msg || "数据获取失败", icon: "none" })
|
|
const categories = data[0][Object.keys(data[0])[0]].map((item: any) => item.weekStr.replace("星期", "周"))
|
|
|
|
const series = data.map((item: any) => {
|
|
const name = Object.keys(item)[0]
|
|
const data = item[name].map((item: any) => Number(item.payCount))
|
|
return {
|
|
name: name.replace("食堂", ""),
|
|
data,
|
|
}
|
|
})
|
|
|
|
areaChartData.value = {
|
|
categories,
|
|
series,
|
|
}
|
|
}
|
|
|
|
const getProductLikeTop = async () => {
|
|
const { code, data, msg } = await totalApi.productLikeTop({})
|
|
if (code !== 0) return uni.showToast({ title: msg || "数据获取失败", icon: "none" })
|
|
productLikeTopList.value = data
|
|
}
|
|
</script>
|