Browse Source

新增修改

wjx 1 month ago
parent
commit
05691eebba

+ 6 - 0
config/routerConfig.ts

@@ -404,6 +404,12 @@ const gameDataStatistics = {
                     name: '封禁IP管理',
                     access: 'banIpManage',
                     component: './gameDataStatistics/player/banIpManage',
+                },
+                {
+                    path: '/gameDataStatistics/player/chatList',
+                    name: '玩家聊天记录',
+                    access: 'chatList',
+                    component: './gameDataStatistics/player/chatList',
                 }
             ]
         },

+ 135 - 0
src/pages/gameDataStatistics/player/chatList/index.tsx

@@ -0,0 +1,135 @@
+import Tables from '@/components/Tables';
+import { useAjax } from '@/Hook/useAjax';
+import { getChatGameListApi, getChatListApi } from '@/services/gameData/player';
+import { Button, Card, Col, DatePicker, Form, Input, Row, Select, Space } from 'antd';
+import React, { useEffect, useState } from 'react';
+import style from '../../components/TableData/index.less'
+import moment from 'moment';
+import { DefaultOptionType } from 'antd/lib/select';
+import columnsPos from './tableConfig';
+
+const ChatList: React.FC = () => {
+
+    /*********************************/
+    const [form] = Form.useForm()
+    const [queryFrom, setQueryFrom] = React.useState<{ supperGameId: number, pageNum: number, pageSize: number, roleId?: string, roleName?: string, chatStart?: string, chatEnd?: string }>({ supperGameId: 0, pageNum: 1, pageSize: 20 })
+    const [gameList, setGameList] = useState<DefaultOptionType[]>([])
+    const getChatGameList = useAjax(() => getChatGameListApi())
+    const getChatList = useAjax((params) => getChatListApi(params))
+    /*********************************/
+
+    useEffect(() => {
+        getChatGameList.run().then(res => {
+            if (res) {
+                const arrayGame = Object.keys(res)
+                setGameList(arrayGame.map(key => ({ label: res[key], value: key })))
+                form.setFieldsValue({ supperGameId: arrayGame[0] })
+                setQueryFrom({ ...queryFrom, supperGameId: arrayGame[0] as any })
+            }
+        })
+    }, [])
+
+    useEffect(() => {
+        if (queryFrom.supperGameId) {
+            getChatList.run(queryFrom)
+        }
+    }, [queryFrom])
+
+    const onFinish = (data: any) => {
+        const oldQueryFrom = JSON.parse(JSON.stringify(queryFrom))
+        const { chatTime, ...params } = { ...oldQueryFrom, ...data, pageNum: 1 }
+        if (chatTime?.length > 1) {
+            params.chatStart = moment(chatTime[0]).format('YYYY-MM-DD')
+            params.chatEnd = moment(chatTime[1]).format('YYYY-MM-DD')
+        } else {
+            delete params?.chatStart
+            delete params?.chatEnd
+        }
+        setQueryFrom(params)
+    }
+
+    return <Card
+        style={{ borderRadius: 8 }}
+        headStyle={{ textAlign: 'left' }}
+        bodyStyle={{ padding: '5px 10px' }}
+    >
+        <div style={{ textAlign: 'center', fontWeight: 'bold', padding: '4px 6px 6px', fontSize: 16, marginBottom: 4, position: 'relative' }}>
+            聊天记录
+        </div>
+
+        <Space style={{ width: '100%' }} direction="vertical" size={10}>
+            <Form 
+                layout="inline" 
+                className='queryForm' 
+                name="basicGameChat" 
+                form={form} 
+                onFinish={onFinish}
+            >
+                <Row gutter={[0, 6]}>
+                    <Col><Form.Item name='supperGameId'>
+                        <Select
+                            showSearch
+                            style={{ minWidth: 140 }}
+                            placeholder={'请选择游戏'}
+                            filterOption={(input, option) =>
+                                (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                            }
+                            onChange={() => {
+                                form.setFieldsValue({ codeType: undefined })
+                            }}
+                            options={gameList}
+                        />
+                    </Form.Item></Col>
+                    <Col><Form.Item name='roleName'>
+                        <Input placeholder="角色名称" allowClear style={{ width: 140 }} />
+                    </Form.Item></Col>
+                    <Col><Form.Item name='roleId'>
+                        <Input placeholder="角色ID" allowClear style={{ width: 140 }} />
+                    </Form.Item></Col>
+                    <Col><Form.Item name='chatTime'>
+                        <DatePicker.RangePicker placeholder={['聊天时间开始', '聊天时间结束']} />
+                    </Form.Item></Col>
+                    <Col>
+                        <Space>
+                            <Button type="primary" htmlType="submit">搜索</Button>
+                            <Button onClick={() => form.resetFields()}>重置</Button>
+                        </Space>
+                    </Col>
+                </Row>
+            </Form>
+
+            <div className={`${style['small']}`}>
+                <Tables
+                    className={`all_table content_table_body`}
+                    bordered
+                    sortDirections={['ascend', 'descend', null]}
+                    current={queryFrom.pageNum}
+                    pageSize={queryFrom.pageSize}
+                    columns={columnsPos()}
+                    dataSource={getChatList?.data?.records}
+                    scroll={{ x: 1000, y: 600 }}
+                    onChange={(pagination: any, filters: any, sortData: any) => {
+                        let { current, pageSize } = pagination
+                        let newQueryForm = JSON.parse(JSON.stringify(queryFrom))
+                        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
+                        setQueryFrom({ ...newQueryForm })
+                    }}
+                    size="small"
+                    total={getChatList?.data?.total}
+                    loading={getChatList?.loading}
+                    defaultPageSize={20}
+                />
+            </div>
+        </Space>
+    </Card>
+};
+
+export default ChatList;

+ 77 - 0
src/pages/gameDataStatistics/player/chatList/tableConfig.tsx

@@ -0,0 +1,77 @@
+
+
+import WidthEllipsis from "@/components/widthEllipsis"
+import React from "react"
+
+function columnsPos() {
+
+    let newArr: any = [
+        {
+            title: '游戏',
+            dataIndex: 'gameName',
+            key: 'gameName',
+            align: 'center',
+            width: 90,
+            render: (a: string) => (<WidthEllipsis value={a} />)
+        },
+        {
+            title: '区服名称',
+            dataIndex: 'serverName',
+            key: 'serverName',
+            align: 'center',
+            width: 90,
+            render: (a: string) => (<WidthEllipsis value={a} />)
+        },
+        {
+            title: '区服ID',
+            dataIndex: 'serverId',
+            key: 'serverId',
+            align: 'center',
+            width: 90,
+            render: (a: string) => (<WidthEllipsis value={a} />)
+        },
+        {
+            title: '角色名称',
+            dataIndex: 'roleName',
+            key: 'roleName',
+            align: 'center',
+            width: 100,
+            render: (a: string) => (<WidthEllipsis value={a} />)
+        },
+        {
+            title: '角色ID',
+            dataIndex: 'roleId',
+            key: 'roleId',
+            align: 'center',
+            width: 90,
+            render: (a: string) => (<WidthEllipsis value={a} />)
+        },
+        {
+            title: '公会名称',
+            dataIndex: 'guildName',
+            key: 'guildName',
+            align: 'center',
+            width: 100,
+            render: (a: string) => (<WidthEllipsis value={a} />)
+        },
+        {
+            title: '聊天时间',
+            dataIndex: 'chatTime',
+            key: 'chatTime',
+            align: 'center',
+            width: 135,
+            render: (a: string) => (<WidthEllipsis value={a} />)
+        },
+        {
+            title: '聊天内容',
+            dataIndex: 'content',
+            key: 'content',
+            width: 450,
+            render: (a: string) => (<WidthEllipsis value={a} />)
+        }
+    ]
+    return newArr
+}
+
+
+export default columnsPos

+ 8 - 0
src/pages/gsData/roleIpMonitor/loginIpDetails.tsx

@@ -32,6 +32,14 @@ const LoginIpDetails: React.FC<{ roleId: any, gameId: number, icon?: React.React
                         dataIndex: 'ip',
                         key: 'ip',
                     },
+                    {
+                        title: '角色IP的登录次数',
+                        dataIndex: 'loginCount',
+                        key: 'loginCount',
+                        render(value) {
+                            return value || 0
+                        },
+                    },
                     {
                         title: 'IP角色数量',
                         dataIndex: 'ipRoleCount',

+ 1 - 1
src/pages/gsData/roleIpMonitor/tableConfig.tsx

@@ -63,7 +63,7 @@ function columns12(): { label: string, fieldSHow?: { label: string, saveField: s
                 },
                 {
                     title: '同玩家角色数量', dataIndex: 'user_role_count', label: '基本信息', align: 'center', width: 65, sorter: true, default: 9,
-                    render: (a: number, b: any) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} suffix={<LookRoleDetails userId={b.association_user_id} icon={<EyeOutlined />} />} />
+                    render: (a: number, b: any) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} suffix={<LookRoleDetails userId={b.user_id} icon={<EyeOutlined />} />} />
                 },
                 {
                     title: '角色同IP的玩家数量', dataIndex: 'user_count', label: '基本信息', align: 'center', width: 70, sorter: true, default: 10,

+ 2 - 5
src/pages/gsData/xjRoleGrade/index.tsx

@@ -20,9 +20,7 @@ const XjRoleGrade: React.FC = () => {
     const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>([])
     const [queryForm, setQueryForm] = useState<GetRoleLevelListProps>({
         pageNum: 1,
-        pageSize: 30,
-        roleLevelMin: 16,
-        roleLevelMax: 16
+        pageSize: 30
     })
     const getRoleLevelList = useAjax((params) => getRoleLevelListApi(params))
     /****************************************/
@@ -43,7 +41,7 @@ const XjRoleGrade: React.FC = () => {
                 <Button type="primary" size="small" disabled={selectedRowKeys.length === 0} onClick={() => assignHandle(selectedRowKeys)}>批量指派</Button>
             </Space>}
             leftChild={<QueryForm
-                initialValues={{ superParentGameId: 12, regPayIntervalTime: [16, 16] }}
+                initialValues={{ superParentGameId: 12 }}
                 isXjRole
                 isGameRoleName
                 isGameRoleId
@@ -52,7 +50,6 @@ const XjRoleGrade: React.FC = () => {
                 isServerIds
                 isCreateRoleDay={{}}
                 isLastActiveTime={{ placeholder: ['等级上报时间开始', '等级上报时间结束'] }}
-                isPayIntervalTime={{ tips: '角色等级区间' }}
                 isSysUserId
                 isCustomerServerId
                 isOperatorId

+ 164 - 0
src/pages/gsData/xjRoleGrade/suspectedUser.tsx

@@ -0,0 +1,164 @@
+import { useAjax } from '@/Hook/useAjax';
+import { getSuspectedRoleDetailListApi } from '@/services/gsData';
+import { Modal, Table } from 'antd';
+import React, { useEffect, useState } from 'react';
+
+/**
+ * 疑似同玩家
+ * @param param0 
+ * @returns 
+ */
+const SuspectedUser: React.FC<{ roleId: string, icon?: React.ReactNode }> = ({ roleId, icon }) => {
+
+    /*********************************/
+    const [visible, setVisible] = useState<boolean>(false)
+    const getSuspectedRoleDetailList = useAjax((params) => getSuspectedRoleDetailListApi(params))
+    /*********************************/
+
+    useEffect(() => {
+        if (visible) {
+            const params = { roleId }
+            getSuspectedRoleDetailList.run(params)
+        }
+    }, [roleId, visible])
+
+    return <>
+        <a onClick={() => setVisible(true)}>{icon}</a>
+        {visible && <Modal
+            title={<strong>疑似同玩家(角色ID:{roleId})</strong>}
+            visible={visible}
+            onCancel={() => setVisible(false)}
+            footer={null}
+            width={1000}
+        >
+            <Table
+                columns={[
+                    {
+                        title: '角色名称',
+                        dataIndex: 'roleName',
+                        key: 'roleName',
+                        ellipsis: true,
+                        width: 90
+                    },
+                    {
+                        title: '角色ID',
+                        dataIndex: 'roleId',
+                        key: 'roleId',
+                        align: 'center',
+                        ellipsis: true,
+                        width: 80
+                    },
+                    {
+                        title: '玩家角色战力',
+                        dataIndex: 'combatNum',
+                        key: 'combatNum',
+                        align: 'center',
+                        width: 90
+                    },
+                    {
+                        title: '角色充值金额',
+                        dataIndex: 'roleTotalAmount',
+                        key: 'roleTotalAmount',
+                        align: 'center',
+                        width: 80
+                    },
+                    {
+                        title: '角色等级',
+                        dataIndex: 'roleLevel',
+                        key: 'roleLevel',
+                        align: 'center',
+                        width: 80
+                    },
+                    {
+                        title: '游戏名称',
+                        dataIndex: 'gameName',
+                        key: 'gameName',
+                        align: 'center',
+                        ellipsis: true,
+                        width: 100
+                    },
+                    {
+                        title: '区服名称',
+                        dataIndex: 'serverName',
+                        key: 'serverName',
+                        align: 'center',
+                        ellipsis: true,
+                        width: 100
+                    },
+                    {
+                        title: '区服ID',
+                        dataIndex: 'serverId',
+                        key: 'serverId',
+                        ellipsis: true,
+                        align: 'center',
+                        width: 70
+                    },
+                    {
+                        title: '系统',
+                        dataIndex: 'os',
+                        key: 'os',
+                        align: 'center',
+                        width: 70,
+                        render(value) {
+                            return value || '--'
+                        },
+                    },
+                    {
+                        title: '创建时间',
+                        dataIndex: 'createTime',
+                        key: 'createTime',
+                        align: 'center',
+                        width: 140,
+                        ellipsis: true,
+                        render(value) {
+                            return value || '--'
+                        },
+                    },
+                    {
+                        title: '更新时间',
+                        dataIndex: 'updateTime',
+                        key: 'updateTime',
+                        align: 'center',
+                        width: 140,
+                        ellipsis: true,
+                        render(value) {
+                            return value || '--'
+                        },
+                    },
+                    {
+                        title: '最近登录时间',
+                        dataIndex: 'lastLoginTime',
+                        key: 'lastLoginTime',
+                        align: 'center',
+                        width: 140,
+                        ellipsis: true,
+                        render(value) {
+                            return value || '--'
+                        },
+                    },
+                    {
+                        title: '最近充值时间',
+                        dataIndex: 'lastRechargeTime',
+                        key: 'lastRechargeTime',
+                        align: 'center',
+                        width: 140,
+                        ellipsis: true,
+                        render(value) {
+                            return value || '--'
+                        },
+                    },
+                ]}
+                rowKey={(record) => {
+                    return record.roleId + '_' + record.gameId + '_' + record.userId
+                }}
+                scroll={{ x: 1000 }}
+                dataSource={getSuspectedRoleDetailList?.data}
+                loading={getSuspectedRoleDetailList?.loading}
+                size="small"
+                bordered
+            />
+        </Modal>}
+    </>
+};
+
+export default SuspectedUser;

+ 48 - 8
src/pages/gsData/xjRoleGrade/tableConfig.tsx

@@ -2,6 +2,11 @@ import WidthEllipsis from "@/components/widthEllipsis"
 import LookRoleDetails from "@/pages/gameDataStatistics/player/role/lookRoleDetails"
 import { Space, Statistic } from "antd"
 import React from "react"
+import LoginIpDetails from "../roleIpMonitor/loginIpDetails"
+import { EyeOutlined } from "@ant-design/icons"
+import TongIpUser from "../roleIpMonitor/tongIpUser"
+import RegIpRoleDetails from "../roleIpMonitor/regIpRoleDetails"
+import SuspectedUser from "./suspectedUser"
 
 function columns12(assignHandle: (data: any) => void): { label: string, fieldSHow?: { label: string, saveField: string, defaultValue: any[], data: any[] }, data: any[] }[] {
 
@@ -58,7 +63,7 @@ function columns12(assignHandle: (data: any) => void): { label: string, fieldSHo
                     render: (a: string) => (<WidthEllipsis value={a} />)
                 },
                 {
-                    title: '等级上报时间距今', dataIndex: 'levelTimeDiff', label: '角色游戏数据', align: 'center', width: 120, default: 9,
+                    title: '等级上报时间距今', dataIndex: 'levelTimeDiff', label: '角色游戏数据', align: 'center', width: 140, default: 9,
                     render: (_: any, b: any) => {
                         if (b?.createTime) {
                             let a = (new Date().getTime() / 1000) - (new Date(b?.levelTime).getTime() / 1000)
@@ -76,7 +81,7 @@ function columns12(assignHandle: (data: any) => void): { label: string, fieldSHo
                     }
                 },
                 {
-                    title: '创角时间至今', dataIndex: 'createTimeDiff', label: '角色游戏数据', align: 'center', width: 120, default: 10,
+                    title: '创角时间至今', dataIndex: 'createTimeDiff', label: '角色游戏数据', align: 'center', width: 140, default: 10,
                     render: (_: any, b: any) => {
                         if (b?.createTime) {
                             let a = (new Date().getTime() / 1000) - (new Date(b?.createTime).getTime() / 1000)
@@ -92,17 +97,52 @@ function columns12(assignHandle: (data: any) => void): { label: string, fieldSHo
                             return '--'
                         }
                     }
+                },
+                {
+                    title: '角色注册IP', dataIndex: 'ip', label: '角色游戏数据', align: 'center', width: 110, default: 11,
+                    render: (a: string) => (<WidthEllipsis value={a} />)
+                },
+                {
+                    title: '角色登录IP数量', dataIndex: 'ipCount', label: '角色游戏数据', align: 'center', width: 65, sorter: true, default: 12,
+                    render: (a: number, b: any) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} suffix={<LoginIpDetails gameId={b.gameId} roleId={b.roleId} icon={<EyeOutlined />} />} />
+                },
+                {
+                    title: '同玩家角色数量', dataIndex: 'userRoleCount', label: '角色游戏数据', align: 'center', width: 65, sorter: true, default: 13,
+                    render: (a: number, b: any) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} suffix={<LookRoleDetails userId={b.userId} icon={<EyeOutlined />} />} />
+                },
+                {
+                    title: '角色同IP的玩家数量', dataIndex: 'userCount', label: '角色游戏数据', align: 'center', width: 70, sorter: true, default: 14,
+                    render: (a: number, b: any) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} suffix={<TongIpUser roleId={b.roleId} icon={<EyeOutlined />} />} />
+                },
+                {
+                    title: '同IP的角色数量', dataIndex: 'roleCount', label: '角色游戏数据', align: 'center', width: 70, sorter: true, default: 15,
+                    render: (a: number, b: any) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} suffix={<RegIpRoleDetails roleId={b.roleId} excludeUserType={0} icon={<EyeOutlined />} />} />
+                },
+                {
+                    title: '同IP的角色数量(排除同玩家)', dataIndex: 'ipRoleCountFilter', label: '角色游戏数据', align: 'center', width: 90, sorter: true, default: 16,
+                    render: (a: number, b: any) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} suffix={<RegIpRoleDetails roleId={b.roleId} excludeUserType={1} icon={<EyeOutlined />} />} />
+                },
+                {
+                    title: '疑似同玩家数量', dataIndex: 'suspectedCount', label: '角色游戏数据', align: 'center', width: 80, sorter: true, default: 17,
+                    render: (a: number, record: any) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} suffix={<SuspectedUser roleId={record.roleId} icon={<EyeOutlined />} />} />
+                },
+                {
+                    title: '同玩家IP的角色数量(排除同玩家)', dataIndex: 'roleUserIpCountFilter', label: '角色游戏数据', align: 'center', width: 100, sorter: true, default: 18,
+                    render: (a: number) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} />
+                },
+                {
+                    title: '角色所在玩家登录过的所有IP的统计数量', dataIndex: 'roleUserIpCount', label: '角色游戏数据', align: 'center', width: 100, sorter: true, default: 19,
+                    render: (a: number) => <Statistic value={a || 0} valueStyle={a > 1 ? { color: 'red' } : {}} />
                 }
-
             ]
         },
         {
             label: '客户管理操作',
             data: [
-                { title: 'GS', dataIndex: 'gsName', label: '客户管理操作', align: 'center', width: 80, default: 11, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
-                { title: '客服', dataIndex: 'customerServiceName', label: '客户管理操作', align: 'center', width: 80, default: 12, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
-                { title: '运营', dataIndex: 'operUserName', label: '客户管理操作', align: 'center', width: 80, default: 13, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
-                { title: '投手', dataIndex: 'putUserName', label: '客户管理操作', align: 'center', width: 80, default: 14, render: (a: string, b: any) => (<WidthEllipsis value={a} />) }
+                { title: 'GS', dataIndex: 'gsName', label: '客户管理操作', align: 'center', width: 80, default: 20, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '客服', dataIndex: 'customerServiceName', label: '客户管理操作', align: 'center', width: 80, default: 21, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '运营', dataIndex: 'operUserName', label: '客户管理操作', align: 'center', width: 80, default: 22, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '投手', dataIndex: 'putUserName', label: '客户管理操作', align: 'center', width: 80, default: 23, render: (a: string, b: any) => (<WidthEllipsis value={a} />) }
             ]
         },
         {
@@ -114,7 +154,7 @@ function columns12(assignHandle: (data: any) => void): { label: string, fieldSHo
                     align: 'center',
                     width: 70,
                     label: '操作',
-                    default: 15,
+                    default: 24,
                     render: (_: any, b: any) => {
                         return <Space>
                             <LookRoleDetails userId={b.userId} />

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

@@ -338,4 +338,28 @@ export async function updateBanIpApi(params: { ip: string, status: number }) {
         method: 'POST',
         data: params,
     });
+}
+
+
+/****************聊天记录******************/
+/**
+ * 获取游戏列表
+ * @returns 
+ */
+export async function getChatGameListApi() {
+    return request(api + `/manage/game/chat/game/list`, {
+        method: 'GET',
+    });
+}
+
+/**
+ * 获取聊天记录
+ * @param data 
+ * @returns 
+ */
+export async function getChatListApi(data: { pageNum: number, pageSize: number, supperGameId: number, roleId?: string, roleName?: string, chatStart?: string, chatEnd?: string }) {
+    return request(api + `/manage/game/chat/list`, {
+        method: 'POST',
+        data
+    });
 }

+ 12 - 0
src/services/gsData/index.ts

@@ -318,4 +318,16 @@ export async function getUserDetailListApi(data: { roleId: string }) {
         method: 'POST',
         data
     });
+}
+
+/**
+ * 查询疑似同玩家角色详情列表
+ * @param data 
+ * @returns 
+ */
+export async function getSuspectedRoleDetailListApi(data: { roleId: string }) {
+    return request(api + `/gameData/role/suspectedRoleDetailList`, {
+        method: 'POST',
+        data
+    });
 }