Bladeren bron

Merge branch 'master' of s.long.bid:Front/web_admin_fortue_tiger_vben

flyzto 3 maanden geleden
bovenliggende
commit
0cdaff466a
24 gewijzigde bestanden met toevoegingen van 835 en 14 verwijderingen
  1. 17 0
      apps/web-antd/src/api/data_statistics/daily_agent.ts
  2. 15 0
      apps/web-antd/src/api/data_statistics/history_agent.ts
  3. 17 0
      apps/web-antd/src/api/log/log_login.ts
  4. 17 0
      apps/web-antd/src/api/log/log_operation.ts
  5. 1 1
      apps/web-antd/src/api/player/player_list.ts
  6. 3 1
      apps/web-antd/src/locales/langs/zh-CN/common.json
  7. 34 0
      apps/web-antd/src/locales/langs/zh-CN/data_statistics.json
  8. 26 0
      apps/web-antd/src/locales/langs/zh-CN/log.json
  9. 62 0
      apps/web-antd/src/router/routes/modules/data_statistics.ts
  10. 1 1
      apps/web-antd/src/router/routes/modules/game_control.ts
  11. 51 0
      apps/web-antd/src/router/routes/modules/log.ts
  12. 1 1
      apps/web-antd/src/router/routes/modules/player_data.ts
  13. 148 0
      apps/web-antd/src/views/data_statistics/daily/agent/index.vue
  14. 80 0
      apps/web-antd/src/views/data_statistics/history/agent/index.vue
  15. 0 1
      apps/web-antd/src/views/game_control/game_config/game_info.vue
  16. 1 1
      apps/web-antd/src/views/game_control/game_config/index.vue
  17. 177 0
      apps/web-antd/src/views/log/agent/login/index.vue
  18. 176 0
      apps/web-antd/src/views/log/agent/operation/index.vue
  19. 1 1
      apps/web-antd/src/views/player_data/funds_change/index.vue
  20. 1 1
      apps/web-antd/src/views/player_data/game_records/index.vue
  21. 2 2
      apps/web-antd/src/views/player_data/player_list/index.vue
  22. 2 3
      apps/web-antd/src/views/player_data/player_list/player_info.vue
  23. 1 0
      apps/web-antd/src/views/player_data/transform_records/index.vue
  24. 1 1
      apps/web-antd/src/views/user/user_list/index.vue

+ 17 - 0
apps/web-antd/src/api/data_statistics/daily_agent.ts

@@ -0,0 +1,17 @@
+import {requestClient} from "#/api/request";
+
+interface ApiResultListData {
+    data: Object;
+    status: number;
+    total: number;
+    list: Array<any>;
+}
+
+/**
+ * 获取转账记录列表
+ */
+export async function getDailyAgentList(data:any) {
+    const params = new URLSearchParams(data); // 创建一个新的URLSearchParams对象
+    const queryString = params.toString(); // 转换为查询字符串
+    return requestClient.get<ApiResultListData>('/merchant_statis/daily?' + queryString);
+}

+ 15 - 0
apps/web-antd/src/api/data_statistics/history_agent.ts

@@ -0,0 +1,15 @@
+import {requestClient} from "#/api/request";
+
+interface ApiResultListData {
+    data: Object;
+    status: number;
+    total: number;
+    list: Array<any>;
+}
+
+/**
+ * 获取转账记录列表
+ */
+export async function getHistoryAgentList() {
+    return requestClient.get<ApiResultListData>('/merchant_statis/history');
+}

+ 17 - 0
apps/web-antd/src/api/log/log_login.ts

@@ -0,0 +1,17 @@
+import {requestClient} from "#/api/request";
+
+interface ApiResultListData {
+    data: Object;
+    status: number;
+    total: number;
+    list: Array<any>;
+}
+
+/**
+ * 获取转账记录列表
+ */
+export async function getLogUserLoginList(data:any) {
+    const params = new URLSearchParams(data); // 创建一个新的URLSearchParams对象
+    const queryString = params.toString(); // 转换为查询字符串
+    return requestClient.get<ApiResultListData>('/login_log/list?' + queryString);
+}

+ 17 - 0
apps/web-antd/src/api/log/log_operation.ts

@@ -0,0 +1,17 @@
+import {requestClient} from "#/api/request";
+
+interface ApiResultListData {
+    data: Object;
+    status: number;
+    total: number;
+    list: Array<any>;
+}
+
+/**
+ * 获取转账记录列表
+ */
+export async function getLogBehaviorList(data:any) {
+    const params = new URLSearchParams(data); // 创建一个新的URLSearchParams对象
+    const queryString = params.toString(); // 转换为查询字符串
+    return requestClient.get<ApiResultListData>('/behavior_log/list?' + queryString);
+}

