Browse Source

feat: 广告列表展示user

lihao
nili 4 months ago
parent
commit
a590cf37cc
  1. 20
      config/routes.ts
  2. 108
      dist/841.2ae59567.async.js
  3. 108
      dist/841.614ef4c0.async.js
  4. 1
      dist/_umi_route_preload_helper.06791e99.js
  5. 1
      dist/_umi_route_preload_helper.77c14e0c.js
  6. 4
      dist/index.html
  7. 1
      dist/p__AdvRecordListV2.30086e42.async.js
  8. 1
      dist/p__App__AppManagement.10ce4bad.async.js
  9. 1
      dist/p__App__AppManagement.37218ab6.async.js
  10. 1
      dist/p__MoneyManagement.79d40f90.async.js
  11. 1
      dist/p__SuperAdmin.2c0b0908.async.js
  12. 1
      dist/p__SuperAdmin.9634e267.async.js
  13. 1
      dist/p__UserManagement.6aa3da9c.async.js
  14. 142
      dist/umi.5f5e048f.js
  15. 5
      package.json
  16. 60
      src/app.tsx
  17. 347
      src/pages/AdvRecordListV2.tsx
  18. 36
      src/pages/App/AppBasicConfigForm.tsx
  19. 13
      src/pages/App/SuperAdminAppManagement.tsx
  20. 11
      src/pages/MoneyManagement.tsx
  21. 1
      src/pages/OSSUploadDragger.tsx
  22. 41
      src/pages/SuperAdmin.tsx
  23. 11
      src/pages/UserManagement.tsx
  24. 1
      src/services/matrix/typings.d.ts
  25. 8
      src/utils/commonUtil.ts
  26. 8
      src/utils/numberUtils.ts

20
config/routes.ts

