|
|
@@ -8,84 +8,197 @@
|
|
|
>
|
|
|
<el-statistic
|
|
|
title="今日新增"
|
|
|
- :value="562"
|
|
|
+ :value="userStatData.todayRegNum"
|
|
|
value-style="font-size:24px"
|
|
|
>
|
|
|
<template #suffix>
|
|
|
<el-icon
|
|
|
style="vertical-align: -0.125em"
|
|
|
- color="#52c41a"
|
|
|
+ :color="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.todayRegNumComparison
|
|
|
+ ).color
|
|
|
+ "
|
|
|
>
|
|
|
- <Top />
|
|
|
+ <component
|
|
|
+ :is="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.todayRegNumComparison
|
|
|
+ ).icon
|
|
|
+ "
|
|
|
+ />
|
|
|
</el-icon>
|
|
|
- <el-text type="success" size="small">15%</el-text>
|
|
|
+ <el-text
|
|
|
+ :type="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.todayRegNumComparison
|
|
|
+ ).type
|
|
|
+ "
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.todayRegNumComparison
|
|
|
+ ).value
|
|
|
+ }}
|
|
|
+ </el-text>
|
|
|
</template>
|
|
|
</el-statistic>
|
|
|
<el-statistic
|
|
|
title="昨日新增"
|
|
|
- :value="562"
|
|
|
+ :value="userStatData.yesterdayRegNum"
|
|
|
value-style="font-size:24px"
|
|
|
>
|
|
|
<template #suffix>
|
|
|
<el-icon
|
|
|
style="vertical-align: -0.125em"
|
|
|
- color="#ff4d4f"
|
|
|
+ :color="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.yesterdayRegNumComparison
|
|
|
+ ).color
|
|
|
+ "
|
|
|
>
|
|
|
- <Bottom />
|
|
|
+ <component
|
|
|
+ :is="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.yesterdayRegNumComparison
|
|
|
+ ).icon
|
|
|
+ "
|
|
|
+ />
|
|
|
</el-icon>
|
|
|
- <el-text type="danger" size="small">25%</el-text>
|
|
|
+ <el-text
|
|
|
+ :type="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.yesterdayRegNumComparison
|
|
|
+ ).type
|
|
|
+ "
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.yesterdayRegNumComparison
|
|
|
+ ).value
|
|
|
+ }}
|
|
|
+ </el-text>
|
|
|
</template>
|
|
|
</el-statistic>
|
|
|
<el-statistic
|
|
|
title="7日新增"
|
|
|
- :value="562"
|
|
|
+ :value="userStatData.sevenDayRegNum"
|
|
|
value-style="font-size:24px"
|
|
|
>
|
|
|
<template #suffix>
|
|
|
<el-icon
|
|
|
style="vertical-align: -0.125em"
|
|
|
- color="#ff4d4f"
|
|
|
+ :color="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.sevenDayRegNumComparison
|
|
|
+ ).color
|
|
|
+ "
|
|
|
>
|
|
|
- <Bottom />
|
|
|
+ <component
|
|
|
+ :is="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.sevenDayRegNumComparison
|
|
|
+ ).icon
|
|
|
+ "
|
|
|
+ />
|
|
|
</el-icon>
|
|
|
- <el-text type="danger" size="small">25%</el-text>
|
|
|
+ <el-text
|
|
|
+ :type="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.sevenDayRegNumComparison
|
|
|
+ ).type
|
|
|
+ "
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.sevenDayRegNumComparison
|
|
|
+ ).value
|
|
|
+ }}
|
|
|
+ </el-text>
|
|
|
</template>
|
|
|
</el-statistic>
|
|
|
<el-statistic
|
|
|
title="30日新增"
|
|
|
- :value="562"
|
|
|
+ :value="userStatData.thirtyDayRegNum"
|
|
|
value-style="font-size:24px"
|
|
|
>
|
|
|
<template #suffix>
|
|
|
<el-icon
|
|
|
style="vertical-align: -0.125em"
|
|
|
- color="#ff4d4f"
|
|
|
+ :color="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.thirtyDayRegNumComparison
|
|
|
+ ).color
|
|
|
+ "
|
|
|
>
|
|
|
- <Bottom />
|
|
|
+ <component
|
|
|
+ :is="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.thirtyDayRegNumComparison
|
|
|
+ ).icon
|
|
|
+ "
|
|
|
+ />
|
|
|
</el-icon>
|
|
|
- <el-text type="danger" size="small">25%</el-text>
|
|
|
+ <el-text
|
|
|
+ :type="
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.thirtyDayRegNumComparison
|
|
|
+ ).type
|
|
|
+ "
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ comparisonDisplay(
|
|
|
+ userStatData.thirtyDayRegNumComparison
|
|
|
+ ).value
|
|
|
+ }}
|
|
|
+ </el-text>
|
|
|
</template>
|
|
|
</el-statistic>
|
|
|
</div>
|
|
|
- <date-search />
|
|
|
+ <date-search @search="fetchUserCurveData" />
|
|
|
</div>
|
|
|
|
|
|
<div class="common-card mb-10">
|
|
|
<div class="common-title">用户数据</div>
|
|
|
- <user-data-line />
|
|
|
+ <user-data-line :chart-data="userCurveData" />
|
|
|
</div>
|
|
|
<div class="common-card flex gap-6">
|
|
|
<div class="flex-1 gray-card">
|
|
|
- <div class="common-title"
|
|
|
- >今日对比昨日| 分时新增新用户数量</div
|
|
|
- >
|
|
|
- <user-add-compare />
|
|
|
+ <div class="common-title">
|
|
|
+ 今日对比昨日| 分时新增新用户数量
|
|
|
+ </div>
|
|
|
+ <user-add-compare
|
|
|
+ :today-reg-num="userStatData.todayRegNum"
|
|
|
+ :yesterday-reg-num="userStatData.yesterdayRegNum"
|
|
|
+ :today-reg-num-comparison="
|
|
|
+ userStatData.todayRegNumComparison
|
|
|
+ "
|
|
|
+ :chat-axis="userStatData.chatAxis"
|
|
|
+ :today-reg-num-charts="userStatData.todayRegNumCharts"
|
|
|
+ :yesterday-reg-num-charts="
|
|
|
+ userStatData.yesterdayRegNumCharts
|
|
|
+ "
|
|
|
+ />
|
|
|
</div>
|
|
|
<div class="flex-1 gray-card">
|
|
|
- <div class="common-title"
|
|
|
- >今日对比昨日| 分时活跃新用户数量</div
|
|
|
- >
|
|
|
- <user-active-compare />
|
|
|
+ <div class="common-title">
|
|
|
+ 今日对比昨日| 分时活跃新用户数量
|
|
|
+ </div>
|
|
|
+ <user-active-compare
|
|
|
+ :today-active-num="userStatData.todayActiveNum"
|
|
|
+ :yesterday-active-num="userStatData.yesterdayActiveNum"
|
|
|
+ :chat-axis="userStatData.chatAxis"
|
|
|
+ :today-active-num-charts="
|
|
|
+ userStatData.todayActiveNumCharts
|
|
|
+ "
|
|
|
+ :yesterday-active-num-charts="
|
|
|
+ userStatData.yesterdayActiveNumCharts
|
|
|
+ "
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
</ele-card>
|
|
|
@@ -93,75 +206,110 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
- import { ref, reactive } from 'vue';
|
|
|
- import { Bottom, Top } from '@element-plus/icons-vue';
|
|
|
- import dateSearch from '@/components/DateSearch/index.vue';
|
|
|
- import pageSearch from '@/views/finance/withdrawal/components/page-search.vue';
|
|
|
- import { useDictData } from '@/utils/use-dict-data';
|
|
|
- import userDataLine from '@/views/customer/stat/components/user-data-line.vue';
|
|
|
- import userActiveCompare from '@/views/customer/stat/components/user-active-compare.vue';
|
|
|
- import userAddCompare from '@/views/customer/stat/components/user-add-compare.vue';
|
|
|
+import { ref, reactive, onMounted } from "vue";
|
|
|
+import { Bottom, Top } from "@element-plus/icons-vue";
|
|
|
+import { EleMessage } from "ele-admin-plus/es";
|
|
|
+import dateSearch from "@/components/DateSearch/index.vue";
|
|
|
+import { getUserStatistic, getUserStatisticCurve } from "@/api/customer/stat";
|
|
|
+import userDataLine from "@/views/customer/stat/components/user-data-line.vue";
|
|
|
+import userActiveCompare from "@/views/customer/stat/components/user-active-compare.vue";
|
|
|
+import userAddCompare from "@/views/customer/stat/components/user-add-compare.vue";
|
|
|
+import request from "@/utils/request";
|
|
|
+import dayjs from "dayjs";
|
|
|
|
|
|
- defineOptions({ name: 'Withdrawal' });
|
|
|
- const [useStatusDicts] = useDictData(['use_status']);
|
|
|
+defineOptions({ name: "UserStat" });
|
|
|
|
|
|
- const useStatus = ref('1');
|
|
|
- function handleStatusChange(value) {
|
|
|
- pageRef.value.reload({ useStatus: value });
|
|
|
- }
|
|
|
+// 用户统计数据
|
|
|
+const userStatData = ref({
|
|
|
+ todayRegNum: 0,
|
|
|
+ yesterdayRegNum: 0,
|
|
|
+ sevenDayRegNum: 0,
|
|
|
+ thirtyDayRegNum: 0,
|
|
|
+ todayRegNumComparison: 0,
|
|
|
+ yesterdayRegNumComparison: 0,
|
|
|
+ sevenDayRegNumComparison: 0,
|
|
|
+ thirtyDayRegNumComparison: 0,
|
|
|
+ todayActiveNum: 0,
|
|
|
+ yesterdayActiveNum: 0,
|
|
|
+ chatAxis: [],
|
|
|
+ todayRegNumCharts: [],
|
|
|
+ yesterdayRegNumCharts: [],
|
|
|
+ todayActiveNumCharts: [],
|
|
|
+ yesterdayActiveNumCharts: [],
|
|
|
+});
|
|
|
|
|
|
- /** 表格列配置 */
|
|
|
- const columns = ref([
|
|
|
- { label: '交易时间', prop: 'createTime', align: 'center', width: 180 },
|
|
|
- { label: '用户UID', prop: 'uid', align: 'center', minWidth: 140 },
|
|
|
- {
|
|
|
- label: '支付单号/流水号',
|
|
|
- prop: 'paymentCode',
|
|
|
- align: 'center',
|
|
|
- minWidth: 160
|
|
|
- },
|
|
|
- { label: '对方账户', prop: 'addressDetail', align: 'center' },
|
|
|
- { label: '结算金额', prop: 'money', align: 'center' },
|
|
|
- {
|
|
|
- label: '交易状态',
|
|
|
- prop: 'useStatus',
|
|
|
- align: 'center',
|
|
|
- formatter: (row) =>
|
|
|
- useStatusDicts.value.find((d) => d.dictValue == row.useStatus)
|
|
|
- ?.dictLabel
|
|
|
- },
|
|
|
- {
|
|
|
- label: '交易类型',
|
|
|
- prop: 'paymentType',
|
|
|
- align: 'center',
|
|
|
- formatter: (row) =>
|
|
|
- useStatusDicts.value.find((d) => d.dictValue == row.useStatus)
|
|
|
- ?.dictLabel
|
|
|
- },
|
|
|
- { label: '订单编号', prop: 'code', align: 'center' }
|
|
|
- ]);
|
|
|
+// 用户统计曲线数据
|
|
|
+const userCurveData = ref({
|
|
|
+ chatAxis: [],
|
|
|
+ regNumCharts: [],
|
|
|
+ activeNumCharts: [],
|
|
|
+});
|
|
|
|
|
|
- /** 页面组件实例 */
|
|
|
- const pageRef = ref(null);
|
|
|
+// 获取用户统计数据
|
|
|
+const fetchUserStatData = async () => {
|
|
|
+ try {
|
|
|
+ const res = await request.get("/user/userInfo/statistic");
|
|
|
+ if (res.data.code===200) {
|
|
|
+ userStatData.value = res.data.data;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ EleMessage.error("获取用户统计数据失败");
|
|
|
+ console.error("Failed to fetch user statistic data:", error);
|
|
|
+ }
|
|
|
+};
|
|
|
|
|
|
- const pageConfig = reactive({
|
|
|
- pageUrl: '/baseinfo/godown/pagelist',
|
|
|
- exportUrl: '/baseinfo/godown/export',
|
|
|
- fileName: '佣金记录',
|
|
|
- cacheKey: 'commissionTable'
|
|
|
- });
|
|
|
+// 获取用户统计曲线数据
|
|
|
+const fetchUserCurveData = async (time = []) => {
|
|
|
+ try {
|
|
|
+ const end = dayjs().subtract(1, "day");
|
|
|
+ const start = dayjs().subtract(7, "day");
|
|
|
+ // 默认获取最近7天的数据
|
|
|
+ const params = {
|
|
|
+ startTime: time[0] || start.format("YYYY-MM-DD"),
|
|
|
+ endTime: time[1] || end.format("YYYY-MM-DD"),
|
|
|
+ };
|
|
|
+ const res = await request.get("/user/userInfo/statisticCurve", {
|
|
|
+ params,
|
|
|
+ });
|
|
|
+ if (res.data.code === 200) {
|
|
|
+ userCurveData.value = res.data.data;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ EleMessage.error("获取用户统计曲线数据失败");
|
|
|
+ console.error("Failed to fetch user curve data:", error);
|
|
|
+ }
|
|
|
+};
|
|
|
|
|
|
- //刷新表格
|
|
|
- function reload(where) {
|
|
|
- pageRef.value?.reload(where);
|
|
|
+// 计算环比显示
|
|
|
+const comparisonDisplay = (comparison) => {
|
|
|
+ if (comparison > 0) {
|
|
|
+ return {
|
|
|
+ icon: Top,
|
|
|
+ color: "#52c41a",
|
|
|
+ type: "success",
|
|
|
+ value: `${comparison}%`,
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ icon: Bottom,
|
|
|
+ color: "#ff4d4f",
|
|
|
+ type: "danger",
|
|
|
+ value: `${Math.abs(comparison)}%`,
|
|
|
+ };
|
|
|
}
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ fetchUserStatData();
|
|
|
+ fetchUserCurveData();
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|
|
|
- .gray-card {
|
|
|
- border-radius: 10px;
|
|
|
- padding: 20px;
|
|
|
- box-sizing: border-box;
|
|
|
- background: #f9f8f7;
|
|
|
- }
|
|
|
+.gray-card {
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 20px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: #f9f8f7;
|
|
|
+}
|
|
|
</style>
|