Browse Source

chore: reduce bundle size by replacing heavy dependencies (#11698)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: afc163 <afc163@gmail.com>
pull/11704/head
afc163 5 months ago
committed by GitHub
parent
commit
ed3e8ace89
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      config/config.ts
  2. 1
      jest.config.ts
  3. 3
      package.json
  4. 70
      pnpm-lock.yaml
  5. 21
      src/components/Footer/index.tsx
  6. 4
      src/pages/account/center/components/Applications/index.tsx
  7. 8
      src/pages/dashboard/analysis/components/Charts/index.tsx
  8. 17
      src/pages/dashboard/analysis/components/IntroduceRow.tsx
  9. 4
      src/pages/dashboard/analysis/components/ProportionSales.tsx
  10. 6
      src/pages/dashboard/analysis/components/SalesCard.tsx
  11. 4
      src/pages/dashboard/analysis/components/TopSearch.tsx
  12. 17
      src/pages/dashboard/monitor/index.tsx
  13. 4
      src/pages/list/search/applications/index.tsx
  14. 4
      src/pages/user/login/__snapshots__/login.test.tsx.snap
  15. 3
      src/typings.d.ts
  16. 16
      src/utils/format.ts

1
config/config.ts

@ -200,5 +200,6 @@ export default defineConfig({
'process.env.CI': process.env.CI, 'process.env.CI': process.env.CI,
'process.env.COMMIT_HASH': process.env.COMMIT_HASH || '', 'process.env.COMMIT_HASH': process.env.COMMIT_HASH || '',
'process.env.CF_PAGES_COMMIT_SHA': process.env.CF_PAGES_COMMIT_SHA || '', 'process.env.CF_PAGES_COMMIT_SHA': process.env.CF_PAGES_COMMIT_SHA || '',
__APP_VERSION__: JSON.stringify(require('./../package.json').version),
}, },
}); });

1
jest.config.ts

@ -21,6 +21,7 @@ export default async (): Promise<any> => {
globals: { globals: {
...config.globals, ...config.globals,
localStorage: null, localStorage: null,
__APP_VERSION__: 'test',
}, },
}; };
}; };

3
package.json

@ -51,8 +51,6 @@
"antd-style": "^4.1.0", "antd-style": "^4.1.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"dayjs": "^1.11.19", "dayjs": "^1.11.19",
"git-url-parse": "^16.1.0",
"numeral": "^2.0.6",
"react": "^19.2.4", "react": "^19.2.4",
"react-dom": "^19.2.4" "react-dom": "^19.2.4"
}, },
@ -66,7 +64,6 @@
"@types/express": "^5.0.6", "@types/express": "^5.0.6",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^25.0.3", "@types/node": "^25.0.3",
"@types/numeral": "^2.0.5",
"@types/react": "^19.2.10", "@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@types/react-helmet": "^6.1.11", "@types/react-helmet": "^6.1.11",

70
pnpm-lock.yaml

