feat 驾驶舱

This commit is contained in:
xxm1995
2024-03-18 00:09:57 +08:00
parent a62f930de5
commit bf5642cdef
8 changed files with 225 additions and 93 deletions

View File

@@ -0,0 +1,87 @@
import { defHttp } from '/@/utils/http/axios'
import { Result } from '/#/axios'
/**
* 支付金额
*/
export function getPayAmount(params: CockpitReportQuery) {
return defHttp.get<Result<number>>({
url: '/report/cockpit//getPayAmount',
method: 'post',
params: params,
})
}
/**
* 退款金额
*/
export function getRefundAmount(params: CockpitReportQuery) {
return defHttp.get<Result<number>>({
url: '/report/cockpit/getRefundAmount',
method: 'post',
params: params,
})
}
/**
* 退款金额
*/
export function getPayOrderCount(params: CockpitReportQuery) {
return defHttp.get<Result<number>>({
url: '/report/cockpit/getPayOrderCount',
method: 'post',
params: params,
})
}
/**
* 退款金额
*/
export function getRefundOrderCount(params: CockpitReportQuery) {
return defHttp.get<Result<number>>({
url: '/report/cockpit/getRefundOrderCount',
method: 'post',
params: params,
})
}
/**
* 退款金额
*/
export function getPayChannelInfo(params: CockpitReportQuery) {
return defHttp.get<Result<ChannelLineReport[]>>({
url: '/report/cockpit/getPayChannelInfo',
method: 'post',
params: params,
})
}
/**
* 退款金额
*/
export function getRefundChannelInfo(params: CockpitReportQuery) {
return defHttp.get<Result<ChannelLineReport[]>>({
url: '/report/cockpit/getRefundChannelInfo',
method: 'post',
params: params,
})
}
/**
* 支付通道折线图报表
*/
export interface ChannelLineReport {
// 支付通道编码
channelCode: string
// 支付通道名称
channelName: string
// 订单金额
orderAmount: number
// 订单数量
orderCount: number
}
/**
* 查询条件
*/
export interface CockpitReportQuery {
// 开始时间
startTime: string
// 结束时间
endTime: string
}

View File

@@ -1,6 +1,6 @@
<template>
<div class="md:flex">
<template v-for="(item, index) in growCardList" :key="item.title">
<template v-for="(item, index) in data" :key="item.title">
<Card
size="small"
:loading="loading"
@@ -8,32 +8,29 @@
class="md:w-1/4 w-full !md:mt-0"
:class="{ '!md:mr-4': index + 1 < 4, '!mt-4': index > 0 }"
>
<template #extra>
<Tag :color="item.color">{{ item.action }}</Tag>
<template v-if="item.action" #extra>
<Tag>{{ item.action }}</Tag>
</template>
<div class="py-4 px-4 flex justify-between items-center">
<CountTo prefix="$" :startVal="1" :endVal="item.value" class="text-2xl" />
<CountTo :startVal="0" :decimals="item.decimals" :endVal="item.value" class="text-2xl" />
<Icon :icon="item.icon" :size="40" />
</div>
<div class="p-2 px-4 flex justify-between">
<span>{{ item.title }}</span>
<CountTo prefix="$" :startVal="1" :endVal="item.total" />
</div>
</Card>
</template>
</div>
</template>
<script lang="ts" setup>
import { CountTo } from '/@/components/CountTo/index'
import { Icon } from '/@/components/Icon'
import { CountTo } from '/@/components/CountTo'
import { Tag, Card } from 'ant-design-vue'
import { growCardList } from '../data'
import Icon from '/@/components/Icon/src/Icon.vue'
import { OrderCountData } from '/@/views/dashboard/analysis/data'
defineProps({
loading: {
type: Boolean,
},
data: {
type: Array<OrderCountData>,
},
})
</script>

View File

@@ -1,5 +1,5 @@
<template>
<Card title="成交占比" :loading="loading">
<Card title="退款各通道分布" :loading="loading">
<div ref="chartRef" :style="{ width, height }"></div>
</Card>
</template>

View File

@@ -1,10 +1,10 @@
<template>
<Card :tab-list="tabListTitle" v-bind="$attrs" :active-tab-key="activeKey" @tab-change="onTabChange">
<p v-if="activeKey === 'tab1'">
<p v-if="activeKey === 't1'">
<VisitAnalysis />
</p>
<p v-if="activeKey === 'tab2'">
<VisitAnalysisBar />
<p v-if="activeKey === 't2'">
<VisitAnalysis />
</p>
</Card>
</template>
@@ -12,18 +12,17 @@
import { ref } from 'vue'
import { Card } from 'ant-design-vue'
import VisitAnalysis from './VisitAnalysis.vue'
import VisitAnalysisBar from './VisitAnalysisBar.vue'
const activeKey = ref('tab1')
const activeKey = ref('t1')
const tabListTitle = [
{
key: 'tab1',
tab: '流量趋势',
key: 't1',
tab: '支付情况',
},
{
key: 'tab2',
tab: '访问量',
key: 't2',
tab: '退款情况',
},
]

View File

