|
|
@@ -4,55 +4,49 @@
|
|
|
<view class="text-area">
|
|
|
<text class="title">{{ state.title }}</text>
|
|
|
</view>-->
|
|
|
- <div class="header">
|
|
|
- <uni-row class="w100">
|
|
|
- <uni-col :span="18" class="header-left">
|
|
|
-<!-- <view >站点:</view>-->
|
|
|
- <picker mode="selector" @change="handleStationCheck" :value="state.index" range-key="stationName" :range="state.stationList">
|
|
|
- <view class="uni-input">{{state.stationList[state.index].stationName}}</view>
|
|
|
- </picker>
|
|
|
- </uni-col>
|
|
|
- <uni-col :span="6" >
|
|
|
- <view class="header-right">{{state.user.username}}</view>
|
|
|
- </uni-col>
|
|
|
- </uni-row>
|
|
|
- </div>
|
|
|
-
|
|
|
-
|
|
|
- <uni-card title="概要统计" type="line" class="w100">
|
|
|
- <view class="content-summary">
|
|
|
- <view v-for="item in state.statList" class="content-summary-item" :key="item.label">
|
|
|
- <view>{{ item.label }}</view>
|
|
|
- <view>{{ item.value }}</view>
|
|
|
+ <uni-card class="w100">
|
|
|
+ <view class="header w100">
|
|
|
+ <view class="header-left">
|
|
|
+ <!-- <view >站点:</view>-->
|
|
|
+ <picker mode="selector" @change="handleStationCheck" :value="state.index" range-key="stationName" :range="state.stationList">
|
|
|
+ <view class="uni-input">{{ state.stationList[state.index]?.stationName }}</view>
|
|
|
+ </picker>
|
|
|
</view>
|
|
|
+ <view class="header-right">
|
|
|
+ <view >{{ state.user?.username }}</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </uni-card>
|
|
|
+
|
|
|
+
|
|
|
+ <uni-card title="今日概要" type="line" class="w100">
|
|
|
+ <view class="content-summary">
|
|
|
+ <view v-for="item in state.statList" class="content-summary-item" :key="item.label">
|
|
|
+ <view>{{ item.label }}</view>
|
|
|
+ <view>{{ item.value }}</view>
|
|
|
</view>
|
|
|
- </uni-card>
|
|
|
+ </view>
|
|
|
+ </uni-card>
|
|
|
<view class="content1 w100">
|
|
|
|
|
|
|
|
|
<block class="w100">
|
|
|
- <uni-card title="运营数据" padding="10px 0" >
|
|
|
+ <uni-card title="运营数据" padding="10px 0">
|
|
|
<uni-segmented-control :current="state.current"
|
|
|
:values="state.items"
|
|
|
@clickItem="handleClickPeriod"
|
|
|
styleType="text" activeColor="#4cd964"></uni-segmented-control>
|
|
|
<view>
|
|
|
- <canvas id="charge-ele-total" canvas-id="charge-ele-total" class="charts" @tap="tap"></canvas>
|
|
|
- </view>
|
|
|
- <view>
|
|
|
- <canvas id="charge-order-money" canvas-id="charge-order-money" class="charts" @tap="tap"></canvas>
|
|
|
- </view>
|
|
|
- <view>
|
|
|
- <canvas id="charge-ele-fee" canvas-id="charge-ele-fee" class="charts" @tap="tap"></canvas>
|
|
|
- </view>
|
|
|
- <view>
|
|
|
- <canvas id="charge-service-money" canvas-id="charge-service-money" class="charts" @tap="tap"></canvas>
|
|
|
+ <view class="title">总金额&服务费</view>
|
|
|
+ <canvas id="charge-ele-total" canvas-id="charge-ele-total" class="charts1" @touchend="tap" :style="{'width':state.cWidth+'px','height':state.cHeight+'px'}"></canvas>
|
|
|
</view>
|
|
|
<view>
|
|
|
- <canvas id="charge-order-user" canvas-id="charge-order-user" class="charts" @tap="tap"></canvas>
|
|
|
+ <view class="title">电量&电费</view>
|
|
|
+ <canvas id="elec-power" canvas-id="elec-power" class="charts1" @touchend="tap" :style="{'width':state.cWidth+'px','height':state.cHeight+'px'}"></canvas>
|
|
|
</view>
|
|
|
<view>
|
|
|
- <canvas id="charge-order-num" canvas-id="charge-order-num" class="charts" @tap="tap"></canvas>
|
|
|
+ <view class="title">充电客户&订单</view>
|
|
|
+ <canvas id="charge-user-order" canvas-id="charge-user-order" class="charts1" @touchend="tap" :style="{'width':state.cWidth+'px','height':state.cHeight+'px'}"></canvas>
|
|
|
</view>
|
|
|
</uni-card>
|
|
|
</block>
|
|
|
@@ -63,16 +57,16 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import {reactive} from 'vue';
|
|
|
-import {onLoad,onShow} from '@dcloudio/uni-app'
|
|
|
+import {reactive, watch,nextTick} from 'vue';
|
|
|
+import {onLoad, onShow} from '@dcloudio/uni-app'
|
|
|
|
|
|
import uCharts from "../../assets/u-charts.min";
|
|
|
-import {cfg,get} from "../../assets/utils";
|
|
|
+import {cfg, get, fmtMoney, fmtDate, msg} from "../../assets/utils";
|
|
|
|
|
|
const uChartsInstance = {};
|
|
|
|
|
|
const state = reactive({
|
|
|
- login:false,
|
|
|
+ login: false,
|
|
|
title: '快与慢运营看板小程序',
|
|
|
cWidth: 750,
|
|
|
cHeight: 500,
|
|
|
@@ -84,11 +78,30 @@ const state = reactive({
|
|
|
{label: '今日充电人数', value: '100'},
|
|
|
{label: '今日充电订单数', value: '100'},
|
|
|
],
|
|
|
- user:null,
|
|
|
- stationList:[],
|
|
|
- index:0,
|
|
|
- items:['7天','30天','90天'],
|
|
|
- current:0
|
|
|
+ user: null,
|
|
|
+ stationList: [],
|
|
|
+ index: 0,
|
|
|
+ items: ['7天', '30天', '90天'],
|
|
|
+ current: 0,
|
|
|
+ chartData: null,
|
|
|
+ uChartsInstance:{}
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 监听站点切换
|
|
|
+ */
|
|
|
+watch(() => state.index, (newVal, oldVal) => {
|
|
|
+ loadTodayStat();
|
|
|
+ loadPeriodStat();
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 监听周期切换
|
|
|
+ */
|
|
|
+watch(() => state.current, (newVal, oldVal) => {
|
|
|
+ loadPeriodStat();
|
|
|
})
|
|
|
|
|
|
|
|
|
@@ -100,45 +113,349 @@ onLoad(() => {
|
|
|
checkLogin();
|
|
|
})
|
|
|
|
|
|
-onShow(()=>{
|
|
|
- state.user=uni.getStorageSync(cfg.key.user);
|
|
|
- if(state.user){
|
|
|
+onShow(() => {
|
|
|
+ state.user = uni.getStorageSync(cfg.key.user);
|
|
|
+ if (state.user) {
|
|
|
loadStationList();
|
|
|
}
|
|
|
})
|
|
|
|
|
|
const loadStationList = () => {
|
|
|
get(`station/listStation`, {pageNum: 1024}).then((res) => {
|
|
|
- state.stationList = res;
|
|
|
+ state.stationList = res||[]?.map(k=>{
|
|
|
+ return {
|
|
|
+ stationId:k.stationId,
|
|
|
+ stationName:k.stationName
|
|
|
+ }
|
|
|
+ });
|
|
|
+ nextTick(()=>{
|
|
|
+ loadTodayStat();
|
|
|
+ loadPeriodStat();
|
|
|
+ })
|
|
|
+ }).catch(e => {
|
|
|
+ console.error(e)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 站点今日的统计数据
|
|
|
+ */
|
|
|
+const loadTodayStat = () => {
|
|
|
+ let station = state.stationList[state.index];
|
|
|
+ if (!station) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let stationId = state.stationList[state.index].stationId;
|
|
|
+ get(`stat/stationTodayStat?stationId=${stationId}`).then((res) => {
|
|
|
+ let {chargeUsers, totalOrders, totalPower, totalMoney, payAmount, elecMoney, serviceMoney, payServiceAmount} = res;
|
|
|
+ state.statList[0].value = totalPower + 'Kwh';
|
|
|
+ state.statList[1].value = fmtMoney(totalMoney) + '元';
|
|
|
+ state.statList[2].value = fmtMoney(elecMoney) + '元';
|
|
|
+ state.statList[3].value = fmtMoney(payServiceAmount) + '元';
|
|
|
+ state.statList[4].value = chargeUsers;
|
|
|
+ state.statList[5].value = totalOrders;
|
|
|
}).catch(e => {
|
|
|
console.error(e)
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 站点最近趋势的统计数据
|
|
|
+ */
|
|
|
+const loadPeriodStat = () => {
|
|
|
+ let station = state.stationList[state.index];
|
|
|
+ if (!station) {
|
|
|
+ msg('无站点统计数据');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let stationId = state.stationList[state.index].stationId;
|
|
|
+ const end = new Date()
|
|
|
+ const start = new Date()
|
|
|
+ let type='day'
|
|
|
+ if (state.current === 0) {
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
|
|
+ } else if (state.current === 1) {
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
|
|
+ } else if (state.current === 2) {
|
|
|
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
|
|
+ }
|
|
|
+ let params = {
|
|
|
+ stationIds: [stationId],
|
|
|
+ startTime: fmtDate(start),
|
|
|
+ endTime: fmtDate(end),
|
|
|
+ type:type
|
|
|
+ }
|
|
|
+
|
|
|
+ get(`/stat/stationStatDetail`, params).then(res => {
|
|
|
+ console.log(res)
|
|
|
+ state.chartData = res;
|
|
|
+ //总金额和服务费折线图
|
|
|
+ drawServiceAndTotalMoneyChart(stationId);
|
|
|
+ //电费和电量折线图
|
|
|
+ drawElectricAndPowerChart(stationId);
|
|
|
+ //充电人数、订单
|
|
|
+ drawChargeUserChart(stationId);
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 总金额和服务费折线图
|
|
|
+ */
|
|
|
+const drawServiceAndTotalMoneyChart = (stationId) => {
|
|
|
+ let dataList = state.chartData[stationId]
|
|
|
+ if(!dataList || dataList.length==0){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let categories = dataList.map(k=>k.statDay);
|
|
|
+ let series =[
|
|
|
+ {
|
|
|
+ name:'总金额',
|
|
|
+ data:dataList.map(k=>fmtMoney(k.totalMoney))
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name:'服务费',
|
|
|
+ data:dataList.map(k=>fmtMoney(k.serviceMoney))
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ let options = {
|
|
|
+ type: "area",
|
|
|
+ color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
|
|
|
+ padding: [15,15,0,15],
|
|
|
+ enableScroll: true,
|
|
|
+ width: state.cWidth,
|
|
|
+ height: state.cHeight,
|
|
|
+ categories: categories,
|
|
|
+ series: series,
|
|
|
+ xAxis: {
|
|
|
+ disableGrid: true,
|
|
|
+ itemCount:4,
|
|
|
+ scrollShow:true
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ gridType: "dash",
|
|
|
+ dashLength: 2
|
|
|
+ },
|
|
|
+ extra: {
|
|
|
+ area: {
|
|
|
+ type: "curve",
|
|
|
+ opacity: 0.2,
|
|
|
+ addLine: true,
|
|
|
+ width: 2,
|
|
|
+ gradient: true,
|
|
|
+ activeType: "hollow"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let charts = state.uChartsInstance["charge-ele-total"];
|
|
|
+ if (charts) {
|
|
|
+ charts.updateData(options);
|
|
|
+ }else{
|
|
|
+ const ctx = uni.createCanvasContext("charge-ele-total");
|
|
|
+ options.context = ctx;
|
|
|
+ console.log(options)
|
|
|
+ console.log(state.cHeight,state.cWidth)
|
|
|
+ // charts.setChartData(options);
|
|
|
+ state. uChartsInstance["charge-ele-total"] = new uCharts(options);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 电费和电量折线图
|
|
|
+ */
|
|
|
+const drawElectricAndPowerChart = (stationId) => {
|
|
|
+ let dataList = state.chartData[stationId]
|
|
|
+ if(!dataList || dataList.length==0){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let categories = dataList.map(k=>k.statDay);
|
|
|
+ let series =[
|
|
|
+ {
|
|
|
+ name:'电量',
|
|
|
+ type: "area",
|
|
|
+ style: "curve",
|
|
|
+ data:dataList.map(k=>k.totalPower)
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name:'电费',
|
|
|
+ type: "line",
|
|
|
+ style: "curve",
|
|
|
+ color: "#1890ff",
|
|
|
+ data:dataList.map(k=>fmtMoney(k.elecMoney))
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ let options = {
|
|
|
+ type: "mix",
|
|
|
+ color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
|
|
|
+ padding: [15,15,0,15],
|
|
|
+ enableScroll: true,
|
|
|
+ animation: true,
|
|
|
+ width: state.cWidth,
|
|
|
+ height: state.cHeight,
|
|
|
+ categories: categories,
|
|
|
+ series: series,
|
|
|
+ xAxis: {
|
|
|
+ disableGrid: true,
|
|
|
+ itemCount:4,
|
|
|
+ scrollShow:true
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ disabled: false,
|
|
|
+ disableGrid: false,
|
|
|
+ splitNumber: 5,
|
|
|
+ gridType: "dash",
|
|
|
+ dashLength: 4,
|
|
|
+ gridColor: "#CCCCCC",
|
|
|
+ padding: 10,
|
|
|
+ showTitle: true,
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ position: "left",
|
|
|
+ title: "折线"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ position: "right",
|
|
|
+ min: 0,
|
|
|
+ max: 200,
|
|
|
+ title: "柱状图",
|
|
|
+ textAlign: "left"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ extra: {
|
|
|
+ mix: {
|
|
|
+ column: {
|
|
|
+ width: 20
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let charts =state. uChartsInstance["elec-power"];
|
|
|
+ if (charts) {
|
|
|
+ charts.updateData(options);
|
|
|
+ }else{
|
|
|
+ const ctx = uni.createCanvasContext("elec-power", this);
|
|
|
+ options.context = ctx;
|
|
|
+ // charts.setChartData(options);
|
|
|
+ state.uChartsInstance["elec-power"] = new uCharts(options);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 充电人数柱状图
|
|
|
+ */
|
|
|
+const drawChargeUserChart = (stationId) => {
|
|
|
+ let dataList = state.chartData[stationId]
|
|
|
+ if(!dataList || dataList.length==0){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let categories = dataList.map(k=>k.statDay);
|
|
|
+ let series =[
|
|
|
+ {
|
|
|
+ name:'人次',
|
|
|
+ data:dataList.map(k=>k.chargeUsers)
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name:'订单',
|
|
|
+ data:dataList.map(k=>k.validOrders)
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ let options = {
|
|
|
+ type: "column",
|
|
|
+ color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
|
|
|
+ padding: [15,15,0,15],
|
|
|
+ enableScroll: true,
|
|
|
+ animation: true,
|
|
|
+ width: state.cWidth,
|
|
|
+ height: state.cHeight,
|
|
|
+ categories: categories,
|
|
|
+ series: series,
|
|
|
+ xAxis: {
|
|
|
+ itemCount:4,
|
|
|
+ scrollShow:true,
|
|
|
+ boundaryGap: "justify",
|
|
|
+ disableGrid: false,
|
|
|
+ min: 0,
|
|
|
+ axisLine: false,
|
|
|
+ max: 40
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ data: [
|
|
|
+ {
|
|
|
+ min: 0
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ extra: {
|
|
|
+ column: {
|
|
|
+ type: "group",
|
|
|
+ width: 30,
|
|
|
+ activeBgColor: "#000000",
|
|
|
+ activeBgOpacity: 0.08,
|
|
|
+ linearType: "custom",
|
|
|
+ seriesGap: 5,
|
|
|
+ linearOpacity: 0.5,
|
|
|
+ barBorderCircle: true,
|
|
|
+ customColor: [
|
|
|
+ "#1890FF",
|
|
|
+ "#91CB74"
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let charts = state.uChartsInstance["charge-user-order"];
|
|
|
+ if (charts) {
|
|
|
+ charts.updateData(options);
|
|
|
+ }else{
|
|
|
+ const ctx = uni.createCanvasContext("charge-user-order", this);
|
|
|
+ options.context = ctx;
|
|
|
+ // charts.setChartData(options);
|
|
|
+ state.uChartsInstance["charge-user-order"] = new uCharts(options);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
const handleStationCheck = (e) => {
|
|
|
+ console.log(e)
|
|
|
+ state.index = e.detail.value;
|
|
|
+}
|
|
|
|
|
|
+const handleClickPeriod = (e) => {
|
|
|
+ console.log(e)
|
|
|
+ state.current = e.currentIndex;
|
|
|
}
|
|
|
|
|
|
const checkLogin = () => {
|
|
|
let user = uni.getStorageSync(cfg.key.user);
|
|
|
- if(user){
|
|
|
+ if (user) {
|
|
|
state.login = true;
|
|
|
- }else{
|
|
|
- state.login=false;
|
|
|
+ } else {
|
|
|
+ state.login = false;
|
|
|
uni.navigateTo({
|
|
|
- url:'/pages/login/index'
|
|
|
+ url: '/pages/login/index'
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const tap = (e) => {
|
|
|
- uChartsInstance[e.target.id].touchLegend(e);
|
|
|
- uChartsInstance[e.target.id].showToolTip(e);
|
|
|
+ state.uChartsInstance[e.target.id].touchLegend(e);
|
|
|
+ state.uChartsInstance[e.target.id].showToolTip(e);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/**
|
|
|
+ * DEMO
|
|
|
+ * @param canvasId
|
|
|
+ * @param data
|
|
|
+ */
|
|
|
const drawCharts = (canvasId, data) => {
|
|
|
const ctx = uni.createCanvasContext(canvasId, this);
|
|
|
- uChartsInstance[canvasId] = new uCharts({
|
|
|
+ state.uChartsInstance[canvasId] = new uCharts({
|
|
|
type: "column",
|
|
|
context: ctx,
|
|
|
width: state.cWidth,
|
|
|
@@ -171,20 +488,25 @@ const drawCharts = (canvasId, data) => {
|
|
|
padding: 15rpx 15rpx;
|
|
|
}
|
|
|
|
|
|
-.header{
|
|
|
+.header {
|
|
|
width: 100%;
|
|
|
+ padding: 10px;
|
|
|
+ display: inline-flex;
|
|
|
+justify-content: space-between;
|
|
|
|
|
|
- .header-left{
|
|
|
+ .header-left {
|
|
|
display: inline-flex;
|
|
|
align-content: center;
|
|
|
+ width: 60%;
|
|
|
}
|
|
|
|
|
|
- .header-left{
|
|
|
- text-align: right;
|
|
|
+ .header-right {
|
|
|
+ text-align: right;
|
|
|
+ width: 35%;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-.content-summary{
|
|
|
+.content-summary {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
width: 100%;
|
|
|
@@ -192,21 +514,22 @@ const drawCharts = (canvasId, data) => {
|
|
|
margin-bottom: 30rpx;
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
- .content-summary-item{
|
|
|
+ .content-summary-item {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- width: 33.33%;
|
|
|
- box-shadow: 2px 2px 2px 2px #e6e6e6;
|
|
|
+ width: 120px;
|
|
|
+ padding: 10px;
|
|
|
+ //box-shadow: 2px 2px 2px 2px #e6e6e6;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-.kanban-title{
|
|
|
+.kanban-title {
|
|
|
display: inline-flex;
|
|
|
}
|
|
|
|
|
|
-.content-chart{
|
|
|
+.content-chart {
|
|
|
width: 100%;;
|
|
|
}
|
|
|
|
|
|
@@ -226,7 +549,10 @@ const drawCharts = (canvasId, data) => {
|
|
|
}
|
|
|
|
|
|
.title {
|
|
|
- font-size: 36rpx;
|
|
|
+ margin-top: 30rpx;
|
|
|
+ margin-left: 20rpx;
|
|
|
+ font-size: 30rpx;
|
|
|
color: #8f8f94;
|
|
|
}
|
|
|
+
|
|
|
</style>
|