@ -50,12 +50,6 @@ importers:
dayjs: dayjs:
specifier: ^1.11.19 specifier: ^1.11.19
version: 1.11.20 version: 1.11.20
git-url-parse:
specifier: ^16.1.0
version: 16.1.0
numeral:
specifier: ^2.0.6
version: 2.0.6
react: react:
specifier: ^19.2.4 specifier: ^19.2.4
version: 19.2.5 version: 19.2.5
@ -90,9 +84,6 @@ importers:
'@types/node': '@types/node':
specifier: ^25.0.3 specifier: ^25.0.3
version: 25.6.0 version: 25.6.0
'@types/numeral':
specifier: ^2.0.5
version: 2.0.5
'@types/react': '@types/react':
specifier: ^19.2.10 specifier: ^19.2.10
version: 19.2.14 version: 19.2.14
@ -2988,16 +2979,9 @@ packages:
'@types/normalize-package-data@2.4.4': '@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
'@types/numeral@2.0.5':
resolution: {integrity: sha512-kH8I7OSSwQu9DS9JYdFWbuvhVzvFRoCPCkGxNwoGgaPeDfEPJlcxNvEOypZhQ3XXHsGbfIuYcxcJxKUfJHnRfw==}
'@types/parse-json@4.0.2': '@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
'@types/parse-path@7.1.0':
resolution: {integrity: sha512-EULJ8LApcVEPbrfND0cRQqutIOdiIgJ1Mgrhpy755r14xMohPTEpkV/k28SJvuOs9bHRFW8x+KeDAEPiGQPB9Q==}
deprecated: This is a stub types definition. parse-path provides its own type definitions, so you do not need this installed.
'@types/pbf@3.0.5': '@types/pbf@3.0.5':
resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==}
@ -5773,12 +5757,6 @@ packages:
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
git-up@8.1.1:
resolution: {integrity: sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==}
git-url-parse@16.1.0:
resolution: {integrity: sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==}
gl-matrix@3.4.4: gl-matrix@3.4.4:
resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==} resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==}
@ -6426,9 +6404,6 @@ packages:
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
is-ssh@1.4.1:
resolution: {integrity: sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==}
is-stream@1.1.0: is-stream@1.1.0:
resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@ -7526,9 +7501,6 @@ packages:
number-to-words@1.2.4: number-to-words@1.2.4:
resolution: {integrity: sha512-/fYevVkXRcyBiZDg6yzZbm0RuaD6i0qRfn8yr+6D0KgBMOndFPxuW10qCHpzs50nN8qKuv78k8MuotZhcVX6Pw==} resolution: {integrity: sha512-/fYevVkXRcyBiZDg6yzZbm0RuaD6i0qRfn8yr+6D0KgBMOndFPxuW10qCHpzs50nN8qKuv78k8MuotZhcVX6Pw==}
numeral@2.0.6:
resolution: {integrity: sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==}
nunjucks@3.2.4: nunjucks@3.2.4:
resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==} resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==}
engines: {node: '>= 6.9.0'} engines: {node: '>= 6.9.0'}
@ -7744,13 +7716,6 @@ packages:
resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
parse-path@7.1.0:
resolution: {integrity: sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==}
parse-url@9.2.0:
resolution: {integrity: sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==}
engines: {node: '>=14.13.0'}
parse5@7.3.0: parse5@7.3.0:
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
@ -8263,9 +8228,6 @@ packages:
protocol-buffers-schema@3.6.1: protocol-buffers-schema@3.6.1:
resolution: {integrity: sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==} resolution: {integrity: sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==}
protocols@2.0.2:
resolution: {integrity: sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==}
proxy-addr@2.0.7: proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
@ -13969,14 +13931,8 @@ snapshots:
'@types/normalize-package-data@2.4.4': {} '@types/normalize-package-data@2.4.4': {}
'@types/numeral@2.0.5': {}
'@types/parse-json@4.0.2': {} '@types/parse-json@4.0.2': {}
'@types/parse-path@7.1.0':
dependencies:
parse-path: 7.1.0
'@types/pbf@3.0.5': {} '@types/pbf@3.0.5': {}
'@types/prismjs@1.26.6': {} '@types/prismjs@1.26.6': {}
@ -17755,15 +17711,6 @@ snapshots:
- conventional-commits-filter - conventional-commits-filter
- conventional-commits-parser - conventional-commits-parser
git-up@8.1.1:
dependencies:
is-ssh: 1.4.1
parse-url: 9.2.0
git-url-parse@16.1.0:
dependencies:
git-up: 8.1.1
gl-matrix@3.4.4: {} gl-matrix@3.4.4: {}
glob-parent@5.1.2: glob-parent@5.1.2:
@ -18429,10 +18376,6 @@ snapshots:
dependencies: dependencies:
call-bound: 1.0.4 call-bound: 1.0.4
is-ssh@1.4.1:
dependencies:
protocols: 2.0.2
is-stream@1.1.0: {} is-stream@1.1.0: {}
is-stream@2.0.1: {} is-stream@2.0.1: {}
@ -19797,8 +19740,6 @@ snapshots:
number-to-words@1.2.4: {} number-to-words@1.2.4: {}
numeral@2.0.6: {}
nunjucks@3.2.4(chokidar@3.6.0): nunjucks@3.2.4(chokidar@3.6.0):
dependencies: dependencies:
a-sync-waterfall: 1.0.1 a-sync-waterfall: 1.0.1
@ -20054,15 +19995,6 @@ snapshots:
parse-node-version@1.0.1: {} parse-node-version@1.0.1: {}
parse-path@7.1.0:
dependencies:
protocols: 2.0.2
parse-url@9.2.0:
dependencies:
'@types/parse-path': 7.1.0
parse-path: 7.1.0
parse5@7.3.0: parse5@7.3.0:
dependencies: dependencies:
entities: 6.0.1 entities: 6.0.1
@ -20537,8 +20469,6 @@ snapshots:
protocol-buffers-schema@3.6.1: {} protocol-buffers-schema@3.6.1: {}
protocols@2.0.2: {}
proxy-addr@2.0.7: proxy-addr@2.0.7:
dependencies: dependencies:
forwarded: 0.2.0 forwarded: 0.2.0