@@ -1,6 +1,6 @@
<template>
<Card title="访问来源" :loading="loading">
<div ref="chartRef" :style="{ width, height }"></div>
<Card title="支付各通道分布" :loading="loading">
<div ref="chartRef" :style="{ width: '100%', height: '300px' }"></div>
</Card>
</template>
<script lang="ts" setup>
@@ -9,24 +9,16 @@
import { useECharts } from '/@/hooks/web/useECharts'
const props = defineProps({
loading: Boolean,
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: '300px',
data: {
type: Array,
},
})
const chartRef = ref<HTMLDivElement | null>(null)
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
watch(
() => props.loading,
() => props.data,
() => {
if (props.loading) {
return
}
setOptions({
tooltip: {
trigger: 'item',
@@ -37,8 +29,7 @@
},
series: [
{
color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
name: '访问来源',
name: '支付通道',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
@@ -61,12 +52,7 @@
labelLine: {
show: false,
},
data: [
{ value: 1048, name: '搜索引擎' },
{ value: 735, name: '直接访问' },
{ value: 580, name: '邮件营销' },
{ value: 484, name: '联盟广告' },
],
data: props.data as any,
animationType: 'scale',
animationEasing: 'exponentialInOut',
animationDelay: function () {

View File

@@ -1,43 +1,10 @@
export interface GrowCardItem {
icon: string
/**
* 订单数量信息
*/
export interface OrderCountData {
title: string
value: number
total: number
color: string
action: string
icon: string
value: number
decimals: number
}
export const growCardList: GrowCardItem[] = [
{
title: '访问数',
icon: 'visit-count|svg',
value: 2000,
total: 120000,
color: 'green',
action: '月',
},
{
title: '成交额',
icon: 'total-sales|svg',
value: 20000,
total: 500000,
color: 'blue',
action: '月',
},
{
title: '下载数',
icon: 'download-count|svg',
value: 8000,
total: 120000,
color: 'orange',
action: '周',
},
{
title: '成交数',
icon: 'transaction|svg',
value: 5000,
total: 50000,
color: 'purple',
action: '年',
},
]

View File

@@ -1,16 +1,112 @@
<template>
<div class="p-4">
<a-card :bordered="false" :loading="loading">
<h1>欢迎使用后台管理系统</h1>
</a-card>
<!-- 订单数 -->
<OrderCount :loading="loading" :data="orderListData" class="enter-y" />
<!-- 占比图 -->
<div class="md:flex !my-4 enter-y">
<!-- 支付 -->
<VisitSource class="md:w-1/2 !md:my-0 !my-4 w-full" :loading="loading" :data="payChannelLine" />
<!-- 退款 -->
<SalesProductPie class="md:w-1/2 !md:mx-4 w-full" :loading="loading" />
</div>
<!-- 订单 -->
<SiteAnalysis class="!my-4 enter-y" :loading="loading" />
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { computed, onMounted, ref } from 'vue'
import OrderCount from './components/OrderCount.vue'
import SiteAnalysis from './components/SiteAnalysis.vue'
import VisitSource from './components/VisitSource.vue'
import SalesProductPie from './components/SalesProductPie.vue'
import dayjs, { OpUnitType } from 'dayjs'
import {
CockpitReportQuery,
getPayAmount,
getPayChannelInfo,
getPayOrderCount,
getRefundAmount,
getRefundOrderCount,
} from '/@/views/dashboard/analysis/components/CockpitReport.api'
import { $ref } from 'vue/macros'
const loading = ref(true)
const loading = ref(false)
setTimeout(() => {
loading.value = false
}, 1500)
let param = $ref<CockpitReportQuery>({ startTime: '', endTime: '' })
/**
* 初始化
*/
onMounted(() => {
initTime()
initOrderCount()
initPayChannelInfo()
})
/**
* 初始化时间
*/
function initTime() {
const now = dayjs()
param.startTime = now.startOf('day').format('YYYY-MM-DD HH:mm:ss')
param.endTime = now.endOf('day').format('YYYY-MM-DD HH:mm:ss')
}
// 订单数量信息
let payAmount = $ref<number>(0)
let refundAmount = $ref<number>(0)
let payCount = $ref<number>(0)
let refundCount = $ref<number>(0)
const orderListData = computed(() => [
{
title: '支付金额',
value: payAmount,
icon: 'total-sales|svg',
action: '单位(元)',
decimals: 2,
},
{
title: '支付订单数',
value: refundAmount,
icon: 'transaction|svg',
action: '',
decimals: 0,
},
{
title: '退款金额',
value: payCount,
icon: 'total-sales|svg',
action: '单位(元)',
decimals: 2,
},
{
title: '退款订单数',
value: refundCount,
icon: 'transaction|svg',
action: '',
decimals: 0,
},
])
/**
* 初始化订单信息
*/
function initOrderCount() {
getPayAmount(param).then(({ data }) => (payAmount = data / 10.0))
getRefundAmount(param).then(({ data }) => (refundAmount = data))
getPayOrderCount(param).then(({ data }) => (payCount = data / 10.0))
getRefundOrderCount(param).then(({ data }) => (refundCount = data))
}
let payChannelLine = $ref<any>()
/**
* 初始化退款订单
*/
function initPayChannelInfo() {
getPayChannelInfo(param).then(({ data }) => {
payChannelLine = data.map((o) => {
return { name: o.channelName, value: o.orderAmount }
})
})
}
</script>

View File

@@ -5,7 +5,7 @@ import { BaseEntity } from '/#/web'
/**
* 重新发送消息通知
*/
export function resetSendNotice(taskId){
export function resetSendNotice(taskId) {
return defHttp.post<Result>({
url: '/task/notice/resetSend',
method: 'post',