wjx 1 년 전
부모
커밋
d5f34d73de
45개의 변경된 파일1566개의 추가작업 그리고 645개의 파일을 삭제
  1. 19 0
      config/routerConfig.ts
  2. 2 0
      src/app.tsx
  3. 1 0
      src/assets/player.svg
  4. 11 1
      src/components/BaseTable/index.less
  5. 27 171
      src/components/BaseTable/index.tsx
  6. 167 10
      src/components/QueryForm/index.tsx
  7. 2 2
      src/components/QueryForm/intervalTime.tsx
  8. 1 1
      src/components/RightContent/AvatarDropdown.tsx
  9. 6 2
      src/components/VirtualTable/index.tsx
  10. 1 1
      src/pages/gameDataStatistics/adlist/monitor/tableConfig.tsx
  11. 5 4
      src/pages/gameDataStatistics/adlist/tencentMonitor/tableConfig.tsx
  12. 93 32
      src/pages/gameDataStatistics/components/TableData/index.tsx
  13. 0 402
      src/pages/gameDataStatistics/components/TableData/index1.tsx
  14. 49 0
      src/pages/gameDataStatistics/components/TableData/isVirtually.tsx
  15. 10 1
      src/pages/gameDataStatistics/extensionData/everyday/index.tsx
  16. 1 1
      src/pages/gameDataStatistics/extensionData/everyday/tableConfig.tsx
  17. 2 1
      src/pages/gameDataStatistics/gameData/active/index.tsx
  18. 10 1
      src/pages/gameDataStatistics/gameData/again/index.tsx
  19. 10 1
      src/pages/gameDataStatistics/gameData/everyday/index.tsx
  20. 5 2
      src/pages/gameDataStatistics/gameData/everyday/tableConfig.tsx
  21. 1 0
      src/pages/gameDataStatistics/gameData/flowingWater/index.tsx
  22. 1 1
      src/pages/gameDataStatistics/gameData/h5Recharge/h5BuyUser.tsx
  23. 1 1
      src/pages/gameDataStatistics/gameData/h5Recharge/h5NatureUser.tsx
  24. 1 0
      src/pages/gameDataStatistics/gameData/h5Recharge/index.tsx
  25. 1 0
      src/pages/gameDataStatistics/gameServer/serverData/index.tsx
  26. 10 1
      src/pages/gameDataStatistics/medium/gameEvery/index.tsx
  27. 10 1
      src/pages/gameDataStatistics/medium/pitcherEvery/index.tsx
  28. 10 1
      src/pages/gameDataStatistics/medium/promotionEvery/index.tsx
  29. 95 0
      src/pages/gameDataStatistics/order/details.tsx
  30. 12 1
      src/pages/gameDataStatistics/order/index.tsx
  31. 18 3
      src/pages/gameDataStatistics/order/tableConfig.tsx
  32. 65 0
      src/pages/gameDataStatistics/order/tableConfigRole.tsx
  33. 10 1
      src/pages/gameDataStatistics/pitcher/everyDay/index.tsx
  34. 10 1
      src/pages/gameDataStatistics/pitcher/everyDayGame/index.tsx
  35. 69 0
      src/pages/gameDataStatistics/player/list/exportH5Modal.tsx
  36. 46 0
      src/pages/gameDataStatistics/player/list/index.less
  37. 183 0
      src/pages/gameDataStatistics/player/list/index.tsx
  38. 82 0
      src/pages/gameDataStatistics/player/list/look.tsx
  39. 93 0
      src/pages/gameDataStatistics/player/list/tableConfig.tsx
  40. 127 0
      src/pages/gameDataStatistics/player/role/index.tsx
  41. 62 0
      src/pages/gameDataStatistics/player/role/tableConfig.tsx
  42. 0 1
      src/pages/gameDataStatistics/rankingList/gamer/index.tsx
  43. 18 0
      src/services/gameData/index.ts
  44. 18 0
      src/services/gameData/order.ts
  45. 201 0
      src/services/gameData/player.ts

+ 19 - 0
config/routerConfig.ts

@@ -279,6 +279,25 @@ const gameDataStatistics = {
                 },
             ]
         },