21
src/components/Footer/index.tsx

@ -1,17 +1,22 @@
import { GithubOutlined } from '@ant-design/icons'; import { GithubOutlined } from '@ant-design/icons';
import { DefaultFooter } from '@ant-design/pro-components'; import { DefaultFooter } from '@ant-design/pro-components';
import packageJson from '@root/package.json'; import packageJson from '@root/package.json';
import GitUrlParse from 'git-url-parse';
import React from 'react'; import React from 'react';
const getRepoUrl = () => { const getRepoUrl = () => {
if (!packageJson.repository) if (!packageJson.repository)
return 'https://github.com/ant-design/ant-design-pro'; return 'https://github.com/ant-design/ant-design-pro';
const parsed = GitUrlParse(packageJson.repository); const repo =
return `https://${parsed.source}/${parsed.owner}/${parsed.name}`; typeof packageJson.repository === 'string'
? packageJson.repository
: (packageJson.repository as { url: string }).url;
// Parse git URLs like git@github.com:owner/name.git or https://github.com/owner/name.git
const match = repo.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
if (!match) return 'https://github.com/ant-design/ant-design-pro';
return `https://github.com/${match[1]}/${match[2]}`;
}; };
const REPO = getRepoUrl(); const REPO_URL = getRepoUrl();
// Git commit hash, can be updated via CI/CD (GitHub Actions or Cloudflare Pages) // Git commit hash, can be updated via CI/CD (GitHub Actions or Cloudflare Pages)
const COMMIT_HASH = const COMMIT_HASH =
@ -27,8 +32,8 @@ const Footer: React.FC = () => {
links={[ links={[
{ {
key: 'version', key: 'version',
title: `v${packageJson.version}`, title: `v${__APP_VERSION__}`,
href: REPO, href: REPO_URL,
blankTarget: true, blankTarget: true,
}, },
...(COMMIT_HASH ...(COMMIT_HASH
@ -36,7 +41,7 @@ const Footer: React.FC = () => {
{ {
key: 'commit', key: 'commit',
title: COMMIT_HASH.slice(0, 7), title: COMMIT_HASH.slice(0, 7),
href: `${REPO}/commit/${COMMIT_HASH}`, href: `${REPO_URL}/commit/${COMMIT_HASH}`,
blankTarget: true, blankTarget: true,
}, },
] ]
@ -49,7 +54,7 @@ const Footer: React.FC = () => {
Ant Design Pro Ant Design Pro
</> </>
), ),
href: REPO, href: REPO_URL,
blankTarget: true, blankTarget: true,
}, },
]} ]}

