mirror of
https://gitee.com/bootx/dax-pay-ui
synced 2026-08-13 15:55:43 +08:00
feat 驾驶舱
This commit is contained in:
87
src/views/dashboard/analysis/components/CockpitReport.api.ts
Normal file
87
src/views/dashboard/analysis/components/CockpitReport.api.ts
Normal 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
|
||||
}
|
||||
@@ -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>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Card title="成交占比" :loading="loading">
|
||||
<Card title="退款各通道分布" :loading="loading">
|
||||
<div ref="chartRef" :style="{ width, height }"></div>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
@@ -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: '退款情况',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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: '年',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user