数据统计

This commit is contained in:
磷叶 2025-04-08 16:18:38 +08:00
parent 06f22f5674
commit 41d5eb5297
19 changed files with 851 additions and 248 deletions

View File

@ -42,3 +42,12 @@ export function delArea(id) {
method: 'delete'
})
}
// 查询运营区简单数据列表
export function listSimpleArea(query) {
return request({
url: '/bst/area/simpleList',
method: 'get',
params: query
})
}

View File

@ -12,3 +12,16 @@ export function getOrderDailyAmount(query) {
params: query
})
}
/**
* 获取订单排行榜数据
* @param {Object} query 查询参数
* @returns {Promise} 返回排行榜数据
*/
export function getOrderRank(query) {
return request({
url: '/dashboard/order/rank',
method: 'get',
params: query
})
}

View File

@ -9,6 +9,8 @@
@visible-change="handleVisibleChange"
remote
:remote-method="remoteMethod"
:clearable="clearable"
:size="size"
>
<div class="select-header">
<div>

View File

@ -48,12 +48,22 @@ export const $remoteSelect = {
// 空数据文本
emptyText: {
type: String,
default: '暂无数据'
default: '请选择'
},
// 获取选项前回调
beforeGetOptions: {
type: Function,
default: () => {return true;}
},
// 是否可清空
clearable: {
type: Boolean,
default: false
},
// 尺寸
size: {
type: String,
default: null
}
},
}

View File

@ -8,6 +8,8 @@
:multiple="multiple"
:init-options="initOptions"
v-on="$listeners"
:clearable="clearable"
:size="size"
/>
</template>

View File

@ -17,7 +17,7 @@ import store from './store';
import { getConfigKey } from '@/api/system/config';
import { getDicts } from '@/api/system/dict/data';
import { checkPermi, checkRole, isSysAdmin } from '@/utils/permission';
import { checkPermi, checkRole, isAgent, isSysAdmin } from '@/utils/permission';
import { addDateRange, handleTree, parseTime, resetForm, selectDictLabel, selectDictLabels } from '@/utils/ruoyi';
import './assets/icons'; // icon
import './permission'; // permission control
@ -59,6 +59,7 @@ Vue.prototype.handleTree = handleTree
Vue.prototype.checkPermi = checkPermi
Vue.prototype.checkRole = checkRole
Vue.prototype.isSysAdmin = isSysAdmin
Vue.prototype.isAgent = isAgent
// 全局组件挂载
Vue.component('DictTag', DictTag)

View File

@ -197,16 +197,29 @@ export const StatKeys = {
ORDER_COUNT: "order_count", // 订单数量
ORDER_PAY_AMOUNT: "order_pay_amount", // 订单支付金额
ORDER_REFUND_AMOUNT: "order_refund_amount", // 订单退款金额
BONUS_COUNT: "bonus_count", // 分成数量
BONUS_AMOUNT: "bonus_amount", // 分成总金额
BONUS_REFUND_AMOUNT: "bonus_refund_amount", // 分成总退款
BONUS_WAIT_DIVIDE_AMOUNT: "bonus_wait_divide_amount", // 分成未入账金额
USER_COUNT: "user_count", // 用户数量
USER_TODAY_COUNT: "user_today_count", // 今日新增用户数量
USER_BALANCE: "user_balance", // 用户余额
USER_MCH_COUNT: "user_mch_count", // 运营商数量
USER_AGENT_COUNT: "user_agent_count", // 代理商数量
DEVICE_COUNT: "device_count", // 设备数量
DEVICE_STATUS_COUNT: "device_status_count", // 设备状态数量
DEVICE_ONLINE_STATUS_COUNT: "device_online_status_count", // 设备在线状态数量
AREA_COUNT: "area_count", // 运营区数量
MODEL_COUNT: "model_count", // 型号数量
AREA_JOIN_COUNT: "area_join_count", // 加盟商数量
AREA_JOIN_PARTNER_COUNT: "area_join_partner_count", // 合伙人数量
WITHDRAW_SUCCESS_AMOUNT: "withdraw_success_amount", // 成功提现金额
}
// 收款账户类型

