wjx 1 anno fa
parent
commit
de1a1e438d

+ 6 - 0
config/routerConfig.ts

@@ -314,6 +314,12 @@ const gameDataStatistics = {
                     name: '玩家角色',
                     access: 'role',
                     component: './gameDataStatistics/player/role',
+                },
+                {
+                    path: '/gameDataStatistics/player/loginLog',
+                    name: '玩家登录日志',
+                    access: 'loginLog',
+                    component: './gameDataStatistics/player/loginLog',
                 }
             ]
         },

+ 23 - 0
src/components/QueryForm/const.tsx

@@ -67,6 +67,22 @@ export const PayType = {
     'mpay': '米大师'
 }
 
+/**
+ * 客户端类型
+ */
+export const DeviceType = {
+    '1': 'Android APP',
+    '2': 'Ios APP',
+    '3': 'H5网页',
+    '4': '小程序'
+}
+
+export const LoginType = {
+    '0': '注册',
+    '1': '登录',
+    '2': '退出'
+}
+
 // 留存数据的枚举
 export enum ActiveEnum {
     reg = '注册留存',
@@ -79,4 +95,11 @@ export enum TableEnum {
     buy = '买量',
     nature = '自然量',
     total = '总量'
+}
+
+export enum SourceSystemEnum {
+    BG_OLD = '布谷-old',
+    BG_NEW = '布谷-new',
+    ZX_SDK = '布谷-zx',
+    ZX_ONE = '赞象'
 }

+ 82 - 18
src/components/QueryForm/index.tsx

@@ -2,8 +2,8 @@ import { Button, Checkbox, Col, DatePicker, Form, Input, InputNumber, Radio, Row
 import React, { useEffect, useState } from "react"
 import moment from "moment"
 import { useAjax } from "@/Hook/useAjax"
-import { getAllOfOwnerUserApi, getChannelChoiceListApi, getGameChoiceListApi, getCpChoiceListApi, getGameChoiceParentListType1Api, getPayListApi, getSubUserWithSelfListApi, getTtAllUserListApi, getUserSystemTypeChoiceListApi, getUserVipLevelChoiceListApi, getRoleUserListApi, getGameServerListApi, getGameListApi } from "@/services/gameData"
-import { ActiveEnum, PayStatus, TYPE, gameClassifyEnum } from "./const"
+import { getAllOfOwnerUserApi, getChannelChoiceListApi, getGameChoiceListApi, getCpChoiceListApi, getGameChoiceParentListType1Api, getPayListApi, getSubUserWithSelfListApi, getTtAllUserListApi, getUserSystemTypeChoiceListApi, getUserVipLevelChoiceListApi, getRoleUserListApi, getGameServerListApi, getGameListApi, getGameServerUnListApi } from "@/services/gameData"
+import { ActiveEnum, DeviceType, LoginType, PayStatus, TYPE, gameClassifyEnum } from "./const"
 import { ADSTATUSEnum as ADSTTTATUSEnum } from "@/pages/gameDataStatistics/adlist/monitor/const"
 import { ADSTATUSEnum } from "@/pages/gameDataStatistics/adlist/tencentMonitor/const"
 import IntervalTime from "./intervalTime"
@@ -166,6 +166,8 @@ interface Props {
     isMobile?: boolean
     /** 是否开启 注册IP 搜索 */
     isRegIp?: boolean
+    /** 是否开启 IP 搜索 */
+    isIp?: boolean
     /** 是否开启 是否实名认证 搜索 */
     isIsAuth?: boolean
     /** 是否开启 是否绑定手机 搜索 */
@@ -198,6 +200,12 @@ interface Props {
     isGameServerName?: boolean
     /** 是否开启多个区服id搜索 */
     isRankingNum?: boolean
+    /** 是否开启 客户端类型 搜索 */
+    isDeviceType?: boolean
+    /** 是否开启 登录类型 搜索 */
+    isLoginType?: boolean
+    /** 是否开启 原始区服列表 搜索 */
+    isServerIdUn?: boolean
 }
 /**
  * 游戏数据系统 请求参数
@@ -211,7 +219,7 @@ const QueryForm: React.FC<Props> = (props) => {
         isGameRoleName, isFirstRecharge, isSwitch, isMerchantNo, isOrderId, isMerchantOrderNo, isPayStatus, isPayWay, isProductName, isRegAgent, isAgentId, isPutAgent, isRegDay, isOs, isParentId, isProjectId, isProjectName, isPromotionId, isPromotionName,
         isSysUserName, isRechargeDate, isBGGameClassify, isGameUserId, isSysUserId, isUserName, isUserId, isSelectRanking, isGameType, isConsumeDay, rechargeDay, isBeginDay, isType, isAdTTStatus, isUserEnterType, isServerName, isServerId, isServerDay, isAdTXStatus,
         payTimeDay, placeAnOrderDay, isPayIntervalTime, isActiveTypes, isNickname, isMobile, isRegIp, isIsAuth, isIsBindMobile, isIsRecharge, isUserStatus, isCreateRole, isRoleCount, isVipLevel, isCreateRoleDay, isIsChange, isIsSendMail, isWeChatCompany, isWeChat,
-        isCustomerServerId, isOperatorId, isGsId, isServerIds, isRankingNum, isIsMergeServer, isSuperParentGameId, isGameServerName
+        isCustomerServerId, isOperatorId, isGsId, isServerIds, isRankingNum, isIsMergeServer, isSuperParentGameId, isGameServerName, isIp, isDeviceType, isLoginType, isServerIdUn
     } = props
     const [form] = Form.useForm()
     const parentId = Form.useWatch('parentId', form)
@@ -242,6 +250,7 @@ const QueryForm: React.FC<Props> = (props) => {
     const getGameList = useAjax(() => getGameListApi())
     const getRoleUserList = useAjax((params) => getRoleUserListApi(params))
     const getGameServerList = useAjax((params) => getGameServerListApi(params))
+    const getGameServerUnList = useAjax((params) => getGameServerUnListApi(params))
     /**************************/
 
     useEffect(() => {
@@ -583,6 +592,7 @@ const QueryForm: React.FC<Props> = (props) => {
                     {Object.keys(ADSTTTATUSEnum).map(key => <Select.Option value={key} key={key}>{ADSTTTATUSEnum[key]}</Select.Option>)}
                 </Select>
             </Form.Item></Col>}
+
             {isAdTXStatus && <Col><Form.Item name='status'>
                 <Select
                     maxTagCount={1}
@@ -598,6 +608,41 @@ const QueryForm: React.FC<Props> = (props) => {
                     {Object.keys(ADSTATUSEnum).map(key => <Select.Option value={key} key={key}>{ADSTATUSEnum[key]}</Select.Option>)}
                 </Select>
             </Form.Item></Col>}
+
+            {/* 客户端类型 */}
+            {isDeviceType && <Col><Form.Item name='deviceType'>
+                <Select
+                    maxTagCount={1}
+                    showSearch
+                    style={{ width: 140 }}
+                    allowClear
+                    dropdownMatchSelectWidth={false}
+                    placeholder={'请选择客户端类型'}
+                    filterOption={(input, option) =>
+                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                >
+                    {Object.keys(DeviceType).map(key => <Select.Option value={key} key={key}>{DeviceType[key]}</Select.Option>)}
+                </Select>
+            </Form.Item></Col>}
+
+            {/* 登录类型 */}
+            {isLoginType && <Col><Form.Item name='type'>
+                <Select
+                    maxTagCount={1}
+                    showSearch
+                    style={{ width: 140 }}
+                    allowClear
+                    dropdownMatchSelectWidth={false}
+                    placeholder={'请选择登录类型'}
+                    filterOption={(input, option) =>
+                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                >
+                    {Object.keys(LoginType).map(key => <Select.Option value={key} key={key}>{LoginType[key]}</Select.Option>)}
+                </Select>
+            </Form.Item></Col>}
+
             {/* 操作设备 */}
             {isDevice && <Col><Form.Item name='device'>
                 <Input placeholder="操作设备" allowClear style={{ width: 140 }} />
@@ -706,6 +751,14 @@ const QueryForm: React.FC<Props> = (props) => {
                                 getGameServerList?.data && getGameServerList.mutate([])
                             }
                         }
+                        if (isServerIdUn) {
+                            form.setFieldsValue({ serverId: undefined })
+                            if (option?.['data-super-id']) {
+                                getGameServerUnList.run({ gameId: option['data-super-id'] })
+                            } else {
+                                getGameServerUnList?.data && getGameServerUnList.mutate([])
+                            }
+                        }
                     }}
                 >
                     {parentGameList?.map((item: any) => <Select.Option value={item.parent_game_id} key={item.parent_game_id} data-super-id={item.super_game_id}>{item.parent_game_name}</Select.Option>)}
@@ -715,7 +768,7 @@ const QueryForm: React.FC<Props> = (props) => {
             {(parentId || superParentGameId) && <>
                 {/* 广告区服名称 */}
                 {isGameServerName && <Col><Form.Item name='serverName'>
-                    <Input placeholder="区服名称" allowClear style={{ width: 140 }} disabled={serverIds?.length > 0}/>
+                    <Input placeholder="区服名称" allowClear style={{ width: 140 }} disabled={serverIds?.length > 0} />
                 </Form.Item></Col>}
 
                 {/* 区服id */}
@@ -741,6 +794,25 @@ const QueryForm: React.FC<Props> = (props) => {
                 {isIsMergeServer && <Col><Form.Item name='isMergeServer' valuePropName="checked">
                     <Checkbox onChange={() => form.setFieldsValue({ serverIds: undefined })}>是否合服</Checkbox>
                 </Form.Item></Col>}
+
+                {/* 区服id */}
+                {isServerIdUn && <Col><Form.Item name='serverId'>
+                    <Select
+                        maxTagCount={1}
+                        mode="multiple"
+                        showSearch
+                        disabled={serverName}
+                        style={{ minWidth: 140 }}
+                        allowClear
+                        placeholder={'请选择区服'}
+                        filterOption={(input, option) =>
+                            (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                        }
+                        loading={getGameServerUnList.loading}
+                    >
+                        {getGameServerUnList?.data?.filter((item: { isSourceServer: any }) => item.isSourceServer)?.map((item: any) => <Select.Option value={item.serverId} key={item.serverId}>{item.serverName}</Select.Option>)}
+                    </Select>
+                </Form.Item></Col>}
             </>}
 
             {/* 游戏应用类型搜索 */}
@@ -998,20 +1070,7 @@ const QueryForm: React.FC<Props> = (props) => {
 
             {/* 用户id */}
             {isUserId && <Col><Form.Item name='userId'>
-                <Select
-                    maxTagCount={1}
-                    showSearch
-                    style={{ minWidth: 140 }}
-                    allowClear
-                    placeholder={'请选择用户'}
-                    filterOption={(input, option) =>
-                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
-                    }
-                >
-                    <Select.Option value={'1'}>用户001</Select.Option>
-                    <Select.Option value={'2'}>用户002</Select.Option>
-                    <Select.Option value={'3'}>用户003</Select.Option>
-                </Select>
+                <Input placeholder="用户ID" allowClear style={{ width: 140 }} />
             </Form.Item></Col>}
 
             {/* 玩家昵称 */}
@@ -1029,6 +1088,11 @@ const QueryForm: React.FC<Props> = (props) => {
                 <Input placeholder="注册IP" allowClear style={{ width: 140 }} />
             </Form.Item></Col>}
 
+            {/* 注册IP */}
+            {isIp && <Col><Form.Item name='ip'>
+                <Input placeholder="IP" allowClear style={{ width: 140 }} />
+            </Form.Item></Col>}
+
             {/* 注册IP */}
             {isRankingNum && <Col><Form.Item name='rankingNum'>
                 <InputNumber placeholder="排名范围" min={1} />

+ 1 - 1
src/pages/gameDataStatistics/components/TableData/index.tsx

@@ -361,7 +361,7 @@ const Tab = React.memo((props: any) => {
         }
     }, [isZj, ran])
     console.log('--end--', new Date().getTime())
-    return < Col span={24} >
+    return <Col span={24}>
         <div className={`${style[size]} ${className ? style[className] : ''} `}>
             {
                 isZj && <Tables

+ 95 - 0
src/pages/gameDataStatistics/player/loginLog/index.tsx

@@ -0,0 +1,95 @@
+import { useAjax } from "@/Hook/useAjax"
+import { LoginLogProps, getLoginLogListApi } from "@/services/gameData/player"
+import React, { useEffect, useState } from "react"
+import columns12 from "./tableConfig"
+import TableData from "../../components/TableData"
+import QueryForm from "@/components/QueryForm"
+import moment from "moment"
+import { Button } from "antd"
+import LoginIpUser from "./loginIpUser"
+
+/**
+ * 登录日志
+ * @returns 
+ */
+const LoginLog: React.FC = () => {
+
+    /************************/
+    const [visible, setVisible] = useState<boolean>(false)
+    const [queryForm, setQueryForm] = useState<LoginLogProps>({ pageNum: 1, pageSize: 50, sourceSystem: 'ZX_ONE' })
+    const getLoginLogList = useAjax((params) => getLoginLogListApi(params))
+    /************************/
+
+    useEffect(() => {
+        getLoginLogList.run(queryForm)
+    }, [queryForm])
+
+
+    return <div>
+        <TableData
+            czChild={<Button size="small" disabled={!queryForm?.ip} type="primary" onClick={() => setVisible(true)}>登陆IP玩家列表</Button>}
+            leftChild={<QueryForm
+                initialValues={{ sourceSystem: 'ZX_ONE' }}
+                onChange={(data: any) => {
+                    console.log(data)
+                    const { beginDay, parentId, ...par } = data
+                    let newQueryForm = JSON.parse(JSON.stringify(queryForm))
+                    newQueryForm.pageNum = 1
+                    newQueryForm.parentGameId = parentId
+                    if (beginDay && beginDay?.length === 2) {
+                        newQueryForm['beginDate'] = moment(beginDay[0]).format('YYYY-MM-DD')
+                        newQueryForm['endDate'] = moment(beginDay[1]).format('YYYY-MM-DD')
+                    } else {
+                        delete newQueryForm['beginDate']
+                        delete newQueryForm['endDate']
+                    }
+                    setQueryForm({ ...newQueryForm, ...par })
+                }}
+                isSource
+                isBeginDay
+                isBGGameClassify
+                isGameId
+                isIp
+                isOs
+                isParentId
+                isGameRoleName
+                isGameRoleId
+                isServerIdUn
+                isUserId
+                isUserName
+                isDeviceType
+                isLoginType
+            />}
+            scroll={{ x: 1000, y: 600 }}
+            ajax={getLoginLogList}
+            fixed={{ left: 1, right: 0 }}
+            dataSource={getLoginLogList?.data?.records}
+            page={getLoginLogList?.data?.current || 1}
+            pageSize={getLoginLogList?.data?.size || 20}
+            total={getLoginLogList?.data?.total || 0}
+            title='玩家登录日志'
+            onChange={(props: any) => {
+                console.log('props--->', props)
+                let { pagination, sortData } = props
+                let { current, pageSize } = pagination
+                let newQueryForm = JSON.parse(JSON.stringify(queryForm))
+                if (sortData && sortData?.order) {
+                    newQueryForm['sortType'] = sortData?.order === 'ascend' ? 'asc' : 'desc'
+                    newQueryForm['sortFiled'] = sortData?.field
+                } else {
+                    delete newQueryForm['sortType']
+                    delete newQueryForm['sortFiled']
+                }
+                newQueryForm.pageNum = current
+                newQueryForm.pageSize = pageSize
+                setQueryForm({ ...newQueryForm })
+            }}
+            config={columns12()}
+            configName={'玩家登录日志'}
+        />
+
+        {visible && <LoginIpUser visible={visible} onClose={() => setVisible(false)} ip={queryForm?.ip || ''}/>}
+    </div>
+}
+
+export default LoginLog

+ 85 - 0
src/pages/gameDataStatistics/player/loginLog/ipTableConfig.tsx

@@ -0,0 +1,85 @@
+import { SourceSystemEnum } from "@/components/QueryForm/const"
+import { CheckCircleOutlined, StopOutlined } from "@ant-design/icons"
+import { Badge, Popconfirm } from "antd"
+import React from "react"
+
+
+function columns12(interdictionHandle: (userId: number, status: number) => void) {
+
+    let newArr: any[] = [
+        {
+            title: 'SDK来源',
+            dataIndex: 'source_system',
+            key: 'source_system',
+            width: 70,
+            align: 'center',
+            ellipsis: true,
+            render: (a: any) => SourceSystemEnum[a],
+        },
+        {
+            title: '玩家ID',
+            dataIndex: 'user_id',
+            key: 'user_id',
+            ellipsis: true,
+            width: 65,
+            align: 'center'
+        },
+        {
+            title: '玩家账号',
+            dataIndex: 'username',
+            key: 'username',
+            ellipsis: true
+        },
+        {
+            title: '玩家昵称',
+            dataIndex: 'nickname',
+            key: 'nickname',
+            ellipsis: true,
+            width: 140
+        },
+        {
+            title: '最近游戏角色ID',
+            dataIndex: 'role_id',
+            key: 'role_id',
+            width: 155,
+            ellipsis: true
+        },
+        {
+            title: '最近游戏角色名',
+            dataIndex: 'role_name',
+            key: 'role_name',
+            ellipsis: true,
+            width: 110,
+            align: 'center'
+        },
+        {
+            title: '玩家状态',
+            dataIndex: 'status',
+            key: 'status',
+            align: 'center',
+            width: 70,
+            render: (a: any) => {
+                return { '3': <Badge status="error" text="冻结" />, '2': <Badge status="success" text="正常" />, '1': <Badge status="warning" text="试玩" /> }[a]
+            }
+        },
+        {
+            title: '操作',
+            dataIndex: 'cz',
+            key: 'cz',
+            width: 75,
+            align: 'center',
+            render: (a: any, b: any) => <Popconfirm
+                title={(b?.status == '1' || b?.status == '2') ? `确定封禁?` : `确定解封?`}
+                onConfirm={() => { interdictionHandle(b?.user_id, (b?.status == '1' || b?.status == '2') ? 1 : 0) }}
+                okText="是"
+                cancelText="否"
+            >
+                <a style={{ fontSize: "12px", color: (b?.status == '1' || b?.status == '2') ? 'red' : '#52c41a' }}> {(b?.status == '1' || b?.status == '2') ? <><StopOutlined /> 封禁</> : <><CheckCircleOutlined /> 解封</>}</a>
+            </Popconfirm>
+        },
+    ]
+
+    return newArr
+}
+
+export default columns12

+ 86 - 0
src/pages/gameDataStatistics/player/loginLog/loginIpUser.tsx

@@ -0,0 +1,86 @@
+import { useAjax } from "@/Hook/useAjax"
+import { IpUserProps, getIpUserListApi, interdictionGamerApi } from "@/services/gameData/player"
+import { Button, Modal, Space, Table, Tag, message } from "antd"
+import React, { useEffect, useState } from "react"
+import columns12 from "./ipTableConfig"
+import { SyncOutlined } from "@ant-design/icons"
+
+
+interface Props {
+    ip: string
+    visible?: boolean,
+    onClose?: () => void
+}
+/**
+ * 登录IP玩家列表
+ * @returns 
+ */
+const LoginIpUser: React.FC<Props> = ({ ip, visible, onClose }) => {
+
+    const getIpUserList = useAjax((params) => getIpUserListApi(params))
+    const [queryForm, setQueryForm] = useState<IpUserProps>({ pageNum: 1, pageSize: 20, ip }) 
+    const interdictionGamer = useAjax((params: { userId: number, status: number }) => interdictionGamerApi(params))
+    
+    useEffect(() => {
+        getIpUserList.run(queryForm)
+    }, [queryForm])
+
+    // 封禁
+    const interdictionHandle = (userId: number, status: number) => {
+        interdictionGamer.run({ userId, status }).then(res => {
+            if (res) {
+                message.success(status === 1 ? '封禁成功!' : '解封成功!');
+                getIpUserList.refresh();
+            } else {
+                message.error(res.msg)
+            }
+        })
+    }
+
+    return <Modal
+        title={<Space>
+            <span>{ip} 玩家列表</span>
+            <Button size="small" type="link" icon={<SyncOutlined />} onClick={() => getIpUserList.refresh()}></Button>
+        </Space>}
+        visible={visible}
+        onCancel={onClose}
+        footer={null}
+        width={900}
+    >
+        <Table 
+            columns={columns12(interdictionHandle)} 
+            dataSource={getIpUserList?.data?.records} 
+            rowKey={'role_id'}
+            size="small"
+            loading={getIpUserList.loading}
+            bordered
+            pagination={{
+                current: queryForm.pageNum,//当前页数,需state控制配合翻页
+                pageSize: queryForm.pageSize,
+                total: getIpUserList?.data?.total || 0,
+                defaultCurrent: 1,//默认初始的当前页数
+                defaultPageSize: 20,//默认初始的每页条数
+                pageSizeOptions: ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100'],
+                showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
+                hideOnSinglePage: false,//只有一页数据隐藏分页
+                showLessItems: true,
+            }}
+            onChange={(props: any, _filters, sorter: any) => {
+                let { current, pageSize } = props
+                let newQueryForm = JSON.parse(JSON.stringify(queryForm))
+                newQueryForm.pageNum = current
+                newQueryForm.pageSize = pageSize
+                if (sorter && sorter?.order) {
+                    newQueryForm['sortType'] = sorter?.order === 'ascend' ? 'asc' : 'desc'
+                    newQueryForm['sortFiled'] = sorter?.field
+                } else {
+                    delete newQueryForm['sortType']
+                    delete newQueryForm['sortFiled']
+                }
+                setQueryForm({ ...newQueryForm })
+            }}
+        />
+    </Modal>
+}
+
+export default React.memo(LoginIpUser)

+ 36 - 0
src/pages/gameDataStatistics/player/loginLog/tableConfig.tsx

@@ -0,0 +1,36 @@
+import WidthEllipsis from "@/components/widthEllipsis"
+import React from "react"
+
+function columns12() {
+
+    let newArr: { label: string, data: any[] }[] = [
+        {
+            label: '玩家登录日志列表',
+            data: [
+                { title: '时间', dataIndex: 'dt', label: '玩家登录日志列表', align: 'center', default: 1, width: 135, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '玩家ID', dataIndex: 'user_id', label: '玩家登录日志列表', align: 'center', default: 2, width: 55 },
+                { title: '玩家账号', dataIndex: 'username', label: '玩家登录日志列表', align: 'center', width: 120, default: 3, render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />) },
+                { title: '登陆游戏名', dataIndex: 'game_name', label: '玩家登录日志列表', align: 'center', width: 90, default: 4, render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />) },
+                { title: '登陆游戏ID', dataIndex: 'game_id', label: '玩家登录日志列表', align: 'center', width: 55, default: 5, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '游戏类型', dataIndex: 'classify', label: '玩家登录日志列表', align: 'center', width: 80, default: 6, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '父游戏名', dataIndex: 'parent_game_name', label: '玩家登录日志列表', align: 'center', width: 80, default: 7, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '父游戏ID', dataIndex: 'parent_game_id', label: '玩家登录日志列表', align: 'center', width: 55, default: 8, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '超父游戏ID', dataIndex: 'super_game_id', label: '玩家登录日志列表', align: 'center', width: 55, default: 9, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '角色名', dataIndex: 'role_name', label: '玩家登录日志列表', align: 'center', width: 75, default: 10, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '角色ID', dataIndex: 'role_id', label: '玩家登录日志列表', align: 'center', width: 80, default: 11, render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />) },
+                { title: '区服名', dataIndex: 'server_name', label: '玩家登录日志列表', align: 'center', width: 80, default: 12, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '区服ID', dataIndex: 'server_id', label: '玩家登录日志列表', align: 'center', width: 75, default: 13, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '原始区服名', dataIndex: 'source_server_name', label: '玩家登录日志列表', align: 'center', width: 90, default: 14, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '操作系统', dataIndex: 'os', label: '玩家登录日志列表', align: 'center', width: 90, default: 15, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '登陆IP', dataIndex: 'ip', label: '玩家登录日志列表', align: 'center', width: 100, default: 16, render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />) },
+                { title: '客户端类型', dataIndex: 'device_type', label: '玩家登录日志列表', align: 'center', width: 75, default: 17, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '登陆类型', dataIndex: 'log_type', label: '玩家登录日志列表', align: 'center', width: 60, default: 18, render: (a: string, b: any) => (<WidthEllipsis value={a} />) }
+            ]
+        },
+
+    ]
+
+    return newArr
+}
+
+export default columns12

+ 5 - 1
src/services/gameData/index.ts

@@ -58,7 +58,7 @@ export async function getSubUserWithSelfListApi() {
  * @param params 
  * @returns 
  */
-export async function getRoleUserListApi(params: {authType: 'GS' | 'CUSTOMER' | 'OPERATE'}) {
+export async function getRoleUserListApi(params: { authType: 'GS' | 'CUSTOMER' | 'OPERATE' }) {
     return request(gameApi + '/manage/game/auth/role/auth/user', {
         method: 'GET',
         params
@@ -130,6 +130,10 @@ export async function getGameServerListApi(params: { gameId: number }) {
     return request(gameApi + `/manage/gameServer/all/server/list`, { method: 'GET', params });
 }
 
+export async function getGameServerUnListApi(params: { gameId: number }) {
+    return request(gameApi + `/manage/gameServer/all/server/list`, { method: 'GET', params });
+}
+
 /**
  * 所有类型游戏列表
  * @returns 

+ 46 - 0
src/services/gameData/player.ts

@@ -198,4 +198,50 @@ export async function downloadRoleListApi(params: PlayerRoleListProps) {
         data: params,
         responseType: 'blob',
     });
+}
+
+
+export interface LoginLogProps extends Paging {
+    beginDate?: string
+    endDate?: string
+    // 客户端类型:1-安卓APP;2-iosAPP;3-H5网页;4-小程序
+    deviceType?: number,
+    gameClassify?: number
+    gameId?: number
+    ip?: string,
+    os?: string,
+    parentGameId?: number
+    roleId?: number
+    roleName?: string,
+    serverId?: number,
+    // 类型:0-注册;1-登陆;2-退出
+    type?: number
+    userId?: number
+    username?: string
+}
+/**
+ * 玩家登录日志列表
+ * @param params 
+ * @returns 
+ */
+export async function getLoginLogListApi(params: LoginLogProps) {
+    return request(wapi + '/player/login/list', {
+        method: 'POST',
+        data: params,
+    });
+}
+
+export interface IpUserProps extends Paging {
+    ip?: string
+}
+/**
+ * 登陆IP玩家列表
+ * @param params 
+ * @returns 
+ */
+export async function getIpUserListApi(params: IpUserProps) {
+    return request(wapi + '/player/banned/list', {
+        method: 'POST',
+        data: params,
+    });
 }