+        {
+            path: '/gameDataStatistics/player',
+            name: '玩家数据',
+            access: 'player',
+            routes: [
+                {
+                    path: '/gameDataStatistics/player/list',
+                    name: '玩家列表',
+                    access: 'list',
+                    component: './gameDataStatistics/player/list',
+                },
+                {
+                    path: '/gameDataStatistics/player/role',
+                    name: '玩家角色',
+                    access: 'role',
+                    component: './gameDataStatistics/player/role',
+                }
+            ]
+        },
         {
             path: '/gameDataStatistics/gameServer',
             name: '游戏区服',

+ 2 - 0
src/app.tsx

@@ -15,6 +15,7 @@ import { ReactComponent as NumberSvg } from '@/assets/number.svg'
 import { ReactComponent as GameSvg } from '@/assets/game.svg'
 import { ReactComponent as GameServerSvg } from '@/assets/gameServer.svg'
 import { ReactComponent as MediaSvg } from '@/assets/media.svg'
+import { ReactComponent as PlayerSvg } from '@/assets/player.svg'
 import versions from './utils/versions';
 
 
@@ -107,6 +108,7 @@ const IconMap = {
     game: <span role="img" aria-label="fund-view" className="anticon anticon-fund-view"><GameSvg /></span>,
     gameServer: <span role="img" aria-label="fund-view" className="anticon anticon-fund-view"><GameServerSvg /></span>,
     media: <span role="img" aria-label="fund-view" className="anticon anticon-fund-view"><MediaSvg /></span>,
+    player: <span role="img" aria-label="fund-view" className="anticon anticon-fund-view"><PlayerSvg /></span>,
     eye: <EyeOutlined />
 };
 //处理菜单

+ 1 - 0
src/assets/player.svg

@@ -0,0 +1 @@
+<svg viewBox="64 64 896 896" focusable="false" data-icon="fund-view" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M736 896H288c-160 0-288-128-288-288s128-288 288-288h480c134.4 0 256 137.6 256 288 0 160-128 288-288 288zM288 384c-121.6 0-224 99.2-224 224s99.2 224 224 224h448c121.6 0 224-99.2 224-224s-102.4-224-192-224H288z" fill="" p-id="4693"></path><path d="M256 480h64v256H256v-256z" fill="" p-id="4694"></path><path d="M160 576h256v64H160v-64zM544 256h-64V192c0-54.4 41.6-96 96-96v64c-19.2 0-32 12.8-32 32v64zM652.8 601.6c-12.8-12.8-32-12.8-44.8 0l-44.8-44.8c38.4-38.4 99.2-38.4 134.4 0l-44.8 44.8z" fill="" p-id="4695"></path><path d="M563.2 691.2c-19.2-19.2-28.8-41.6-28.8-67.2s9.6-51.2 28.8-67.2l44.8 44.8c-6.4 6.4-9.6 12.8-9.6 22.4 0 9.6 3.2 16 9.6 22.4l-44.8 44.8zM844.8 601.6c-12.8-12.8-32-12.8-44.8 0l-44.8-44.8c38.4-38.4 99.2-38.4 134.4 0l-44.8 44.8z" fill="" p-id="4696"></path><path d="M755.2 691.2c-19.2-19.2-28.8-41.6-28.8-67.2s9.6-51.2 28.8-67.2l44.8 44.8c-6.4 6.4-9.6 12.8-9.6 22.4 0 9.6 3.2 16 9.6 22.4l-44.8 44.8z" fill="" p-id="4697"></path></svg>

+ 11 - 1
src/components/BaseTable/index.less

@@ -12,12 +12,22 @@
 .BaseTable__row {
     border-bottom: 1px solid #e0e0e0;
 }
-
+.BaseTable__table-frozen-left .BaseTable__header-cell:first-child, .BaseTable__table-frozen-left .BaseTable__row-cell:first-child {
+    padding-left: 5px;
+}
+.BaseTable__table-frozen-right .BaseTable__header-cell:last-child, .BaseTable__table-frozen-right .BaseTable__row-cell:last-child {
+    padding-right: 5px;
+}
 .BaseTable__row-cell,
 .BaseTable__header-cell {
     border-right: 1px solid #e0e0e0;
+    padding: 2px 5px;
 }
 
 .BaseTable__row-cell > div {
     width: 100%;
+}
+
+.BaseTable__row--frozen > div {
+    font-weight: bold;
 }

+ 27 - 171
src/components/BaseTable/index.tsx

@@ -1,9 +1,9 @@
 import { useSize } from "ahooks";
-import React, { useRef, useState, useCallback, useEffect } from "react"
-import Table, { BaseTableProps, Column, ColumnShape, SortOrder } from 'react-base-table'
+import React, { useRef, useState, useEffect } from "react"
+import Table, { BaseTableProps, ColumnShape, SortOrder } from 'react-base-table'
 import 'react-base-table/styles.css'
 import './index.less'
-import { Empty, Pagination, Spin } from "antd";
+import { Empty, Pagination, Skeleton, Spin } from "antd";
 import { PaginationProps } from "antd/es/pagination";
 
 interface Props extends Omit<BaseTableProps, 'width'> {
@@ -32,180 +32,29 @@ const BaseTable: React.FC<Props> = ({ isPagination = true, pagination, width, he
         setOperate({ ...operate, pagination: { current: pagination?.current || 1, pageSize: pagination?.pageSize || pagination?.defaultPageSize || 20 } })
     }, [pagination?.current, pagination?.pageSize, pagination?.defaultPageSize])
 
-    // let columns: ColumnShape<any>[] = [
-    //     {
-    //         key: 'name',
-    //         title: 'Name',
-    //         dataKey: 'name',
-    //         width: 150,
-    //         resizable: true,
-    //         sortable: true,
-    //         frozen: Column.FrozenDirection.LEFT,
-    //     },
-    //     {
-    //         key: 'score',
-    //         title: 'Score',
-    //         dataKey: 'score.math',
-    //         width: 60,
-    //         align: Column.Alignment.CENTER,
-    //         sortable: false,
-    //     },
-    //     {
-    //         key: 'gender',
-    //         title: '♂♀',
-    //         dataKey: 'gender',
-    //         width: 60,
-    //         align: Column.Alignment.CENTER,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'birthday',
-    //         title: 'Birthday',
-    //         dataKey: 'birthday',
-    //         width: 100,
-    //         align: Column.Alignment.RIGHT,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'email',
-    //         title: 'Email',
-    //         dataKey: 'email',
-    //         width: 200,
-    //         resizable: true,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'country',
-    //         title: 'Country',
-    //         dataKey: 'country',
-    //         width: 100,
-    //         resizable: true,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'address',
-    //         title: 'Address',
-    //         dataKey: 'address.street',
-    //         width: 200,
-    //         resizable: true,
-    //     },
-    //     {
-    //         key: 'name1',
-    //         title: 'Name',
-    //         dataKey: 'name',
-    //         width: 150,
-    //         resizable: true,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'name2',
-    //         title: 'Name',
-    //         dataKey: 'name',
-    //         width: 150,
-    //         resizable: true,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'name3',
-    //         title: 'Name',
-    //         dataKey: 'name',
-    //         width: 150,
-    //         resizable: true,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'name4',
-    //         title: 'Name',
-    //         dataKey: 'name',
-    //         width: 150,
-    //         resizable: true,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'name5',
-    //         title: 'Name',
-    //         dataKey: 'name',
-    //         width: 150,
-    //         resizable: true,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'name6',
-    //         title: 'Name',
-    //         dataKey: 'name',
-    //         width: 150,
-    //         resizable: true,
-    //         sortable: true,
-    //     },
-    //     {
-    //         key: 'description',
-    //         title: 'Description',
-    //         dataKey: 'description',
-    //         width: 200,
-    //         resizable: true,
-    //         sortable: true,
-    //         cellRenderer: ({ rowData, cellData }: any) => (
-    //             <a
-    //                 onClick={() => {
-    //                     console.log(rowData, cellData)
-    //                 }}
-    //             >
-    //                 Remove
-    //             </a>
-    //         ),
-    //     },
-    //     // {
-    //     //     title: '操作',
-    //     //     key: 'action',
-    //     //     width: 100,
-    //     //     align: Column.Alignment.CENTER,
-    //     //     frozen: Column.FrozenDirection.RIGHT,
-
-    //     //     cellRenderer: ({ rowData, cellData }: any) => (
-    //     //         <button
-    //     //             onClick={() => {
-    //     //                 console.log(rowData, cellData)
-    //     //             }}
-    //     //         >
-    //     //             Remove
-    //     //         </button>
-    //     //     ),
-    //     // },
-    // ]
-
-    // const defaultData = Array.from({ length: 10000 }, (_, key) => ({
-    //     id: key,
-    //     name: 'row' + key,
-    //     gender: '男',
-    //     score: {
-    //         math: 30,
-    //     },
-    //     birthday: 222,
-    //     attachments: 111,
-    //     email: '7787@qq.com',
-    //     country: '22',
-    //     description: '11',
-    // }));
-
     let tableProps: BaseTableProps = {
         fixed: fixed || true,  // 是否开启 列的宽度是固定的还是灵活的
-        // columns,               // 表的列
-        // data: defaultData,     // 表数据
         width: width || size.width || 900,  // 表固定宽度
-        height: height || 600,              // 表固定高度
+        height: height || 700,              // 表固定高度
     }
     if (estimatedRowHeight) {
         tableProps.estimatedRowHeight = estimatedRowHeight   // 灵活高度
+        tableProps.rowHeight = estimatedRowHeight() || rowHeight || 26
         if (props?.data?.length < 10) {
-            tableProps.maxHeight = 600
+            tableProps.maxHeight = 700
         }
     } else {
         tableProps.rowHeight = rowHeight || 26               // 固定高度
         if (props?.data?.length < 20) {
-            tableProps.maxHeight = 600
+            tableProps.maxHeight = 700
         }
     }
-
+    if (props.frozenData?.length > 0 && tableProps.rowHeight && tableProps.height) {
+        tableProps.height = tableProps.height + tableProps.rowHeight
+    }
+    if (tableProps.rowHeight && tableProps.rowHeight < 26) {
+        tableProps.rowHeight = 26
+    }
     if (columns) {
         let totalWidth = columns.reduce((pre: number, cur: { width: number; }) => {
             pre += cur.width
@@ -214,7 +63,7 @@ const BaseTable: React.FC<Props> = ({ isPagination = true, pagination, width, he
         if (totalWidth < tableProps.width) {
             let length = columns?.length || 1
             let diffW = (tableProps.width - totalWidth - 6) / length
-
+            tableProps.fixed = false
             columns = columns.map((item: any) => {
                 return { ...item, width: item.width + diffW }
             })
@@ -230,7 +79,7 @@ const BaseTable: React.FC<Props> = ({ isPagination = true, pagination, width, he
     tableProps = { ...tableProps, ...props }
 
     // 排序操作
-    const onColumnSort = useCallback((sortBy: { column: ColumnShape<unknown>, key: React.Key, order: SortOrder }) => {
+    const onColumnSort = (sortBy: { column: ColumnShape<unknown>, key: React.Key, order: SortOrder }) => {
         const { key, order } = sortBy;
         let newOperate = JSON.parse(JSON.stringify(operate))
         const sortData = newOperate?.sortData
@@ -245,7 +94,12 @@ const BaseTable: React.FC<Props> = ({ isPagination = true, pagination, width, he
         }
         setOperate(newOperate)
         onChange?.({ ...newOperate, sortData: newOperate?.sortData ? { ...newOperate.sortData, field: newOperate.sortData.key, order: newOperate.sortData.order === 'asc' ? 'ascend' : 'descend' } : undefined })
-    }, [operate])
+    }
+
+    // const rowRenderer = ({ isScrolling, cells }: any) => {
+    //     if (isScrolling) return <Skeleton.Button active size="small" block />
+    //     return cells
+    // }
 
     return <Spin spinning={loading}>
         <div ref={ref}>
@@ -255,16 +109,18 @@ const BaseTable: React.FC<Props> = ({ isPagination = true, pagination, width, he
                 emptyRenderer={<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
                 sortBy={operate?.sortData}
                 onColumnSort={onColumnSort}
+                // useIsScrolling
+                // rowRenderer={rowRenderer}
                 {...tableProps}
             />
             {isPagination && <div className="pagination">
-                <Pagination 
+                <Pagination
                     onChange={(page: number, pageSize: number) => {
-                        setOperate({...operate, pagination: { current: page, pageSize }});
+                        setOperate({ ...operate, pagination: { current: page, pageSize } });
                         onChange?.({ ...operate, pagination: { current: page, pageSize }, sortData: operate?.sortData ? { ...operate.sortData, field: operate.sortData.key, order: operate.sortData.order === 'asc' ? 'ascend' : 'descend' } : undefined });
                         (tableRef.current as any)?.scrollToTop(0)
-                    }} 
-                    {...pagination} 
+                    }}
+                    {...pagination}
                 />
             </div>}
         </div>

+ 167 - 10
src/components/QueryForm/index.tsx

@@ -2,7 +2,7 @@ import { Button, Col, DatePicker, Form, Input, Radio, Row, Select, Space } from
 import React, { useEffect, useState } from "react"
 import moment from "moment"
 import { useAjax } from "@/Hook/useAjax"
-import { getAllOfOwnerUserApi, getChannelChoiceListApi, getGameChoiceListApi, getGameChoiceParentListType1Api, getPayListApi, getSubUserWithSelfListApi, getTtAllUserListApi, getUserSystemTypeChoiceListApi } from "@/services/gameData"
+import { getAllOfOwnerUserApi, getChannelChoiceListApi, getGameChoiceListApi, getCpChoiceListApi, getGameChoiceParentListType1Api, getPayListApi, getSubUserWithSelfListApi, getTtAllUserListApi, getUserSystemTypeChoiceListApi, getUserVipLevelChoiceListApi } from "@/services/gameData"
 import { ActiveEnum, PayStatus, TYPE, gameClassifyEnum } from "./const"
 import { ADSTATUSEnum as ADSTTTATUSEnum } from "@/pages/gameDataStatistics/adlist/monitor/const"
 import { ADSTATUSEnum } from "@/pages/gameDataStatistics/adlist/tencentMonitor/const"
@@ -33,6 +33,10 @@ interface Props {
     isCreateDay?: {
         ranges?: any
     }
+    /** 是否开启 角色创建日期 搜索 */
+    isCreateRoleDay?: {
+        ranges?: any
+    }
     /** 是否开启 操作设备 搜索 */
     isDevice?: boolean
     /** 是否开启 注册游戏名 搜索 */
@@ -146,8 +150,30 @@ interface Props {
     isPayIntervalTime?: {
         tips?: string
     }
+    /** 是否开启 充值到支付的间隔时间 搜索 */
+    isRoleCount?: {
+        tips?: string
+    }
     /** 是否开启 留存数据的类型 搜索 */
     isActiveTypes?: boolean
+    /** 是否开启 玩家昵称 搜索 */
+    isNickname?: boolean
+    /** 是否开启 绑定手机 搜索 */
+    isMobile?: boolean
+    /** 是否开启 注册IP 搜索 */
+    isRegIp?: boolean
+    /** 是否开启 是否实名认证 搜索 */
+    isIsAuth?: boolean
+    /** 是否开启 是否绑定手机 搜索 */
+    isIsBindMobile?: boolean
+    /** 是否开启 是否充值 搜索 */
+    isIsRecharge?: boolean
+    /** 是否开启 玩家状态 搜索 */
+    isUserStatus?: boolean
+    /** 是否开启 是否创角 搜索 */
+    isCreateRole?: boolean
+    /** 是否开启 角色VIP 搜索 */
+    isVipLevel?: boolean
 }
 /**
  * 游戏数据系统 请求参数
@@ -160,7 +186,7 @@ const QueryForm: React.FC<Props> = (props) => {
         onChange, initialValues, isSource, isAccount, isAccountId, isCompanyId, isAgentKey, isAgentName, isCpId, isCpName, isCpOrderId, isCpStatus, isCreateDay, isDevice, isGameName, isRechargeGameName, isGameId, isGameIds, isOrderGameId, isGameRoleId,
         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
+        payTimeDay, placeAnOrderDay, isPayIntervalTime, isActiveTypes, isNickname, isMobile, isRegIp, isIsAuth, isIsBindMobile, isIsRecharge, isUserStatus, isCreateRole, isRoleCount, isVipLevel, isCreateRoleDay
     } = props
     const [form] = Form.useForm()
     const [accountList, setAccountList] = useState<any[]>([])
@@ -173,8 +199,9 @@ const QueryForm: React.FC<Props> = (props) => {
     const getChannelChoiceList = useAjax(() => getChannelChoiceListApi())
     const getGameChoiceParentListType1 = useAjax(() => getGameChoiceParentListType1Api())
     const getUserSystemTypeChoiceList = useAjax(() => getUserSystemTypeChoiceListApi())
+    const getCpChoiceList = useAjax(() => getCpChoiceListApi())
     const getPayList = useAjax(() => getPayListApi())
-
+    const getUserVipLevelChoiceList = useAjax(() => getUserVipLevelChoiceListApi())
     /**************************/
 
     useEffect(() => {
@@ -206,6 +233,18 @@ const QueryForm: React.FC<Props> = (props) => {
         }
     }, [isGameId, isGameIds, isOrderGameId, isParentId])
 
+    useEffect(() => {
+        if (isCpId) {
+            getCpChoiceList.run()
+        }
+    }, [isCpId])
+
+    useEffect(() => {
+        if (isVipLevel) {
+            getUserVipLevelChoiceList.run()
+        }
+    }, [isVipLevel])
+
     /** 投手列表 */
     useEffect(() => {
         if (isSysUserId) {
@@ -392,7 +431,6 @@ const QueryForm: React.FC<Props> = (props) => {
                     style={{ width: 140 }}
                     allowClear
                     placeholder={'广告账号'}
-                    dropdownMatchSelectWidth={false}
                     filterOption={(input, option) =>
                         (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
                     }
@@ -432,8 +470,7 @@ const QueryForm: React.FC<Props> = (props) => {
                         (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
                     }
                 >
-                    <Select.Option value={'1'}>CP001</Select.Option>
-                    <Select.Option value={'2'}>CP002</Select.Option>
+                    {getCpChoiceList?.data?.map((item: { id: React.Key | null | undefined; cpName: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined }) => <Select.Option value={item.id} key={item.id}>{item.cpName}</Select.Option>)}
                 </Select>
             </Form.Item></Col>}
             {/* CP方订单ID */}
@@ -479,7 +516,7 @@ const QueryForm: React.FC<Props> = (props) => {
                 <Select
                     maxTagCount={1}
                     showSearch
-                    style={{ minWidth: 140 }}
+                    style={{ width: 140 }}
                     allowClear
                     dropdownMatchSelectWidth={false}
                     placeholder={'请选择广告状态'}
@@ -494,7 +531,7 @@ const QueryForm: React.FC<Props> = (props) => {
                 <Select
                     maxTagCount={1}
                     showSearch
-                    style={{ minWidth: 140 }}
+                    style={{ width: 140 }}
                     allowClear
                     dropdownMatchSelectWidth={false}
                     placeholder={'请选择广告状态'}
@@ -795,7 +832,118 @@ const QueryForm: React.FC<Props> = (props) => {
                 </Select>
             </Form.Item></Col>}
 
-            {/* 用户id */}
+            {/* 玩家昵称 */}
+            {isNickname && <Col><Form.Item name='nickname'>
+                <Input placeholder="玩家昵称" allowClear style={{ width: 140 }} />
+            </Form.Item></Col>}
+
+            {/* 绑定手机 */}
+            {isMobile && <Col><Form.Item name='mobile'>
+                <Input placeholder="绑定手机" allowClear style={{ width: 140 }} />
+            </Form.Item></Col>}
+
+            {/* 注册IP */}
+            {isRegIp && <Col><Form.Item name='regIp'>
+                <Input placeholder="注册IP" allowClear style={{ width: 140 }} />
+            </Form.Item></Col>}
+
+            {/* 是否充值 */}
+            {isIsRecharge && <Col><Form.Item name='isRecharge'>
+                <Select
+                    showSearch
+                    style={{ width: 98 }}
+                    allowClear
+                    placeholder={'是否充值'}
+                    filterOption={(input, option) =>
+                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                >
+                    <Select.Option value={false}>否</Select.Option>
+                    <Select.Option value={true}>是</Select.Option>
+                </Select>
+            </Form.Item></Col>}
+
+            {/* 实名状态 */}
+            {isIsAuth && <Col><Form.Item name='isAuth'>
+                <Select
+                    showSearch
+                    allowClear
+                    style={{ width: 98 }}
+                    placeholder={'实名状态'}
+                    filterOption={(input, option) =>
+                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                >
+                    <Select.Option value={false}>未实名</Select.Option>
+                    <Select.Option value={true}>已实名</Select.Option>
+                </Select>
+            </Form.Item></Col>}
+
+            {/* 是否绑定手机 */}
+            {isIsBindMobile && <Col><Form.Item name='isBindMobile'>
+                <Select
+                    showSearch
+                    allowClear
+                    style={{ width: 126 }}
+                    placeholder={'是否绑定手机'}
+                    filterOption={(input, option) =>
+                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                >
+                    <Select.Option value={false}>未绑定</Select.Option>
+                    <Select.Option value={true}>已绑定</Select.Option>
+                </Select>
+            </Form.Item></Col>}
+
+            {/* 玩家状态 */}
+            {isUserStatus && <Col><Form.Item name='userStatus'>
+                <Select
+                    showSearch
+                    allowClear
+                    style={{ width: 98 }}
+                    placeholder={'玩家状态'}
+                    filterOption={(input, option) =>
+                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                >
+                    <Select.Option value={'1'}>试玩</Select.Option>
+                    <Select.Option value={'2'}>正常</Select.Option>
+                    <Select.Option value={'3'}>冻结</Select.Option>
+                </Select>
+            </Form.Item></Col>}
+            
+            {/* 是否创角 */}
+            {isCreateRole && <Col><Form.Item name='createRole'>
+                <Select
+                    showSearch
+                    allowClear
+                    style={{ width: 98 }}
+                    placeholder={'是否创角'}
+                    filterOption={(input, option) =>
+                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                >
+                    <Select.Option value={true}>是</Select.Option>
+                    <Select.Option value={false}>否</Select.Option>
+                </Select>
+            </Form.Item></Col>}
+
+            {/* vip等级 */}
+            {isCreateRole && <Col><Form.Item name='vipLevel'>
+                <Select
+                    showSearch
+                    allowClear
+                    style={{ width: 98 }}
+                    placeholder={'角色VIP'}
+                    filterOption={(input, option) =>
+                        (option?.children as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    }
+                >
+                    {getUserVipLevelChoiceList?.data?.map((item: { vipLevel: React.Key | null | undefined; vipLevelName: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined }) => <Select.Option value={item.vipLevel} key={item.vipLevel}>{item.vipLevelName}</Select.Option>)}
+                </Select>
+            </Form.Item></Col>}
+
+            {/* 操作系统 */}
             {isOs && <Col><Form.Item name='os'>
                 <Select
                     maxTagCount={1}
@@ -813,7 +961,7 @@ const QueryForm: React.FC<Props> = (props) => {
 
             {/* 用户注册日期搜索 */}
             {isRegDay && <Col><Form.Item name='regDay'>
-                <DatePicker.RangePicker style={{ width: 230 }} placeholder={['用户注册开始日期', '用户注册结束日期']} {...isRegDay} />
+                <DatePicker.RangePicker style={{ width: 230 }} placeholder={['注册开始日期', '注册结束日期']} {...isRegDay} />
             </Form.Item></Col>}
 
             {/* 消耗日期 搜索 */}
@@ -849,6 +997,11 @@ const QueryForm: React.FC<Props> = (props) => {
                 <DatePicker.RangePicker style={{ width: 230 }} placeholder={['开服开始日期', '开服结束日期']} {...isServerDay} />
             </Form.Item></Col>}
 
+            {/* 角色创建日期搜索 */}
+            {isCreateRoleDay && <Col><Form.Item name='createRoleDay'>
+                <DatePicker.RangePicker style={{ width: 230 }} placeholder={['角色创建开始日期', '角色创建结束日期']} {...isCreateRoleDay} />
+            </Form.Item></Col>}
+
             {/* 单个充值日期搜索 */}
             {isRechargeDate && <Col><Form.Item name='rechargeDate'>
                 <DatePicker placeholder={'充值日期'} />
@@ -859,6 +1012,10 @@ const QueryForm: React.FC<Props> = (props) => {
                 <IntervalTime {...isPayIntervalTime} />
             </Form.Item></Col>}
 
+            {isRoleCount && <Col><Form.Item name='roleCount'>
+                <IntervalTime {...isRoleCount} />
+            </Form.Item></Col>}
+
             <Col>
                 <Space>
                     <Button type="primary" htmlType="submit">搜索</Button>

+ 2 - 2
src/components/QueryForm/intervalTime.tsx

@@ -34,9 +34,9 @@ const IntervalTime: React.FC<Props> = ({ value = [undefined, undefined], onChang
     }
 
     return <Space>
-        <InputNumber value={data[0]} style={{ width: 110 }} min={0} placeholder="最小间隔时间" onChange={(num) => handleOk(num, 0)} />
+        <InputNumber value={data[0]} style={{ width: 90 }} min={0} placeholder="最小间隔" onChange={(num) => handleOk(num, 0)} />
         ~
-        <InputNumber value={data[1]} style={{ width: 110 }} min={0} placeholder="最大间隔时间" onChange={(num) => handleOk(num, 1)} />
+        <InputNumber value={data[1]} style={{ width: 90 }} min={0} placeholder="最大间隔" onChange={(num) => handleOk(num, 1)} />
         {tips && <Tooltip title={tips}>
             <QuestionCircleOutlined />
         </Tooltip>}

+ 1 - 1
src/components/RightContent/AvatarDropdown.tsx

@@ -40,7 +40,7 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
   const { copy } = useCopy()
   const selectCompany = useAjax((companyId: number) => selectCompanyApi(companyId), { formatResult: true })
   const { initialState, setInitialState } = useModel('@@initialState');
-  const { edit, modifyPassword } = useModel('useOperating.useUser')
+  const { modifyPassword } = useModel('useOperating.useUser')
   const [visible, setVisible] = useState<boolean>(false)
   const [oldPassWord, setOldPassWord] = useState<string>('')
   const [passWord, setPassWord] = useState<string>('')

+ 6 - 2
src/components/VirtualTable/index.tsx

@@ -1,4 +1,4 @@
-import React, { useEffect, useRef, useState } from "react";
+import React, { useEffect, useMemo, useRef, useState } from "react";
 import "antd/dist/antd.css";
 import "./index.less";
 import { Spin, Table, Tag } from "antd";
@@ -166,6 +166,10 @@ const VTable = <RecordType extends object>(props: Props<RecordType>) => {
         );
     };
 
+    const a = useMemo(() => {
+        return <div>22</div>
+    }, [columnsRef.current])
+
     return <Spin style={{ width: '100%' }} spinning={loading}>
         <ResizeObserver
             onResize={({ width }) => {
@@ -261,7 +265,7 @@ const columns: ColumnsType<any> = [
 
 const data = Array.from({ length: 100 }, (_, key) => ({
     key,
-    dd: "啊大大撒1111"
+    dd: "啊大大撒1111啊大大阿三打撒"
 }));
 
 

+ 1 - 1
src/pages/gameDataStatistics/adlist/monitor/tableConfig.tsx

@@ -127,7 +127,7 @@ function columns12(dayHandle: (data: any) => void): { label: string, fieldSHow?:
                 },
                 {
                     title: '广告ID', dataIndex: 'promotionId', label: '广告信息', align: 'center', width: 90, default: 5,
-                    render: (a: string, b: any) => (<a><WidthEllipsis value={a} /></a>)
+                    render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />)
                 },
                 {
                     title: '项目名称', dataIndex: 'projectName', label: '广告信息', align: 'center', width: 130,

+ 5 - 4
src/pages/gameDataStatistics/adlist/tencentMonitor/tableConfig.tsx

@@ -127,7 +127,7 @@ function columns12(dayHandle: (data: any) => void): { label: string, fieldSHow?:
                 },
                 {
                     title: '广告ID', dataIndex: 'promotionId', label: '广告信息', align: 'center', width: 90, default: 5,
-                    render: (a: string, b: any) => (<a onClick={() => { dayHandle(b) }}><WidthEllipsis value={a} /></a>)
+                    render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />)
                 },
                 {
                     title: '项目名称', dataIndex: 'projectName', label: '广告信息', align: 'center', width: 130,
@@ -228,7 +228,7 @@ function columns12(dayHandle: (data: any) => void): { label: string, fieldSHow?:
                     render: (a: any) => <Statistic value={a || 0} />
                 },
                 {
-                    title: '小游戏注册率', dataIndex: 'miniGameRegisterRate', label: '广告媒体端数据', align: 'center', className: "adDataBackColorClass", width: 80, sorter: true, default: 19,
+                    title: '小游戏注册率', dataIndex: 'miniGameRegisterRate', label: '广告媒体端数据', align: 'center', className: "adDataBackColorClass", width: 95, sorter: true, default: 19,
                     render: (a: number) => <Statistic value={a ? a * 100 : 0} precision={2} valueStyle={!a ? {} : a >= 1 ? { color: 'red' } : { color: '#0f990f' }} suffix="%" />
                 },
                 {
@@ -587,7 +587,7 @@ function columns12(dayHandle: (data: any) => void): { label: string, fieldSHow?:
             label: '操作',
             data: [
                 {
-                    title: '操作', dataIndex: 'cz', label: '操作', align: 'center', width: 170, default: 41,
+                    title: '操作', dataIndex: 'cz', label: '操作', align: 'center', width: 150, default: 41,
                     render: (_: number, b: any) => {
                         if (b?.accountName === '总计') return '--'
                         return <Space>
@@ -596,7 +596,8 @@ function columns12(dayHandle: (data: any) => void): { label: string, fieldSHow?:
                                 b?.accountType === 'BYTE' ? <a onClick={() => {
                                     window.open(`https://ad.oceanengine.com/superior/promote-manage/ad?aadvid=${b?.accountId}&searchInput=%2522${b?.promotionId}%2522&searchType=%25229%2522`)
                                 }}>头条广告</a> : <a onClick={() => {
-                                    window.open(`https://ad.qq.com/atlas/${b?.accountId}/admanage/adgroup?query={%22operation_status%22:[%22CALCULATE_STATUS_EXCLUDE_DEL%22],%22system_status%22:[],%22search_name%22:%22${b.promotionId}%22}`)
+                                    window.open(`https://ad.qq.com/atlas/${b?.accountId}/admanage/adgroup?tab=adgroup&query={%22operation_status%22:[%22CALCULATE_STATUS_EXCLUDE_DEL%22],%22search_name%22:%22${b.promotionId}%22}`)
+                                
                                 }}>腾讯广告</a>
                             }
                         </Space>

+ 93 - 32
src/pages/gameDataStatistics/components/TableData/index.tsx

@@ -1,13 +1,15 @@
 import CustomListModel from '@/components/CustomList'
 import Tables from '@/components/Tables'
-import TableBase from '@/components/Tables/index1'
 import { FullscreenExitOutlined, FullscreenOutlined, QuestionCircleOutlined, RedoOutlined, SearchOutlined, SettingOutlined } from '@ant-design/icons'
-import { useDebounceFn, useFullscreen, useThrottleFn } from 'ahooks'
-import { Button, Card, Col, Row, Space, Tooltip, } from 'antd'
+import { useDebounceFn, useFullscreen, useThrottleFn, useUpdateEffect } from 'ahooks'
+import { Button, Card, Col, Row, Space, Tag, Tooltip, } from 'antd'
 import React, { useEffect, useRef, useState, useCallback } from 'react'
 import style from './index.less'
 import moment from 'moment'
 import lodash from 'lodash';
+import BaseTable from '@/components/BaseTable'
+import { getBaseTableColumn } from '@/components/BaseTable/utils'
+import IsVirtually from './isVirtually'
 
 interface Prosp {
     isZj?: boolean,//是否查总计
@@ -46,6 +48,9 @@ interface Prosp {
         field?: string,
         order?: "descend" | "ascend"
     }
+    estimatedRowHeight?: number | (() => number)
+    headerHeight?: number
+    isVirtually?: boolean
 }
 
 export const version = '1.0.0'
@@ -53,7 +58,7 @@ export const version = '1.0.0'
 function TableData(props: Prosp) {
 
     /*************************/
-    const { isZj, totalData, scroll, title, dataSource, expandedRowRender, sortData, className, rowClassName, leftChild, page = undefined, pageSize = undefined, size = 'small', total = 0, onChange, config, configName, ajax, fixed = { left: 0, right: 1 }, summary } = props
+    const { isZj, totalData, scroll, title, dataSource, expandedRowRender, isVirtually = true, sortData, headerHeight, className, rowClassName, leftChild, page = undefined, pageSize = undefined, size = 'small', total = 0, onChange, config, configName, ajax, fixed = { left: 0, right: 1 }, summary, estimatedRowHeight } = props
     const [visible, setVisible] = useState<boolean>(false)
     const [isFullscreen, setIsFullscreen] = useState<boolean>(true)
     const [oldSelectData, setoldSelectData] = useState<any[]>([])
@@ -86,6 +91,7 @@ function TableData(props: Prosp) {
             }
         }
     }, [originalColumns, sortData])
+    
 
     const { run: runSet } = useThrottleFn((newArr, newConfig, fixedData) => {
         console.log('设置配置改变重新赋值')
@@ -134,22 +140,6 @@ function TableData(props: Prosp) {
                 }
             })
             setOriginalColumns(c)
-            // setNewColumns(c)
-            // setNewColumns(newArr.map((newItem: any, index: number) => {
-            //     let oldItem = newConfig.find((c: { dataIndex: any }) => c.dataIndex === newItem.dataIndex)
-            //     if (newItem?.width !== oldItem?.width) {
-            //         oldItem.width = newItem?.width
-            //     }
-            //     if (index < Number(fixedData.left)) {//设置左悬浮
-            //         oldItem['fixed'] = 'left'
-            //     } else if (index > (newArr?.length - Number(fixedData.right) - 1)) {//设置右悬浮
-            //         oldItem['fixed'] = 'right'
-            //     } else {
-            //         oldItem['fixed'] = false
-            //     }
-            //     let { label, default: a, ...ite } = oldItem
-            //     return ite
-            // }))
         }
     }, { wait: 500 });
     /**重组选中的字段 */
@@ -197,10 +187,16 @@ function TableData(props: Prosp) {
         }
     }, [selectData, oldSelectData, dataSource, oldFixed, configName, config, timer])
 
-    const { run: runResize } = useDebounceFn((columns) => {
+    const { run: runResize } = useDebounceFn((columns, type: string) => {
         if (configName) {
             let newSelectData = selectData?.selectData?.map((item, index) => {
-                item['width'] = columns[index]['width']
+                if (type === 'vir') {
+                    if (item.dataIndex === columns.key) {
+                        item['width'] = Math.ceil(columns['width'])
+                    }
+                } else {
+                    item['width'] = columns[index]['width']
+                }
                 return item
             })
             localStorage.setItem(`myAdMonitorConfig${version}_` + configName, JSON.stringify(newSelectData))
@@ -208,8 +204,8 @@ function TableData(props: Prosp) {
     }, { wait: 100 });
 
     //拖动宽度设置设置保存
-    const handelResize = useCallback((columns: any) => {
-        runResize(columns)
+    const handelResize = useCallback((columns: any, type: string) => {
+        runResize(columns, type)
     }, [configName, selectData])
 
     const header = <Col span={24}>
@@ -279,17 +275,47 @@ function TableData(props: Prosp) {
                 headStyle={{ textAlign: 'left' }}
                 bodyStyle={{ padding: '5px 10px' }}
             >
-                <div style={{ textAlign: 'center', fontWeight: 'bold', padding: '4px 6px 6px', fontSize: 16, marginBottom: 4 }}>{title}</div>
+                <div style={{ textAlign: 'center', fontWeight: 'bold', padding: '4px 6px 6px', fontSize: 16, marginBottom: 4, position: 'relative' }}>
+                    {title}
+                    {isVirtually && <IsVirtually title={title} />}
+                </div>
                 <Row gutter={[0, 16]}>
                     {header}
                     <Tab {...{ size, newColumns, handelResize, className, isZj, totalData, rowClassName, scroll, isFull, page, pageSize, dataSource, onChange, expandedRowRender, total, ajax, summary }} />
                 </Row>
             </Card>
         </Col>
+    </Row>
+    const content1 = <Row gutter={[0, 20]} ref={ref} style={isFull ? { background: '#fff' } : {}}>
+        {/**table */}
+        <Col span={24}>
+            <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' }}>
+                    {title}
+                    {isVirtually && <IsVirtually title={title} />}
+                </div>
+                <Row gutter={[0, 16]}>
+                    {header}
+                    <Tab1 {...{ size, newColumns, className, handelResize, headerHeight, page, pageSize, totalData, dataSource, onChange, total, ajax, estimatedRowHeight }} />
+                </Row>
+            </Card>
+        </Col>
     </Row >
-    return <>
-        {content}
-    </>
+
+    const tableNames = localStorage.getItem('TABLENAMES')
+    if (tableNames && title && tableNames.split(',').includes(title)) {
+        return <>
+            {content1}
+        </>
+    } else {
+        return <>
+            {content}
+        </>
+    }
 }
 
 /**表格 */
@@ -313,7 +339,6 @@ const Tab = React.memo((props: any) => {
         if (isZj) {
             document.querySelector(`.content_table_body_${ran} .ant-table-body`)?.addEventListener('scroll', contentBodyScroll);
             document.querySelector(`.header_table_body_${ran} .ant-table-body`)?.addEventListener('scroll', headerBodyScroll);
-            // document.querySelectorAll('.content_table_body .ant-table-body')
         }
         () => {
             if (isZj) {
@@ -339,7 +364,7 @@ const Tab = React.memo((props: any) => {
                     loading={ajax?.loading}
                     className={`all_table header_table_body header_table_body_${ran} ${className ? className : ''}`}
                     sortDirections={['ascend', 'descend', null]}
-                    handelResize={((columns: any) => handelResize(columns))}
+                    handelResize={((columns: any) => handelResize(columns, 'antd'))}
                     onChange={(pagination: any, filters: any, sorter: any) => onChange && onChange({ pagination, filters, sortData: sorter })}
                 />
             }
@@ -360,10 +385,46 @@ const Tab = React.memo((props: any) => {
                 total={total}
                 loading={ajax?.loading}
                 defaultPageSize={20}
-                handelResize={((columns: any) => handelResize(columns))}
+                handelResize={((columns: any) => handelResize(columns, 'antd'))}
                 summary={summary}
             />
-            
+
+        </div>
+    </Col >
+})
+
+const Tab1 = React.memo((props: any) => {
+    const { size, newColumns, className, handelResize, page, pageSize, headerHeight = 65, totalData, dataSource, onChange, total, ajax, estimatedRowHeight } = props
+    let ww = document.body.clientWidth < 415
+
+    return < Col span={24} >
+        <div className={`${style[size]} ${className ? style[className] : ''} `}>
+            <BaseTable
+                columns={getBaseTableColumn(newColumns)}
+                data={dataSource}
+                loading={ajax?.loading}
+                onColumnResizeEnd={({ column }: any) => handelResize(column, 'vir')}
+                onChange={(data) => onChange?.(data)}
+                estimatedRowHeight={estimatedRowHeight}
+                frozenData={totalData}
+                headerHeight={headerHeight}
+                pagination={
+                    {
+                        size: 'small',
+                        total: total || 0,//总共多少条数据,服务器给,设置后分页自动计算页数
+                        current: page,//当前页数,需state控制配合翻页
+                        pageSize: pageSize,
+                        defaultCurrent: 1,//默认初始的当前页数
+                        defaultPageSize: 20,//默认初始的每页条数
+                        pageSizeOptions: ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100'],
+                        showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
+                        showSizeChanger: true, //手动开启条数筛选器,默认超过50条开启
+                        simple: ww ? true : false,//开启简单分页
+                        hideOnSinglePage: false,//只有一页数据隐藏分页
+                        showLessItems: true
+                    }
+                }
+            />
         </div>
     </Col >
 })

+ 0 - 402
src/pages/gameDataStatistics/components/TableData/index1.tsx

@@ -1,402 +0,0 @@
-import CustomListModel from '@/components/CustomList'
-import Tables from '@/components/Tables'
-import { FullscreenExitOutlined, FullscreenOutlined, QuestionCircleOutlined, RedoOutlined, SearchOutlined, SettingOutlined } from '@ant-design/icons'
-import { useDebounceFn, useFullscreen, useThrottleFn } from 'ahooks'
-import { Button, Card, Col, Row, Space, Tag, Tooltip, } from 'antd'
-import React, { useEffect, useRef, useState, useCallback } from 'react'
-import style from './index.less'
-import moment from 'moment'
-import lodash from 'lodash';
-import BaseTable from '@/components/BaseTable'
-import { getBaseTableColumn } from '@/components/BaseTable/utils'
-
-interface Prosp {
-    isZj?: boolean,//是否查总计
-    tableTotal?: { [key: string]: string },//是个开启总计
-    scroll?: { x?: number, y?: number },//开启行滑动并设置容器最大宽度
-    title?: string,//tabel的标题
-    tooltip?: JSX.Element,//是否在标题后加问号展示说明
-    dataSource: any[],//table的数据
-    expandedRowRender?: (data: any) => JSX.Element,
-    className?: string,//自定义class
-    isdownload?: boolean,
-    leftChild?: JSX.Element,
-    config?: any,
-    configName?: any,
-    page?: number,
-    pageSize?: number,
-    size?: 'small' | 'middle' | 'large',
-    total?: number,
-    onChange?: (props: {
-        pagination?: { current?: number, pageSize?: number, gzh?: string },
-        filters?: any,
-        sortData?: {
-            column: { dataIndex: string },
-            order?: "ascend" | "descend"
-        }
-    }) => void,
-    ajax?: any,//接口刷新
-    fixed?: {
-        left: number,
-        right: number
-    },
-    totalData?: any[]
-    summary?: ((data: readonly any[]) => React.ReactNode)
-    rowClassName?: string | ((record: any, index: any) => string)
-    sortData?: {
-        field?: string,
-        order?: "descend" | "ascend"
-    }
-}
-
-export const version = '1.0.0'
-
-function TableData(props: Prosp) {
-
-    /*************************/
-    const { isZj, totalData, scroll, title, dataSource, expandedRowRender, sortData, className, rowClassName, leftChild, page = undefined, pageSize = undefined, size = 'small', total = 0, onChange, config, configName, ajax, fixed = { left: 0, right: 1 }, summary } = props
-    const [visible, setVisible] = useState<boolean>(false)
-    const [isFullscreen, setIsFullscreen] = useState<boolean>(true)
-    const [oldSelectData, setoldSelectData] = useState<any[]>([])
-    const [oldFixed, setoldFixed] = useState<any>({ left: '0', right: '0' })
-    const [newColumns, setNewColumns] = useState<any[]>([])
-    const [originalColumns, setOriginalColumns] = useState<any[]>([])
-    const [timer, setTimer] = useState<string>(moment().format('HH:mm:ss'))
-    const [selectData, setSelectData] = useState<{ selectData: any[], fixed: { left: number, right: number } }>({ selectData: [], fixed: { left: fixed.left, right: fixed.right } })
-    const ref = useRef(null)
-    const [isFull, { toggleFull }] = useFullscreen(ref);
-    const oldName = useRef(null)
-    /*************************/
-
-    useEffect(() => {
-        if (originalColumns.length > 0) {
-            if (sortData?.field && sortData.order) {
-                setNewColumns(originalColumns.map((item: any) => {
-                    if (item.dataIndex === sortData?.field) {
-                        item.sortOrder = sortData.order
-                    } else if (item?.sortOrder) {
-                        delete item.sortOrder
-                    }
-                    return item
-                }))
-            } else {
-                setNewColumns(originalColumns.map((item: any) => {
-                    const { sortOrder, ...ite } = item
-                    return ite
-                }))
-            }
-        }
-    }, [originalColumns, sortData])
-
-    const { run: runSet } = useThrottleFn((newArr, newConfig, fixedData) => {
-        console.log('设置配置改变重新赋值')
-        setoldSelectData(selectData.selectData)
-        setoldFixed(selectData.fixed)
-        if (newArr.length > 0) {
-            console.log('改变---->')
-            let c: any[] = []
-            newArr.forEach((newItem: any, index: number) => {
-                let oldItem = newConfig.find((c: { dataIndex: any }) => c.dataIndex === newItem.dataIndex)
-                if (oldItem) {
-                    // if (newItem?.width !== oldItem?.width) {
-                    oldItem.width = newItem?.width
-                    // }
-                    if (index < Number(fixedData.left)) {//设置左悬浮
-                        oldItem['fixed'] = 'left'
-                    } else if (index > (newArr?.length - Number(fixedData.right) - 1)) {//设置右悬浮
-                        oldItem['fixed'] = 'right'
-                        if (oldItem?.children?.length > 0) {
-                            oldItem['children'] = oldItem?.children.map((item: { [x: string]: string }) => {
-                                item['fixed'] = 'right'
-                                return item
-                            })
-                        }
-                    } else {
-                        oldItem['fixed'] = false
-                        if (oldItem?.children?.length > 0) {
-                            oldItem['children'] = oldItem?.children.map((item: { [x: string]: any }) => {
-                                item['fixed'] = false
-                                return item
-                            })
-                        }
-                    }
-                    let { label, default: a, tips, title, ...ite } = oldItem
-                    if (tips) {
-                        ite.title = <Space size={2}>
-                            {title}
-                            <Tooltip title={tips} placement='bottom'>
-                                <QuestionCircleOutlined />
-                            </Tooltip>
-                        </Space>
-                    } else {
-                        ite.title = title
-                    }
-                    c.push(ite)
-                }
-            })
-            setOriginalColumns(c)
-            // setNewColumns(c)
-            // setNewColumns(newArr.map((newItem: any, index: number) => {
-            //     let oldItem = newConfig.find((c: { dataIndex: any }) => c.dataIndex === newItem.dataIndex)
-            //     if (newItem?.width !== oldItem?.width) {
-            //         oldItem.width = newItem?.width
-            //     }
-            //     if (index < Number(fixedData.left)) {//设置左悬浮
-            //         oldItem['fixed'] = 'left'
-            //     } else if (index > (newArr?.length - Number(fixedData.right) - 1)) {//设置右悬浮
-            //         oldItem['fixed'] = 'right'
-            //     } else {
-            //         oldItem['fixed'] = false
-            //     }
-            //     let { label, default: a, ...ite } = oldItem
-            //     return ite
-            // }))
-        }
-    }, { wait: 500 });
-    /**重组选中的字段 */
-    useEffect(() => {
-        let oldConfigName = oldName.current || ''
-        let oldSelectDataString = JSON.stringify(oldSelectData)
-        if (configName !== oldConfigName && oldSelectData.length > 0) {
-            oldSelectDataString = ''
-        }
-        if (configName) {
-            const defSelectData = localStorage.getItem(`myAdMonitorConfig${version}_` + configName)
-            const defFixed = localStorage.getItem(`myAdMonitorConfigFixed${version}_` + configName)
-            let newArr: any = [], fixedData: { left: number, right: number } = selectData.fixed
-            const newConfig = config?.map((item: { data: any }) => item.data)?.flat()
-            if (defSelectData) {
-                newArr = JSON.parse(defSelectData)
-            }
-            if (defSelectData && (selectData?.selectData?.length === 0 || configName !== oldConfigName)) {//首次查找个人配置是否存在,并且selectData为空,存在用个人配置设置selectData
-                console.log('首次使用个人配置赋值')
-                let newDefSelectData = JSON.parse(defSelectData)
-                newDefSelectData = newDefSelectData.filter((item: any) => !!item && newConfig.some((c: { dataIndex: any }) => c.dataIndex === item.dataIndex))//去除空项
-                setSelectData(() => ({ selectData: newDefSelectData, fixed: defFixed ? JSON.parse(defFixed) : { left: 0, right: 0 } }))
-                fixedData = defFixed ? JSON.parse(defFixed) : { left: 0, right: 0 }
-                newArr = newDefSelectData
-            }
-            if (!defSelectData && (selectData?.selectData?.length === 0 || configName !== oldConfigName)) {//首次查找个人配置是否存在,并且selectData为空,不存在默认配置设置selectData
-                let newSelectData: any[] = []
-                config?.forEach((item: { data: { default: any }[] }) => {
-                    item?.data?.forEach((d: { default: any }) => {
-                        if (d.default) {
-                            newSelectData[d.default - 1] = d
-                        }
-                    })
-                })
-                console.log('首次使用默认配置赋值')
-                setSelectData(() => ({ ...selectData, selectData: newSelectData }))
-                newArr = newSelectData
-            }
-            if ((JSON.stringify(oldSelectDataString) !== JSON.stringify(selectData?.selectData)) || (JSON.stringify(selectData.fixed) !== JSON.stringify(oldFixed))) {
-                runSet(newArr, newConfig, fixedData)
-            }
-        }
-        if (configName !== oldConfigName) {
-            oldName.current = configName
-        }
-    }, [selectData, oldSelectData, dataSource, oldFixed, configName, config, timer])
-
-    const { run: runResize } = useDebounceFn((columns) => {
-        if (configName) {
-            let newSelectData = selectData?.selectData?.map((item) => {
-                if (item.dataIndex === columns.key) {
-                    item['width'] = columns['width'].toFixed(2)
-                }
-                return item
-            })
-            localStorage.setItem(`myAdMonitorConfig${version}_` + configName, JSON.stringify(newSelectData))
-        }
-    }, { wait: 100 });
-
-    //拖动宽度设置设置保存
-    const handelResize = useCallback((columns: any) => {
-        runResize(columns)
-    }, [configName, selectData])
-
-    const header = <Col span={24}>
-        <Row gutter={[0, 10]} align='bottom'>
-            <Col flex='1 1 150px'>
-                {isFullscreen && leftChild}
-            </Col>
-            <Col flex='0 1 150px'>
-                {/*紧凑*/}
-                <Space style={{ float: 'right', marginBottom: 4 }}>
-                    <Button size='small' type='text' style={{ color: '#F56C6C' }} onClick={() => { setIsFullscreen(!isFullscreen) }}>
-                        <Tooltip title={isFullscreen ? '隐藏搜索' : '显示搜索'}><SearchOutlined /></Tooltip>
-                    </Button>
-                    {ajax && <Button
-                        size='small'
-                        type='text'
-                        style={{ color: '#67C23A' }}
-                        onClick={() => {
-                            ajax.refresh()
-                        }}>
-                        {/* <span style={{ fontSize: 10, color: '#999' }}>刷新时间:{ajax?.data?.reqTime}</span> */}
-                        <Tooltip title='刷新'><RedoOutlined /></Tooltip>
-                    </Button>}
-                    <Button
-                        size='small'
-                        type='text'
-                        style={{ color: '#E6A23C' }}
-                        onClick={() => {
-                            setVisible(true)
-                        }}>
-                        <Tooltip title='设置'><SettingOutlined /></Tooltip>
-                    </Button>
-                    <Button
-                        type='text'
-                        size='small'
-                        style={{ color: '#409EFF' }}
-                        onClick={toggleFull}>
-                        {<Tooltip title={!isFull ? '全屏' : '退出全屏'}>{!isFull ? <FullscreenOutlined /> : <FullscreenExitOutlined />}</Tooltip>}
-                    </Button>
-                    {visible && <CustomListModel
-                        sysFixed={fixed}
-                        version={version}
-                        config={config}
-                        configName={configName}
-                        visible={visible}
-                        onClose={() => { setVisible(false) }}
-                        onChange={(arr: any) => {
-                            setTimer(moment().format('HH:mm:ss'));
-                            if (arr) {
-                                setSelectData({ selectData: [], fixed: { left: fixed.left, right: fixed.right } })
-                            } else {
-                                setSelectData({ selectData: [], fixed: { left: fixed.left, right: fixed.right } })
-                            }
-                        }}
-                        columns={newColumns}
-                    />}
-                </Space>
-            </Col>
-        </Row>
-    </Col>
-    const content = <Row gutter={[0, 20]} ref={ref} style={isFull ? { background: '#fff' } : {}}>
-        {/**table */}
-        <Col span={24}>
-            <Card
-                style={{ borderRadius: 8 }}
-                // title={<div style={{ textAlign: 'center', fontWeight: 'bold' }}>{title}</div>}
-                headStyle={{ textAlign: 'left' }}
-                bodyStyle={{ padding: '5px 10px' }}
-            >
-                <div style={{ textAlign: 'center', fontWeight: 'bold', padding: '4px 6px 6px', fontSize: 16, marginBottom: 4 }}>{title}</div>
-                <Row gutter={[0, 16]}>
-                    {header}
-                    <Tab {...{ size, newColumns, handelResize, className, isZj, totalData, rowClassName, scroll, isFull, page, pageSize, dataSource, onChange, expandedRowRender, total, ajax, summary }} />
-                </Row>
-            </Card>
-        </Col>
-    </Row >
-    return <>
-        {content}
-    </>
-}
-
-/**表格 */
-const Tab = React.memo((props: any) => {
-    const { size, newColumns, className, handelResize, scroll, isFull, page, isZj, rowClassName, pageSize, totalData, dataSource, onChange, expandedRowRender, total, ajax, summary } = props
-    let ran = Math.ceil(Math.random() * 100)
-
-    useEffect(() => {
-        const contentBodyScroll = (e: any) => {
-            let el = document.querySelector(`.header_table_body_${ran} .ant-table-body`);
-            if (el) {
-                el.scrollLeft = e.target.scrollLeft
-            }
-        }
-        const headerBodyScroll = (e: any) => {
-            let el = document.querySelector(`.content_table_body_${ran} .ant-table-body`);
-            if (el) {
-                el.scrollLeft = e.target.scrollLeft
-            }
-        }
-        if (isZj) {
-            document.querySelector(`.content_table_body_${ran} .ant-table-body`)?.addEventListener('scroll', contentBodyScroll);
-            document.querySelector(`.header_table_body_${ran} .ant-table-body`)?.addEventListener('scroll', headerBodyScroll);
-            // document.querySelectorAll('.content_table_body .ant-table-body')
-        }
-        () => {
-            if (isZj) {
-                document.querySelector(`.content_table_body_${ran} .ant-table-body`)?.removeEventListener('scroll', contentBodyScroll);
-                document.querySelector(`.header_table_body_${ran} .ant-table-body`)?.removeEventListener('scroll', headerBodyScroll);
-            }
-        }
-    }, [isZj, ran])
-    let ww = document.body.clientWidth < 415
-    
-    return < Col span={24} >
-        <div className={`${style[size]} ${className ? style[className] : ''} `}>
-            {/* {
-                isZj && <Tables
-                    bordered
-                    columns={newColumns}
-                    dataSource={totalData?.length > 0 ? [...totalData] : [{ id: 1 }]}
-                    scroll={scroll ? isFull ? { ...scroll, y: document.body.clientHeight - 300 } : scroll : {}}
-                    size={size}
-                    pagination={false}
-                    hideOnSinglePage
-                    current={page}
-                    pageSize={pageSize}
-                    loading={ajax?.loading}
-                    className={`all_table header_table_body header_table_body_${ran} ${className ? className : ''}`}
-                    sortDirections={['ascend', 'descend', null]}
-                    handelResize={((columns: any) => handelResize(columns))}
-                    onChange={(pagination: any, filters: any, sorter: any) => onChange && onChange({ pagination, filters, sortData: sorter })}
-                />
-            } */}
-            {/* <Tables
-                showHeader={!isZj}
-                className={`all_table content_table_body content_table_body_${ran} ${className ? className : ''}`}
-                bordered
-                sortDirections={['ascend', 'descend', null]}
-                current={page}
-                pageSize={pageSize}
-                columns={newColumns}
-                dataSource={dataSource}
-                scroll={scroll ? isFull ? { ...scroll, y: document.body.clientHeight - 300 } : scroll : {}}
-                onChange={(pagination: any, filters: any, sorter: any) => onChange && onChange({ pagination, filters, sortData: sorter })}
-                rowClassName={rowClassName}
-                expandedRowRender={expandedRowRender ? expandedRowRender : undefined}
-                size={size}
-                total={total}
-                loading={ajax?.loading}
-                defaultPageSize={20}
-                handelResize={((columns: any) => handelResize(columns))}
-                summary={summary}
-            /> */}
-            <BaseTable
-                columns={getBaseTableColumn(newColumns)}
-                data={dataSource}
-                loading={ajax?.loading}
-                onColumnResizeEnd={({ column }: any) => handelResize(column)}
-                onChange={(data) => onChange?.(data)}
-                pagination={
-                    {
-                        size: 'small',
-                        total: total || 0,//总共多少条数据,服务器给,设置后分页自动计算页数
-                        current: page,//当前页数,需state控制配合翻页
-                        pageSize: pageSize,
-                        defaultCurrent: 1,//默认初始的当前页数
-                        defaultPageSize: 20,//默认初始的每页条数
-                        pageSizeOptions: ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100'],
-                        showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
-                        showSizeChanger: true, //手动开启条数筛选器,默认超过50条开启
-                        // onChange: pageChange, //点击页码或条数筛选时触发获取当前页数和每页条数
-                        // onShowSizeChange: sizeChange,//点击条数筛选器触发
-                        simple: ww ? true : false,//开启简单分页
-                        hideOnSinglePage: false,//只有一页数据隐藏分页
-                        showLessItems: true
-                    }
-                }
-            />
-
-        </div>
-    </Col >
-})
-
-export default React.memo(TableData, (prevProps, nextProps) => {
-    return lodash.isEqual(nextProps, prevProps); // 假设 deepEqual 是一个深层比较函数
-})

+ 49 - 0
src/pages/gameDataStatistics/components/TableData/isVirtually.tsx

@@ -0,0 +1,49 @@
+import { Checkbox, Tooltip } from "antd"
+import { CheckboxChangeEvent } from "antd/lib/checkbox"
+import React, { useEffect, useState } from "react"
+
+
+
+interface Props {
+    title?: string
+}
+/**
+ * 是否使用虚拟列表
+ * @param param0 
+ * @returns 
+ */
+const IsVirtually: React.FC<Props> = ({ title }) => {
+
+    const [check, setCheck] = useState<boolean>(false)
+
+    const onChange = (e: CheckboxChangeEvent) => {
+        if (title) {
+            let tableNames = localStorage.getItem('TABLENAMES') || ''
+            if (e.target.checked) {
+                tableNames = tableNames + ',' + title
+            } else {
+                let tableNamesArray = tableNames.split(',')
+                const result = tableNamesArray.filter(item => item !== title);
+                tableNames = result.join(',')
+            }
+            localStorage.setItem('TABLENAMES', tableNames)
+            window.location.reload()
+        }
+    }
+
+    useEffect(() => {
+        if (title) {
+            const tableNames = localStorage.getItem('TABLENAMES') || ''
+            setCheck(tableNames.split(',').includes(title))
+        }
+    }, [localStorage.getItem('TABLENAMES')])
+
+    
+    return <div style={{ position: 'absolute', right: 0, top: '50%', transform: 'translateY(-50%)' }}>
+        <Tooltip title='列表卡顿,渲染慢可勾选切换虚拟列表表格' placement="left">
+            <Checkbox onChange={onChange} checked={check}/>
+        </Tooltip>
+    </div>
+}
+
+export default React.memo(IsVirtually)

+ 10 - 1
src/pages/gameDataStatistics/extensionData/everyday/index.tsx

@@ -2,7 +2,7 @@ import QueryForm from "@/components/QueryForm"
 import { useAjax } from "@/Hook/useAjax"
 import { EverydayListType, getPromoteDayListApi, getPromoteDayTotalApi } from "@/services/gameData/extensionData"
 import React, { useEffect, useState } from "react"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 import columns12 from "./tableConfig"
 import moment from "moment"
 import RechargeTrend from "@/components/rechargeTrend"
@@ -72,6 +72,15 @@ const Everyday: React.FC = () => {
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'
             }}
+            estimatedRowHeight={() => {
+                let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_推广每日数据`)
+                if (mySelectFieldData) {
+                    let newSelectFieldData = JSON.parse(mySelectFieldData).date_field
+                    return newSelectFieldData?.length * 20.5 || 20.5 * 5
+                } else {
+                    return 20.5 * 5
+                }
+            }}
             title='推广每日数据'
             onChange={(props: any) => {
                 let { pagination, sortData } = props

+ 1 - 1
src/pages/gameDataStatistics/extensionData/everyday/tableConfig.tsx

@@ -147,7 +147,7 @@ function columns12(rechargeTrendHandle: (data: any) => void): { label: string, f
             data: [
                 {
                     title: '推广账号', dataIndex: 'accountId', key: 'accountId', label: '推广账号信息', align: 'center', width: 70, default: 2,
-                    render: (a: any) => (<span>{a || '--'}</span>)
+                    render: (a: any) => (<div style={{ wordWrap: 'break-word' }}>{a || '--'}</div>)
                 },
                 {
                     title: '投放渠道', dataIndex: 'agentName', key: 'agentName', label: '推广账号信息', align: 'center', width: 130, default: 3,

+ 2 - 1
src/pages/gameDataStatistics/gameData/active/index.tsx

@@ -1,5 +1,5 @@
 import React, { useEffect, useState } from "react"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 import QueryForm from "@/components/QueryForm"
 import { useAjax } from "@/Hook/useAjax"
 import { ActiveDataProps, getActiveDataListApi, getActiveDataTotalApi } from "@/services/gameData/game"
@@ -78,6 +78,7 @@ const Active: React.FC = () => {
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'
             }}
+            estimatedRowHeight={() => 41}
             title={`游戏留存数据(用户活跃数据2023-08-20开始统计)`}
             onChange={(props: any) => {
                 let { pagination, sortData } = props

+ 10 - 1
src/pages/gameDataStatistics/gameData/again/index.tsx

@@ -2,7 +2,7 @@ import { AgainListProps, getAgainListApi, getAgainTotalApi } from "@/services/ga
 import React, { useEffect, useState } from "react"
 import moment from "moment"
 import { useAjax } from "@/Hook/useAjax"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 import QueryForm from "@/components/QueryForm"
 import columns12 from "./tableConfig"
 import { getPresets } from "@/components/QueryForm/const"
@@ -72,6 +72,15 @@ const Again: React.FC = () => {
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'
             }}
+            estimatedRowHeight={() => {
+                let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_游戏首日复充`)
+                if (mySelectFieldData) {
+                    let newSelectFieldData = JSON.parse(mySelectFieldData).date_field
+                    return (newSelectFieldData?.length + 1) * 20.5 || 20.5 * 4
+                } else {
+                    return 20.5 * 4
+                }
+            }}
             title={`游戏首日复充`}
             onChange={(props: any) => {
                 let { pagination, sortData } = props

+ 10 - 1
src/pages/gameDataStatistics/gameData/everyday/index.tsx

@@ -1,5 +1,5 @@
 import React, { useEffect, useState } from "react"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 import columns12 from "./tableConfig"
 import { GameDayProps, getGameDayListApi, getGameDayTotalApi } from "@/services/gameData/game"
 import { useAjax } from "@/Hook/useAjax"
@@ -85,6 +85,15 @@ const Everyday: React.FC = () => {
             total={getGameDayList?.data?.total}
             page={queryForm.pageNum}
             pageSize={queryForm.pageSize}
+            estimatedRowHeight={() => {
+                let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_游戏每日付费趋势`)
+                if (mySelectFieldData) {
+                    let newSelectFieldData = JSON.parse(mySelectFieldData).date_field
+                    return newSelectFieldData?.length * 20.5 || 20.5 * 5
+                } else {
+                    return 20.5 * 5
+                }
+            }}
             sortData={{
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'

+ 5 - 2
src/pages/gameDataStatistics/gameData/everyday/tableConfig.tsx

@@ -128,10 +128,13 @@ function columnsNature12(rechargeTrendHandle: (data: any) => void): { label: str
         {
             label: '游戏信息',
             data: [
-                { title: '推广游戏名称', dataIndex: 'gameName', label: '游戏信息', align: 'center', width: 70, default: 2 },
+                {
+                    title: '推广游戏名称', dataIndex: 'gameName', label: '游戏信息', align: 'center', width: 70, default: 2,
+                    render: (a: string) => a || '--'
+                },
                 {
                     title: '推广游戏应用类型', dataIndex: 'gameClassify', label: '游戏信息', align: 'center', width: 80,
-                    render: (a: string) => (<span>{gameClassifyEnum[a]}</span>)
+                    render: (a: string, b?: any) => (<span>{gameClassifyEnum[a]}</span>)
                 }
             ]
         },

+ 1 - 0
src/pages/gameDataStatistics/gameData/flowingWater/index.tsx

@@ -40,6 +40,7 @@ const FlowingWater: React.FC = () => {
                     setQueryForm({ ...newQueryForm, ...params })
                 }}
             />}
+            isVirtually={false}
             scroll={{ x: 1000, y: 600 }}
             ajax={getGameWaterList}
             fixed={{ left: 1, right: 0 }}

+ 1 - 1
src/pages/gameDataStatistics/gameData/h5Recharge/h5BuyUser.tsx

@@ -88,7 +88,7 @@ const H5BuyUser: React.FC<Props> = ({ gameName, h5BuyUserVOList }) => {
     /**************************************/
 
     return <>
-        <Button type="link" style={{ padding: 0 }} onClick={() => setVisible(true)}>买量导量</Button>
+        <Button type="link" style={{ padding: 0, height: 'auto' }} onClick={() => setVisible(true)}>买量导量</Button>
         {visible && <Modal title={`${gameName} 游戏买量导量用户数据`} width={900} visible={visible} onCancel={() => setVisible(false)} footer={null}>
             <Table size="small" dataSource={h5BuyUserVOList?.map((item: any, index: number) => ({...item, id: index + 1}))} columns={columns} />
         </Modal>}

+ 1 - 1
src/pages/gameDataStatistics/gameData/h5Recharge/h5NatureUser.tsx

@@ -76,7 +76,7 @@ const H5NatureUser: React.FC<Props> = ({ gameName, h5NatureUserVOList }) => {
     /**************************************/
 
     return <>
-        <Button type="link" style={{ padding: 0 }} onClick={() => setVisible(true)}>官方导量</Button>
+        <Button type="link" style={{ padding: 0, height: 'auto' }} onClick={() => setVisible(true)}>官方导量</Button>
         {visible && <Modal title={`${gameName} 游戏官方导量用户数据`} width={900} visible={visible} onCancel={() => setVisible(false)} footer={null}>
             <Table size="small" dataSource={h5NatureUserVOList?.map((item: any, index: number) => ({ ...item, id: index + 1 }))} columns={columns} />
         </Modal>}

+ 1 - 0
src/pages/gameDataStatistics/gameData/h5Recharge/index.tsx

@@ -65,6 +65,7 @@ const H5Recharge: React.FC = () => {
             page={queryForm.pageNum}
             pageSize={queryForm.pageSize}
             title='H5游戏充值表'
+            size="small"
             onChange={(props: any) => {
                 let { pagination, sortData } = props
                 let { current, pageSize } = pagination

+ 1 - 0
src/pages/gameDataStatistics/gameServer/serverData/index.tsx

@@ -55,6 +55,7 @@ const ServerData: React.FC = () => {
                 isServerId
             />}
             isZj
+            isVirtually={false}
             totalData={totalData}
             scroll={{ x: 1000, y: 600 }}
             ajax={getGameServerList}

+ 10 - 1
src/pages/gameDataStatistics/medium/gameEvery/index.tsx

@@ -4,7 +4,7 @@ import React, { useEffect, useState } from "react"
 import moment from "moment"
 import columns12 from "./tableConfig"
 import { getPresets } from "@/components/QueryForm/const"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 import QueryForm from "@/components/QueryForm"
 
 
@@ -79,6 +79,15 @@ const GameEvery: React.FC = () => {
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'
             }}
+            estimatedRowHeight={() => {
+                let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_游戏媒体每日数据`)
+                if (mySelectFieldData) {
+                    let newSelectFieldData = JSON.parse(mySelectFieldData).date_field
+                    return newSelectFieldData?.length * 20.5 || 20.5 * 5
+                } else {
+                    return 20.5 * 5
+                }
+            }}
             title={`游戏媒体每日数据`}
             onChange={(props: any) => {
                 let { pagination, sortData } = props

+ 10 - 1
src/pages/gameDataStatistics/medium/pitcherEvery/index.tsx

@@ -5,7 +5,7 @@ import moment from 'moment'
 import columns12 from "./tableConfig"
 import { getPresets } from "@/components/QueryForm/const"
 import QueryForm from "@/components/QueryForm"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 
 
 /**
@@ -76,6 +76,15 @@ const PitcherEvery: React.FC = () => {
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'
             }}
+            estimatedRowHeight={() => {
+                let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_投手推广每日数据`)
+                if (mySelectFieldData) {
+                    let newSelectFieldData = JSON.parse(mySelectFieldData).date_field
+                    return newSelectFieldData?.length * 20.5 || 20.5 * 5
+                } else {
+                    return 20.5 * 5
+                }
+            }}
             title={`投手推广每日数据`}
             onChange={(props: any) => {
                 let { pagination, sortData } = props

+ 10 - 1
src/pages/gameDataStatistics/medium/promotionEvery/index.tsx

@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"
 import moment from "moment"
 import { useAjax } from "@/Hook/useAjax"
 import { MediaPromotionDayProps, getMediaPromotionDayListApi, getMediaPromotionDayTotalApi } from "@/services/gameData/medium"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 import QueryForm from "@/components/QueryForm"
 import { getPresets } from "@/components/QueryForm/const"
 import columns12 from "./tableConfig"
@@ -79,6 +79,15 @@ const PromotionEvery: React.FC = () => {
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'
             }}
+            estimatedRowHeight={() => {
+                let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_推广媒体每日数据`)
+                if (mySelectFieldData) {
+                    let newSelectFieldData = JSON.parse(mySelectFieldData).date_field
+                    return newSelectFieldData?.length * 20.5 || 20.5 * 5
+                } else {
+                    return 20.5 * 5
+                }
+            }}
             title={`推广媒体每日数据`}
             onChange={(props: any) => {
                 let { pagination, sortData } = props

+ 95 - 0
src/pages/gameDataStatistics/order/details.tsx

@@ -0,0 +1,95 @@
+import { useAjax } from "@/Hook/useAjax"
+import { PayStatus, PayType, gameClassifyEnum } from "@/components/QueryForm/const"
+import Tables from "@/components/Tables"
+import WidthEllipsis from "@/components/widthEllipsis"
+import { CpLogListProps, getOrderCpNoticeApi } from "@/services/gameData/order"
+import { Badge, Descriptions, Divider, Drawer, Statistic } from "antd"
+import React, { useEffect, useState } from "react"
+import columns from "./tableConfigRole"
+
+
+interface Props {
+    visible?: boolean
+    onClose?: () => void
+    initialValues?: any
+}
+const Details: React.FC<Props> = ({ visible, onClose, initialValues = {} }) => {
+
+
+    /********************************/
+    const [queryFrom, setQueryForm] = useState<CpLogListProps>({ pageNum: 1, pageSize: 20, orderId: initialValues?.orderId })
+    const [logList, setLogList] = useState<any>()
+    const getOrderCpNotice = useAjax((params) => getOrderCpNoticeApi(params))
+    /********************************/
+
+    useEffect(() => {
+        if (initialValues?.orderStatus && initialValues?.orderStatus > 0) {
+            getList()
+        }
+    }, [queryFrom])
+
+    const getList = () => {
+        getOrderCpNotice.run(queryFrom).then(res => {
+            setLogList(res?.data)
+        })
+    }
+
+    /** 分页 */
+    let pageChange = (page: number, pageSize?: number) => {
+        setQueryForm({ ...queryFrom, pageNum: page, pageSize: pageSize || queryFrom.pageSize })
+    }
+
+    return <Drawer title={'订单详情'} width={1180} placement="right" onClose={onClose} visible={visible}>
+        <Divider orientation="left" style={{ marginTop: 0 }}>订单详情</Divider>
+        <Descriptions title="" bordered column={3} size="small">
+            <Descriptions.Item label="商户订单号" contentStyle={{ width: 240 }}>{initialValues?.orderId || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="CP订单号" contentStyle={{ width: 240 }}>{<WidthEllipsis value={initialValues?.cpOrderId || '<空>'}/>}</Descriptions.Item>
+            <Descriptions.Item label="第三方支付订单号" contentStyle={{ width: 240 }}>{<WidthEllipsis value={initialValues?.merchantOrderNo || '<空>'} />}</Descriptions.Item>
+            <Descriptions.Item label="CP名称" contentStyle={{ width: 240 }}>{initialValues?.cpName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="游戏名称" contentStyle={{ width: 240 }}>{initialValues?.gameName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="游戏应用类型" contentStyle={{ width: 240 }}>{gameClassifyEnum[initialValues?.classify] || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="产品ID" contentStyle={{ width: 240 }}>{initialValues?.productId || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="产品名称" contentStyle={{ width: 240 }}>{initialValues?.productName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="渠道" contentStyle={{ width: 240 }}>{initialValues?.agentName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="支付方式" contentStyle={{ width: 240 }}>{PayType[initialValues?.payway] || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="支付场景" contentStyle={{ width: 240 }}>{initialValues?.payScene || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="收款商户" contentStyle={{ width: 240 }}>{initialValues?.merchantName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="订单金额" contentStyle={{ width: 240 }}><Statistic value={initialValues?.amount || 0} precision={2} /></Descriptions.Item>
+            <Descriptions.Item label="订单实付金额" contentStyle={{ width: 240 }}><Statistic value={initialValues?.realAmount || 0} precision={2} /></Descriptions.Item>
+            <Descriptions.Item label="支付状态" contentStyle={{ width: 240 }}>{PayStatus[initialValues?.orderStatus]}</Descriptions.Item>
+            <Descriptions.Item label="创建时间" contentStyle={{ width: 240 }}>{initialValues?.orderCreateTime || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="支付时间" contentStyle={{ width: 240 }}>{initialValues?.payTime || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="最后通知时间" contentStyle={{ width: 240 }}>{initialValues?.lastCpNotifyTime || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="CP通知状态" contentStyle={{ width: 240 }}>{{ '1': <Badge status="processing" text="待处理" />, '2': <Badge status="success" text="成功" />, '-1': <Badge status="error" text="失败" /> }[initialValues?.cpStatus]}</Descriptions.Item>
+            <Descriptions.Item label="操作系统" contentStyle={{ width: 240 }}>{initialValues?.os || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="是否首充" contentStyle={{ width: 240 }}>{{ '1': '是', '0': '否' }[initialValues?.isFirstRecharge]}</Descriptions.Item>
+        </Descriptions>
+        <Divider orientation="left">玩家信息</Divider>
+        <Descriptions title="" bordered column={3} size="small">
+            <Descriptions.Item label="玩家ID" contentStyle={{ width: 240 }}>{initialValues?.gameUserId || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="玩家账号" contentStyle={{ width: 240 }}><WidthEllipsis value={initialValues?.username || '<空>'}/></Descriptions.Item>
+            <Descriptions.Item label="玩家注册时间" contentStyle={{ width: 240 }}>{initialValues?.regTime || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="CP名称" contentStyle={{ width: 240 }}>{initialValues?.cpName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="归因投放人员" contentStyle={{ width: 240 }}>{initialValues?.zxPitcherName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="游戏区服" contentStyle={{ width: 240 }}>{initialValues?.serverName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="游戏角色" contentStyle={{ width: 240 }}>{initialValues?.roleName || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="角色等级" contentStyle={{ width: 240 }}>{initialValues?.roleLevel || '<空>'}</Descriptions.Item>
+            <Descriptions.Item label="角色VIP" contentStyle={{ width: 240 }}>{initialValues?.roleVip}</Descriptions.Item>
+        </Descriptions>
+        <Divider orientation="left">CP通知记录</Divider>
+        <Tables
+            columns={columns()}
+            dataSource={logList?.records}
+            total={logList?.total}
+            loading={getOrderCpNotice.loading}
+            current={queryFrom.pageNum}
+            pageChange={pageChange}
+            sizeChange={pageChange}
+            size="small"
+            scroll={{ x: 1000 }}
+            bordered
+        />
+    </Drawer>
+}
+
+export default React.memo(Details)

+ 12 - 1
src/pages/gameDataStatistics/order/index.tsx

@@ -6,6 +6,7 @@ import TableData from "../components/TableData"
 import columns12 from "./tableConfig"
 import { getPresets } from "@/components/QueryForm/const"
 import moment from "moment"
+import Details from "./details"
 
 
 const Order: React.FC = () => {
@@ -13,6 +14,8 @@ const Order: React.FC = () => {
     /***************************/
     const [queryForm, setQueryForm] = useState<OrderListType>({ pageNum: 1, pageSize: 100, sourceSystem: 'ZX_ONE', sortFiled: 'orderCreateTime', sortType: 'desc' })
     const [totalData, setTotalData] = useState<any[]>([])
+    const [visible, setVisible] = useState<boolean>(false)
+    const [orderData, setOrderData] = useState<any>({})
     const getOrderList = useAjax((params) => getOrderListApi(params))
     const getOrderTotal = useAjax((params) => getOrderTotalApi(params))
     /***************************/
@@ -26,6 +29,12 @@ const Order: React.FC = () => {
         })
     }, [queryForm])
 
+    // 详情
+    const onDetail = (data: any) => {
+        setOrderData(data)
+        setVisible(true)
+    }
+
     return <div>
 
         <TableData
@@ -118,9 +127,11 @@ const Order: React.FC = () => {
                 newQueryForm.pageSize = pageSize
                 setQueryForm({ ...newQueryForm })
             }}
-            config={columns12()}
+            config={columns12(onDetail)}
             configName={'订单明细'}
         />
+
+        {visible && <Details visible={visible} initialValues={orderData} onClose={() => setVisible(false)}/>}
     </div>
 }
 

+ 18 - 3
src/pages/gameDataStatistics/order/tableConfig.tsx

@@ -4,7 +4,7 @@ import { Statistic } from "antd"
 import React from "react"
 
 
-function columns12(): { label: string, fieldSHow?: { label: string, saveField: string, defaultValue: any[], data: any[] }, data: any[] }[] {
+function columns12(onDetail: (data: any) => void): { label: string, fieldSHow?: { label: string, saveField: string, defaultValue: any[], data: any[] }, data: any[] }[] {
 
     return [
         {
@@ -83,11 +83,11 @@ function columns12(): { label: string, fieldSHow?: { label: string, saveField: s
                     render: (a: string, b: any) => (<WidthEllipsis value={a} />)
                 },
                 {
-                    title: '订单金额', dataIndex: 'amount', label: '订单明细', align: 'center', width: 90, default: 16, sorter: true,
+                    title: '订单金额', dataIndex: 'amount', label: '订单明细', align: 'center', width: 95, default: 16, sorter: true,
                     render: (a: any, b: any) => <Statistic value={a || 0} valueStyle={b?.day === '总计' ? { color: 'red' } : {}} precision={2} />
                 },
                 {
-                    title: '订单实付金额', dataIndex: 'realAmount', label: '订单明细', align: 'center', width: 80, default: 17, sorter: true,
+                    title: '订单实付金额', dataIndex: 'realAmount', label: '订单明细', align: 'center', width: 95, default: 17, sorter: true,
                     render: (a: any, b: any) => <Statistic value={a || 0} valueStyle={b?.day === '总计' ? { color: 'red' } : {}} precision={2} />
                 },
                 {
@@ -195,6 +195,21 @@ function columns12(): { label: string, fieldSHow?: { label: string, saveField: s
                         return '--'
                     }
                 },
+                // {
+                //     title: '操作', 
+                //     dataIndex: 'cz', 
+                //     label: '订单明细', 
+                //     align: 'center', 
+                //     width: 70, 
+                //     default: 34,
+                //     render: (a: any, b: any) => {
+                //         if (b?.day !== '总计') {
+                //             return <a onClick={() => onDetail(b)}>订单详情</a>
+                //         }
+                //         return '--'
+
+                //     }
+                // }
             ]
         },
     ]

+ 65 - 0
src/pages/gameDataStatistics/order/tableConfigRole.tsx

@@ -0,0 +1,65 @@
+import React from "react"
+
+let columns = () => [
+    {
+        title: 'ID',
+        dataIndex: 'id',
+        key: 'id',
+        width: 60,
+        align: 'center',
+    },
+    {
+        title: '支付状态',
+        dataIndex: 'status',
+        key: 'status',
+        width: 120,
+        align: 'center',
+        render: (a: number, b: any) => {
+            return <span>{a === 1 ? '待处理' : a === 2 ? '成功' : '失败'}</span>
+        }
+    },
+    {
+        title: 'CP通知状态',
+        dataIndex: 'cpStatus',
+        key: 'cpStatus',
+        width: 120,
+        align: 'center',
+        render: (a: number, b: any) => {
+            return <span>{a === 1 ? '待处理' : a === 2 ? '成功' : '失败'}</span>
+        }
+    },
+    {
+        title: 'CP支付回调',
+        dataIndex: 'cpPaybackUrl',
+        key: 'cpPaybackUrl',
+        width: 180,
+        ellipsis: true,
+        align: 'center',
+    },
+    {
+        title: '请求参数',
+        dataIndex: 'params',
+        key: 'params',
+        width: 180,
+        ellipsis: true,
+        align: 'center',
+    },
+    {
+        title: 'EXT参数',
+        dataIndex: 'ext',
+        key: 'ext',
+        width: 180,
+        ellipsis: true,
+        align: 'center',
+    },
+    {
+        title: '创建时间',
+        dataIndex: 'createTime',
+        key: 'createTime',
+        width: 140,
+        ellipsis: true,
+        align: 'center',
+    }
+]
+
+export default columns

+ 10 - 1
src/pages/gameDataStatistics/pitcher/everyDay/index.tsx

@@ -5,7 +5,7 @@ import { useAjax } from "@/Hook/useAjax"
 import columns12 from "./tableConfig"
 import { getPresets } from "@/components/QueryForm/const"
 import QueryForm from "@/components/QueryForm"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 
 /**
  * 投手每日数据
@@ -73,6 +73,15 @@ const EvertDay: React.FC = () => {
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'
             }}
+            estimatedRowHeight={() => {
+                let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_投手每日数据`)
+                if (mySelectFieldData) {
+                    let newSelectFieldData = JSON.parse(mySelectFieldData).date_field
+                    return newSelectFieldData?.length * 20.5 || 20.5 * 5
+                } else {
+                    return 20.5 * 5
+                }
+            }}
             title={`投手每日数据`}
             onChange={(props: any) => {
                 let { pagination, sortData } = props

+ 10 - 1
src/pages/gameDataStatistics/pitcher/everyDayGame/index.tsx

@@ -3,7 +3,7 @@ import React, { useEffect, useState } from "react"
 import moment from "moment"
 import { PitcherGameDayProps, getPitcherGameDayListApi, getPitcherGameDaySumApi } from "@/services/gameData/pitcher"
 import { getPresets } from "@/components/QueryForm/const"
-import TableData from "../../components/TableData"
+import TableData, { version } from "../../components/TableData"
 import QueryForm from "@/components/QueryForm"
 import columns12 from "./tableConfig"
 
@@ -78,6 +78,15 @@ const EvertDayGame: React.FC = () => {
                 field: queryForm?.sortFiled,
                 order: queryForm?.sortType === 'asc' ? 'ascend' : 'descend'
             }}
+            estimatedRowHeight={() => {
+                let mySelectFieldData = localStorage.getItem(`myAdFieldConfig${version}_投手游戏每日数据`)
+                if (mySelectFieldData) {
+                    let newSelectFieldData = JSON.parse(mySelectFieldData).date_field
+                    return newSelectFieldData?.length * 20.5 || 20.5 * 5
+                } else {
+                    return 20.5 * 5
+                }
+            }}
             title={`投手游戏每日数据`}
             onChange={(props: any) => {
                 let { pagination, sortData } = props

+ 69 - 0
src/pages/gameDataStatistics/player/list/exportH5Modal.tsx

@@ -0,0 +1,69 @@
+import { useAjax } from "@/Hook/useAjax"
+import { exportUserH5Api } from "@/services/gameData/player"
+import { Form, Input, Modal, message } from "antd"
+import React from "react"
+
+
+interface Props {
+    initialValues: any
+    visible?: boolean
+    onChange?: () => void
+    onClose?: () => void
+}
+/**
+ * 小程序账号到H5
+ * @param param0 
+ * @returns 
+ */
+const ExportH5Modal: React.FC<Props> = ({ initialValues = {}, visible, onChange, onClose }) => {
+
+    /*****************************/
+    const [form] = Form.useForm()
+
+    const exportUserH5 = useAjax((params) => exportUserH5Api(params))
+    /*****************************/
+
+    const handleOk = async () => {
+        let data = await form.validateFields()
+        console.log(data)
+        exportUserH5.run({ ...data, userId: initialValues.userId }).then(res => {
+            if (res.data) {
+                message.success('导量成功')
+                onChange?.()
+            }
+        })
+    }
+
+    return <Modal title={`${initialValues.username} 导到H5游戏`} visible={visible} onCancel={onClose} onOk={handleOk} confirmLoading={exportUserH5.loading}>
+        <Form
+            name="basicExport"
+            form={form}
+            labelCol={{ span: 4 }}
+            wrapperCol={{ span: 20 }}
+            autoComplete="off"
+            initialValues={{ ...initialValues }}
+        >
+            <Form.Item
+                label="手机号码"
+                name="mobile"
+                rules={[
+                    {
+                        required: true,
+                        validator(_rule, value) {
+                            let reg = new RegExp(/^1[3-9]\d{9}$/,'g')
+                            if (!value) {
+                                return Promise.reject(new Error('请输入手机号!'))
+                            } else if (!reg.test(value)) {
+                                return Promise.reject(new Error('请输入正确的手机号!'))
+                            }
+                            return Promise.resolve()
+                        }
+                    }
+                ]}>
+                <Input placeholder="请输入手机号码" allowClear />
+            </Form.Item>
+        </Form>
+    </Modal>
+}
+
+export default React.memo(ExportH5Modal)

+ 46 - 0
src/pages/gameDataStatistics/player/list/index.less

@@ -0,0 +1,46 @@
+.lookCard {
+    .ant-card-body {
+        padding: 10px;
+    }
+}
+.info {
+    .playerInfo {
+        width: 100%;
+        height: 230px;
+        border: 1px solid #eee;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        padding: 20px;
+        box-sizing: border-box;
+        gap: 10px;
+        img {
+            border-radius: 50%;
+        }
+        .name {
+            font-size: 20px;
+            font-weight: 700;
+        }
+        .vip {
+            background-color: red;
+            width: 80px;
+            color: #fff;
+            text-align: center;
+            padding: 4px 0;
+            border-radius: 20px;
+            font-size: 14px;
+        }
+    }
+
+    .playerEdit {
+        margin-top: 10px;
+        .playerPayInfo {
+            >div {
+                margin-bottom: 16px;
+                input {
+                    border-radius: 4px;
+                }
+            }
+        }
+    }
+}

+ 183 - 0
src/pages/gameDataStatistics/player/list/index.tsx

@@ -0,0 +1,183 @@
+import { useAjax } from "@/Hook/useAjax"
+import { PlayerListProps, getPlayerListApi, getUserInfotApi, getUserUpdateApi, interdictionGamerApi } 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 { getPresetsRanking } from "@/components/QueryForm/const"
+import { message } from "antd"
+import ExportH5Modal from "./exportH5Modal"
+import Look from "./look"
+
+let ajax: any = null, ajax1: any = null
+const List: React.FC = () => {
+
+    /************************/
+    const [queryForm, setQueryForm] = useState<PlayerListProps>({ pageNum: 1, pageSize: 50, sourceSystem: 'ZX_ONE' })
+    const [lookShow, setLookShow] = useState<boolean>(false) // 新增标签控制弹窗
+    const [exportData, setExportData] = useState<any>({})
+    const [exportShow, setExportShow] = useState<boolean>(false)
+    const getPlayerList = useAjax((params) => getPlayerListApi(params))
+    ajax = getPlayerList
+    const getUserInfo = useAjax((params) => getUserInfotApi(params))
+    ajax1 = getUserInfo
+    const interdictionGamer = useAjax((params) => interdictionGamerApi(params))
+    const getUserUpdate = useAjax((params) => getUserUpdateApi(params))
+    /************************/
+
+    useEffect(() => {
+        getPlayerList.run(queryForm)
+    }, [queryForm])
+
+
+    // 查看详情
+    const lookHandle = (data: any) => {
+        setLookShow(true)
+        getUserInfo.run(data)
+    }
+
+    //编辑玩家按钮
+    const exportH5 = (data: any) => {
+        setExportData({
+            username: data?.username,
+            mobile: data?.mobile,
+            userId: data.id
+        })
+        setExportShow(true)
+    }
+
+    // 封禁
+    const interdictionHandle = (userId: number, status: number) => {
+
+        interdictionGamer.run({ userId, status }).then(res => {
+            if (res) {
+                message.success(status === 1 ? '封禁成功!' : '解封成功!');
+                ajax.refresh();
+            } else {
+                message.error(res.msg)
+            }
+        })
+    }
+
+    // 编辑确定发送
+    const editUser = (params: any) => {
+        Object.keys(params).forEach(key => {
+            if (!params[key]) {
+                delete params[key]
+            }
+        })
+        getUserUpdate.run(params).then(res => {
+            if (res.data) {
+                message.success('编辑成功!')
+                ajax.refresh()//重新获取用户列表
+                ajax1.refresh()//重新获取详情列表
+            } else {
+                message.error(res.msg)
+            }
+        })
+    }
+    return <div>
+        <TableData
+            leftChild={<QueryForm
+                initialValues={{ sourceSystem: 'ZX_ONE' }}
+                onChange={(data: any) => {
+                    const { gameUserId, username, gameClassify, regStartDay, regEndDay, rechargeDay, regPayIntervalTime, userStatus, agentId, roleCount, ...par } = data
+                    let newQueryForm = JSON.parse(JSON.stringify(queryForm))
+                    newQueryForm.pageNum = 1
+                    newQueryForm.userId = gameUserId
+                    newQueryForm.userName = username
+                    newQueryForm.gameCategoryId = gameClassify
+                    newQueryForm.status = userStatus
+                    newQueryForm.channelId = agentId
+
+                    if (regStartDay && regEndDay) {
+                        newQueryForm.beginDate = regStartDay
+                        newQueryForm.endDate = regEndDay
+                    } else {
+                        delete newQueryForm.beginDate
+                        delete newQueryForm.endDate
+                    }
+
+                    if (rechargeDay && rechargeDay?.length === 2) {
+                        newQueryForm['rechargeBeginDate'] = moment(rechargeDay[0]).format('YYYY-MM-DD')
+                        newQueryForm['rechargeEndDate'] = moment(rechargeDay[1]).format('YYYY-MM-DD')
+                    } else {
+                        delete newQueryForm['rechargeBeginDate']
+                        delete newQueryForm['rechargeEndDate']
+                    }
+
+                    if (regPayIntervalTime?.length > 0 && (regPayIntervalTime[0] || regPayIntervalTime[1])) {
+                        newQueryForm.regPayIntervalTimeMin = regPayIntervalTime[0]
+                        newQueryForm.regPayIntervalTimeMax = regPayIntervalTime[1]
+                    } else {
+                        delete newQueryForm.regPayIntervalTimeMin
+                        delete newQueryForm.regPayIntervalTimeMax
+                    }
+
+                    if (roleCount?.length > 0 && (roleCount[0] || roleCount[1])) {
+                        newQueryForm.roleCountMin = roleCount[0]
+                        newQueryForm.roleCountMax = roleCount[1]
+                    } else {
+                        delete newQueryForm.roleCountMin
+                        delete newQueryForm.roleCountMax
+                    }
+                    setQueryForm({ ...newQueryForm, ...par })
+                }}
+                isSource
+                isGameUserId
+                isUserName
+                isNickname
+                isMobile
+                isRegIp
+                isIsAuth
+                isIsBindMobile
+                isCpId
+                isGameId
+                isBGGameClassify
+                isRegDay={{ ranges: getPresetsRanking() }}
+                rechargeDay={{ ranges: getPresetsRanking() }}
+                isIsRecharge
+                isUserStatus
+                isAgentId
+                isAccountId
+                isSysUserId
+                isCreateRole
+                isPayIntervalTime={{ tips: '充值距注册时间区间(分钟)' }}
+                isRoleCount={{ tips: '每个账号角色数量区间' }}
+            />}
+            scroll={{ x: 1000, y: 600 }}
+            ajax={getPlayerList}
+            fixed={{ left: 1, right: 2 }}
+            dataSource={getPlayerList?.data?.records}
+            page={getPlayerList?.data?.current || 1}
+            pageSize={getPlayerList?.data?.size || 20}
+            total={getPlayerList?.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(lookHandle, exportH5, interdictionHandle)}
+            configName={'玩家列表'}
+        />
+
+        {exportShow && <ExportH5Modal initialValues={exportData} visible={exportShow} onClose={() => { setExportShow(false); setExportData({}) }} onChange={() => { setExportShow(false); setExportData({}); ajax.refresh() }} />}
+        {/* 查看详情 */}
+        {lookShow && <Look visible={lookShow} onClose={() => { setLookShow(false) }} onChange={(params: any) => { editUser(params) }} userInfo={getUserInfo?.data || null} />}
+    </div>
+}
+
+export default List

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 82 - 0
src/pages/gameDataStatistics/player/list/look.tsx


+ 93 - 0
src/pages/gameDataStatistics/player/list/tableConfig.tsx

@@ -0,0 +1,93 @@
+import WidthEllipsis from "@/components/widthEllipsis"
+import { CheckCircleOutlined, EyeOutlined, StopOutlined, SwapOutlined } from "@ant-design/icons";
+import { Badge, Col, Popconfirm, Row, Statistic } from "antd"
+import React from "react"
+
+function columns12(lookHandle: (data: any) => void, exportH5: (data: any) => void, interdictionHandle: (userId: number, status: number) => void) {
+
+    let newArr: { label: string, data: any[] }[] = [
+        {
+            label: '玩家列表',
+            data: [
+                { title: '玩家ID', dataIndex: 'id', label: '玩家列表', align: 'center', width: 55 },
+                { title: '玩家账号', dataIndex: 'username', label: '玩家列表', align: 'center', width: 120, default: 1, render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />) },
+                { title: '最近游戏角色', dataIndex: 'lastGameRoleName', label: '玩家列表', align: 'center', width: 110, default: 2, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '玩家昵称', dataIndex: 'nickname', label: '玩家列表', align: 'center', width: 120, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '玩家注册IP', dataIndex: 'regIp', label: '玩家列表', align: 'center', width: 100, default: 3, render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />) },
+                { title: '玩家注册时间', dataIndex: 'createTime', label: '玩家列表', align: 'center', width: 140, default: 4, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '注册渠道', dataIndex: 'agentName', label: '玩家列表', align: 'center', width: 120, default: 5, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: 'CP名称', dataIndex: 'cpName', label: '玩家列表', align: 'center', width: 70, default: 6, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '注册游戏', dataIndex: 'gameName', label: '玩家列表', align: 'center', width: 80, default: 7, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '注册游戏应用类型', dataIndex: 'gameCategoryName', label: '玩家列表', align: 'center', width: 80, default: 8, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '归因投放人员', dataIndex: 'pitcherName', label: '玩家列表', align: 'center', width: 60, default: 9, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '归因推广账号', dataIndex: 'accountId', label: '玩家列表', align: 'center', width: 75, default: 10, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '关联游戏名称', dataIndex: 'relationGameName', label: '玩家列表', align: 'center', width: 80, default: 11, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '关联用户ID', dataIndex: 'relationUserId', label: '玩家列表', align: 'center', width: 80, default: 12, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '关联建立时间', dataIndex: 'relationCreateTime', label: '玩家列表', align: 'center', width: 140, default: 13, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '绑定手机', dataIndex: 'mobile', label: '玩家列表', align: 'center', width: 90, default: 14, render: (a: string, b: any) => (<WidthEllipsis value={a || '--'} />) },
+                { title: '充值金额', dataIndex: 'rechargeMoney', label: '玩家列表', align: 'center', width: 80, default: 15, render: (a: string, b: any) => (<Statistic value={a || 0} />) },
+                { title: '充值次数', dataIndex: 'rechargeCount', label: '玩家列表', align: 'center', width: 45, default: 16, render: (a: string, b: any) => (<Statistic value={a || 0} />) },
+                { title: '创角数', dataIndex: 'roleCount', label: '玩家列表', align: 'center', width: 45, default: 17, render: (a: string, b: any) => (<Statistic value={a || 0} />) },
+                { title: '最近登录时间', dataIndex: 'updateTime', label: '玩家列表', align: 'center', width: 140, default: 18, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '最近充值时间', dataIndex: 'lastRechargeTime', label: '玩家列表', align: 'center', width: 140, default: 19, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                {
+                    title: '注册充值时间差',
+                    dataIndex: 'regPayTimeDiff',
+                    align: 'center',
+                    label: '玩家列表',
+                    width: 140,
+                    default: 20,
+                    render: (a: string, b: any) => {
+                        function secondsToDhms(seconds: any) {
+                            const days = Math.floor(seconds / (3600 * 24));
+                            const hours = Math.floor((seconds % (3600 * 24)) / 3600);
+                            const minutes = Math.floor((seconds % 3600) / 60);
+                            const remainingSeconds = seconds % 60;
+                            return `${days ? days + "天" : ''}${hours ? hours + "小时" : ''}${minutes ? minutes + "分" : ''}${remainingSeconds ? remainingSeconds + "秒" : ''}`
+                        }
+                        return a ? <WidthEllipsis value={secondsToDhms(a)} /> : '--'
+                    }
+                },
+                {
+                    title: '玩家状态', dataIndex: 'status', label: '玩家列表', align: 'center', width: 70, default: 21,
+                    render: (a: any) => {
+                        return { '3': <Badge status="error" text="冻结" />, '2': <Badge status="success" text="正常" />, '1': <Badge status="warning" text="试玩" /> }[a]
+                    }
+                },
+            ]
+        },
+        {
+            label: '操作',
+            data: [
+                {
+                    title: '操作',
+                    dataIndex: 'cz',
+                    align: 'center',
+                    width: 155,
+                    label: '操作',
+                    default: 22,
+                    render: (a: string, b: any) => {
+                        return <Row justify='center' gutter={[10, 0]}>
+                            {b?.gameCategoryId === 6 && !b?.relationUserId && <Col><a style={{ fontSize: "12px" }} onClick={() => { exportH5(b) }}><SwapOutlined /> 导H5</a></Col>}
+                            <Col><a style={{ fontSize: "12px" }} onClick={() => { lookHandle(b.id) }}><EyeOutlined /> 查看</a></Col>
+                            <Col>
+                                <Popconfirm
+                                    title={(b?.status == '1' || b?.status == '2') ? `确定封禁?` : `确定解封?`}
+                                    onConfirm={() => { interdictionHandle(b?.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>
+                            </Col>
+                        </Row>
+                    }
+                }
+            ]
+        }
+    ]
+
+    return newArr
+}
+
+export default columns12

+ 127 - 0
src/pages/gameDataStatistics/player/role/index.tsx

@@ -0,0 +1,127 @@
+import { useAjax } from "@/Hook/useAjax"
+import { PlayerRoleListProps, getUserRoleListApi } from "@/services/gameData/player"
+import React, { useEffect, useState } from "react"
+import TableData from "../../components/TableData"
+import QueryForm from "@/components/QueryForm"
+import { getPresetsRanking } from "@/components/QueryForm/const"
+import columns12 from "./tableConfig"
+import moment from "moment"
+
+/**
+ * 玩家角色列表
+ * @returns 
+ */
+const Role: React.FC = () => {
+
+    /************************/
+    const [queryForm, setQueryForm] = useState<PlayerRoleListProps>({ pageNum: 1, pageSize: 50, sourceSystem: 'ZX_ONE' })
+    const getUserRoleList = useAjax((params) => getUserRoleListApi(params))
+    /************************/
+
+    useEffect(() => {
+        getUserRoleList.run(queryForm)
+    }, [queryForm])
+
+    return <div>
+        <TableData
+            leftChild={<QueryForm
+                initialValues={{ sourceSystem: 'ZX_ONE' }}
+                onChange={(data: any) => {
+                    console.log(data)
+                    const { gameUserId, username, gameClassify, agentId, roleCount, rechargeDay, regStartDay, regEndDay, regPayIntervalTime, createRoleDay, ...par } = data
+                    let newQueryForm = JSON.parse(JSON.stringify(queryForm))
+                    newQueryForm.pageNum = 1
+                    newQueryForm.userId = gameUserId
+                    newQueryForm.userName = username
+                    newQueryForm.gameCategoryId = gameClassify
+                    newQueryForm.channelId = agentId
+                    if (rechargeDay && rechargeDay?.length === 2) {
+                        newQueryForm['rechargeBeginDate'] = moment(rechargeDay[0]).format('YYYY-MM-DD')
+                        newQueryForm['rechargeEndDate'] = moment(rechargeDay[1]).format('YYYY-MM-DD')
+                    } else {
+                        delete newQueryForm['rechargeBeginDate']
+                        delete newQueryForm['rechargeEndDate']
+                    }
+                    if (createRoleDay && createRoleDay?.length === 2) {
+                        newQueryForm['beginDate'] = moment(createRoleDay[0]).format('YYYY-MM-DD')
+                        newQueryForm['endDate'] = moment(createRoleDay[1]).format('YYYY-MM-DD')
+                    } else {
+                        delete newQueryForm['beginDate']
+                        delete newQueryForm['endDate']
+                    }
+                    if (regStartDay && regEndDay) {
+                        newQueryForm.regTimeBeginDate = regStartDay
+                        newQueryForm.regTimeEndDate = regEndDay
+                    } else {
+                        delete newQueryForm.regTimeBeginDate
+                        delete newQueryForm.regTimeEndDate
+                    }
+                    if (regPayIntervalTime?.length > 0 && (regPayIntervalTime[0] || regPayIntervalTime[1])) {
+                        newQueryForm.regPayIntervalTimeMin = regPayIntervalTime[0]
+                        newQueryForm.regPayIntervalTimeMax = regPayIntervalTime[1]
+                    } else {
+                        delete newQueryForm.regPayIntervalTimeMin
+                        delete newQueryForm.regPayIntervalTimeMax
+                    }
+                    if (roleCount?.length > 0 && (roleCount[0] || roleCount[1])) {
+                        newQueryForm.roleLevelMin = roleCount[0]
+                        newQueryForm.roleLevelMax = roleCount[1]
+                    } else {
+                        delete newQueryForm.roleLevelMin
+                        delete newQueryForm.roleLevelMax
+                    }
+                    setQueryForm({ ...newQueryForm, ...par })
+                }}
+                isSource
+                isGameUserId
+                isUserName
+                isNickname
+                isRegIp
+                isServerName
+                isGameRoleName
+                isCpId
+                isGameId
+                isBGGameClassify
+                isAgentId
+                isAccountId
+                isSysUserId
+                isOs
+                isIsRecharge
+                isCreateRole
+                rechargeDay={{ ranges: getPresetsRanking() }}
+                isRegDay={{ ranges: getPresetsRanking() }}
+                isCreateRoleDay={{ ranges: getPresetsRanking() }}
+                isPayIntervalTime={{ tips: '充值距注册时间区间(分钟)' }}
+                isRoleCount={{ tips: '玩家等级区间' }}
+            />}
+            scroll={{ x: 1000, y: 600 }}
+            ajax={getUserRoleList}
+            fixed={{ left: 1, right: 0 }}
+            dataSource={getUserRoleList?.data?.records}
+            page={getUserRoleList?.data?.current || 1}
+            pageSize={getUserRoleList?.data?.size || 20}
+            total={getUserRoleList?.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={'玩家角色列表'}
+        />
+    </div>
+}
+
+export default Role

+ 62 - 0
src/pages/gameDataStatistics/player/role/tableConfig.tsx

@@ -0,0 +1,62 @@
+import WidthEllipsis from "@/components/widthEllipsis"
+import { Statistic } from "antd"
+import React from "react"
+
+function columns12() {
+
+    let newArr: { label: string, data: any[] }[] = [
+        {
+            label: '玩家列表',
+            data: [
+                { title: '玩家ID', dataIndex: 'id', label: '玩家列表', align: 'center', default: 1, width: 55 },
+                { title: '玩家账号', dataIndex: 'username', label: '玩家列表', align: 'center', width: 120, default: 2, render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />) },
+                { title: '玩家昵称', dataIndex: 'nickname', label: '玩家列表', align: 'center', width: 120, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '玩家注册IP', dataIndex: 'regIp', label: '玩家列表', align: 'center', width: 100, default: 3, render: (a: string, b: any) => (<WidthEllipsis isCopy value={a} />) },
+                { title: '玩家注册时间', dataIndex: 'createTime', label: '玩家列表', align: 'center', width: 140, default: 4, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '注册渠道', dataIndex: 'agentName', label: '玩家列表', align: 'center', width: 120, default: 5, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: 'CP名称', dataIndex: 'cpName', label: '玩家列表', align: 'center', width: 70, default: 6, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '归因投放人员', dataIndex: 'pitcherName', label: '玩家列表', align: 'center', width: 60, default: 7, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '归因推广账号', dataIndex: 'accountId', label: '玩家列表', align: 'center', width: 75, default: 8, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '游戏名称', dataIndex: 'gameName', label: '玩家列表', align: 'center', width: 80, default: 9, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '游戏应用类型', dataIndex: 'gameCategoryName', label: '玩家列表', align: 'center', width: 80, default: 10, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '原始游戏区服', dataIndex: 'sourceServerName', label: '玩家列表', align: 'center', width: 80, default: 11, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '游戏区服', dataIndex: 'serverName', label: '玩家列表', align: 'center', width: 75, default: 12, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '游戏角色', dataIndex: 'roleName', label: '玩家列表', align: 'center', width: 90, default: 13, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '游戏角色ID', dataIndex: 'roleId', label: '玩家列表', align: 'center', width: 130, default: 14, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '角色等级', dataIndex: 'roleLevel', label: '玩家列表', align: 'center', width: 70, default: 15, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '战力', dataIndex: 'rolePower', label: '玩家列表', align: 'center', width: 85, default: 16, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '角色VIP', dataIndex: 'roleVipLevel', label: '玩家列表', align: 'center', width: 60, default: 17, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '操作系统', dataIndex: 'os', label: '玩家列表', align: 'center', width: 65, default: 18, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '充值金额', dataIndex: 'rechargeMoney', label: '玩家列表', align: 'center', width: 80, default: 19, render: (a: string, b: any) => (<Statistic value={a || 0} />) },
+                { title: '充值次数', dataIndex: 'rechargeCount', label: '玩家列表', align: 'center', width: 45, default: 20, render: (a: string, b: any) => (<Statistic value={a || 0} />) },
+                { title: '游戏角色创建时间', dataIndex: 'createTime', label: '玩家列表', align: 'center', width: 140, default: 21, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '最近登录时间', dataIndex: 'lastLoginTime', label: '玩家列表', align: 'center', width: 140, default: 22, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '游戏角色更新时间', dataIndex: 'updateTime', label: '玩家列表', align: 'center', width: 140, default: 23, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                { title: '最近充值时间', dataIndex: 'lastRechargeTime', label: '玩家列表', align: 'center', width: 140, default: 24, render: (a: string, b: any) => (<WidthEllipsis value={a} />) },
+                {
+                    title: '注册充值时间差',
+                    dataIndex: 'regPayTimeDiff',
+                    align: 'center',
+                    label: '玩家列表',
+                    width: 140,
+                    default: 25,
+                    render: (a: string, b: any) => {
+                        function secondsToDhms(seconds: any) {
+                            const days = Math.floor(seconds / (3600 * 24));
+                            const hours = Math.floor((seconds % (3600 * 24)) / 3600);
+                            const minutes = Math.floor((seconds % 3600) / 60);
+                            const remainingSeconds = seconds % 60;
+                            return `${days ? days + "天" : ''}${hours ? hours + "小时" : ''}${minutes ? minutes + "分" : ''}${remainingSeconds ? remainingSeconds + "秒" : ''}`
+                        }
+                        return a ? <WidthEllipsis value={secondsToDhms(a)} /> : '--'
+                    }
+                }
+            ]
+        },
+       
+    ]
+
+    return newArr
+}
+
+export default columns12

+ 0 - 1
src/pages/gameDataStatistics/rankingList/gamer/index.tsx

@@ -2,7 +2,6 @@ import { useAjax } from "@/Hook/useAjax"
 import { getRechargeUserListApi, UserRechargeListType } from "@/services/gameData/rankingList"
 import React, { useEffect, useState } from "react"
 import TableData from "../../components/TableData"
-import TableData1 from "../../components/TableData/index1"
 import columns12 from "./tableConfig"
 import QueryForm from "@/components/QueryForm"
 import moment from "moment"

+ 18 - 0
src/services/gameData/index.ts

@@ -33,6 +33,16 @@ export async function getGameChoiceListApi() {
     });
 }
 
+/**
+ * CP列表
+ * @returns 
+ */
+export async function getCpChoiceListApi() {
+    return request(gameApi + `/manage/choice/cp/list`, {
+        method: 'GET',
+    });
+}
+
 /**
  * 投手列表
  * @returns 
@@ -81,4 +91,12 @@ export async function getUserSystemTypeChoiceListApi() {
  */
 export async function getPayListApi() {
     return request(gameApi + '/manage/choice/pay/way/list');
+}
+
+/**
+ * vip等级选择列表选择列表
+ * @returns 
+ */
+export async function getUserVipLevelChoiceListApi() {
+    return request(gameApi + `/manage/choice/vip/level/list`);
 }

+ 18 - 0
src/services/gameData/order.ts

@@ -82,4 +82,22 @@ export async function getOrderTotalApi(data: OrderListType) {
         method: 'POST',
         data
     });
+}
+
+/** 获取通知CP记录 */
+export interface CpLogListProps {
+    pageNum: number,
+    pageSize: number,
+    orderId?: string  // 订单ID
+}
+/**
+ * cp通知记录
+ * @param data 
+ * @returns 
+ */
+export async function getOrderCpNoticeApi(data: CpLogListProps) {
+    return request(wapi + `/order/detail`, {
+        method: 'POST',
+        data
+    });
 }

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

@@ -0,0 +1,201 @@
+import { request } from 'umi';
+import { api } from '../api';
+import { Paging, SortProps } from './rankingList';
+let wapi = api + '/gameData'
+
+export interface PlayerListProps extends Paging, SortProps {
+    userId?: string,  // 玩家ID
+    userName?: string, // 玩家账号
+    nickname?: string, // 玩家昵称
+    mobile?: string,     // 绑定手机
+    regIp?: string,  // 注册IP
+    isAuth?: any,  // 是否实名认证
+    isBindMobile?: any,  // 手机绑定状态
+    cpId?: any,   // CP
+    gameId?: number, // 游戏
+    gameCategoryId?: any, // 游戏应用类型对应的id
+    beginDate?: string,  // 注册开始时间
+    endDate?: string,
+    rechargeBeginDate?: string, // 最近充值开始时间
+    rechargeEndDate?: string
+    isRecharge?: boolean, // 是否充值
+    status?: number   // 玩家状态, 0 : 正常, 1 : 封禁
+    channelId?: number,  // 注册渠道对应的id
+    accountId?: string,  // 归因推广账号
+    pitcherId?: number,  // 归因投放人员
+    createRole?: boolean,  // 是否创角
+    regPayIntervalTimeMin?: number  // 充值距注册时间区间(分钟)
+    regPayIntervalTimeMax?: number
+    roleCountMin?: number,   // 角色数量最大值
+    roleCountMax?: number
+}
+/**
+ * 投手总数居
+ * @param data 
+ * @returns 
+ */
+export async function getPlayerListApi(data: PlayerListProps) {
+    return request(wapi + `/player/list`, {
+        method: 'POST',
+        data
+    });
+}
+
+/**玩家详情
+ * @param id 玩家ID
+ * */
+export async function getUserInfotApi(id: number) {
+    return request(api + `/manage/user/info?id=${id}`, {
+        method: 'get',
+    });
+}
+
+/**
+ * 封禁结晶
+ * @param data 
+ * @returns 
+ */
+export async function interdictionGamerApi(data: { userId: number, status: number }) {
+    return request(api + `/manage/ban/user/add/or/update`, {
+        method: 'POST',
+        data
+    });
+}
+
+/**
+ * 小游戏玩家导量到H5游戏
+ * @param params 
+ * @returns 
+ */
+export async function exportUserH5Api(params: {mobile: number, userId: string}) {
+    return request(api + `/manage/user/applet/to/h5`, {
+        method: 'PATCH',
+        params
+    });
+}
+
+/**
+ * 地址列表
+ * @param id 玩家ID
+ * @returns
+ * */
+export async function getUserAddressListApi(id: number) {
+    return request(api + `/manage/user/address/list?userId=${id}`, {
+        method: 'get',
+    });
+}
+
+/**
+ * 玩家游戏角色列表
+ * @param id 玩家ID
+ * @returns
+ * */
+export async function getUserGameRoleListApi(id: number) {
+    return request(api + `/manage/user/game/role/list?userId=${id}`, {
+        method: 'GET',
+    });
+}
+
+/**
+ * 玩家登录记录列表
+ * @param userId 玩家ID
+ * @returns
+ * */
+export async function getUserLoginListApi(params: { userId: number, pageNum: number, pageSize: number }) {
+    return request(api + `/manage/user/login/list`, {
+        method: 'POST',
+        data: params,
+    });
+}
+
+/**
+ * 玩家下单记录列表
+ * @param userId 玩家ID
+ * @returns
+ * */
+export async function getUserOrderListApi(params: { userId: number, pageNum: number, pageSize: number }) {
+    return request(api + `/manage/user/order/list`, {
+        method: 'POST',
+        data: params,
+    });
+}
+
+/**
+ * 玩家信息编辑
+ * @param aliPay 绑定支付宝账号
+ * @param idCard 证件号码
+ * @param mobile 绑定手机号码
+ * @param password 密码
+ * @param realName 真实姓名
+ * @param userId 玩家id
+ * @param username 玩家账号
+ * */
+export type UserUpdateParams = {
+    aliPay?: string,
+    idCard?: string,
+    mobile?: string,
+    password?: string,
+    realName?: string,
+    userId?: string,
+    username?: string
+}
+export async function getUserUpdateApi(params: UserUpdateParams) {
+    return request(api + `/manage/user/update`, {
+        method: 'POST',
+        data: params,
+    });
+}
+
+/**获取微信信息*/ 
+export async function getUserWeChatApi(userId: any) {
+    return request(api + `/manage/user/weChat/info?userId=${userId}`, {
+        method: 'GET',
+    });
+}
+
+
+
+/*****************玩家角色******************/
+
+/** 获取玩家游戏角色列表 */
+export interface PlayerRoleListProps extends Paging, SortProps {
+    accountId?: string, // 归因推广账号
+    beginDate?:string,//开始时间
+    endDate?:string,//结束时间
+    channelId?:number,//注册渠道对应的id
+    cpId?:number,//cp名称对应的id
+    gameCategoryId?:number,//游戏应用类型对应的id
+    gameId?:number,//游戏名称对应的id
+    isRecharge?:boolean,//是否充值, true : 是, false : 否, 全部 : null或者不传
+    nickname?:string,//玩家昵称
+    os?:string,//操作系统对应的id, 全部 : null或者不传
+    rechargeBeginDate?:string,//最近充值开始时间(注册开始时间请使用beginDate参数)
+    rechargeEndDate?:string,//最近充值结束时间(注册结束时间请使用endDate参数)
+    regIp?:string,//注册IP
+    roleName?:string,//游戏角色
+    serverName?:string,//游戏区服
+    pitcherId?: number, // 归因投放人员
+    userId?:string,//玩家id
+    userName?:string,//玩家账号
+    vipLevel?:number,//角色vip, 全部 : null或者不传
+    roleLevelMin?: number,  // 最大角色等级
+    roleLevelMax?: number,
+    regPayIntervalTimeMin?: number, // 充值到注册的间隔时间(分)
+    regPayIntervalTimeMax?: number
+}
+
+/** 玩家角色列表 */
+export async function getUserRoleListApi(params: PlayerRoleListProps) {
+    return request(wapi + '/player/role/list', {
+        method: 'POST',
+        data: params,
+    });
+}
+
+export async function downloadRoleListApi(params: PlayerRoleListProps) {
+    return request(api + '/manage/user/role/list/excel', {
+        method: 'POST',
+        data: params,
+        responseType: 'blob',
+    });
+}

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.