统计数据
This commit is contained in:
parent
58d2e40f23
commit
c53155e371
14
src/api/dashboard/dashboardOrder.js
Normal file
14
src/api/dashboard/dashboardOrder.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
* @param {Object} query 查询参数
|
||||
* @returns {Promise} 返回统计数据
|
||||
*/
|
||||
export function getOrderDailyAmount(query) {
|
||||
return request({
|
||||
url: '/dashboard/order/dailyAmount',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
1
src/assets/icons/svg/down.svg
Normal file
1
src/assets/icons/svg/down.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="12" height="12" viewBox="0 0 12 12"><defs><clipPath id="master_svg0_0_7134"><rect x="0" y="12" width="12" height="12" rx="0"/></clipPath></defs><g transform="matrix(1,0,0,-1,0,24)" clip-path="url(#master_svg0_0_7134)"><g><path d="M6.016670023841858,12.2998046875C6.016670023841858,12.2998046875,10.683330023841858,18.3227646875,10.683330023841858,18.3227646875C10.683330023841858,18.3227646875,7.620220023841858,17.6377646875,7.620220023841858,17.6377646875C7.620220023841858,17.6377646875,7.571000023841858,17.6587346875,7.571000023841858,17.6587346875C7.571000023841858,17.6587346875,7.532860023841858,17.9395546875,7.532860023841858,17.9395546875C7.091520023841858,20.761944687499998,5.262260023841858,23.0130046875,2.908160023841858,23.6776046875C3.657010023841858,22.6032046875,3.9502300238418577,22.3181046875,4.222270023841858,20.790864687499997C4.403620023841858,19.7726946875,4.486390023841858,18.7275246875,4.470570023841858,17.6553546875C4.470570023841858,17.6553546875,4.553000023841857,17.6544746875,4.553000023841857,17.6544746875C4.553000023841857,17.6544746875,4.515530023841858,17.6377646875,4.515530023841858,17.6377646875C4.515530023841858,17.6377646875,1.350000023841858,18.3227646875,1.350000023841858,18.3227646875C1.350000023841858,18.3227646875,6.016670023841858,12.2998046875,6.016670023841858,12.2998046875C6.016670023841858,12.2998046875,6.016670023841858,12.2998046875,6.016670023841858,12.2998046875Z" fill-rule="evenodd" fill="#00B42A" fill-opacity="1"/></g></g></svg>
|
After Width: | Height: | Size: 1.6 KiB |
1
src/assets/icons/svg/up.svg
Normal file
1
src/assets/icons/svg/up.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="12" height="12" viewBox="0 0 12 12"><defs><clipPath id="master_svg0_0_7191"><rect x="0" y="0" width="12" height="12" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_0_7191)"><g><path d="M6.016670023841858,0.2998046875C6.016670023841858,0.2998046875,10.683330023841858,6.3227646875,10.683330023841858,6.3227646875C10.683330023841858,6.3227646875,7.620220023841858,5.6377646875,7.620220023841858,5.6377646875C7.620220023841858,5.6377646875,7.571000023841858,5.6587346875,7.571000023841858,5.6587346875C7.571000023841858,5.6587346875,7.532860023841858,5.9395546875,7.532860023841858,5.9395546875C7.091520023841858,8.7619446875,5.262260023841858,11.0130046875,2.908160023841858,11.6776046875C3.657010023841858,10.6032046875,3.9502300238418577,10.3181046875,4.222270023841858,8.7908646875C4.403620023841858,7.7726946875,4.486390023841858,6.7275246875,4.470570023841858,5.6553546875C4.470570023841858,5.6553546875,4.553000023841857,5.6544746875,4.553000023841857,5.6544746875C4.553000023841857,5.6544746875,4.515530023841858,5.6377646875,4.515530023841858,5.6377646875C4.515530023841858,5.6377646875,1.350000023841858,6.3227646875,1.350000023841858,6.3227646875C1.350000023841858,6.3227646875,6.016670023841858,0.2998046875,6.016670023841858,0.2998046875C6.016670023841858,0.2998046875,6.016670023841858,0.2998046875,6.016670023841858,0.2998046875Z" fill-rule="evenodd" fill="#F53F3F" fill-opacity="1"/></g></g></svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -2,9 +2,18 @@
|
|||
<div class="statistics-card" :style="cardStyle">
|
||||
<div class="card-content">
|
||||
<div class="info">
|
||||
<div class="value" :style="valueStyle">{{ value }}</div>
|
||||
<div class="label" :style="labelStyle">{{ label }}</div>
|
||||
<div v-if="subtitle" class="subtitle" :style="subtitleStyle">{{ subtitle }}</div>
|
||||
<div class="label" :style="labelStyle">{{ label | dv}}</div>
|
||||
<div class="value" :style="valueStyle">
|
||||
<count-to :start-val="0" :end-val="value" :duration="3000" :decimals="precision"/>
|
||||
</div>
|
||||
<div v-if="subLabel" class="subtitle" :style="subtitleStyle">
|
||||
<span class="sub-label">{{ subLabel | dv}}</span>
|
||||
<span class="sub-value" :class="{ 'up': subValue >= 0, 'down': subValue < 0 }">
|
||||
<count-to :start-val="0" :end-val="subValue" :duration="3000" :decimals="precision"/>
|
||||
<svg-icon v-if="showValueChange && subValue >= 0" icon-class="up" />
|
||||
<svg-icon v-else-if="showValueChange && subValue < 0" icon-class="down" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="icon-wrapper">
|
||||
<i :class="icon" :style="iconStyle"></i>
|
||||
|
@ -14,20 +23,28 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import CountTo from 'vue-count-to'
|
||||
export default {
|
||||
name: 'StatisticsCard',
|
||||
components: {
|
||||
CountTo
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: [Number, String],
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
subtitle: {
|
||||
subLabel: {
|
||||
type: String,
|
||||
default: ''
|
||||
default: null
|
||||
},
|
||||
subValue: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
|
@ -48,6 +65,16 @@ export default {
|
|||
height: {
|
||||
type: [Number, String],
|
||||
default: 120
|
||||
},
|
||||
// 是否显示值变化
|
||||
showValueChange: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 小数位数
|
||||
precision: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -65,7 +92,7 @@ export default {
|
|||
return {
|
||||
value: Math.max(16, Math.round(28 * scale)),
|
||||
label: Math.max(12, Math.round(16 * scale)),
|
||||
subtitle: Math.max(10, Math.round(12 * scale)),
|
||||
subtitle: Math.max(10, Math.round(14 * scale)),
|
||||
icon: Math.max(32, Math.round(64 * scale))
|
||||
};
|
||||
},
|
||||
|
@ -113,10 +140,10 @@ export default {
|
|||
transition: all 0.3s ease;
|
||||
backdrop-filter: blur(5px);
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px 0 rgba(0,0,0,.15);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
|
@ -144,8 +171,24 @@ export default {
|
|||
}
|
||||
|
||||
.subtitle {
|
||||
color: #909399;
|
||||
opacity: 0.8;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
.sub-label {
|
||||
color: #333;
|
||||
opacity: 0.8;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.sub-value {
|
||||
color: #333;
|
||||
opacity: 0.8;
|
||||
&.up {
|
||||
color: #dc3545;
|
||||
}
|
||||
&.down {
|
||||
color: #198754;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +208,7 @@ export default {
|
|||
&:hover {
|
||||
.icon-wrapper i {
|
||||
opacity: 0.25;
|
||||
transform: scale(1.05) rotate(5deg);
|
||||
transform: scale(1.2) rotate(10deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,16 +196,11 @@ export const StatKeys = {
|
|||
ORDER_USER_COUNT: "order_user_count", // 累计订单用户
|
||||
ORDER_COUNT: "order_count", // 订单数量
|
||||
ORDER_PAY_AMOUNT: "order_pay_amount", // 订单支付金额
|
||||
ORDER_REFUNDED_AMOUNT: "order_refunded_amount", // 订单已退款金额
|
||||
ORDER_REFUNDING_AMOUNT: "order_refunding_amount", // 订单退款中金额
|
||||
ORDER_TODAY_PAY_AMOUNT: "order_today_pay_amount", // 订单今日支付金额
|
||||
ORDER_TODAY_REFUND_AMOUNT: "order_today_refund_amount", // 订单今日退款金额
|
||||
ORDER_TODAY_REFUNDING_AMOUNT: "order_today_refunding_amount", // 订单今日退款中金额
|
||||
ORDER_REFUND_AMOUNT: "order_refund_amount", // 订单退款金额
|
||||
BONUS_COUNT: "bonus_count", // 分成数量
|
||||
BONUS_AMOUNT: "bonus_amount", // 分成总金额
|
||||
BONUS_REFUND_AMOUNT: "bonus_refund_amount", // 分成总退款
|
||||
USER_COUNT: "user_count", // 用户数量
|
||||
USER_TODAY_COUNT: "user_today_count", // 今日新增用户数量
|
||||
USER_BALANCE: "user_balance", // 用户余额
|
||||
DEVICE_COUNT: "device_count", // 设备数量
|
||||
DEVICE_STATUS_COUNT: "device_status_count", // 设备状态数量
|
||||
|
|
102
src/views/bst/index/components/DeviceStat.vue
Normal file
102
src/views/bst/index/components/DeviceStat.vue
Normal file
|
@ -0,0 +1,102 @@
|
|||
<template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-card class="box-card" shadow="never">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="3" v-for="dict in dict.type.device_status" :key="dict.value">
|
||||
<el-statistic
|
||||
class="statistic"
|
||||
group-separator=","
|
||||
:value="stat.device.statusCount[dict.value] || 0"
|
||||
:title="getDeviceStatusLabel(dict.value)"
|
||||
suffix="辆"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon :class="statusMap[dict.value].icon" :style="{ color: statusMap[dict.value].color }" font-size="20px"/>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="3" v-for="status in ['1', '0']" :key="`online-${status}`">
|
||||
<el-statistic
|
||||
class="statistic"
|
||||
group-separator=","
|
||||
:value="stat.device.onlineStatusCount[status] || 0"
|
||||
:title="status == 1 ? '在线' : '离线'"
|
||||
suffix="辆"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon :class="onlineMap[status].icon" :style="{ color: onlineMap[status].color }" font-size="20px"/>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { dictLabel } from '@/utils'
|
||||
import { DeviceStatus } from '@/utils/enums'
|
||||
|
||||
export default {
|
||||
name: 'DeviceStat',
|
||||
dicts: ['device_status'],
|
||||
props: {
|
||||
stat: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statusMap: {
|
||||
[DeviceStatus.STORAGE]: {
|
||||
icon: 'el-icon-box',
|
||||
color: '#13C2C2' // 青色,表示在仓库
|
||||
},
|
||||
[DeviceStatus.AVAILABLE]: {
|
||||
icon: 'el-icon-bicycle',
|
||||
color: '#52C41A' // 绿色,表示可用
|
||||
},
|
||||
[DeviceStatus.RESERVED]: {
|
||||
icon: 'el-icon-timer',
|
||||
color: '#722ED1' // 紫色,表示预约中
|
||||
},
|
||||
[DeviceStatus.IN_USE]: {
|
||||
icon: 'el-icon-user-solid',
|
||||
color: '#73D13D' // 浅绿色,表示使用中
|
||||
},
|
||||
[DeviceStatus.TEMP_LOCKED]: {
|
||||
icon: 'el-icon-lock',
|
||||
color: '#EB2F96' // 粉色,表示锁定
|
||||
},
|
||||
[DeviceStatus.DISPATCHING]: {
|
||||
icon: 'el-icon-position',
|
||||
color: '#FF7A45' // 橙色,表示调度中
|
||||
},
|
||||
[DeviceStatus.DISABLED]: {
|
||||
icon: 'el-icon-warning-outline',
|
||||
color: '#FF4D4F' // 红色,表示禁用
|
||||
}
|
||||
},
|
||||
onlineMap: {
|
||||
'1': {
|
||||
icon: 'el-icon-success',
|
||||
color: '#52C41A' // 绿色,表示在线
|
||||
},
|
||||
'0': {
|
||||
icon: 'el-icon-error',
|
||||
color: '#FF4D4F' // 红色,表示离线
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDeviceStatusLabel(value) {
|
||||
return dictLabel(this.dict.type.device_status, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
35
src/views/bst/index/components/OrderDailyStat.vue
Normal file
35
src/views/bst/index/components/OrderDailyStat.vue
Normal file
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<el-card header="订单统计" shadow="never">
|
||||
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getOrderDailyAmount } from '@/api/dashboard/dashboardOrder'
|
||||
|
||||
export default {
|
||||
name: "OrderDailyStat",
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
orderDailyAmount: [],
|
||||
queryParams: {},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getOrderDailyAmount();
|
||||
},
|
||||
methods: {
|
||||
getOrderDailyAmount() {
|
||||
this.loading = true;
|
||||
getOrderDailyAmount(this.orderQueryParams).then(res => {
|
||||
this.orderDailyAmount = res.data;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
80
src/views/bst/index/components/Stat.vue
Normal file
80
src/views/bst/index/components/Stat.vue
Normal file
|
@ -0,0 +1,80 @@
|
|||
<template>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.order.payAmount - stat.orderRefund.amount"
|
||||
label="订单实收"
|
||||
icon="el-icon-money"
|
||||
start-color="#FF4D4F"
|
||||
end-color="#FF7A45"
|
||||
sub-label="今日订单实收"
|
||||
:sub-value="todayStat.order.payAmount - todayStat.orderRefund.amount"
|
||||
:precision="2"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.device.count"
|
||||
label="车辆总数"
|
||||
icon="el-icon-bicycle"
|
||||
start-color="#52C41A"
|
||||
end-color="#73D13D"
|
||||
sub-label="车型总数"
|
||||
:sub-value="stat.model.count"
|
||||
:show-value-change="false"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.user.count"
|
||||
label="用户总数"
|
||||
icon="el-icon-user"
|
||||
start-color="#722ED1"
|
||||
end-color="#EB2F96"
|
||||
sub-label="今日新增"
|
||||
:sub-value="todayStat.user.count"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.area.count"
|
||||
label="运营区数量"
|
||||
icon="el-icon-location"
|
||||
start-color="#13C2C2"
|
||||
end-color="#52C41A"
|
||||
sub-label="商户余额"
|
||||
:sub-value="stat.user.balance"
|
||||
:show-value-change="false"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import StatisticsCard from '@/components/StatisticsCard'
|
||||
export default {
|
||||
name: 'Stat',
|
||||
components: {
|
||||
StatisticsCard
|
||||
},
|
||||
props: {
|
||||
stat: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
todayStat: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
span: 6
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
101
src/views/bst/index/components/TodoList.vue
Normal file
101
src/views/bst/index/components/TodoList.vue
Normal file
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<el-card class="todo-list" v-loading="loading" shadow="never" header="待办事项">
|
||||
<div class="todo-item" @click="$router.push('/money/withdraw?status=11')">
|
||||
<div class="label"><i class="el-icon-wallet"/> 提现申请</div>
|
||||
<div class="value">
|
||||
<count-to :start-val="0" :end-val="stat.withdrawCount" :duration="3000"/>
|
||||
</div>
|
||||
<div class="unit">条</div>
|
||||
</div>
|
||||
<div class="todo-item" @click="$router.push('/money/withdraw?status=11')">
|
||||
<div class="label"><i class="el-icon-refresh"/> 还车审核</div>
|
||||
<div class="value">
|
||||
<count-to :start-val="0" :end-val="stat.withdrawCount" :duration="3000"/>
|
||||
</div>
|
||||
<div class="unit">条</div>
|
||||
</div>
|
||||
<div class="todo-item" @click="$router.push('/complaint/mchApply?status=0')">
|
||||
<div class="label"><i class="el-icon-office-building"/> 商家加盟</div>
|
||||
<div class="value">
|
||||
<count-to :start-val="0" :end-val="stat.mchApplyCount" :duration="3000"/>
|
||||
</div>
|
||||
<div class="unit">条</div>
|
||||
</div>
|
||||
<div class="todo-item" @click="$router.push('/complaint/abnormal?status=1')">
|
||||
<div class="label"><i class="el-icon-warning-outline"/> 待处理故障信息</div>
|
||||
<div class="value">
|
||||
<count-to :start-val="0" :end-val="stat.abnormalCount" :duration="3000"/>
|
||||
</div>
|
||||
<div class="unit">条</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CountTo from 'vue-count-to'
|
||||
|
||||
export default {
|
||||
name: 'TodoList',
|
||||
components: {
|
||||
CountTo
|
||||
},
|
||||
props: {
|
||||
stat: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.todo-list {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.todo-item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
transition: .25s;
|
||||
padding: 0.55em 1em;
|
||||
cursor: pointer;
|
||||
border-radius: 16px;
|
||||
vertical-align: bottom;
|
||||
background: #fff;
|
||||
.value {
|
||||
display: inline-block;
|
||||
width: fit-content;
|
||||
margin-left: 1em;
|
||||
color: #165DFF;
|
||||
font-size: 20px;
|
||||
}
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #1D252F;
|
||||
flex: 1;
|
||||
i {
|
||||
color: #165DFF;
|
||||
font-size: 20px;
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
}
|
||||
.unit {
|
||||
display: inline-block;
|
||||
margin-left: 0.5em;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.todo-item:hover {
|
||||
background: linear-gradient(180deg, #F2F9FE -3%, #E6F4FE 100%);
|
||||
}
|
||||
.todo-item:nth-child(n + 2) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
|
@ -1,127 +1,32 @@
|
|||
<template>
|
||||
<div class="app-container" style="min-height: 600px;" v-loading="loading">
|
||||
<el-row :gutter="20" v-if="stat">
|
||||
<el-row :gutter="gutter" v-if="stat">
|
||||
<el-col :span="18">
|
||||
<el-row :gutter="10">
|
||||
<!-- 用户相关统计 -->
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.user.balance"
|
||||
label="用户总余额"
|
||||
icon="el-icon-wallet"
|
||||
start-color="#1890FF"
|
||||
end-color="#36CBCB"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.user.count"
|
||||
label="用户总数"
|
||||
icon="el-icon-user"
|
||||
start-color="#722ED1"
|
||||
end-color="#EB2F96"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.user.todayCount"
|
||||
label="今日新增用户"
|
||||
icon="el-icon-user-plus"
|
||||
start-color="#FA541C"
|
||||
end-color="#FAAD14"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.area.count"
|
||||
label="运营区数量"
|
||||
icon="el-icon-location"
|
||||
start-color="#13C2C2"
|
||||
end-color="#52C41A"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="10" style="margin-top: 10px;">
|
||||
<!-- 订单相关统计 -->
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="formatAmount(stat.order.payAmount - (stat.order.refundingAmount) - (stat.order.refundedAmount))"
|
||||
label="订单总收入"
|
||||
icon="el-icon-money"
|
||||
start-color="#FF4D4F"
|
||||
end-color="#FF7A45"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="formatAmount(stat.order.todayPayAmount - (stat.order.todayRefundingAmount) - (stat.order.todayRefundedAmount))"
|
||||
label="今日订单收入"
|
||||
icon="el-icon-date"
|
||||
start-color="#2F54EB"
|
||||
end-color="#597EF7"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.device.count"
|
||||
label="车辆总数"
|
||||
icon="el-icon-bicycle"
|
||||
start-color="#52C41A"
|
||||
end-color="#73D13D"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="span">
|
||||
<statistics-card
|
||||
:value="stat.model.count"
|
||||
label="车型总数"
|
||||
icon="el-icon-menu"
|
||||
start-color="#722ED1"
|
||||
end-color="#85A5FF"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 车辆状态统计 -->
|
||||
<el-row :gutter="20" style="margin-top: 20px;">
|
||||
<el-col :span="24">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>车辆状态统计</span>
|
||||
</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="4" v-for="status in deviceStatusList" :key="status">
|
||||
<div class="status-item">
|
||||
<div class="status-count">{{ stat.device.statusCount[status] || 0 }}</div>
|
||||
<div class="status-label">{{ getDeviceStatusLabel(status) }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 统计信息 -->
|
||||
<stat :stat="stat" :today-stat="todayStat" />
|
||||
|
||||
<!-- 设备统计信息 -->
|
||||
<device-stat :stat="stat" style="margin-top: 12px;"/>
|
||||
|
||||
<!-- 车辆在线状态统计 -->
|
||||
<el-row :gutter="20" style="margin-top: 20px;">
|
||||
<el-col :span="24">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>车辆在线状态统计</span>
|
||||
</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12" v-for="status in ['1', '0']" :key="status">
|
||||
<div class="status-item">
|
||||
<div class="status-count">{{ stat.device.onlineStatusCount[status] || 0 }}</div>
|
||||
<div class="status-label">{{ status === '1' ? '在线' : '离线' }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="gutter" style="margin-top:12px">
|
||||
<el-col :span="16">
|
||||
<order-daily-stat/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card header="提现" shadow="never">
|
||||
待实现
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="6">
|
||||
<!-- 待办事项 -->
|
||||
<todo-list :stat="stat"/>
|
||||
|
||||
<el-card style="margin-top: 12px;" header="订单排行" shadow="never">
|
||||
待实现
|
||||
</el-card>
|
||||
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
@ -132,42 +37,36 @@
|
|||
<script>
|
||||
import { getStat } from '@/api/dashboard/dashboard'
|
||||
import { StatKeys } from '@/utils/enums'
|
||||
import { DeviceStatus } from '@/utils/enums'
|
||||
import StatisticsCard from '@/components/StatisticsCard'
|
||||
import Stat from '@/views/bst/index/components/Stat'
|
||||
import DeviceStat from '@/views/bst/index/components/DeviceStat'
|
||||
import TodoList from '@/views/bst/index/components/TodoList'
|
||||
import { getLastDateStr } from '@/utils'
|
||||
import OrderDailyStat from './components/OrderDailyStat.vue'
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
StatisticsCard
|
||||
Stat,
|
||||
DeviceStat,
|
||||
TodoList,
|
||||
OrderDailyStat,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
span: 6,
|
||||
gutter: 12,
|
||||
loading: false,
|
||||
stat: null,
|
||||
deviceStatusList: [
|
||||
DeviceStatus.STORAGE, // 仓库中
|
||||
DeviceStatus.AVAILABLE, // 待骑行
|
||||
DeviceStatus.RESERVED, // 预约中
|
||||
DeviceStatus.IN_USE, // 骑行中
|
||||
DeviceStatus.TEMP_LOCKED, // 临时锁车
|
||||
DeviceStatus.DISPATCHING, // 调度中
|
||||
DeviceStatus.DISABLED // 禁用
|
||||
],
|
||||
todayStat: null,
|
||||
queryParams: {
|
||||
keys: [
|
||||
StatKeys.ORDER_COUNT,
|
||||
StatKeys.ORDER_PAY_AMOUNT,
|
||||
StatKeys.ORDER_REFUNDED_AMOUNT,
|
||||
StatKeys.ORDER_REFUNDING_AMOUNT,
|
||||
StatKeys.ORDER_TODAY_PAY_AMOUNT,
|
||||
StatKeys.ORDER_TODAY_REFUND_AMOUNT,
|
||||
StatKeys.ORDER_TODAY_REFUNDING_AMOUNT,
|
||||
StatKeys.ORDER_REFUND_AMOUNT,
|
||||
StatKeys.BONUS_COUNT,
|
||||
StatKeys.BONUS_AMOUNT,
|
||||
StatKeys.BONUS_REFUND_AMOUNT,
|
||||
StatKeys.USER_COUNT,
|
||||
StatKeys.USER_TODAY_COUNT,
|
||||
StatKeys.USER_BALANCE,
|
||||
StatKeys.DEVICE_COUNT,
|
||||
StatKeys.DEVICE_STATUS_COUNT,
|
||||
|
@ -179,7 +78,8 @@ export default {
|
|||
}
|
||||
},
|
||||
created() {
|
||||
this.getStat()
|
||||
this.getStat();
|
||||
this.getTodayStat();
|
||||
},
|
||||
methods: {
|
||||
getStat() {
|
||||
|
@ -190,52 +90,21 @@ export default {
|
|||
this.loading = false;
|
||||
})
|
||||
},
|
||||
formatAmount(amount) {
|
||||
return Number(amount).toFixed(2)
|
||||
},
|
||||
getDeviceStatusLabel(status) {
|
||||
const statusMap = {
|
||||
[DeviceStatus.STORAGE]: '仓库中',
|
||||
[DeviceStatus.AVAILABLE]: '待骑行',
|
||||
[DeviceStatus.RESERVED]: '预约中',
|
||||
[DeviceStatus.IN_USE]: '骑行中',
|
||||
[DeviceStatus.TEMP_LOCKED]: '临时锁车',
|
||||
[DeviceStatus.DISPATCHING]: '调度中',
|
||||
[DeviceStatus.DISABLED]: '禁用'
|
||||
}
|
||||
return statusMap[status] || '未知状态'
|
||||
getTodayStat() {
|
||||
getStat({
|
||||
keys:[
|
||||
StatKeys.USER_COUNT,
|
||||
StatKeys.ORDER_PAY_AMOUNT,
|
||||
StatKeys.ORDER_REFUND_AMOUNT,
|
||||
],
|
||||
dateRange: [
|
||||
getLastDateStr(0),
|
||||
getLastDateStr(0)
|
||||
]
|
||||
}).then(res => {
|
||||
this.todayStat = res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-row {
|
||||
margin-bottom: 20px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.box-card {
|
||||
.status-item {
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.status-count {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user