@ -42,6 +42,26 @@ export default [
access: 'canAdmin',
component: './AdvRecordList',
},
{
path: '/advListV2/:code',
name: '广告列表',
access: 'canAdmin',
component: './AdvRecordListV2',
},
{
path: '/user/:code',
name: '用户管理',
icon: 'smile',
access: 'canAdmin',
component: './UserManagement',
},
{
path: '/money/:code',
name: '提现管理',
icon: 'smile',
access: 'canAdmin',
component: './MoneyManagement',
},
{
path: '/app/:code',
name: '应用列表',

108
dist/841.2ae59567.async.js

File diff suppressed because one or more lines are too long

108
dist/841.614ef4c0.async.js

File diff suppressed because one or more lines are too long

1
dist/_umi_route_preload_helper.06791e99.js

@ -1 +0,0 @@
!function(){"use strict";var t="/".replace(/([^/])$/,"$1/"),e=location.pathname,n=e.startsWith(t)&&decodeURI("/".concat(e.slice(t.length)));if(n){var a=document,c=a.head,r=a.createElement.bind(a),i=function(t,e,n){var a,c=e.r[t]||(null===(a=Object.entries(e.r).find((function(e){var n=e[0];return new RegExp("^".concat(n.replace(/\/:[^/]+/g,"/[^/]+").replace("/*","/.+"),"$")).test(t)})))||void 0===a?void 0:a[1]);return null==c?void 0:c.map((function(t){var a=e.f[t][1],c=e.f[t][0];return{type:c.split(".").pop(),url:"".concat(n.publicPath).concat(c),attrs:[["data-".concat(e.b),"".concat(e.p,":").concat(a)]]}}))}(n,{"p":"ant-design-pro","b":"webpack","f":[["51.a2ea1b3b.async.js",51],["63.86ff1d28.async.js",63],["134.6fc81d91.async.js",134],["169.57647c7d.async.js",169],["p__Welcome.61596037.async.js",185],["235.ac8537cc.async.js",235],["247.3fe8fb10.async.js",247],["t__plugin-layout__Layout.6cae69f5.chunk.css",301],["t__plugin-layout__Layout.4594a64b.async.js",301],["335.fcb437d3.async.js",335],["p__User__Login__index.9d3ab92e.async.js",366],["p__DeviceOwnerApp.1442f75c.async.js",371],["390.41467286.async.js",390],["393.38316f72.async.js",393],["397.fb5f72c1.async.js",397],["p__SuperAdmin.2c0b0908.async.js",455],["531.3d4ec55a.async.js",531],["p__Bind.b6ee068f.async.js",557],["559.016bfdbb.async.js",559],["p__404.0c100574.async.js",571],["635.20e45f05.async.js",635],["p__App__AppManagement.10ce4bad.async.js",731],["p__AdminManagement.4b0ea38b.async.js",816],["841.2ae59567.async.js",841],["848.32a73e48.async.js",848],["p__AdvRecordList.957040e5.async.js",857],["905.6e225d1b.async.js",905],["930.fca7adbf.async.js",930]],"r":{"/*":[19,26],"/":[2,7,8,18,20,26],"/welcome":[2,3,4,13,18,27,7,8,20,26],"/super":[0,1,2,3,5,6,15,27,7,8,18,20,26],"/adminList":[0,3,5,22,24,2,7,8,18,20,26],"/bind":[2,3,13,14,17,18,27,7,8,20,26],"/appList":[0,1,2,3,5,6,9,14,16,21,24,26,27,7,8,18,20],"/advList/:code":[0,1,2,3,5,9,16,18,23,24,25,26,27,7,8,20],"/app/:code":[0,1,2,3,5,9,11,16,18,23,24,26,27,7,8,20],"/user/login":[1,2,3,5,10,16,24]}},{publicPath:"/"});null==i||i.forEach((function(t){var e,n=t.type,a=t.url;if("js"===n)(e=r("script")).src=a,e.async=!0;else{if("css"!==n)return;(e=r("link")).href=a,e.rel="preload",e.as="style"}t.attrs.forEach((function(t){e.setAttribute(t[0],t[1]||"")})),c.appendChild(e)}))}}();

1
dist/_umi_route_preload_helper.77c14e0c.js

@ -0,0 +1 @@
!function(){"use strict";var t="/".replace(/([^/])$/,"$1/"),e=location.pathname,n=e.startsWith(t)&&decodeURI("/".concat(e.slice(t.length)));if(n){var a=document,c=a.head,r=a.createElement.bind(a),i=function(t,e,n){var a,c=e.r[t]||(null===(a=Object.entries(e.r).find((function(e){var n=e[0];return new RegExp("^".concat(n.replace(/\/:[^/]+/g,"/[^/]+").replace("/*","/.+"),"$")).test(t)})))||void 0===a?void 0:a[1]);return null==c?void 0:c.map((function(t){var a=e.f[t][1],c=e.f[t][0];return{type:c.split(".").pop(),url:"".concat(n.publicPath).concat(c),attrs:[["data-".concat(e.b),"".concat(e.p,":").concat(a)]]}}))}(n,{"p":"ant-design-pro","b":"webpack","f":[["51.a2ea1b3b.async.js",51],["63.86ff1d28.async.js",63],["134.6fc81d91.async.js",134],["169.57647c7d.async.js",169],["p__Welcome.61596037.async.js",185],["p__MoneyManagement.79d40f90.async.js",190],["235.ac8537cc.async.js",235],["247.3fe8fb10.async.js",247],["t__plugin-layout__Layout.6cae69f5.chunk.css",301],["t__plugin-layout__Layout.4594a64b.async.js",301],["335.fcb437d3.async.js",335],["p__User__Login__index.9d3ab92e.async.js",366],["p__DeviceOwnerApp.1442f75c.async.js",371],["390.41467286.async.js",390],["393.38316f72.async.js",393],["397.fb5f72c1.async.js",397],["p__SuperAdmin.9634e267.async.js",455],["531.3d4ec55a.async.js",531],["p__AdvRecordListV2.30086e42.async.js",542],["p__Bind.b6ee068f.async.js",557],["559.016bfdbb.async.js",559],["p__404.0c100574.async.js",571],["635.20e45f05.async.js",635],["p__App__AppManagement.37218ab6.async.js",731],["p__AdminManagement.4b0ea38b.async.js",816],["841.614ef4c0.async.js",841],["848.32a73e48.async.js",848],["p__AdvRecordList.957040e5.async.js",857],["p__UserManagement.6aa3da9c.async.js",903],["905.6e225d1b.async.js",905],["930.fca7adbf.async.js",930]],"r":{"/*":[21,29],"/":[2,8,9,20,22,29],"/welcome":[2,3,4,14,20,30,8,9,22,29],"/super":[0,1,2,3,6,7,16,30,8,9,20,22,29],"/adminList":[0,3,6,24,26,2,8,9,20,22,29],"/bind":[2,3,14,15,19,20,30,8,9,22,29],"/appList":[0,1,2,3,6,7,10,15,17,23,26,29,30,8,9,20,22],"/advList/:code":[0,1,2,3,6,10,17,20,25,26,27,29,30,8,9,22],"/advListV2/:code":[0,1,2,3,6,10,17,18,20,25,26,29,30,8,9,22],"/user/:code":[2,3,28,30,8,9,20,22,29],"/money/:code":[2,3,5,30,8,9,20,22,29],"/app/:code":[0,1,2,3,6,10,12,17,20,25,26,29,30,8,9,22],"/user/login":[1,2,3,6,11,17,26]}},{publicPath:"/"});null==i||i.forEach((function(t){var e,n=t.type,a=t.url;if("js"===n)(e=r("script")).src=a,e.async=!0;else{if("css"!==n)return;(e=r("link")).href=a,e.rel="preload",e.as="style"}t.attrs.forEach((function(t){e.setAttribute(t[0],t[1]||"")})),c.appendChild(e)}))}}();

4
dist/index.html

@ -7,10 +7,10 @@
<title>Ant Design Pro</title>
<link rel="stylesheet" href="/umi.1ca9308c.css">
<script async src="/scripts/loading.js"></script>
<script src="/_umi_route_preload_helper.06791e99.js"></script>
<script src="/_umi_route_preload_helper.77c14e0c.js"></script>
</head>
<body>
<div id="root"></div>
<script src="/umi.3080703f.js"></script>
<script src="/umi.5f5e048f.js"></script>
</body>
</html>

1
dist/p__AdvRecordListV2.30086e42.async.js

File diff suppressed because one or more lines are too long

1
dist/p__App__AppManagement.10ce4bad.async.js

File diff suppressed because one or more lines are too long

1
dist/p__App__AppManagement.37218ab6.async.js

File diff suppressed because one or more lines are too long

1
dist/p__MoneyManagement.79d40f90.async.js

@ -0,0 +1 @@
"use strict";(self.webpackChunkant_design_pro=self.webpackChunkant_design_pro||[]).push([[190],{3295:function(s,e,n){n.r(e);var t=n(90930),_=n(85893),a=function(){return(0,_.jsx)(t._z,{children:(0,_.jsx)("p",{children:"TODO"})})};e.default=a}}]);

1
dist/p__SuperAdmin.2c0b0908.async.js

File diff suppressed because one or more lines are too long

1
dist/p__SuperAdmin.9634e267.async.js

File diff suppressed because one or more lines are too long

1
dist/p__UserManagement.6aa3da9c.async.js

@ -0,0 +1 @@
"use strict";(self.webpackChunkant_design_pro=self.webpackChunkant_design_pro||[]).push([[903],{47989:function(a,e,n){n.r(e);var _=n(90930),s=n(85893),t=function(){return(0,s.jsx)(_._z,{children:(0,s.jsx)("p",{children:"TODO"})})};e.default=t}}]);

142
dist/umi.3080703f.js → dist/umi.5f5e048f.js

File diff suppressed because one or more lines are too long

5
package.json

@ -51,7 +51,7 @@
"@ant-design/pro-components": "^2.6.48",
"@umijs/route-utils": "^2.2.2",
"ali-oss": "^6.20.0",
"antd": "^5.13.2",
"antd": "^5.17.3",
"antd-style": "^3.6.1",
"classnames": "^2.5.1",
"lodash": "^4.17.21",
@ -68,12 +68,13 @@
"devDependencies": {
"@ant-design/pro-cli": "^3.3.0",
"@testing-library/react": "^13.4.0",
"@types/ali-oss": "^6.16.11",
"@types/classnames": "^2.3.1",
"@types/express": "^4.17.21",
"@types/history": "^4.7.11",
"@types/jest": "^29.5.11",
"@types/lodash": "^4.14.202",
"@types/react": "^18.2.48",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.2.18",
"@types/react-helmet": "^6.1.11",
"@types/spark-md5": "^3.0.2",

60
src/app.tsx

@ -7,6 +7,7 @@ import { Link, history } from '@umijs/max';
import { appList } from '@/services/matrix/admin';
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
import type { RunTimeLayoutConfig } from '@umijs/max';
import { JSXElementConstructor, ReactElement, ReactNode, ReactPortal } from 'react';
import defaultSettings from '../config/defaultSettings';
import access from './access';
import { errorConfig } from './requestErrorConfig';
@ -49,6 +50,41 @@ export async function getInitialState(): Promise<{
};
}
const matrixMenu = (app: API.MatrixAppBo): MenuDataItem => {
if (!app.enableCash) {
return {
path: '/advList/' + app.code,
name: app.name,
access: 'canAdmin',
component: './AdvRecordList',
};
}
return {
name: app.name,
access: 'canAdmin',
children: [
{
name: '广告数据',
path: '/advListV2/' + app.code,
access: 'canAdmin',
component: './AdvRecordListV2',
},
{
name: '用户管理',
path: '/user/' + app.code,
access: 'canAdmin',
component: './UserManagement',
},
{
name: '提现管理',
path: '/money/' + app.code,
access: 'canAdmin',
component: './MoneyManagement',
},
],
};
};
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
return {
@ -64,12 +100,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
apps.data?.forEach((x: any) => {
if (x.hide === 1 && role <= 2) {
} else {
menuData.push({
path: '/advList/' + x.code,
name: x.name,
access: 'canAdmin',
component: './AdvRecordList',
});
menuData.push(matrixMenu(x));
}
if (role === 4) {
menuData.push({
@ -109,7 +140,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
},
},
// 添加权限校验逻辑
menuDataRender: (menuData) =>
menuDataRender: (menuData: MenuDataItem[]) =>
menuData.map((item) => {
const val = item.access;
if (!val) {
@ -130,7 +161,18 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
avatarProps: {
// src: initialState?.currentUser?.avatar,
title: <AvatarName />,
render: (_, avatarChildren) => {
render: (
_: any,
avatarChildren:
| string
| number
| boolean
| ReactElement<any, string | JSXElementConstructor<any>>
| Iterable<ReactNode>
| ReactPortal
| null
| undefined,
) => {
return <AvatarDropdown>{avatarChildren}</AvatarDropdown>;
},
},
@ -168,7 +210,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
links: isDev
? [
<Link key="openapi" to="/umi/plugin/openapi" target="_blank">
<LinkOutlined onPointerEnterCapture={undefined} onPointerLeaveCapture={undefined} />
<LinkOutlined onPointerOverCapture={undefined} onPointerMoveCapture={undefined} />
<span>OpenAPI </span>
</Link>,
]

347
src/pages/AdvRecordListV2.tsx

@ -0,0 +1,347 @@
import { advList, incomeDaily, incomeOverview } from '@/services/matrix/admin';
import { Column } from '@ant-design/charts';
import {
ColumnsState,
PageContainer,
ProColumns,
ProFormDateRangePicker,
ProFormSelect,
ProTable,
QueryFilter,
StatisticCard,
} from '@ant-design/pro-components';
import { Avatar, Row, Tabs } from 'antd';
import TabPane from 'antd/es/tabs/TabPane';
import moment from 'moment';
import RcResizeObserver from 'rc-resize-observer';
import React, { useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
// import { RequestOptionsType, ProFieldRequestData } from "@ant-design/pro-utils";
import { formatIncome } from '@/utils/numberUtils';
import type { ActionType } from '@ant-design/pro-components';
const AdvRecordListV2: React.FC = () => {
const actionRef = useRef<ActionType>();
const [income, setIncome] = useState<number | undefined>(undefined);
const isMobile = () => {
return window.innerWidth <= 768;
};
const [columnsState, setColumnsState] = useState<Record<string, ColumnsState>>({
deviceId: { show: !isMobile() },
appName: { show: !isMobile() },
platform: { show: !isMobile() },
deviceBrand: { show: !isMobile() },
deviceName: { show: !isMobile() },
ip: { show: !isMobile() },
advType: { show: !isMobile() },
});
const columns: ProColumns<API.MatrixAdvRecordBo>[] = [
{
title: '设备id',
dataIndex: 'deviceId',
valueType: 'textarea',
ellipsis: true,
copyable: true,
},
{
title: '应用名称',
hideInSearch: true,
dataIndex: 'appName',
valueType: 'textarea',
},
{
title: '平台',
dataIndex: 'platform',
width: 80,
valueEnum: {
1: {
text: '穿山甲',
},
2: {
text: '腾讯',
},
3: {
text: '百度联盟',
},
4: {
text: 'Mintegral',
},
5: {
text: '快手',
},
6: {
text: '游可赢',
},
7: {
text: 'Sigmob',
},
8: {
text: 'Admob',
},
},
},
{
title: '广告类型',
dataIndex: 'advType',
valueEnum: {
1: {
text: '横幅',
status: 'Default',
},
2: {
text: '插页',
status: 'Processing',
},
3: {
text: '激励视频',
status: 'Success',
},
},
},
{
title: 'ecpm(元)',
dataIndex: 'ecpm',
hideInSearch: true,
renderText: (x) => {
return x / 100;
},
},
{
title: '设备',
dataIndex: 'device',
hideInSearch: true,
renderText: (_, record) => {
return (
<>
<p>{record.deviceBrand}</p>
<p>{record.deviceName}</p>
</>
);
},
},
{
title: 'ip',
dataIndex: 'ip',
hideInSearch: true,
valueType: 'textarea',
},
{
title: '用户',
dataIndex: 'user',
hideInSearch: true,
renderText: (_, record) => {
if (!record.user) {
return;
}
return (
<Row>
<Avatar src={record.user?.avatar} />
<p style={{ fontSize: 12 }}>
id:{record.user.id}
<br />
{record.user?.nickname || record.user?.mobile}
</p>
</Row>
);
},
},
{
title: '时间',
hideInSearch: true,
dataIndex: 'createdAt',
valueType: 'dateTime',
},
{
title: '时间',
hideInTable: true,
dataIndex: 'createdAt',
valueType: 'dateRange',
},
// {
// title: "应用名称",
// hideInTable: true,
// dataIndex: 'appId',
// valueType: "select",
// request: appNameMap
// }
];
const { code } = useParams();
const [overview, setOverview] = useState<API.OverviewBo>();
const [daily, setDaily] = useState<API.DateIncome[]>([]);
const { Divider } = StatisticCard;
const [responsive, setResponsive] = useState(false);
const fetchOverview = async (param: string | undefined) => {
const res = await incomeOverview({ appCode: param });
if (res.data) {
setOverview(res.data);
}
};
const fetchDaily = async (params: API.IncomeQuery) => {
const res = await incomeDaily({ ...params, code: code });
if (res.data) {
setDaily(res.data);
}
};
useEffect(() => {
actionRef.current?.reload();
fetchOverview(code);
fetchDaily({ code: code });
}, [code]);
const processedChartData: { date: string | number; income: number }[] = daily.map((item) => ({
date: (() => {
const inputDateStr = item.date + '';
const year: string = inputDateStr.slice(0, 4);
const month: string = inputDateStr.slice(4, 6);
const day: string = inputDateStr.slice(6, 8);
return `${year}-${month}-${day}`;
})(),
income: formatIncome(item.income),
}));
const config = {
data: processedChartData,
xField: 'date',
yField: 'income',
tooltip: {
name: '收入',
field: 'income',
},
axis: {
date: {
title: '日期',
},
},
title:
'累计' +
formatIncome(daily.reduce((acc, data) => acc + (data.income ? data.income : 0), 0)) +
'元',
height: 400,
label: {
text: (d: any) => (d.income > 0 ? d.income : ''),
textBaseline: 'bottom',
},
};
return (
<PageContainer>
<Tabs defaultActiveKey="1" centered style={{ backgroundColor: 'white', padding: '20px' }}>
<TabPane tab="广告详情" key="1">
<ProTable<API.MatrixAdvRecordBo, API.AdvRecordQuery>
headerTitle={income ? '表格累计:' + formatIncome(income) + '元' : ''}
actionRef={actionRef}
rowKey="key"
search={{
labelWidth: 120,
}}
request={async (params: API.AdvRecordQuery) => {
const res = await advList({ ...params, code: code });
if (params.current === 1) {
setIncome(res.data?.sum);
}
return {
data: res.data?.data,
total: res.data?.total,
success: true,
};
}}
columns={columns}
columnsState={{
value: columnsState,
onChange: (newState) => {
setColumnsState(newState);
},
}}
/>
</TabPane>
<TabPane tab="数据总览" key="2">
<RcResizeObserver
key="resize-observer"
onResize={(offset) => {
setResponsive(offset.width < 596);
}}
>
<StatisticCard>
<StatisticCard.Group direction={responsive ? 'column' : 'row'}>
<StatisticCard
statistic={{
title: '上月收入(元)',
value: formatIncome(overview?.lastMonthIncome),
}}
/>
<Divider type={responsive ? 'horizontal' : 'vertical'} />
<StatisticCard
statistic={{
title: '本月收入(元)',
value: formatIncome(overview?.thisMonthIncome),
}}
/>
<Divider type={responsive ? 'horizontal' : 'vertical'} />
<StatisticCard
statistic={{
title: '今日收入(元)',
value: formatIncome(overview?.todayIncome),
}}
/>
<Divider type={responsive ? 'horizontal' : 'vertical'} />
<StatisticCard
statistic={{
title: '昨日收入(元)',
value: formatIncome(overview?.yesterdayIncome),
}}
/>
</StatisticCard.Group>
</StatisticCard>
</RcResizeObserver>
<QueryFilter defaultCollapsed split onFinish={fetchDaily}>
<ProFormSelect
label="平台"
name="platform"
valueEnum={{
1: '穿山甲',
2: '腾讯',
3: '百度联盟',
4: 'Mintegral',
5: '快手',
6: '游可赢',
7: 'Sigmob',
8: 'Admob',
}}
/>
<ProFormSelect
name="advType"
label="广告类型"
valueEnum={{
1: '横幅',
2: '插页',
3: '激励视频',
}}
/>
<ProFormDateRangePicker
fieldProps={{
disabledDate: (current: any) => current && current >= moment().startOf('day'),
}}
name="date"
label="时间"
/>
</QueryFilter>
{/* <Line {...config} /> */}
<Column {...config} />
</TabPane>
</Tabs>
</PageContainer>
);
};
export default AdvRecordListV2;

36
src/pages/App/AppBasicConfigForm.tsx

@ -1,6 +1,7 @@
import { Form, Input, Modal, Select } from 'antd';
import React, { useEffect, useState } from 'react';
import { getBasicConfig, saveBasicConfig } from '../../services/matrix/matrixAppConfigController';
import { channelList } from '../../utils/commonUtil';
import OSSUpload from '../OSSUpload';
export type AppBasicConfigFormProps = {
@ -62,11 +63,7 @@ const AppBasicConfigForm: React.FC<AppBasicConfigFormProps> = (props) => {
</Form.Item>
<Form.Item label="应用图片" name="img">
<Input.Group compact>
<Form.Item
name="img"
noStyle
rules={[{ required: true, message: '请输入图片地址或选择图片上传!' }]}
>
<Form.Item name="img" noStyle>
<Input />
</Form.Item>
<OSSUpload
@ -78,11 +75,7 @@ const AppBasicConfigForm: React.FC<AppBasicConfigFormProps> = (props) => {
</Form.Item>
<Form.Item label="下载地址" name="url">
<Input.Group compact>
<Form.Item
name="url"
noStyle
rules={[{ required: true, message: '请输入下载地址或选择安装包上传!' }]}
>
<Form.Item name="url" noStyle>
<Input />
</Form.Item>
<OSSUpload
@ -96,24 +89,15 @@ const AppBasicConfigForm: React.FC<AppBasicConfigFormProps> = (props) => {
<Input />
</Form.Item>
<Form.Item label="菜单栏中" name="hide">
<Select>
<Select.Option key="0" value={0}>
</Select.Option>
<Select.Option key="1" value={1}>
</Select.Option>
</Select>
<Select
options={[
{ label: '展示', value: 0 },
{ label: '隐藏', value: 1 },
]}
></Select>
</Form.Item>
<Form.Item label="渠道" name="channel">
<Select disabled={editing}>
<Select.Option key="fanmiyou" value="fanmiyou">
</Select.Option>
<Select.Option key="qiji" value="qiji">
</Select.Option>
</Select>
<Select disabled={editing} options={channelList()}></Select>
</Form.Item>
</Form>
</Modal>

13
src/pages/App/SuperAdminAppManagement.tsx

@ -1,4 +1,5 @@
import { appList } from '@/services/matrix/admin';
import { channelList } from '@/utils/commonUtil';
import { PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { Button, Flex, Input, Popover, QRCode, Tag } from 'antd';
import { useEffect, useState } from 'react';
@ -73,13 +74,9 @@ const SuperAdminAppManagement = () => {
dataIndex: 'channel',
hideInSearch: true,
renderText: (r: string) => {
switch (r) {
case 'fanmiyou':
return '凡米游';
case 'qiji':
return '奇迹';
}
return r;
const channel = channelList();
const matchedChannel = channel.find((x) => x.value === r);
return matchedChannel ? matchedChannel.label : r;
},
},
{
@ -162,7 +159,7 @@ const SuperAdminAppManagement = () => {
<Input
key="name"
placeholder="请输入应用名"
onChange={(e) => handleSearch(e.target.value)}
onChange={(e: { target: { value: string } }) => handleSearch(e.target.value)}
/>,
],
}}

11
src/pages/MoneyManagement.tsx

@ -0,0 +1,11 @@
import { PageContainer } from '@ant-design/pro-components';
const MoneyManagement: React.FC = () => {
return (
<PageContainer>
<p>TODO</p>
</PageContainer>
);
};
export default MoneyManagement;

1
src/pages/OSSUploadDragger.tsx

@ -111,6 +111,7 @@ const OSSUploadDragger: React.FC<OSSUploadProps> = ({ onUploadSuccess, onUploadE
await navigator.clipboard.writeText(file.url || '');
message.success('链接复制成功 ' + file.url);
}}
capture={undefined}
>
<p className="ant-upload-drag-icon">
<i className="anticon anticon-inbox" />

41
src/pages/SuperAdmin.tsx

@ -6,6 +6,7 @@ import {
scheduleList,
whiteList1,
} from '@/services/matrix/admin';
import { channelList } from '@/utils/commonUtil';
import { MinusCircleOutlined } from '@ant-design/icons';
import { PageContainer } from '@ant-design/pro-components';
import {
@ -70,13 +71,9 @@ const SuperAdmin: React.FC = () => {
title: '渠道',
dataIndex: 'channel',
render: (r: string) => {
switch (r) {
case 'fanmiyou':
return '凡米游';
case 'qiji':
return '奇迹';
}
return r;
const channel = channelList();
const matchedChannel = channel.find((x) => x.value === r);
return matchedChannel ? matchedChannel.label : r;
},
},
{
@ -130,13 +127,9 @@ const SuperAdmin: React.FC = () => {
title: '渠道',
dataIndex: 'channel',
render: (r: string) => {
switch (r) {
case 'fanmiyou':
return '凡米游';
case 'qiji':
return '奇迹';
}
return r;
const channel = channelList();
const matchedChannel = channel.find((x) => x.value === r);
return matchedChannel ? matchedChannel.label : r;
},
},
{
@ -263,7 +256,7 @@ const SuperAdmin: React.FC = () => {
<PageContainer>
<Tabs
defaultActiveKey="1"
onChange={(activeKey) => {
onChange={(activeKey: string) => {
if (activeKey === '1') {
fetchWhiteList();
} else if (activeKey === '2') {
@ -284,10 +277,7 @@ const SuperAdmin: React.FC = () => {
<Input />
</Form.Item>
<Form.Item label="渠道" name="channel">
<Select>
<Select.Option value="fanmiyou"></Select.Option>
<Select.Option value="qiji"></Select.Option>
</Select>
<Select options={channelList()}></Select>
</Form.Item>
</Form>
</Modal>
@ -301,13 +291,12 @@ const SuperAdmin: React.FC = () => {
<Modal title="添加任务" visible={sVisible} onOk={handleSOk} onCancel={handleSCancel}>
<Form form={scheduleForm} onFinish={handleSaveMock}>
<Form.Item label="应用" name="appId">
<Select>
{appArr.map((app) => (
<Select.Option key={app.id} value={app.id}>
{app.name}
</Select.Option>
))}
</Select>
<Select
options={appArr.map((app) => ({
label: app.name,
value: app.id,
}))}
></Select>
</Form.Item>
<Form.Item name="incomeYuan" label="金额(元)">
<Input />

11
src/pages/UserManagement.tsx

@ -0,0 +1,11 @@
import { PageContainer } from '@ant-design/pro-components';
const UserManagement: React.FC = () => {
return (
<PageContainer>
<p>TODO</p>
</PageContainer>
);
};
export default UserManagement;

1
src/services/matrix/typings.d.ts

@ -257,6 +257,7 @@ declare namespace API {
appId?: number;
createdAt?: number;
id?: number;
user?: UserBo;
adminName?: string;
};

8
src/utils/commonUtil.ts

@ -0,0 +1,8 @@
const channelList = () => {
return [
{ label: '凡米游', value: 'fanmiyou' },
{ label: '奇迹', value: 'qiji' },
];
};
export { channelList };

8
src/utils/numberUtils.ts

@ -0,0 +1,8 @@
const formatIncome = (v: number | undefined) => {
if (!v) {
return 0;
}
return parseFloat((v / 1000_00).toFixed(2));
};
export { formatIncome };
Loading…
Cancel
Save