瀏覽代碼

日志管理

ssvfdn 3 月之前
父節點
當前提交
26babf64f1

+ 17 - 0
apps/web-antd/src/api/player/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/player/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);
+}

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

@@ -8,5 +8,6 @@
     "error": "失败",
     "abnormal": "异常",
     "warn": "警告",
-    "warning": "待处理"
+    "warning": "待处理",
+    "serial": "序号"
 }

+ 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": "登录结果"
+    }
+}

+ 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: [
             {

+ 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/player/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/player/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')} },

+ 1 - 1
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 },

+ 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

@@ -99,7 +99,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 },