View File

@ -52,3 +52,10 @@ export function checkRole(value) {
export function isSysAdmin() {
return checkRole(['sysAdmin'])
}
/**
* 是否代理商
*/
export function isAgent() {
return checkRole(['agent'])
}

View File

@ -11,7 +11,7 @@
<el-button size="mini" icon="el-icon-full-screen" @click="setFitView">全局查看</el-button>
<el-button size="mini" icon="el-icon-picture" @click="toggleMapStyle">切换样式</el-button>
<el-button size="mini" icon="el-icon-document" @click="toggleLabels">{{ showLabels ? '隐藏' : '显示' }}文字</el-button>
<el-button size="mini" icon="el-icon-video-play" @click="togglePlaybackPanel">{{ isPlaybackVisible ? '隐藏' : '显示' }}轨迹控制台</el-button>
<el-button size="mini" icon="el-icon-video-play" v-if="locationLogList && locationLogList.length > 0" @click="togglePlaybackPanel">{{ isPlaybackVisible ? '隐藏' : '显示' }}轨迹控制台</el-button>
</el-button-group>
</div>

View File

@ -94,6 +94,11 @@ export default {
methods: {
//
getArea() {
if (!this.areaId) {
this.area = {};
this.areaSubList = [];
return;
}
getArea(this.areaId).then(res => {
this.area = res.data;
this.getAreaSubList();

View File

@ -0,0 +1,115 @@
<template>
<div class="app-container" style="min-height: 600px;" v-loading="loading">
<el-row :gutter="gutter" v-if="stat">
<el-col :span="18">
<!-- 统计信息 -->
<admin-stat :stat="stat" :today-stat="todayStat" />
<!-- 设备统计信息 -->
<device-stat :stat="stat"/>
<el-row :gutter="gutter" style="margin-top:12px">
<el-col :span="24">
<order-daily-stat/>
</el-col>
</el-row>
</el-col>
<el-col :span="6">
<!-- 待办事项 -->
<todo-list :stat="stat"/>
<order-rank style="margin-top: 12px;"/>
</el-col>
</el-row>
</div>
</template>
<script>
import { getStat } from '@/api/dashboard/dashboard'
import { StatKeys } from '@/utils/enums'
import AdminStat from '@/views/bst/index/components/AdminStat'
import DeviceStat from '@/views/bst/index/components/DeviceStat'
import TodoList from '@/views/bst/index/components/TodoList'
import { getLastDateStr } from '@/utils'
import OrderDailyStat from '@/views/bst/index/components/OrderDailyStat'
import OrderRank from '@/views/bst/index/components/OrderRank'
export default {
name: 'AdminIndex',
components: {
AdminStat,
DeviceStat,
TodoList,
OrderDailyStat,
OrderRank,
},
data() {
return {
span: 6,
gutter: 12,
loading: false,
stat: null,
todayStat: null,
userInfo: null,
userName: null,
}
},
created() {
this.getStat();
this.getTodayStat();
},
methods: {
getStat() {
this.loading = true;
getStat({
keys: [
StatKeys.ORDER_COUNT,
StatKeys.ORDER_PAY_AMOUNT,
StatKeys.ORDER_REFUND_AMOUNT,
StatKeys.DEVICE_COUNT,
StatKeys.DEVICE_STATUS_COUNT,
StatKeys.DEVICE_ONLINE_STATUS_COUNT,
StatKeys.AREA_COUNT,
StatKeys.AREA_JOIN_COUNT,
StatKeys.AREA_JOIN_PARTNER_COUNT,
StatKeys.USER_COUNT,
StatKeys.USER_BALANCE,
StatKeys.USER_MCH_COUNT,
StatKeys.USER_AGENT_COUNT,
StatKeys.MODEL_COUNT,
StatKeys.WITHDRAW_SUCCESS_AMOUNT,
]
}).then(res => {
this.stat = res.data
}).finally(() => {
this.loading = false;
})
},
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 scoped lang="scss">
.title-1 {
font-size: 18px;
margin-bottom: 8px;
color: #409EFF;
}
</style>

View File

@ -0,0 +1,152 @@
<template>
<div class="app-container" style="min-height: 600px;" v-loading="loading">
<el-row :gutter="gutter" v-if="stat">
<el-col :span="18">
<div class="title-1">
<i class="el-icon-s-data"></i>
运营统计
<el-select v-model="areaId" @change="onChangeArea" placeholder="请选择运营区">
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</div>
<!-- 统计信息 -->
<mch-stat :stat="stat" :today-stat="todayStat" />
<!-- 设备统计信息 -->
<device-stat :stat="stat"/>
<el-row :gutter="gutter" style="margin-top:12px">
<el-col :span="24">
<order-daily-stat/>
</el-col>
</el-row>
</el-col>
<el-col :span="6">
<div class="title-1">
<i class="el-icon-user"></i>
我的
</div>
<balance-panel v-if="userInfo" :balance="userInfo.balance" :waitBonus="userStat.bonus.waitAmount" :totalWithdraw="userStat.withdraw.successAmount"/>
<!-- 待办事项 -->
<todo-list :stat="stat"/>
</el-col>
</el-row>
</div>
</template>
<script>
import { getStat } from '@/api/dashboard/dashboard'
import { StatKeys } from '@/utils/enums'
import MchStat from '@/views/bst/index/components/MchStat'
import DeviceStat from '@/views/bst/index/components/DeviceStat'
import TodoList from '@/views/bst/index/components/TodoList'
import { getLastDateStr } from '@/utils'
import OrderDailyStat from '@/views/bst/index/components/OrderDailyStat'
import { getInfo } from '@/api/login'
import { listSimpleArea } from '@/api/bst/area'
import BalancePanel from '@/views/bst/index/components/BalancePanel'
export default {
name: 'Index',
components: {
MchStat,
DeviceStat,
TodoList,
OrderDailyStat,
BalancePanel,
},
data() {
return {
span: 6,
gutter: 12,
loading: false,
stat: null,
todayStat: null,
userInfo: null,
areaId: null,
areaList: [],
}
},
created() {
this.getUserInfo();
this.getAreaList();
},
methods: {
getAreaList() {
listSimpleArea().then(res => {
this.areaList = res.data;
if (this.areaList.length > 0) {
this.areaId = this.areaList[0].id;
this.onChangeArea();
}
})
},
onChangeArea() {
this.getStat();
this.getTodayStat();
},
getUserInfo() {
getInfo().then(res => {
this.userInfo = res.user;
this.userStat = res.stat;
})
},
//
getStat() {
this.loading = true;
getStat({
areaId: this.areaId,
keys: [
StatKeys.ORDER_COUNT,
StatKeys.ORDER_PAY_AMOUNT,
StatKeys.ORDER_REFUND_AMOUNT,
StatKeys.BONUS_AMOUNT,
StatKeys.BONUS_REFUND_AMOUNT,
StatKeys.DEVICE_COUNT,
StatKeys.DEVICE_STATUS_COUNT,
StatKeys.DEVICE_ONLINE_STATUS_COUNT,
StatKeys.AREA_JOIN_COUNT,
StatKeys.AREA_JOIN_PARTNER_COUNT,
]
}).then(res => {
this.stat = res.data
}).finally(() => {
this.loading = false;
})
},
//
getTodayStat() {
getStat({
areaId: this.areaId,
keys:[
StatKeys.ORDER_COUNT,
StatKeys.ORDER_PAY_AMOUNT,
StatKeys.ORDER_REFUND_AMOUNT,
StatKeys.BONUS_AMOUNT,
StatKeys.BONUS_REFUND_AMOUNT,
StatKeys.DEVICE_COUNT,
],
dateRange: [
getLastDateStr(0),
getLastDateStr(0)
]
}).then(res => {
this.todayStat = res.data
})
}
}
}
</script>
<style scoped lang="scss">
.title-1 {
font-size: 18px;
margin-bottom: 8px;
color: #409EFF;
line-height: 36px;
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<div class="stat-container">
<statistics-card
class="stat-card"
:value="stat.order.payAmount - stat.orderRefund.amount"
label="订单实收"
icon="el-icon-money"
start-color="#1890FF"
end-color="#69C0FF"
sub-label="今日订单实收"
:sub-value="todayStat.order.payAmount - todayStat.orderRefund.amount"
:precision="2"
/>
<statistics-card
class="stat-card"
:value="stat.order.count"
label="订单数量"
icon="el-icon-tickets"
start-color="#52C41A"
end-color="#95DE64"
sub-label="今日订单数量"
:sub-value="todayStat.order.count"
/>
<statistics-card
class="stat-card"
:value="stat.device.count"
label="车辆总数"
icon="el-icon-bicycle"
start-color="#722ED1"
end-color="#B37FEB"
sub-label="车型总数"
:sub-value="stat.model.count"
:show-value-change="false"
/>
<statistics-card
class="stat-card"
:value="stat.area.count"
label="运营区"
icon="el-icon-map-location"
start-color="#13C2C2"
end-color="#5CDBD3"
sub-label="店铺数量"
:sub-value="0"
:show-value-change="false"
/>
<statistics-card
class="stat-card"
:value="stat.areaJoin.joinCount"
label="加盟商"
icon="el-icon-office-building"
start-color="#FA8C16"
end-color="#FFC069"
sub-label="合伙人"
:sub-value="stat.areaJoin.partnerCount"
:show-value-change="false"
/>
<statistics-card
class="stat-card"
:value="stat.user.count"
label="用户总数"
icon="el-icon-user-solid"
start-color="#EB2F96"
end-color="#FF85C0"
sub-label="今日新增"
:sub-value="todayStat.user.count"
/>
<statistics-card
class="stat-card"
:value="stat.user.mchCount"
label="运营商"
icon="el-icon-s-custom"
start-color="#2F54EB"
end-color="#85A5FF"
sub-label="代理商"
:sub-value="stat.user.agentCount"
:show-value-change="false"
/>
<statistics-card
class="stat-card"
:value="stat.user.balance"
label="用户余额"
icon="el-icon-wallet"
start-color="#F5222D"
end-color="#FF7875"
sub-label="累计提现"
:sub-value="stat.withdraw.successAmount"
:show-value-change="false"
:precision="2"
/>
</div>
</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: 4
}
},
}
</script>
<style lang="scss" scoped>
.stat-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 10px;
.stat-card {
flex: 0 1 calc(25% - 10px);
}
}
</style>

View File

@ -0,0 +1,219 @@
<template>
<el-card class="balance-panel" shadow="never">
<div class="panel-content">
<!-- 主要数据区域 -->
<div class="main-data">
<div class="balance-item">
<div class="item-icon" style="background: linear-gradient(135deg, #36a3f7, #5b8def);">
<i class="el-icon-money"></i>
</div>
<div class="item-info">
<div class="item-label">当前余额</div>
<div class="item-value">{{balance | fix2 | dv}}</div>
</div>
</div>
<div class="balance-item">
<div class="item-icon" style="background: linear-gradient(135deg, #f6ab4f, #ffbc58);">
<i class="el-icon-time"></i>
</div>
<div class="item-info">
<div class="item-label">未入账</div>
<div class="item-value">{{waitBonus | fix2 | dv}}</div>
</div>
</div>
</div>
<!-- 次要数据区域 -->
<div class="secondary-data">
<div class="withdraw-item">
<div class="item-label">累计提现</div>
<div class="item-value">{{totalWithdraw | fix2 | dv}}</div>
</div>
</div>
<!-- 提现按钮区域 -->
<div class="withdraw-btn-area">
<el-button type="primary" icon="el-icon-wallet" @click="handleWithdraw">申请提现</el-button>
</div>
</div>
<!-- 提现弹窗 -->
<withdraw-add-dialog
:visible.sync="withdrawDialogVisible"
@success="$emit('refresh')"
/>
</el-card>
</template>
<script>
import WithdrawAddDialog from "@/views/bst/withdraw/components/WithdrawAddDialog.vue";
export default {
name: 'BalancePanel',
components: {
WithdrawAddDialog
},
props: {
//
balance: {
type: Number,
default: 0
},
//
waitBonus: {
type: Number,
default: 0
},
//
totalWithdraw: {
type: Number,
default: 0
},
},
data() {
return {
withdrawDialogVisible: false
}
},
methods: {
//
handleWithdraw() {
this.withdrawDialogVisible = true;
}
}
}
</script>
<style lang="scss" scoped>
.balance-panel {
margin-bottom: 12px;
.panel-content {
padding-top: 10px;
.main-data {
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
.balance-item {
width: 50%;
padding-right: 10px;
display: flex;
align-items: center;
margin-bottom: 10px;
transition: all 0.3s;
&:last-child {
padding-right: 0;
}
.item-icon {
width: 52px;
height: 52px;
border-radius: 14px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 12px;
transition: all 0.3s;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1);
i {
font-size: 26px;
color: white;
transition: all 0.3s;
}
}
.item-info {
flex: 1;
.item-label {
font-size: 15px;
color: #606266;
margin-bottom: 6px;
}
.item-value {
font-size: 22px;
font-weight: 600;
color: #303133;
background: linear-gradient(135deg, #333, #666);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
}
.secondary-data {
border-top: 1px dashed #eaeaea;
padding-top: 8px;
margin-bottom: 8px;
.withdraw-item {
display: flex;
justify-content: space-between;
align-items: center;
.item-label {
font-size: 14px;
color: #606266;
}
.item-value {
font-size: 15px;
color: #606266;
font-weight: 500;
}
}
}
.withdraw-btn-area {
display: flex;
justify-content: center;
.el-button {
font-size: 16px;
padding: 12px 25px;
width: 100%;
border-radius: 8px;
font-weight: 500;
transition: all 0.3s;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
&:active {
transform: translateY(1px);
}
}
}
}
}
@media screen and (max-width: 768px) {
.balance-panel {
.panel-content {
.main-data {
.balance-item {
width: 100%;
padding: 10px 0;
&:first-child {
padding-top: 0;
}
&:last-child {
padding-bottom: 0;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<div class="stat-container">
<statistics-card
class="stat-card"
:value="stat.order.payAmount - stat.orderRefund.amount"
label="订单实收"
icon="el-icon-bank-card"
start-color="#FF6F61"
end-color="#FF9F80"
sub-label="今日订单实收"
:sub-value="todayStat.order.payAmount - todayStat.orderRefund.amount"
:precision="2"
/>
<statistics-card
class="stat-card"
:value="stat.order.count"
label="订单数量"
icon="el-icon-document"
start-color="#FF6F61"
end-color="#FF9F80"
sub-label="今日订单数量"
:sub-value="todayStat.order.count"
/>
<statistics-card
class="stat-card"
:value="stat.bonus.amount - stat.bonusRefund.amount"
label="收入金额"
icon="el-icon-document"
start-color="#FF6F61"
end-color="#FF9F80"
sub-label="今日收入金额"
:sub-value="todayStat.bonus.amount - todayStat.bonusRefund.amount"
/>
<statistics-card
class="stat-card"
:value="stat.device.count"
label="车辆总数"
icon="el-icon-bicycle"
start-color="#73D13D"
end-color="#A0D911"
sub-label="今日新增"
:sub-value="todayStat.device.count"
/>
<statistics-card
class="stat-card"
:value="stat.areaJoin.joinCount"
label="加盟商"
icon="el-icon-money"
start-color="#FFC069"
end-color="#FF9C6E"
sub-label="合伙人"
:sub-value="stat.areaJoin.partnerCount"
:show-value-change="false"
/>
</div>
</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: 4
}
},
}
</script>
<style lang="scss" scoped>
.stat-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
.stat-card {
flex: 1;
margin-bottom: 10px;
}
}
</style>

View File

@ -0,0 +1,68 @@
<template>
<el-card shadow="never" header="订单排行">
<el-date-picker
v-model="queryParams.createDateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
@change="getRankList"
style="width: 100%;"
size="mini"
:picker-options="DatePickerOptions.DEFAULT"
/>
<el-table
:data="rankList"
style="width: 100%;"
size="mini"
v-loading="loading"
>
<el-table-column label="排行" type="index" width="50">
<template slot-scope="d">{{d.$index + 1}}</template>
</el-table-column>
<el-table-column label="运营区" prop="areaName" />
<el-table-column label="金额" prop="orderAmount" />
<el-table-column label="数量" prop="orderCount" />
<el-table-column label="进行中" prop="processingCount" />
</el-table>
</el-card>
</template>
<script>
import { getOrderRank } from '@/api/dashboard/dashboardOrder'
import { getLastDateStr } from '@/utils'
import { DatePickerOptions } from '@/utils/constants'
export default {
data() {
return {
DatePickerOptions,
loading: false,
rankList: [],
queryParams: {
createDateRange: [getLastDateStr(0), getLastDateStr(0)],
}
}
},
created() {
this.getRankList();
},
methods: {
getRankList() {
this.loading = true;
getOrderRank(this.queryParams).then(res => {
this.rankList = res.data;
}).finally(() => {
this.loading = false;
});
}
},
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,155 +0,0 @@
<template>
<el-row :gutter="10">
<el-col :span="span" class="stat-col">
<statistics-card
:value="stat.order.payAmount - stat.orderRefund.amount"
label="订单实收"
icon="el-icon-bank-card"
start-color="#FF6F61"
end-color="#FF9F80"
sub-label="今日订单实收"
:sub-value="todayStat.order.payAmount - todayStat.orderRefund.amount"
:precision="2"
/>
</el-col>
<el-col :span="span" class="stat-col">
<statistics-card
:value="stat.order.count"
label="订单数量"
icon="el-icon-document"
start-color="#FF6F61"
end-color="#FF9F80"
sub-label="今日订单数量"
:sub-value="todayStat.order.count"
/>
</el-col>
<el-col :span="span" class="stat-col">
<statistics-card
:value="stat.area.count"
label="总收入"
icon="el-icon-wallet"
start-color="#69C0FF"
end-color="#40A9FF"
sub-label="今日收入"
:sub-value="stat.user.balance"
:precision="2"
/>
</el-col>
<el-col :span="span" class="stat-col" v-if="isSysAdmin()">
<statistics-card
:value="stat.user.balance"
label="商户余额"
icon="el-icon-wallet"
start-color="#69C0FF"
end-color="#40A9FF"
sub-label="待结算金额"
:sub-value="stat.user.balance"
:show-value-change="false"
:precision="2"
/>
</el-col>
<el-col :span="span" class="stat-col">
<statistics-card
:value="stat.device.count"
label="车辆总数"
icon="el-icon-bicycle"
start-color="#73D13D"
end-color="#A0D911"
sub-label="车型总数"
:sub-value="stat.model.count"
:show-value-change="false"
/>
</el-col>
<el-col :span="span" class="stat-col" v-if="isSysAdmin()">
<statistics-card
:value="stat.area.count"
label="运营区数量"
icon="el-icon-map-location"
start-color="#FFC069"
end-color="#FF9C6E"
sub-label="店铺数量"
:sub-value="stat.user.balance"
:show-value-change="false"
/>
</el-col>
<el-col :span="span" class="stat-col">
<statistics-card
:value="stat.user.count"
label="用户总数"
icon="el-icon-user"
start-color="#9254DE"
end-color="#F759AB"
sub-label="今日新增"
:sub-value="todayStat.user.count"
/>
</el-col>
<el-col :span="span" class="stat-col">
<statistics-card
:value="stat.area.count"
label="累计提现"
icon="el-icon-money"
start-color="#FFC069"
end-color="#FF9C6E"
sub-label="审核中"
:sub-value="stat.user.balance"
:show-value-change="false"
:precision="2"
/>
</el-col>
<el-col :span="span" class="stat-col" v-if="!isSysAdmin()">
<statistics-card
:value="stat.area.count"
label="加盟商"
icon="el-icon-money"
start-color="#FFC069"
end-color="#FF9C6E"
sub-label="合伙人"
:sub-value="stat.user.balance"
:show-value-change="false"
/>
</el-col>
<el-col :span="span" class="stat-col" v-if="!isSysAdmin()">
<statistics-card
:value="stat.area.count"
label="用户投诉"
icon="el-icon-warning"
start-color="#FFC069"
end-color="#FF9C6E"
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>
.stat-col {
margin-bottom: 10px;
}
</style>

View File

@ -1,105 +1,27 @@
<template>
<div class="app-container" style="min-height: 600px;" v-loading="loading">
<el-row :gutter="gutter" v-if="stat">
<el-col :span="18">
<!-- 统计信息 -->
<stat :stat="stat" :today-stat="todayStat" />
<!-- 设备统计信息 -->
<device-stat :stat="stat"/>
<el-row :gutter="gutter" style="margin-top:12px">
<el-col :span="24">
<order-daily-stat/>
</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>
<div>
<mch-index v-if="active === 'mch'"/>
<admin-index v-if="active === 'admin'"/>
</div>
</template>
<script>
import { getStat } from '@/api/dashboard/dashboard'
import { StatKeys } from '@/utils/enums'
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'
import MchIndex from '@/views/bst/index/MchIndex.vue'
import AdminIndex from '@/views/bst/index/AdminIndex.vue'
export default {
name: 'Index',
components: {
Stat,
DeviceStat,
TodoList,
OrderDailyStat,
MchIndex,
AdminIndex
},
data() {
return {
span: 6,
gutter: 12,
loading: false,
stat: null,
todayStat: null,
queryParams: {
keys: [
StatKeys.ORDER_COUNT,
StatKeys.ORDER_PAY_AMOUNT,
StatKeys.ORDER_REFUND_AMOUNT,
StatKeys.BONUS_COUNT,
StatKeys.BONUS_AMOUNT,
StatKeys.BONUS_REFUND_AMOUNT,
StatKeys.USER_COUNT,
StatKeys.USER_BALANCE,
StatKeys.DEVICE_COUNT,
StatKeys.DEVICE_STATUS_COUNT,
StatKeys.DEVICE_ONLINE_STATUS_COUNT,
StatKeys.AREA_COUNT,
StatKeys.MODEL_COUNT
]
}
active: 'mch',
}
},
created() {
this.getStat();
this.getTodayStat();
},
methods: {
getStat() {
this.loading = true;
getStat(this.queryParams).then(res => {
this.stat = res.data
}).finally(() => {
this.loading = false;
})
},
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
})
if (this.isSysAdmin()) {
this.active = 'admin'
}
}
}

View File

@ -12,11 +12,10 @@
<form-col :span="span" label="车型名称" prop="name">
<el-input v-model="form.name" placeholder="请输入车型名称" />
</form-col>
<form-col :span="span" label="所属用户" prop="userId">
<form-col :span="span" label="所属用户" prop="userId" v-if="checkPermi(['system:user:list'])">
<user-input
v-model="form.userId"
:text.sync="form.userName"
:disabled="!checkPermi(['system:user:list'])"
@change="handleChangeUser"
/>
</form-col>