4
src/pages/account/center/components/Applications/index.tsx

@ -6,8 +6,8 @@ import {
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { Avatar, Card, Dropdown, List, Tooltip } from 'antd'; import { Avatar, Card, Dropdown, List, Tooltip } from 'antd';
import numeral from 'numeral';
import React from 'react'; import React from 'react';
import { formatNumber } from '@/utils/format';
import type { ListItemDataType } from '../../data.d'; import type { ListItemDataType } from '../../data.d';
import { queryFakeList } from '../../service'; import { queryFakeList } from '../../service';
import useStyles from './index.style'; import useStyles from './index.style';
@ -123,7 +123,7 @@ const Applications: React.FC = () => {
<div> <div>
<CardInfo <CardInfo
activeUser={formatWan(item.activeUser)} activeUser={formatWan(item.activeUser)}
newUser={numeral(item.newUser).format('0,0')} newUser={formatNumber(item.newUser)}
/> />
</div> </div>
</Card> </Card>

8
src/pages/dashboard/analysis/components/Charts/index.tsx

@ -1,13 +1,11 @@
import numeral from 'numeral'; import { formatYuan } from '@/utils/format';
import ChartCard from './ChartCard'; import ChartCard from './ChartCard';
import Field from './Field'; import Field from './Field';
const yuan = (val: number | string) => `¥ ${numeral(val).format('0,0')}`;
const Charts = { const Charts = {
yuan, yuan: formatYuan,
ChartCard, ChartCard,
Field, Field,
}; };
export { ChartCard, Charts as default, Field, yuan }; export { ChartCard, Charts as default, Field, formatYuan as yuan };

17
src/pages/dashboard/analysis/components/IntroduceRow.tsx

@ -1,7 +1,7 @@
import { InfoCircleOutlined } from '@ant-design/icons'; import { InfoCircleOutlined } from '@ant-design/icons';
import { Area, Column } from '@ant-design/plots'; import { Area, Column } from '@ant-design/plots';
import { Col, Progress, Row, Tooltip } from 'antd'; import { Col, Progress, Row, Tooltip } from 'antd';
import numeral from 'numeral'; import { formatNumber } from '@/utils/format';
import type { DataItem } from '../data.d'; import type { DataItem } from '../data.d';
import useStyles from '../style.style'; import useStyles from '../style.style';
import Yuan from '../utils/Yuan'; import Yuan from '../utils/Yuan';
@ -39,12 +39,7 @@ const IntroduceRow = ({
} }
loading={loading} loading={loading}
total={() => <Yuan>126560</Yuan>} total={() => <Yuan>126560</Yuan>}
footer={ footer={<Field label="日销售额" value={`¥${formatNumber(12423)}`} />}
<Field
label="日销售额"
value={`¥${numeral(12423).format('0,0')}`}
/>
}
contentHeight={46} contentHeight={46}
> >
<Trend <Trend
@ -73,10 +68,8 @@ const IntroduceRow = ({
<InfoCircleOutlined /> <InfoCircleOutlined />
</Tooltip> </Tooltip>
} }
total={numeral(8846).format('0,0')} total={formatNumber(8846)}
footer={ footer={<Field label="日访问量" value={formatNumber(1234)} />}
<Field label="日访问量" value={numeral(1234).format('0,0')} />
}
contentHeight={46} contentHeight={46}
> >
<Area <Area
@ -105,7 +98,7 @@ const IntroduceRow = ({
<InfoCircleOutlined /> <InfoCircleOutlined />
</Tooltip> </Tooltip>
} }
total={numeral(6560).format('0,0')} total={formatNumber(6560)}
footer={<Field label="转化率" value="60%" />} footer={<Field label="转化率" value="60%" />}
contentHeight={46} contentHeight={46}
> >

4
src/pages/dashboard/analysis/components/ProportionSales.tsx

@ -1,7 +1,7 @@
import { Pie } from '@ant-design/plots'; import { Pie } from '@ant-design/plots';
import { Card, Segmented, Typography } from 'antd'; import { Card, Segmented, Typography } from 'antd';
import numeral from 'numeral';
import React from 'react'; import React from 'react';
import { formatNumber } from '@/utils/format';
import type { DataItem } from '../data.d'; import type { DataItem } from '../data.d';
import useStyles from '../style.style'; import useStyles from '../style.style';
@ -58,7 +58,7 @@ const ProportionSales = ({
label={{ label={{
position: 'spider', position: 'spider',
text: (item: { x: number; y: number }) => text: (item: { x: number; y: number }) =>
`${item.x}: ${numeral(item.y).format('0,0')}`, `${item.x}: ${formatNumber(item.y)}`,
}} }}
/> />
</Card> </Card>

6
src/pages/dashboard/analysis/components/SalesCard.tsx

@ -1,7 +1,7 @@
import { Column } from '@ant-design/plots'; import { Column } from '@ant-design/plots';
import { Button, Card, Col, DatePicker, Row, Tabs } from 'antd'; import { Button, Card, Col, DatePicker, Row, Tabs } from 'antd';
import type { RangePickerProps } from 'antd/es/date-picker'; import type { RangePickerProps } from 'antd/es/date-picker';
import numeral from 'numeral'; import { formatNumber } from '@/utils/format';
import type { DataItem } from '../data.d'; import type { DataItem } from '../data.d';
import useStyles from '../style.style'; import useStyles from '../style.style';
@ -147,7 +147,7 @@ const SalesCard = ({
> >
{item.title} {item.title}
</span> </span>
<span>{numeral(item.total).format('0,0')}</span> <span>{formatNumber(item.total)}</span>
</li> </li>
))} ))}
</ul> </ul>
@ -208,7 +208,7 @@ const SalesCard = ({
> >
{item.title} {item.title}
</span> </span>
<span>{numeral(item.total).format('0,0')}</span> <span>{formatNumber(item.total)}</span>
</li> </li>
))} ))}
</ul> </ul>