+ 1 - 1
apps/web-antd/src/api/player/player_list.ts

@@ -27,7 +27,7 @@ export async function getPlayerList(data:any) {
  * 获取玩家详情
  */
 export async function getPlayerInfo(user_id:string | number) {
-    return requestClient.get<ApiResultInfoData>('/player/detail?player_id=' + user_id, {
+    return requestClient.get<ApiResultInfoData>('/player/detail?user_id=' + user_id, {
         // withCredentials: true,
     });
 }

+ 3 - 1
apps/web-antd/src/locales/langs/zh-CN/common.json

@@ -2,11 +2,13 @@
     "placeholder": "请输入",
     "placeholder_select": "请选择",
     "range_time": "时间选择",
+    "day_range_time": "日期选择",
     "game_method": "玩法",
     "all": "全部",
     "success": "成功",
     "error": "失败",
     "abnormal": "异常",
     "warn": "警告",
-    "warning": "待处理"
+    "warning": "待处理",
+    "serial": "序号"
 }

+ 34 - 0
apps/web-antd/src/locales/langs/zh-CN/data_statistics.json

@@ -0,0 +1,34 @@
+{
+    "title": "综合数据",
+    "daily_title": "每日数据",
+    "agent_title": "商户每日数据",
+    "game_title": "游戏每日数据",
+    "history_title": "历史数据统计",
+    "history_agent_title": "商户统计",
+    "search": {
+
+    },
+    "daily_agent": {
+        "date": "日期",
+        "game_profit": "游戏输赢",
+        "game_profit_desc": "筛选日期内的游戏输赢数据",
+        "rtp": "游戏RTP",
+        "rtp_desc": "游戏的回报率;值越高玩家盈利机会越高",
+        "bet_amount": "注单金额",
+        "bet_amount_desc": "商户旗下玩家的下注金额数量",
+        "bet_count": "注单数",
+        "bet_count_desc": "商户旗下玩家的下注次数",
+        "bet_users": "投注用户",
+        "bet_users_desc": "进入游戏投注的人数,去重",
+        "register_users": "注册用户",
+        "register_users_desc": "商户的新增注册玩家数量",
+        "login_users": "登录用户",
+        "login_users_desc": "商户旗下玩家登录进游戏的人数去重",
+        "commission_amount": "抽水额度",
+        "commission_amount_desc": "统计筛选日期内的游戏抽水(含利润率)费用",
+        "platform_fee": "平台费用",
+        "platform_fee_desc": "对应品牌的总盈利值 * 该商户对应品牌的费用比例 = 平台收入",
+        "buy_free_bet": "购买免费游戏次数",
+        "buy_free_bet_desc": "玩家在游戏中购买免费游戏的次数"
+    }
+}

+ 26 - 0
apps/web-antd/src/locales/langs/zh-CN/log.json

@@ -0,0 +1,26 @@
+{
+    "title": "日志管理",
+    "agent_title": "商户后台日志",
+    "login_title": "登录日志",
+    "operation_title": "操作日志",
+    "search": {
+        "login_status": "登录结果",
+        "behavior": "行为",
+        "behavior_status": "行为结果"
+    },
+    "log_login": {
+        "login_time": "登录时间",
+        "user_name": "账号名称",
+        "nick_name": "账号昵称",
+        "login_device": "登录设备",
+        "login_status": "状态",
+        "login_ip": "登录IP"
+    },
+    "log_operation": {
+        "create_time": "操作时间",
+        "user_name": "账号名称",
+        "behavior": "行为",
+        "behavior_desc": "行为描述",
+        "behavior_status": "登录结果"
+    }
+}

+ 62 - 0
apps/web-antd/src/router/routes/modules/data_statistics.ts

@@ -0,0 +1,62 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+    {
+        meta: {
+            keepAlive: true,
+            icon: 'solar:cloud-check-outline',
+            order: 1,
+            title: $t('data_statistics.title'),
+        },
+        name: 'DataStatistics',
+        path: '/data-statistics',
+        children: [
+            {
+                meta: {
+                    title: $t('data_statistics.daily_title'),
+                    icon:'solar:notebook-linear',
+                    keepAlive: true
+                },
+                name: 'Daily',
+                path: '/data-statistics/daily',
+                children: [
+                    {
+                        meta: {
+                            title: $t('data_statistics.agent_title'),
+                            // icon:'solar:file-text-outline',
+                            keepAlive: true
+                        },
+                        name: 'DailyAgent',
+                        path: '/data-statistics/daily/agent',
+                        component: () => import('#/views/data_statistics/daily/agent/index.vue'),
+                    },
+                ]
+            },
+            {
+                meta: {
+                    title: $t('data_statistics.history_title'),
+                    icon:'solar:sort-by-time-outline',
+                    keepAlive: true
+                },
+                name: 'History',
+                path: '/data-statistics/history',
+                children: [
+                    {
+                        meta: {
+                            title: $t('data_statistics.history_agent_title'),
+                            // icon:'solar:file-text-outline',
+                            keepAlive: true
+                        },
+                        name: 'HistoryAgent',
+                        path: '/data-statistics/history/agent',
+                        component: () => import('#/views/data_statistics/history/agent/index.vue'),
+                    },
+                ]
+            }
+        ],
+    },
+];
+
+export default routes;

+ 1 - 1
apps/web-antd/src/router/routes/modules/game_control.ts

@@ -10,7 +10,7 @@ const routes: RouteRecordRaw[] = [
             order: 3,
             title: $t('game_control.title'),
         },
-        name: $t('game_control.game_config'),
+        name: 'gameControl',
         path: '/game-control',
         children: [
             {

+ 51 - 0
apps/web-antd/src/router/routes/modules/log.ts

@@ -0,0 +1,51 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+    {
+        meta: {
+            keepAlive: true,
+            icon: 'solar:document-text-outline',
+            order: 4,
+            title: $t('log.title'),
+        },
+        name: 'Log',
+        path: '/log',
+        children: [
+            {
+                meta: {
+                    title: $t('log.agent_title'),
+                    icon:'solar:document-add-linear',
+                    keepAlive: true
+                },
+                name: 'LogAgent',
+                path: '/log/agent',
+                children: [
+                    {
+                        meta: {
+                            title: $t('log.login_title'),
+                            // icon:'solar:file-text-outline',
+                            keepAlive: true
+                        },
+                        name: 'LogAgentLogin',
+                        path: '/log/agent/login',
+                        component: () => import('#/views/log/agent/login/index.vue'),
+                    },
+                    {
+                        meta: {
+                            title: $t('log.operation_title'),
+                            // icon:'solar:checklist-outline',
+                            keepAlive: true
+                        },
+                        name: 'LogOperation',
+                        path: '/log/agent/operation',
+                        component: () => import('#/views/log/agent/operation/index.vue'),
+                    },
+                ]
+            }
+        ],
+    },
+];
+
+export default routes;

+ 1 - 1
apps/web-antd/src/router/routes/modules/player_data.ts

@@ -10,7 +10,7 @@ const routes: RouteRecordRaw[] = [
             order: 2,
             title: $t('player_data.title'),
         },
-        name: $t('player_data.player_list'),
+        name: 'PlayerData',
         path: '/player-data',
         children: [
             {

+ 148 - 0
apps/web-antd/src/views/data_statistics/daily/agent/index.vue

@@ -0,0 +1,148 @@
+<script setup>
+import {Page} from "@vben/common-ui";
+import dayjs from "dayjs";
+import {useVbenForm} from "#/adapter/form.js";
+import {$t} from "@vben/locales";
+import {useVbenVxeGrid} from "#/adapter/vxe-table.js";
+import {Avatar, Card, Input, InputGroup, Select, SelectOption, Tag} from "ant-design-vue";
+import {getDailyAgentList} from "#/api/data_statistics/daily_agent.js";
+
+const disabledDate = (current) => {
+	return current && current > dayjs().endOf('day');
+};
+const [QueryForm, formApi] = useVbenForm({
+	// 默认展开
+	collapsed: false,
+	// 所有表单项共用,可单独在表单内覆盖
+	commonConfig: {
+		// 所有表单项
+		componentProps: {
+			class: 'w-full',
+		},
+	},
+	// 提交函数
+	handleSubmit: onSubmit,
+	handleReset: onReset,
+	// 垂直布局,label和input在不同行,值为vertical
+	// 水平布局,label和input在同一行
+	layout: 'horizontal',
+	schema: [
+		{
+			label:$t("common.day_range_time"),
+			component: 'RangePicker',
+			defaultValue: undefined,
+			fieldName: 'range_time',
+			componentProps: {
+				disabledDate: disabledDate,
+			}
+		},
+	],
+	// 是否可展开
+	submitButtonOptions: {
+		content: '查询',
+	},
+	wrapperClass: 'grid-cols-1 md:grid-cols-3',
+});
+function onSubmit(values) {
+	gridApi.reload();
+}
+function onReset() {
+	formApi.resetForm();
+	gridApi.reload();
+}
+
+
+// 列表
+const gridOptions = {
+	border: true,
+	stripe: true,
+	scrollbarConfig: {
+		x: {
+			visible: 'visible'
+		},
+		y: {
+			visible: 'auto'
+		}
+	},
+	columns: [
+		{ fixed: 'left',  title: $t('common.serial'), type: 'seq', width: 50},
+		{ field: 'date', title: $t('data_statistics.daily_agent.date'), width: 120},
+		{ field: 'game_profit', title: $t('data_statistics.daily_agent.game_profit'), width:160, titlePrefix: {'content':$t('data_statistics.daily_agent.game_profit_desc')}, slots:{'default':'game_profit'}},
+		{ field: 'rtp', title: $t('data_statistics.daily_agent.rtp'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.rtp_desc')}},
+		{ field: 'bet_amount', title: $t('data_statistics.daily_agent.bet_amount'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.bet_amount_desc')}},
+		{ field: 'bet_count', title: $t('data_statistics.daily_agent.bet_count'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.bet_count_desc')}},
+		{ field: 'bet_users', title: $t('data_statistics.daily_agent.bet_users'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.bet_users_desc')}},
+		{ field: 'register_users', title: $t('data_statistics.daily_agent.register_users'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.register_users_desc')}},
+		{ field: 'login_users', title: $t('data_statistics.daily_agent.login_users'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.login_users_desc')}},
+		{ field: 'commission_amount', title: $t('data_statistics.daily_agent.commission_amount'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.commission_amount_desc')}},
+		{ field: 'platform_fee', title: $t('data_statistics.daily_agent.platform_fee'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.platform_fee_desc')}},
+		{ field: 'buy_free_bet', title: $t('data_statistics.daily_agent.buy_free_bet'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.buy_free_bet_desc')}},
+	],
+	keepSource: true,
+	proxyConfig: {
+		ajax: {
+			query: async ({ page }) => {
+				let form = {
+					page: page.currentPage,
+					limit: page.pageSize,
+					compress: 0
+				};
+				const search = await formApi.getValues();
+				for(let key in search) {
+					if(search[key]) {
+						form[key] = search[key];
+					}
+				}
+				if(search.range_time) {
+					if(form.range_time) {
+						delete form.range_time;
+					}
+					form['start_time'] = search.range_time[0].format('YYYY-MM-DD');
+					form['end_time'] = search.range_time[1].format('YYYY-MM-DD');
+				}
+				const list = await getDailyAgentList(form);
+				return {
+					total: list.total,
+					items: list.list
+				}
+			},
+		},
+	},
+	rowConfig: {
+		isHover: true,
+	},
+	toolbarConfig: {
+		custom: true,
+		export: true,
+		// import: true,
+		refresh: true,
+		zoom: true,
+	},
+};
+const [Grid, gridApi] = useVbenVxeGrid({
+	gridOptions,
+});
+</script>
+
+<template>
+	<Page>
+		<Card class="mb-5">
+			<QueryForm>
+			</QueryForm>
+		</Card>
+		<Card>
+			<div class="vp-raw w-full">
+				<Grid>
+					<template #game_profit="{ row }">
+						<span style="color:green" v-if="row.game_profit >= 0">{{row.game_profit}}</span>
+						<span style="color:red" v-else>{{row.game_profit}}</span>
+					</template>
+				</Grid>
+			</div>
+		</Card>
+	</Page>
+</template>
+
+<style scoped>
+
+</style>

+ 80 - 0
apps/web-antd/src/views/data_statistics/history/agent/index.vue

@@ -0,0 +1,80 @@
+<script setup>
+import {Page} from "@vben/common-ui";
+import dayjs from "dayjs";
+import {useVbenForm} from "#/adapter/form.js";
+import {$t} from "@vben/locales";
+import {useVbenVxeGrid} from "#/adapter/vxe-table.js";
+import {Avatar, Card, Input, InputGroup, Select, SelectOption, Tag} from "ant-design-vue";
+import {getHistoryAgentList} from "#/api/data_statistics/history_agent.js";
+
+// 列表
+const gridOptions = {
+	border: true,
+	stripe: true,
+	scrollbarConfig: {
+		x: {
+			visible: 'visible'
+		},
+		y: {
+			visible: 'auto'
+		}
+	},
+	columns: [
+		{ fixed: 'left',  title: $t('common.serial'), type: 'seq', width: 50},
+		{ field: 'rtp', title: $t('data_statistics.daily_agent.rtp'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.rtp_desc')}},
+		{ field: 'bet_count', title: $t('data_statistics.daily_agent.bet_count'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.bet_count_desc')}},
+		{ field: 'bet_amount', title: $t('data_statistics.daily_agent.bet_amount'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.bet_amount_desc')}},
+		{ field: 'game_profit', title: $t('data_statistics.daily_agent.game_profit'), width:160, titlePrefix: {'content':$t('data_statistics.daily_agent.game_profit_desc')}, slots:{'default':'game_profit'}},
+		{ field: 'login_users', title: $t('data_statistics.daily_agent.login_users'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.login_users_desc')}},
+		{ field: 'register_users', title: $t('data_statistics.daily_agent.register_users'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.register_users_desc')}},
+		{ field: 'bet_users', title: $t('data_statistics.daily_agent.bet_users'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.bet_users_desc')}},
+		{ field: 'commission_amount', title: $t('data_statistics.daily_agent.commission_amount'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.commission_amount_desc')}},
+		{ field: 'buy_free_bet', title: $t('data_statistics.daily_agent.buy_free_bet'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.buy_free_bet_desc')}},
+		// { field: 'platform_fee', title: $t('data_statistics.daily_agent.platform_fee'), width: 160, titlePrefix: {'content':$t('data_statistics.daily_agent.platform_fee_desc')}},
+	],
+	keepSource: true,
+	proxyConfig: {
+		ajax: {
+			query: async ({ page }) => {
+				const list = await getHistoryAgentList();
+				return {
+					total: list.total,
+					items: list.list
+				}
+			},
+		},
+	},
+	rowConfig: {
+		isHover: true,
+	},
+	toolbarConfig: {
+		custom: true,
+		export: true,
+		// import: true,
+		refresh: true,
+		zoom: true,
+	},
+};
+const [Grid, gridApi] = useVbenVxeGrid({
+	gridOptions,
+});
+</script>
+
+<template>
+	<Page>
+		<Card>
+			<div class="vp-raw w-full">
+				<Grid>
+					<template #game_profit="{ row }">
+						<span style="color:green" v-if="row.game_profit >= 0">{{row.game_profit}}</span>
+						<span style="color:red" v-else>{{row.game_profit}}</span>
+					</template>
+				</Grid>
+			</div>
+		</Card>
+	</Page>
+</template>
+
+<style scoped>
+
+</style>

+ 0 - 1
apps/web-antd/src/views/game_control/game_config/game_info.vue

@@ -1,7 +1,6 @@
 <script setup>
 import {h, reactive, ref, toRaw} from 'vue';
 import {useVbenModal} from '@vben/common-ui';
-import {getPlayerInfo} from "#/api/player/player_list.js";
 import {Form, FormItem, Select, SelectOption, Switch, Input,InputNumber} from "ant-design-vue";
 import {getGameInfo, updateGameDetail} from "#/api/game_control/game_config.js";
 

+ 1 - 1
apps/web-antd/src/views/game_control/game_config/index.vue

@@ -72,7 +72,7 @@ const gridOptions = {
 		// labelField: 'name',
 	},
 	columns: [
-		{ fixed: 'left',  title: '序号', type: 'seq', width: 50 },
+		{ fixed: 'left',  title: $t('common.serial'), type: 'seq', width: 50 },
 		{ align: 'left', field: 'title', title: $t('game_control.game_list.game_title'), width: 250, slots: {default:'title'} },
 		{ field: 'title_en', title:  $t('game_control.game_list.game_en_title'), width: 200},
 		{ field: 'game_id', title: $t('game_control.game_list.game_id'), width: 140 },

+ 177 - 0
apps/web-antd/src/views/log/agent/login/index.vue

@@ -0,0 +1,177 @@
+<script setup>
+import {Page} from "@vben/common-ui";
+import dayjs from "dayjs";
+import {useVbenForm} from "#/adapter/form.js";
+import {$t} from "@vben/locales";
+import {useVbenVxeGrid} from "#/adapter/vxe-table.js";
+import {Card, Input, InputGroup, Select, SelectOption, Tag} from "ant-design-vue";
+import {getLogUserLoginList} from "#/api/log/log_login.js";
+
+const disabledDate = (current) => {
+	return current && current > dayjs().endOf('day');
+};
+const [QueryForm, formApi] = useVbenForm({
+	// 默认展开
+	collapsed: false,
+	// 所有表单项共用,可单独在表单内覆盖
+	commonConfig: {
+		// 所有表单项
+		componentProps: {
+			class: 'w-full',
+		},
+	},
+	// 提交函数
+	handleSubmit: onSubmit,
+	handleReset: onReset,
+	// 垂直布局,label和input在不同行,值为vertical
+	// 水平布局,label和input在同一行
+	layout: 'horizontal',
+	schema: [
+		{
+			// 组件需要在 #/adapter.ts内注册,并加上类型
+			component: 'Input',
+			fieldName: 'user_name',
+			label: $t('log.log_login.user_name'),
+			componentProps: {
+				allowClear: true,
+			}
+		},
+		{
+			// 组件需要在 #/adapter.ts内注册,并加上类型
+			component: 'Input',
+			fieldName: 'login_ip',
+			label: $t('log.log_login.login_ip'),
+			componentProps: {
+				allowClear: true,
+			}
+		},
+		{
+			component: 'Select',
+			defaultValue:"",
+			componentProps: {
+				filterOption: true,
+				name:'login_status',
+				options: [
+					{label: $t('common.all'), value: ""},
+					{label: $t('common.success'), value: "1"},
+					{label: $t('common.error'), value: "0"},
+				],
+				placeholder: $t('common.placeholder_select'),
+				// showSearch: true,
+			},
+			fieldName: 'login_status',
+			label: $t('log.search.login_status'),
+		},
+		{
+			label:$t("common.range_time"),
+			component: 'RangePicker',
+			defaultValue: undefined,
+			fieldName: 'range_time',
+			componentProps: {
+				disabledDate: disabledDate,
+			}
+		},
+	],
+	// 是否可展开
+	submitButtonOptions: {
+		content: '查询',
+	},
+	wrapperClass: 'grid-cols-1 md:grid-cols-3',
+});
+function onSubmit(values) {
+	gridApi.reload();
+}
+function onReset() {
+	formApi.resetForm();
+	gridApi.reload();
+}
+
+
+// 列表
+const gridOptions = {
+	border: true,
+	stripe: true,
+	scrollbarConfig: {
+		x: {
+			visible: 'visible'
+		},
+		y: {
+			visible: 'auto'
+		}
+	},
+	columns: [
+		{ fixed: 'left',  title: $t('common.serial'), type: 'seq', width: 50},
+		{ field: 'login_time', title: $t('log.log_login.login_time')},
+		{ field: 'user_name', title: $t('log.log_login.user_name')},
+		{ field: 'nick_name', title: $t('log.log_login.nick_name')},
+		{ field: 'login_device', title: $t('log.log_login.login_device')},
+		{ field: 'login_status', title: $t('log.log_login.login_status'), slots:{'default':'login_status'}},
+		{ field: 'login_ip', title: $t('log.log_login.login_ip')},
+	],
+	keepSource: true,
+	proxyConfig: {
+		ajax: {
+			query: async ({ page }) => {
+				let form = {
+					page: page.currentPage,
+					limit: page.pageSize,
+					compress: 0
+				};
+				const search = await formApi.getValues();
+				for(let key in search) {
+					if(search[key]) {
+						form[key] = search[key];
+					}
+				}
+				if(search.range_time) {
+					if(form.range_time) {
+						delete form.range_time;
+					}
+					form['start_time'] = search.range_time[0].format('YYYY-MM-DD');
+					form['end_time'] = search.range_time[1].format('YYYY-MM-DD');
+				}
+				const list = await getLogUserLoginList(form);
+				return {
+					total: list.total,
+					items: list.list
+				}
+			},
+		},
+	},
+	rowConfig: {
+		isHover: true,
+	},
+	toolbarConfig: {
+		custom: true,
+		export: true,
+		// import: true,
+		refresh: true,
+		zoom: true,
+	},
+};
+const [Grid, gridApi] = useVbenVxeGrid({
+	gridOptions,
+});
+
+</script>
+
+<template>
+	<Page>
+		<Card class="mb-5">
+			<QueryForm>
+			</QueryForm>
+		</Card>
+		<Card>
+			<Grid>
+				<template #login_status="{ row }">
+					<Tag v-if="row.login_status == 1" color="green">{{$t('common.success')}}</Tag>
+					<Tag v-else color="red">{{$t('common.error')}}</Tag>
+				</template>
+			</Grid>
+		</Card>
+	</Page>
+</template>
+
+<style scoped>
+
+</style>

+ 176 - 0
apps/web-antd/src/views/log/agent/operation/index.vue

@@ -0,0 +1,176 @@
+<script setup>
+import {Page} from "@vben/common-ui";
+import dayjs from "dayjs";
+import {useVbenForm} from "#/adapter/form.js";
+import {$t} from "@vben/locales";
+import {useVbenVxeGrid} from "#/adapter/vxe-table.js";
+import {Card, Input, InputGroup, Select, SelectOption, Tag} from "ant-design-vue";
+import {getLogBehaviorList} from "#/api/log/log_operation.js";
+
+const disabledDate = (current) => {
+	return current && current > dayjs().endOf('day');
+};
+const [QueryForm, formApi] = useVbenForm({
+	// 默认展开
+	collapsed: false,
+	// 所有表单项共用,可单独在表单内覆盖
+	commonConfig: {
+		// 所有表单项
+		componentProps: {
+			class: 'w-full',
+		},
+	},
+	// 提交函数
+	handleSubmit: onSubmit,
+	handleReset: onReset,
+	// 垂直布局,label和input在不同行,值为vertical
+	// 水平布局,label和input在同一行
+	layout: 'horizontal',
+	schema: [
+		{
+			// 组件需要在 #/adapter.ts内注册,并加上类型
+			component: 'Input',
+			fieldName: 'user_name',
+			label: $t('log.log_login.user_name'),
+			componentProps: {
+				allowClear: true,
+			}
+		},
+		{
+			// 组件需要在 #/adapter.ts内注册,并加上类型
+			component: 'Input',
+			fieldName: 'behavior',
+			label: $t('log.search.behavior'),
+			componentProps: {
+				allowClear: true,
+			}
+		},
+		{
+			component: 'Select',
+			defaultValue:"",
+			componentProps: {
+				filterOption: true,
+				name:'behavior_status',
+				options: [
+					{label: $t('common.all'), value: ""},
+					{label: $t('common.success'), value: "1"},
+					{label: $t('common.error'), value: "0"},
+				],
+				placeholder: $t('common.placeholder_select'),
+			},
+			fieldName: 'behavior_status',
+			label: $t('log.search.behavior_status'),
+		},
+		{
+			label:$t("common.range_time"),
+			component: 'RangePicker',
+			defaultValue: undefined,
+			fieldName: 'range_time',
+			componentProps: {
+				disabledDate: disabledDate,
+			}
+		},
+	],
+	// 是否可展开
+	submitButtonOptions: {
+		content: '查询',
+	},
+	wrapperClass: 'grid-cols-1 md:grid-cols-3',
+});
+function onSubmit(values) {
+	gridApi.reload();
+}
+function onReset() {
+	formApi.resetForm();
+	gridApi.reload();
+}
+
+
+// 列表
+const gridOptions = {
+	border: true,
+	stripe: true,
+	scrollbarConfig: {
+		x: {
+			visible: 'visible'
+		},
+		y: {
+			visible: 'auto'
+		}
+	},
+	columns: [
+		{ fixed: 'left',  title: $t('common.serial'), type: 'seq', width: 50},
+		{ field: 'create_time', title: $t('log.log_operation.create_time')},
+		{ field: 'user_name', title: $t('log.log_operation.user_name')},
+		{ field: 'behavior', title: $t('log.log_operation.behavior')},
+		{ field: 'behavior_desc', title: $t('log.log_operation.behavior_desc')},
+		{ field: 'behavior_status', title: $t('log.log_operation.behavior_status'), slots:{'default':'behavior_status'}},
+		{ field: 'behavior_url', title: 'URL'},
+	],
+	keepSource: true,
+	proxyConfig: {
+		ajax: {
+			query: async ({ page }) => {
+				let form = {
+					page: page.currentPage,
+					limit: page.pageSize,
+					compress: 0
+				};
+				const search = await formApi.getValues();
+				for(let key in search) {
+					if(search[key]) {
+						form[key] = search[key];
+					}
+				}
+				if(search.range_time) {
+					if(form.range_time) {
+						delete form.range_time;
+					}
+					form['start_time'] = search.range_time[0].format('YYYY-MM-DD');
+					form['end_time'] = search.range_time[1].format('YYYY-MM-DD');
+				}
+				const list = await getLogBehaviorList(form);
+				return {
+					total: list.total,
+					items: list.list
+				}
+			},
+		},
+	},
+	rowConfig: {
+		isHover: true,
+	},
+	toolbarConfig: {
+		custom: true,
+		export: true,
+		// import: true,
+		refresh: true,
+		zoom: true,
+	},
+};
+const [Grid, gridApi] = useVbenVxeGrid({
+	gridOptions,
+});
+
+</script>
+
+<template>
+	<Page>
+		<Card class="mb-5">
+			<QueryForm>
+			</QueryForm>
+		</Card>
+		<Card>
+			<Grid>
+				<template #behavior_status="{ row }">
+					<Tag v-if="row.behavior_status == 1" color="green">{{$t('common.success')}}</Tag>
+					<Tag v-else color="red">{{$t('common.error')}}</Tag>
+				</template>
+			</Grid>
+		</Card>
+	</Page>
+</template>
+
+<style scoped>
+
+</style>

+ 1 - 1
apps/web-antd/src/views/player_data/funds_change/index.vue

@@ -159,7 +159,7 @@ const gridOptions = {
 	// 	highlight: true,
 	// },
 	columns: [
-		{ fixed: 'left',  title: '序号', type: 'seq', width: 50},
+		{ fixed: 'left',  title: $t('common.serial'), type: 'seq', width: 50},
 		{ fixed: 'left', field: 'third_gid', title: $t('player_data.search.third_gid'), width: 230, titlePrefix: {'content':$t('player_data.gameRecords.tips.third_gid')}, treeNode: true  },
 		{ field: 'third_order_id', title:  $t('player_data.fundsChange.uuid'), width: 230},
 		{ field: 'third_round_id', title: $t('player_data.gameRecords.third_round_id'), width: 230, titlePrefix: {'content':$t('player_data.gameRecords.tips.third_round_id')} },

+ 1 - 1
apps/web-antd/src/views/player_data/game_records/index.vue

@@ -147,7 +147,7 @@ const gridOptions = {
 	// 	highlight: true,
 	// },
 	columns: [
-		{ fixed: 'left',  title: '序号', type: 'seq', width: 50},
+		{ fixed: 'left',  title: $t('common.serial'), type: 'seq', width: 50},
 		{ fixed: 'left', field: 'third_gid', title: $t('player_data.gameRecords.third_gid'), width: 230, titlePrefix: {'content':$t('player_data.gameRecords.tips.third_gid')}, treeNode: true  },
 		{ field: 'uuid', title:  $t('player_data.gameRecords.uuid'), width: 230},
 		{ field: 'create_time', title: $t('player_data.gameRecords.create_time'), width: 200, titlePrefix: {'content':$t('player_data.gameRecords.tips.create_time')} },

+ 2 - 2
apps/web-antd/src/views/player_data/player_list/index.vue

@@ -93,7 +93,7 @@ const gridOptions = {
 		highlight: true,
 	},
 	columns: [
-		{ fixed: 'left',  title: '序号', type: 'seq', width: 50 },
+		{ fixed: 'left',  title: $t('common.serial'), type: 'seq', width: 50 },
 		{ field: 'user_id', title: $t('player_data.playlist.user_id'), width: 100 },
 		{ field: 'uname', title:  $t('player_data.playlist.uname'), width: 120, slots: {default:'uname'}},
 		{ field: 'nickname', title: $t('player_data.playlist.nickname'), width: 140 },
@@ -164,7 +164,7 @@ const [Modal, modalApi] = useVbenModal({
 });
 const playerInfo = (row) => {
 	modalApi.setData({
-		uname: row.uname
+		user_id: row.user_id
 	}).open();
 }
 

+ 2 - 3
apps/web-antd/src/views/player_data/player_list/player_info.vue

@@ -4,7 +4,6 @@ import {useVbenModal} from '@vben/common-ui';
 import {getPlayerInfo} from "#/api/player/player_list.js";
 import {Descriptions, DescriptionsItem, Spin} from 'ant-design-vue';
 
-const uname = ref();
 const data = ref();
 const loading = ref(false);
 const [Modal, modalApi] = useVbenModal({
@@ -12,9 +11,9 @@ const [Modal, modalApi] = useVbenModal({
 	async onOpenChange(isOpen) {
 		loading.value = false;
 		if (isOpen) {
-			uname.value = modalApi.getData().uname;
+			let user_id = modalApi.getData().user_id;
 			loading.value = true;
-			data.value = await getPlayerInfo(uname.value);
+			data.value = await getPlayerInfo(user_id);
 			loading.value = false;
 		}
 	},

+ 1 - 0
apps/web-antd/src/views/player_data/transform_records/index.vue

@@ -13,6 +13,7 @@ import {useVbenVxeGrid} from "#/adapter/vxe-table.js";
 const filterData = reactive({
 	'search_type':"uname",
 });
+
 const disabledDate = (current) => {
 	return current && current > dayjs().endOf('day');
 };

+ 1 - 1
apps/web-antd/src/views/user/user_list/index.vue

@@ -101,7 +101,7 @@ const gridOptions = {
     highlight: true,
   },
   columns: [
-    { fixed: 'left', title: '序号', type: 'seq', width: 60 },
+    { fixed: 'left', title: $t('common.serial'), type: 'seq', width: 60 },
     { field: 'user_id', title: $t('user.table.user_id'), width: 60 },
     { field: 'user_name', title: $t('user.table.user_name'), width: 100 },
     { field: 'nick_name', title: $t('user.table.nick_name'), width: 150 },