|
|
@@ -4,31 +4,39 @@
|
|
|
<span class="card-title">资金曲线-按用户</span>
|
|
|
</template>
|
|
|
<template v-slot:body>
|
|
|
- <div class="custom-form-layout">
|
|
|
- <lay-form class="form-wp" :model="pageParams" mode="inline" size="sm">
|
|
|
- <lay-form-item label="查询时间" prop="rangeTime">
|
|
|
- <lay-date-picker v-model="pageParams.rangeTime" range type="datetime" :placeholder="['开始日期', '结束日期']" />
|
|
|
- </lay-form-item>
|
|
|
- <lay-form-item label="统计间隔" prop="granularity">
|
|
|
- <lay-input v-model="pageParams.granularity" />
|
|
|
- </lay-form-item>
|
|
|
- <div class="form-button-wp">
|
|
|
- <lay-button @click="getUserBalanceData()">查询</lay-button>
|
|
|
- </div>
|
|
|
- <lay-form-item>
|
|
|
- <lay-button-group>
|
|
|
- <lay-button type="default" @click="handleRangeTime(1)">本日</lay-button>
|
|
|
- <lay-button type="default" @click="handleRangeTime(2)">本周</lay-button>
|
|
|
- <lay-button type="default" @click="handleRangeTime(3)">本月</lay-button>
|
|
|
- </lay-button-group>
|
|
|
- </lay-form-item>
|
|
|
- </lay-form>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <lay-loading :loading="pageConfig.loading">
|
|
|
+ <lay-loading class="custom-loading" :loading="pageConfig.loading">
|
|
|
+ <div class="custom-form-layout">
|
|
|
+ <lay-form class="form-wp" :model="pageParams" mode="inline" size="sm">
|
|
|
+ <lay-form-item label="查询时间" prop="rangeTime">
|
|
|
+ <lay-date-picker v-model="pageParams.rangeTime" range type="datetime" :placeholder="['开始日期', '结束日期']" />
|
|
|
+ </lay-form-item>
|
|
|
+ <lay-form-item label="统计间隔" prop="granularity">
|
|
|
+ <lay-input v-model="pageParams.granularity" />
|
|
|
+ </lay-form-item>
|
|
|
+ <div class="form-button-wp">
|
|
|
+ <lay-button @click="getUserBalanceData()">查询</lay-button>
|
|
|
+ </div>
|
|
|
+ <lay-form-item>
|
|
|
+ <lay-button-group>
|
|
|
+ <lay-button type="default" @click="handleRangeTime(1)">本日</lay-button>
|
|
|
+ <lay-button type="default" @click="handleRangeTime(2)">本周</lay-button>
|
|
|
+ <lay-button type="default" @click="handleRangeTime(3)">本月</lay-button>
|
|
|
+ <lay-button type="default" @click="handleRangeTime(4)">上月</lay-button>
|
|
|
+ </lay-button-group>
|
|
|
+ </lay-form-item>
|
|
|
+ <lay-form-item>
|
|
|
+ <lay-button-group>
|
|
|
+ <lay-button type="default" @click="initChart(balanceData, 1)">按收益率</lay-button>
|
|
|
+ <lay-button type="default" @click="initChart(balanceData, 2)">按收益</lay-button>
|
|
|
+ <lay-button type="default" @click="initChart(balanceData, 3)">按资金</lay-button>
|
|
|
+ </lay-button-group>
|
|
|
+ </lay-form-item>
|
|
|
+ </lay-form>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
<div class="chart" ref="balanceChartRef"></div>
|
|
|
- </lay-loading>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ </lay-loading>
|
|
|
</template>
|
|
|
</lay-card>
|
|
|
</template>
|
|
|
@@ -39,7 +47,7 @@ import * as echarts from "echarts";
|
|
|
import dayjs from "dayjs";
|
|
|
import isoWeek from "dayjs/plugin/isoWeek";
|
|
|
import Decimal from "decimal.js";
|
|
|
-import { get_user_balance, get_user_list_all } from "@/api";
|
|
|
+import { get_user_balance } from "@/api";
|
|
|
|
|
|
dayjs.extend(isoWeek);
|
|
|
|
|
|
@@ -60,32 +68,63 @@ let pageConfig: PageConfig = reactive({
|
|
|
const pageParams: FormItem = reactive({ rangeTime: [dayjs().subtract(24, "hour").format("YYYY-MM-DD HH:mm:ss"), dayjs().format("YYYY-MM-DD HH:mm:ss")], granularity: 60 });
|
|
|
|
|
|
let balanceChart = shallowRef();
|
|
|
-let userList = ref();
|
|
|
+let balanceData = ref();
|
|
|
+let earningsRateData = ref<Array<any>>([]);
|
|
|
+let earningsData = ref<Array<any>>([]);
|
|
|
+let totalBalanceData = ref<Array<any>>([]);
|
|
|
|
|
|
const getUserBalanceData = () => {
|
|
|
+ balanceData.value = [];
|
|
|
+ earningsRateData.value = [];
|
|
|
+ earningsData.value = [];
|
|
|
+ totalBalanceData.value = [];
|
|
|
const params = {
|
|
|
startTime: +dayjs(pageParams.rangeTime[0]),
|
|
|
endTime: +dayjs(pageParams.rangeTime[1]),
|
|
|
granularity: pageParams.granularity,
|
|
|
};
|
|
|
pageConfig.loading = true;
|
|
|
- get_user_balance(params, (data: any) => {
|
|
|
+ get_user_balance(params, async (data: any) => {
|
|
|
pageConfig.loading = false;
|
|
|
if (data.code == 200) {
|
|
|
- initChart(data.data);
|
|
|
+ balanceData.value = data.data;
|
|
|
+ await handleBalanceData(data.data);
|
|
|
+ initChart(balanceData.value, 1);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
getUserBalanceData();
|
|
|
|
|
|
-// 获取用户列表
|
|
|
-const getUserList = () => {
|
|
|
- const params = {};
|
|
|
- get_user_list_all(params, (data: any) => {
|
|
|
- userList.value = data.data;
|
|
|
+const handleBalanceData = (data: any) => {
|
|
|
+ return new Promise((resolve: any) => {
|
|
|
+ // 过滤无效数据
|
|
|
+ balanceData.value = { ...data, userList: data.userList.filter((item: any) => item.balance.length > 0) };
|
|
|
+ balanceData.value.userList.map((item: any) => {
|
|
|
+ let earningList: any = [];
|
|
|
+ let earningRateList: any = [];
|
|
|
+ let lastBalance = 0;
|
|
|
+ let transferBalance = 0;
|
|
|
+ item.balance.map((items: any) => {
|
|
|
+ const isTransfer = new Decimal(items || 0)
|
|
|
+ .minus(lastBalance || 0)
|
|
|
+ .mod(50)
|
|
|
+ .toNumber();
|
|
|
+ if (!isTransfer && items != lastBalance) transferBalance += items - lastBalance;
|
|
|
+ lastBalance = items;
|
|
|
+ let totalBalance = item.balance[0] + transferBalance;
|
|
|
+ let earning = new Decimal(items || 0).minus(totalBalance || 0);
|
|
|
+ let earningRate = earning.div(totalBalance || 1).mul(100);
|
|
|
+ earningList.push(earning.toNumber());
|
|
|
+ earningRateList.push(earningRate.toNumber());
|
|
|
+ });
|
|
|
+
|
|
|
+ earningsData.value.push({ name: item.name, type: "line", stack: item.name, data: earningList });
|
|
|
+ earningsRateData.value.push({ name: item.name, type: "line", stack: item.name, data: earningRateList });
|
|
|
+ totalBalanceData.value.push({ name: item.name, type: "line", stack: item.name, data: item.balance });
|
|
|
+ });
|
|
|
+ resolve(true);
|
|
|
});
|
|
|
};
|
|
|
-getUserList();
|
|
|
|
|
|
const handleRangeTime = (type: number) => {
|
|
|
switch (type) {
|
|
|
@@ -98,75 +137,130 @@ const handleRangeTime = (type: number) => {
|
|
|
case 3:
|
|
|
pageParams.rangeTime = [`${dayjs().startOf("month").hour(10).minute(0).second(0).millisecond(0)}`, `${dayjs()}`];
|
|
|
break;
|
|
|
+ case 4:
|
|
|
+ let upMonthTime = +dayjs().startOf("month") - 1;
|
|
|
+ pageParams.rangeTime = [`${dayjs(upMonthTime).startOf("month").hour(10).minute(0).second(0).millisecond(0)}`, `${dayjs().startOf("month").hour(10).minute(0).second(0).millisecond(0)}`];
|
|
|
+ break;
|
|
|
}
|
|
|
getUserBalanceData();
|
|
|
};
|
|
|
|
|
|
-const initChart = (data: any) => {
|
|
|
+const initChart = (data: any, type: number) => {
|
|
|
+ if (balanceChart.value != null && !balanceChart.value.isDisposed()) echarts.dispose(balanceChart.value);
|
|
|
balanceChart.value = echarts.init(balanceChartRef.value);
|
|
|
|
|
|
window.removeEventListener("resize", () => balanceChart.value.resize());
|
|
|
window.addEventListener("resize", () => balanceChart.value.resize());
|
|
|
|
|
|
const xData = data.timeList.map((item: any) => dayjs(item * 1).format("MM-DD HH:mm"));
|
|
|
- const sData = data.userList.filter((item: any) => item.balance.length > 0);
|
|
|
- const legendData = sData.map((item: any) => item.name);
|
|
|
- let yMax = -9999999;
|
|
|
- let yMin = 9999999;
|
|
|
- const seriesData = sData.map((item: any) => {
|
|
|
- const balanceList = item.balance.map((items: any) => {
|
|
|
- let percent = new Decimal(items || 0)
|
|
|
- .minus(item.balance[0] || 0)
|
|
|
- .div(item.balance[0] || 1)
|
|
|
- .mul(100)
|
|
|
- .add(100)
|
|
|
- .toNumber();
|
|
|
- yMax = percent > yMax ? percent : yMax;
|
|
|
- yMin = percent < yMin ? percent : yMin;
|
|
|
- return percent;
|
|
|
- });
|
|
|
- return { name: item.name, type: "line", data: balanceList };
|
|
|
- });
|
|
|
-
|
|
|
- const balanceChartOption = {
|
|
|
- tooltip: {
|
|
|
- trigger: "axis",
|
|
|
- formatter: (value: any) => {
|
|
|
- const axisLabel = `${value[0].axisValueLabel}`;
|
|
|
- const info = value.map((item: any) => `${item.marker}${item.seriesName}: ${item.data.toFixed(2)}%`);
|
|
|
- return `${axisLabel}<br/>${info.join("<br/>")}`;
|
|
|
+ const legendData = data.userList.map((item: any) => item.name);
|
|
|
+ if (type == 1) {
|
|
|
+ const earningsRateOption = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ formatter: (value: any) => {
|
|
|
+ const axisLabel = `${value[0].axisValueLabel}`;
|
|
|
+ const info = value.map((item: any) => `${item.marker}${item.seriesName}: ${item.data.toFixed(2)}%`);
|
|
|
+ return `${axisLabel}<br/>${info.join("<br/>")}`;
|
|
|
+ },
|
|
|
},
|
|
|
- },
|
|
|
- toolbox: {
|
|
|
- feature: {
|
|
|
- dataZoom: {},
|
|
|
- brush: {
|
|
|
- type: ["rect", "clear"],
|
|
|
+ toolbox: {
|
|
|
+ feature: {
|
|
|
+ dataZoom: {},
|
|
|
+ brush: {
|
|
|
+ type: ["rect", "clear"],
|
|
|
+ },
|
|
|
},
|
|
|
},
|
|
|
- },
|
|
|
- legend: {
|
|
|
- data: legendData,
|
|
|
- top: "bottom",
|
|
|
- },
|
|
|
- xAxis: {
|
|
|
- type: "category",
|
|
|
- data: xData,
|
|
|
- },
|
|
|
- yAxis: {
|
|
|
- type: "value",
|
|
|
- max: yMax + 1,
|
|
|
- min: yMin - 1,
|
|
|
- axisLabel: {
|
|
|
+ legend: {
|
|
|
+ data: legendData,
|
|
|
+ top: "bottom",
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: xData,
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ min: "dataMin",
|
|
|
+ axisLabel: {
|
|
|
+ formatter: (value: any) => {
|
|
|
+ return `${value.toFixed(2)}%`;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ series: earningsRateData.value,
|
|
|
+ };
|
|
|
+ balanceChart.value.setOption(earningsRateOption);
|
|
|
+ }
|
|
|
+ if (type == 2) {
|
|
|
+ const earningsOption = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
formatter: (value: any) => {
|
|
|
- return `${value.toFixed(2)}%`;
|
|
|
+ const axisLabel = `${value[0].axisValueLabel}`;
|
|
|
+ const info = value.map((item: any) => `${item.marker}${item.seriesName}: ${item.data}`);
|
|
|
+ return `${axisLabel}<br/>${info.join("<br/>")}`;
|
|
|
},
|
|
|
},
|
|
|
- scale: true,
|
|
|
- },
|
|
|
- series: seriesData,
|
|
|
- };
|
|
|
- balanceChart.value.setOption(balanceChartOption);
|
|
|
+ toolbox: {
|
|
|
+ feature: {
|
|
|
+ dataZoom: {},
|
|
|
+ brush: {
|
|
|
+ type: ["rect", "clear"],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ data: legendData,
|
|
|
+ top: "bottom",
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: xData,
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ min: "dataMin",
|
|
|
+ },
|
|
|
+ series: earningsData.value,
|
|
|
+ };
|
|
|
+ balanceChart.value.setOption(earningsOption);
|
|
|
+ }
|
|
|
+ if (type == 3) {
|
|
|
+ const earningsOption = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ formatter: (value: any) => {
|
|
|
+ const axisLabel = `${value[0].axisValueLabel}`;
|
|
|
+ const info = value.map((item: any) => `${item.marker}${item.seriesName}: ${item.data}`);
|
|
|
+ return `${axisLabel}<br/>${info.join("<br/>")}`;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ toolbox: {
|
|
|
+ feature: {
|
|
|
+ dataZoom: {},
|
|
|
+ brush: {
|
|
|
+ type: ["rect", "clear"],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ data: legendData,
|
|
|
+ top: "bottom",
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ data: xData,
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: "value",
|
|
|
+ min: "dataMin",
|
|
|
+ },
|
|
|
+ series: totalBalanceData.value,
|
|
|
+ };
|
|
|
+ balanceChart.value.setOption(earningsOption);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
onUnmounted(() => {
|