4
src/pages/dashboard/analysis/components/TopSearch.tsx

@ -1,8 +1,8 @@
import { InfoCircleOutlined } from '@ant-design/icons'; import { InfoCircleOutlined } from '@ant-design/icons';
import { Area } from '@ant-design/plots'; import { Area } from '@ant-design/plots';
import { Card, Col, Row, Table, Tooltip } from 'antd'; import { Card, Col, Row, Table, Tooltip } from 'antd';
import numeral from 'numeral';
import React from 'react'; import React from 'react';
import { formatNumber } from '@/utils/format';
import type { DataItem } from '../data.d'; import type { DataItem } from '../data.d';
import NumberInfo from './NumberInfo'; import NumberInfo from './NumberInfo';
import Trend from './Trend'; import Trend from './Trend';
@ -105,7 +105,7 @@ const TopSearch = ({
</span> </span>
} }
gap={8} gap={8}
total={numeral(12321).format('0,0')} total={formatNumber(12321)}
status="up" status="up"
subTotal={17.1} subTotal={17.1}
/> />

17
src/pages/dashboard/monitor/index.tsx

@ -1,14 +1,15 @@
import { Gauge, Liquid, WordCloud } from '@ant-design/plots'; import { Gauge, Liquid, WordCloud } from '@ant-design/plots';
import { GridContent } from '@ant-design/pro-components'; import { GridContent } from '@ant-design/pro-components';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { Card, Col, Progress, Row, Statistic } from 'antd'; import { Card, Col, Progress, Row, Spin, Statistic } from 'antd';
import numeral from 'numeral'; import { type FC, lazy, Suspense } from 'react';
import type { FC } from 'react'; import { formatNumber } from '@/utils/format';
import ActiveChart from './components/ActiveChart'; import ActiveChart from './components/ActiveChart';
import MonitorMap from './components/Map';
import { queryTags } from './service'; import { queryTags } from './service';
import useStyles from './style.style'; import useStyles from './style.style';
const MonitorMap = lazy(() => import('./components/Map'));
const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Moment is also OK const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Moment is also OK
const Monitor: FC = () => { const Monitor: FC = () => {
@ -43,7 +44,7 @@ const Monitor: FC = () => {
<Statistic <Statistic
title="今日交易总额" title="今日交易总额"
suffix="元" suffix="元"
value={numeral(124543233).format('0,0')} value={formatNumber(124543233)}
/> />
</Col> </Col>
<Col md={6} sm={12} xs={24}> <Col md={6} sm={12} xs={24}>
@ -61,12 +62,14 @@ const Monitor: FC = () => {
<Statistic <Statistic
title="每秒交易总额" title="每秒交易总额"
suffix="元" suffix="元"
value={numeral(234).format('0,0')} value={formatNumber(234)}
/> />
</Col> </Col>
</Row> </Row>
<div className={styles.mapChart}> <div className={styles.mapChart}>
<MonitorMap /> <Suspense fallback={<Spin />}>
<MonitorMap />
</Suspense>
</div> </div>
</Card> </Card>
</Col> </Col>

4
src/pages/list/search/applications/index.tsx

@ -16,10 +16,10 @@ import {
Select, Select,
Tooltip, Tooltip,
} from 'antd'; } from 'antd';
import numeral from 'numeral';
import type { FC } from 'react'; import type { FC } from 'react';
import React from 'react'; import React from 'react';
import { StandardFormRow, TagSelect } from '@/components'; import { StandardFormRow, TagSelect } from '@/components';
import { formatNumber } from '@/utils/format';
import { categoryOptions } from '../../mock'; import { categoryOptions } from '../../mock';
import type { ListItemDataType } from './data.d'; import type { ListItemDataType } from './data.d';
import { queryFakeList } from './service'; import { queryFakeList } from './service';
@ -232,7 +232,7 @@ export const Applications: FC<Record<string, any>> = () => {
<div> <div>
<CardInfo <CardInfo
activeUser={formatWan(item.activeUser)} activeUser={formatWan(item.activeUser)}
newUser={numeral(item.newUser).format('0,0')} newUser={formatNumber(item.newUser)}
/> />
</div> </div>
</Card> </Card>

4
src/pages/user/login/__snapshots__/login.test.tsx.snap

@ -473,7 +473,7 @@ exports[`Login Page should login success 1`] = `
target="_blank" target="_blank"
title="version" title="version"
> >
v6.0.0-beta.4 vtest
</a> </a>
<a <a
class="ant-pro-global-footer-list-link" class="ant-pro-global-footer-list-link"
@ -984,7 +984,7 @@ exports[`Login Page should show login form 1`] = `
target="_blank" target="_blank"
title="version" title="version"
> >
v6.0.0-beta.4 vtest
</a> </a>
<a <a
class="ant-pro-global-footer-list-link" class="ant-pro-global-footer-list-link"

3
src/typings.d.ts

@ -11,5 +11,6 @@ declare module '*.gif';
declare module '*.bmp'; declare module '*.bmp';
declare module '*.tiff'; declare module '*.tiff';
declare module 'omit.js'; declare module 'omit.js';
declare module 'numeral';
declare module 'mockjs'; declare module 'mockjs';
declare const __APP_VERSION__: string;

16
src/utils/format.ts

@ -0,0 +1,16 @@
const numberFormatter = new Intl.NumberFormat('en-US');
/**
* Format a number with thousand separators.
* Replaces numeral(val).format('0,0')
*/
export const formatNumber = (val: number | string): string => {
const parsed = Number(val);
return Number.isFinite(parsed) ? numberFormatter.format(parsed) : '';
};
/**
* Format a number as yuan currency string.
* Replaces `¥ ${numeral(val).format('0,0')}`
*/
export const formatYuan = (val: number | string) => `¥ ${formatNumber(val)}`;
Loading…
Cancel
Save