|
@@ -0,0 +1,212 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="new-app-container layout-vertical summary-page">
|
|
|
|
|
+ <div class="content-panel">
|
|
|
|
|
+ <el-tabs v-model="activeTab" class="summary-tabs" @tab-click="handleTabClick">
|
|
|
|
|
+ <el-tab-pane label="在线用户" name="online" />
|
|
|
|
|
+ <el-tab-pane label="新用户汇总" name="newUser" />
|
|
|
|
|
+ </el-tabs>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 在线用户 -->
|
|
|
|
|
+ <template v-if="activeTab === 'online'">
|
|
|
|
|
+ <YMTableSearch :loading="loading" :search-form="onlineSearchForm" @submit="onSubmit" />
|
|
|
|
|
+ <div class="table-section">
|
|
|
|
|
+ <el-table v-loading="loading" :data="onlineFilteredData" border stripe
|
|
|
|
|
+ height="calc(100vh - 340px)" style="width: 100%; border-radius: 8px;"
|
|
|
|
|
+ empty-text="暂无在线用户数据">
|
|
|
|
|
+ <el-table-column prop="member_id" label="会员ID" width="100" align="center" />
|
|
|
|
|
+ <el-table-column prop="first_name" label="会员昵称" width="130" align="center" />
|
|
|
|
|
+ <el-table-column prop="balance" label="账户余额" width="120" align="center" />
|
|
|
|
|
+ <el-table-column prop="ip" label="IP地址" width="150" align="center" />
|
|
|
|
|
+ <el-table-column prop="location" label="位置" width="130" align="center" />
|
|
|
|
|
+ <el-table-column prop="website" label="登录网站" min-width="180" align="center" />
|
|
|
|
|
+ <el-table-column prop="platform" label="平台" width="100" align="center" />
|
|
|
|
|
+ <el-table-column prop="browser" label="浏览器" width="120" align="center" />
|
|
|
|
|
+ <el-table-column prop="os" label="操作系统" width="120" align="center" />
|
|
|
|
|
+ <el-table-column prop="login_time" label="登入时间" width="175" align="center" :formatter="formatTime" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 新用户汇总 -->
|
|
|
|
|
+ <template v-if="activeTab === 'newUser'">
|
|
|
|
|
+ <YMTableSearch :loading="loading" :search-form="newUserSearchForm" @submit="onSubmit" />
|
|
|
|
|
+ <div class="info-lines">
|
|
|
|
|
+ <div class="info-line">1. 活跃会员:新注册会员下注>=¥50</div>
|
|
|
|
|
+ <div class="info-line">2. 有效会员:下注金额>=¥50的会员数</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="table-section">
|
|
|
|
|
+ <el-table v-loading="loading" :data="newUserFilteredData" border stripe
|
|
|
|
|
+ height="calc(100vh - 440px)" style="width: 100%; border-radius: 8px;"
|
|
|
|
|
+ empty-text="暂无新用户汇总数据">
|
|
|
|
|
+ <el-table-column prop="date" label="时间" width="150" align="center" />
|
|
|
|
|
+ <el-table-column prop="h5_reg" label="H5注册" width="100" align="center" />
|
|
|
|
|
+ <el-table-column prop="app_reg" label="APP注册" width="100" align="center" />
|
|
|
|
|
+ <el-table-column prop="h5_first_deposit" label="H5首存次数" width="110" align="center" />
|
|
|
|
|
+ <el-table-column prop="app_first_deposit" label="APP首存次数" width="110" align="center" />
|
|
|
|
|
+ <el-table-column prop="active_members" label="活跃会员" width="100" align="center" />
|
|
|
|
|
+ <el-table-column prop="total_deposit" label="存款总额" width="120" align="center" />
|
|
|
|
|
+ <el-table-column prop="total_bet" label="下注总数" width="120" align="center" />
|
|
|
|
|
+ <el-table-column prop="company_profit" label="公司盈利" width="120" align="center" />
|
|
|
|
|
+ <el-table-column prop="valid_members" label="有效会员" width="100" align="center" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+const ONLINE_MOCK = [
|
|
|
|
|
+ { member_id: 10001, first_name: "test01", balance: 1250.50, ip: "192.168.1.100", location: "上海", website: "www.example.com", platform: "PC", browser: "Chrome 120", os: "Windows 10", login_time: 1722499200 },
|
|
|
|
|
+ { member_id: 10002, first_name: "test02", balance: 3200.00, ip: "192.168.1.101", location: "北京", website: "com.example.app", platform: "Android", browser: "WebView", os: "Android 14", login_time: 1722502800 },
|
|
|
|
|
+ { member_id: 10003, first_name: "test03", balance: 580.20, ip: "192.168.1.102", location: "广州", website: "www.example.com", platform: "iOS", browser: "Safari 17", os: "iOS 17.5", login_time: 1722506400 },
|
|
|
|
|
+ { member_id: 10004, first_name: "test04", balance: 8880.00, ip: "10.0.0.1", location: "深圳", website: "www.example.com", platform: "PC", browser: "Edge 120", os: "Windows 11", login_time: 1722513600 },
|
|
|
|
|
+ { member_id: 10005, first_name: "test05", balance: 150.00, ip: "192.168.1.105", location: "杭州", website: "com.example.mini", platform: "WeChat", browser: "XWeb", os: "iOS 17.4", login_time: 1722517200 },
|
|
|
|
|
+ { member_id: 10006, first_name: "test06", balance: 0.00, ip: "172.16.0.1", location: "纽约", website: "www.example.com", platform: "PC", browser: "Chrome 121", os: "macOS 14", login_time: 1722524400 },
|
|
|
|
|
+ { member_id: 10007, first_name: "test07", balance: 2350.00, ip: "192.168.1.107", location: "武汉", website: "com.example.app", platform: "iOS", browser: "Safari 17", os: "iOS 17.5", login_time: 1722528000 },
|
|
|
|
|
+ { member_id: 10008, first_name: "test08", balance: 680.50, ip: "192.168.1.108", location: "南京", website: "m.example.com", platform: "Mobile", browser: "Chrome Mobile", os: "Android 13", login_time: 1722535200 },
|
|
|
|
|
+ { member_id: 10009, first_name: "test09", balance: 4200.00, ip: "192.168.1.109", location: "重庆", website: "com.example.app", platform: "Android", browser: "WebView", os: "Android 12", login_time: 1722538800 },
|
|
|
|
|
+ { member_id: 10010, first_name: "test10", balance: 920.00, ip: "192.168.1.110", location: "厦门", website: "com.example.app", platform: "iOS", browser: "Safari 17", os: "iOS 17.5", login_time: 1722546000 },
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
|
|
+const NEWUSER_MOCK = [
|
|
|
|
|
+ { date: "2026-08-01", h5_reg: 45, app_reg: 32, h5_first_deposit: 28, app_first_deposit: 20, active_members: 35, total_deposit: 28500, total_bet: 156000, company_profit: 8200, valid_members: 30 },
|
|
|
|
|
+ { date: "2026-08-02", h5_reg: 52, app_reg: 38, h5_first_deposit: 31, app_first_deposit: 24, active_members: 42, total_deposit: 32100, total_bet: 183000, company_profit: 9500, valid_members: 36 },
|
|
|
|
|
+ { date: "2026-08-03", h5_reg: 38, app_reg: 29, h5_first_deposit: 22, app_first_deposit: 18, active_members: 30, total_deposit: 19800, total_bet: 112000, company_profit: 6100, valid_members: 25 },
|
|
|
|
|
+ { date: "2026-08-04", h5_reg: 61, app_reg: 45, h5_first_deposit: 35, app_first_deposit: 28, active_members: 48, total_deposit: 35600, total_bet: 201000, company_profit: 11200, valid_members: 42 },
|
|
|
|
|
+ { date: "2026-08-05", h5_reg: 49, app_reg: 36, h5_first_deposit: 30, app_first_deposit: 22, active_members: 38, total_deposit: 26800, total_bet: 145000, company_profit: 7800, valid_members: 33 },
|
|
|
|
|
+ { date: "2026-08-06", h5_reg: 55, app_reg: 41, h5_first_deposit: 33, app_first_deposit: 26, active_members: 44, total_deposit: 34000, total_bet: 192000, company_profit: 10500, valid_members: 38 },
|
|
|
|
|
+ { date: "2026-08-07", h5_reg: 42, app_reg: 30, h5_first_deposit: 25, app_first_deposit: 19, active_members: 33, total_deposit: 22000, total_bet: 128000, company_profit: 6900, valid_members: 28 },
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ name: "UserOnlineSummary",
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ activeTab: "online",
|
|
|
|
|
+ loading: false,
|
|
|
|
|
+ onlineSearchForm: [
|
|
|
|
|
+ { label: "会员ID", type: "input", prop: "member_id", clearable: true },
|
|
|
|
|
+ { label: "会员昵称", type: "input", prop: "first_name", clearable: true },
|
|
|
|
|
+ { label: "IP地址", type: "input", prop: "ip", clearable: true },
|
|
|
|
|
+ { label: "平台", type: "select", prop: "platform", options: [
|
|
|
|
|
+ { label: "全部", value: "" },
|
|
|
|
|
+ { label: "PC", value: "PC" },
|
|
|
|
|
+ { label: "Android", value: "Android" },
|
|
|
|
|
+ { label: "iOS", value: "iOS" },
|
|
|
|
|
+ { label: "Mobile", value: "Mobile" },
|
|
|
|
|
+ { label: "WeChat", value: "WeChat" },
|
|
|
|
|
+ ], clearable: true },
|
|
|
|
|
+ ],
|
|
|
|
|
+ newUserSearchForm: [
|
|
|
|
|
+ { label: "开始日期", type: "date", prop: "start_date", clearable: true },
|
|
|
|
|
+ { label: "结束日期", type: "date", prop: "end_date", clearable: true },
|
|
|
|
|
+ ],
|
|
|
|
|
+ onlineFilteredData: [],
|
|
|
|
|
+ newUserFilteredData: [],
|
|
|
|
|
+ allOnlineData: [...ONLINE_MOCK],
|
|
|
|
|
+ allNewUserData: [...NEWUSER_MOCK],
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ formatTime(row) {
|
|
|
|
|
+ if (!row.login_time) return "--"
|
|
|
|
|
+ const d = new Date(row.login_time * 1000)
|
|
|
|
|
+ const pad = n => String(n).padStart(2, "0")
|
|
|
|
|
+ return d.getFullYear() + "-" + pad(d.getMonth()+1) + "-" + pad(d.getDate()) + " " + pad(d.getHours()) + ":" + pad(d.getMinutes()) + ":" + pad(d.getSeconds())
|
|
|
|
|
+ },
|
|
|
|
|
+ handleTabClick() {
|
|
|
|
|
+ this.onSubmit({})
|
|
|
|
|
+ },
|
|
|
|
|
+ onValueChange(val) {},
|
|
|
|
|
+ onSubmit(params) {
|
|
|
|
|
+ this.loading = true
|
|
|
|
|
+ params = params || {}
|
|
|
|
|
+ if (this.activeTab === "online") {
|
|
|
|
|
+ this.filterOnline(params)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.filterNewUser(params)
|
|
|
|
|
+ }
|
|
|
|
|
+ this.loading = false
|
|
|
|
|
+ },
|
|
|
|
|
+ filterOnline(params) {
|
|
|
|
|
+ let filtered = [...this.allOnlineData]
|
|
|
|
|
+ if (params.member_id) filtered = filtered.filter(r => String(r.member_id).includes(params.member_id))
|
|
|
|
|
+ if (params.first_name) filtered = filtered.filter(r => r.first_name.includes(params.first_name))
|
|
|
|
|
+ if (params.ip) filtered = filtered.filter(r => r.ip.includes(params.ip))
|
|
|
|
|
+ if (params.platform) filtered = filtered.filter(r => r.platform === params.platform)
|
|
|
|
|
+ this.onlineFilteredData = filtered
|
|
|
|
|
+ },
|
|
|
|
|
+ filterNewUser(params) {
|
|
|
|
|
+ let filtered = [...this.allNewUserData]
|
|
|
|
|
+ if (params.start_date) {
|
|
|
|
|
+ filtered = filtered.filter(r => r.date >= params.start_date)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (params.end_date) {
|
|
|
|
|
+ filtered = filtered.filter(r => r.date <= params.end_date)
|
|
|
|
|
+ }
|
|
|
|
|
+ this.newUserFilteredData = filtered
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ mounted() {
|
|
|
|
|
+ this.onSubmit({})
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.summary-page {
|
|
|
|
|
+ padding: 16px;
|
|
|
|
|
+ background: #f5f7fa;
|
|
|
|
|
+}
|
|
|
|
|
+.min-height-100 { min-height: 100%; }
|
|
|
|
|
+.content-panel {
|
|
|
|
|
+ min-height: calc(100vh - 82px);
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.summary-tabs {
|
|
|
|
|
+ ::v-deep .el-tabs__header {
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ padding: 0 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep .el-tabs__item {
|
|
|
|
|
+ height: 52px;
|
|
|
|
|
+ line-height: 52px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.filter-panel {
|
|
|
|
|
+ padding: 16px 20px 0;
|
|
|
|
|
+ border-bottom: 1px solid #ebeef5;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.table-section {
|
|
|
|
|
+ padding: 18px 20px 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.info-lines {
|
|
|
|
|
+ padding: 12px 20px 4px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+}
|
|
|
|
|
+.info-line {
|
|
|
|
|
+ line-height: 28px;
|
|
|
|
|
+}
|
|
|
|
|
+.info-line + .info-line {
|
|
|
|
|
+ margin-top: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|