From ac7615091500909392d65a1a9007b01de7eb02ba Mon Sep 17 00:00:00 2001 From: zihluwang Date: Tue, 14 Apr 2026 11:17:31 +0800 Subject: [PATCH] feat: implement user authentication with login functionality - Add auth-api for handling login requests. - Update index.ts to export AuthApi. - Modify HeroLayout to display username or login link based on authentication state. - Create LoginPage component for user login. - Update router to include login route with EmptyLayout. - Configure WebClient to include credentials in requests. - Add auth-slice for managing authentication state in Redux. - Update Redux store to include auth reducer. - Define LoginRequest and User types in types/index.ts. - Configure Vite to proxy API requests to the backend server. --- package.json | 10 +- pnpm-lock.yaml | 184 +++++++++++++++---------------- src/api/auth-api.ts | 9 ++ src/api/index.ts | 1 + src/layout/hero-layout/index.tsx | 14 +++ src/page/login/index.tsx | 67 +++++++++++ src/router/index.tsx | 11 ++ src/shared/web-client/index.ts | 1 + src/store/auth-slice.ts | 26 +++++ src/store/index.ts | 4 +- src/types/index.ts | 11 ++ vite.config.ts | 9 ++ 12 files changed, 249 insertions(+), 98 deletions(-) create mode 100644 src/api/auth-api.ts create mode 100644 src/page/login/index.tsx create mode 100644 src/store/auth-slice.ts diff --git a/package.json b/package.json index ee3fbfd..a88e178 100644 --- a/package.json +++ b/package.json @@ -18,13 +18,13 @@ "@tailwindcss/vite": "^4.2.2", "@tanstack/react-virtual": "^3.13.23", "antd": "^6.3.5", - "axios": "^1.14.0", + "axios": "^1.15.0", "dayjs": "^1.11.20", "react": "^19.2.5", "react-dom": "^19.2.5", "react-redux": "^9.2.0", - "react-router": "^7.14.0", - "react-router-dom": "^7.14.0", + "react-router": "^7.14.1", + "react-router-dom": "^7.14.1", "redux-persist": "^6.0.0", "tailwindcss": "^4.2.2" }, @@ -33,8 +33,8 @@ "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", - "globals": "^17.4.0", - "prettier": "^3.8.1", + "globals": "^17.5.0", + "prettier": "^3.8.2", "typescript": "~6.0.2", "vite": "^8.0.8" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 631d2f9..ef94ac3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: ^6.3.5 version: 6.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5) axios: - specifier: ^1.14.0 - version: 1.14.0 + specifier: ^1.15.0 + version: 1.15.0 dayjs: specifier: ^1.11.20 version: 1.11.20 @@ -39,11 +39,11 @@ importers: specifier: ^9.2.0 version: 9.2.0(@types/react@19.2.14)(react@19.2.5)(redux@5.0.1) react-router: - specifier: ^7.14.0 - version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: ^7.14.1 + version: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-router-dom: - specifier: ^7.14.0 - version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + specifier: ^7.14.1 + version: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) redux-persist: specifier: ^6.0.0 version: 6.0.0(react@19.2.5)(redux@5.0.1) @@ -64,11 +64,11 @@ importers: specifier: ^6.0.1 version: 6.0.1(vite@8.0.8(@types/node@22.19.17)(esbuild@0.27.4)(jiti@2.6.1)) globals: - specifier: ^17.4.0 - version: 17.4.0 + specifier: ^17.5.0 + version: 17.5.0 prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.8.2 + version: 3.8.2 typescript: specifier: ~6.0.2 version: 6.0.2 @@ -372,8 +372,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - '@rc-component/image@1.8.0': - resolution: {integrity: sha512-Dr41bFevLB5NgVaJhEUmNvbEf+ynAhim6W98ZW2xvCsdFISc2TYP4ZvCVdie3eaZdum2kieVcvpNHu+UrzAAHA==} + '@rc-component/image@1.8.1': + resolution: {integrity: sha512-JfPCijmMl+EaMvbftsEs/4VHmTyJKsZBh5ujFowSA45i9NTVYS1vuHtgpVV/QrGa27kXwbVOZriffCe/PNKuMw==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -583,8 +583,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - '@rc-component/util@1.10.0': - resolution: {integrity: sha512-aY9GLBuiUdpyfIUpAWSYer4Tu3mVaZCo5A0q9NtXcazT3MRiI3/WNHCR+DUn5VAtR6iRRf0ynCqQUcHli5UdYw==} + '@rc-component/util@1.10.1': + resolution: {integrity: sha512-q++9S6rUa5Idb/xIBNz6jtvumw5+O5YV5V0g4iK9mn9jWs4oGJheE3ZN1kAnE723AXyaD8v95yeOASmdk8Jnng==} peerDependencies: react: '>=18.0.0' react-dom: '>=18.0.0' @@ -856,8 +856,8 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - axios@1.14.0: - resolution: {integrity: sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==} + axios@1.15.0: + resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==} call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} @@ -930,8 +930,8 @@ packages: picomatch: optional: true - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -959,8 +959,8 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - globals@17.4.0: - resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==} + globals@17.5.0: + resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==} engines: {node: '>=18'} gopd@1.2.0: @@ -1096,12 +1096,12 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.9: + resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} engines: {node: ^10 || ^12 || >=14} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.2: + resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==} engines: {node: '>=14'} hasBin: true @@ -1129,15 +1129,15 @@ packages: redux: optional: true - react-router-dom@7.14.0: - resolution: {integrity: sha512-2G3ajSVSZMEtmTjIklRWlNvo8wICEpLihfD/0YMDxbWK2UyP5EGfnoIn9AIQGnF3G/FX0MRbHXdFcD+rL1ZreQ==} + react-router-dom@7.14.1: + resolution: {integrity: sha512-ZkrQuwwhGibjQLqH1eCdyiZyLWglPxzxdl5tgwgKEyCSGC76vmAjleGocRe3J/MLfzMUIKwaFJWpFVJhK3d2xA==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router@7.14.0: - resolution: {integrity: sha512-m/xR9N4LQLmAS0ZhkY2nkPA1N7gQ5TUVa5n8TgANuDTARbn1gt+zLPXEm7W0XDTbrQ2AJSJKhoa6yx1D8BcpxQ==} + react-router@7.14.1: + resolution: {integrity: sha512-5BCvFskyAAVumqhEKh/iPhLOIkfxcEUz8WqFIARCkMg8hZZzDYX9CtwxXA0e+qT8zAxmMC0x3Ckb9iMONwc5jg==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -1197,16 +1197,16 @@ packages: tailwindcss@4.2.2: resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} throttle-debounce@5.0.2: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} tslib@2.8.1: @@ -1278,7 +1278,7 @@ snapshots: dependencies: '@ant-design/cssinjs': 2.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@babel/runtime': 7.29.2 - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1287,7 +1287,7 @@ snapshots: '@babel/runtime': 7.29.2 '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 csstype: 3.2.3 react: 19.2.5 @@ -1302,7 +1302,7 @@ snapshots: dependencies: '@ant-design/colors': 8.0.1 '@ant-design/icons-svg': 4.4.2 - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1452,14 +1452,14 @@ snapshots: dependencies: '@rc-component/select': 1.6.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/tree': 1.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/checkbox@2.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1468,7 +1468,7 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1476,14 +1476,14 @@ snapshots: '@rc-component/color-picker@3.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@ant-design/fast-color': 3.0.1 - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/context@2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1491,7 +1491,7 @@ snapshots: dependencies: '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1500,7 +1500,7 @@ snapshots: dependencies: '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1508,7 +1508,7 @@ snapshots: '@rc-component/dropdown@1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1516,16 +1516,16 @@ snapshots: '@rc-component/form@1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@rc-component/async-validator': 5.1.0 - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - '@rc-component/image@1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@rc-component/image@1.8.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1533,14 +1533,14 @@ snapshots: '@rc-component/input-number@1.6.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@rc-component/mini-decimal': 1.1.3 - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/input@1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1551,7 +1551,7 @@ snapshots: '@rc-component/menu': 1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/textarea': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1561,7 +1561,7 @@ snapshots: '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/overflow': 1.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1572,21 +1572,21 @@ snapshots: '@rc-component/motion@1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/mutate-observer@2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/notification@1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1595,14 +1595,14 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/pagination@1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1612,7 +1612,7 @@ snapshots: '@rc-component/overflow': 1.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1621,14 +1621,14 @@ snapshots: '@rc-component/portal@2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/progress@1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1641,14 +1641,14 @@ snapshots: '@rc-component/rate@1.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/resize-observer@1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1656,7 +1656,7 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1665,7 +1665,7 @@ snapshots: dependencies: '@rc-component/overflow': 1.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/virtual-list': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 @@ -1673,21 +1673,21 @@ snapshots: '@rc-component/slider@1.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/steps@1.2.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/switch@1.0.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1696,7 +1696,7 @@ snapshots: dependencies: '@rc-component/context': 2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/virtual-list': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 @@ -1708,7 +1708,7 @@ snapshots: '@rc-component/menu': 1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1717,7 +1717,7 @@ snapshots: dependencies: '@rc-component/input': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1725,7 +1725,7 @@ snapshots: '@rc-component/tooltip@1.4.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1734,7 +1734,7 @@ snapshots: dependencies: '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1743,7 +1743,7 @@ snapshots: dependencies: '@rc-component/select': 1.6.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/tree': 1.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1751,7 +1751,7 @@ snapshots: '@rc-component/tree@1.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/virtual-list': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 @@ -1762,19 +1762,19 @@ snapshots: '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) '@rc-component/upload@1.1.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - '@rc-component/util@1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': + '@rc-component/util@1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: is-mobile: 5.0.0 react: 19.2.5 @@ -1785,7 +1785,7 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) @@ -1976,7 +1976,7 @@ snapshots: '@rc-component/drawer': 1.4.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/dropdown': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/form': 1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/image': 1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/image': 1.8.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/input': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/input-number': 1.6.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/mentions': 1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -2004,7 +2004,7 @@ snapshots: '@rc-component/tree-select': 1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@rc-component/upload': 1.1.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@rc-component/util': 1.10.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) clsx: 2.1.1 dayjs: 1.11.20 react: 19.2.5 @@ -2018,9 +2018,9 @@ snapshots: asynckit@0.4.0: {} - axios@1.14.0: + axios@1.15.0: dependencies: - follow-redirects: 1.15.11 + follow-redirects: 1.16.0 form-data: 4.0.5 proxy-from-env: 2.1.0 transitivePeerDependencies: @@ -2058,7 +2058,7 @@ snapshots: enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.2 es-define-property@1.0.1: {} @@ -2109,7 +2109,7 @@ snapshots: optionalDependencies: picomatch: 4.0.4 - follow-redirects@1.15.11: {} + follow-redirects@1.16.0: {} form-data@4.0.5: dependencies: @@ -2142,7 +2142,7 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - globals@17.4.0: {} + globals@17.5.0: {} gopd@1.2.0: {} @@ -2235,13 +2235,13 @@ snapshots: picomatch@4.0.4: {} - postcss@8.5.8: + postcss@8.5.9: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - prettier@3.8.1: {} + prettier@3.8.2: {} proxy-from-env@2.1.0: {} @@ -2261,13 +2261,13 @@ snapshots: '@types/react': 19.2.14 redux: 5.0.1 - react-router-dom@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + react-router-dom@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react-router: 7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + react-router@7.14.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: cookie: 1.1.1 react: 19.2.5 @@ -2328,11 +2328,11 @@ snapshots: tailwindcss@4.2.2: {} - tapable@2.3.0: {} + tapable@2.3.2: {} throttle-debounce@5.0.2: {} - tinyglobby@0.2.15: + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 @@ -2352,9 +2352,9 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.8 + postcss: 8.5.9 rolldown: 1.0.0-rc.15 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 optionalDependencies: '@types/node': 22.19.17 esbuild: 0.27.4 diff --git a/src/api/auth-api.ts b/src/api/auth-api.ts new file mode 100644 index 0000000..745e60d --- /dev/null +++ b/src/api/auth-api.ts @@ -0,0 +1,9 @@ +import { LoginRequest, User } from "@/types" +import { WebClient } from "@/shared/web-client" + +export async function login(loginRequest: LoginRequest): Promise { + const { data } = await WebClient.post("/auth/login", { + ...loginRequest, + }) + return data +} diff --git a/src/api/index.ts b/src/api/index.ts index eb0551b..edb4561 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,3 +1,4 @@ export * as FirearmApi from "./firearm-api" export * as ModificationApi from "./modification-api" export * as TagApi from "./tag-api" +export * as AuthApi from "./auth-api" diff --git a/src/layout/hero-layout/index.tsx b/src/layout/hero-layout/index.tsx index 113005e..d1ef79c 100644 --- a/src/layout/hero-layout/index.tsx +++ b/src/layout/hero-layout/index.tsx @@ -1,6 +1,7 @@ import { Outlet, Link } from "react-router-dom" import { useMemo } from "react" import dayjs from "dayjs" +import { useAppSelector } from "@/store" /** * Main application component that serves as the root layout. @@ -8,6 +9,7 @@ import dayjs from "dayjs" */ export default function HeroLayout() { const today = useMemo(() => dayjs(), []) + const user = useAppSelector((state) => state.auth.user) return (
@@ -33,6 +35,18 @@ export default function HeroLayout() { > 改枪码 + {user ? ( + + {user.username} + + ) : ( + + 登录 + + )} +
+ + + 登录 + + + 使用你的帐号登录后即可继续操作 + + + layout="vertical" onFinish={onFinish} requiredMark={false}> + + name="principle" + label="帐号" + rules={[{ required: true, message: "请输入帐号" }]} + > + + + + + name="credential" + label="密码" + rules={[{ required: true, message: "请输入密码" }]} + > + + + + + + + + +
+
+ ) +} diff --git a/src/router/index.tsx b/src/router/index.tsx index b506a3c..1a23589 100644 --- a/src/router/index.tsx +++ b/src/router/index.tsx @@ -1,6 +1,7 @@ import { ComponentType } from "react" import { createBrowserRouter } from "react-router-dom" import ErrorPage from "@/components/error-page" +import EmptyLayout from "@/layout/empty-layout" import HeroLayout from "@/layout/hero-layout" function lazy }>(importer: () => Promise) { @@ -37,6 +38,16 @@ const router = createBrowserRouter( }, ], }, + { + element: , + errorElement: , + children: [ + { + path: "login", + lazy: lazy(() => import("@/page/login")), + }, + ], + }, ], { basename: "/", diff --git a/src/shared/web-client/index.ts b/src/shared/web-client/index.ts index b6b2081..a797175 100644 --- a/src/shared/web-client/index.ts +++ b/src/shared/web-client/index.ts @@ -4,6 +4,7 @@ import dayjs from "dayjs" const WebClient = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: dayjs.duration({ seconds: 10 }).asMilliseconds(), + withCredentials: true }) export { WebClient } diff --git a/src/store/auth-slice.ts b/src/store/auth-slice.ts new file mode 100644 index 0000000..71dc980 --- /dev/null +++ b/src/store/auth-slice.ts @@ -0,0 +1,26 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit" +import { User } from "@/types" + +interface AuthState { + user: User | null +} + +const initialState: AuthState = { + user: null, +} + +const authSlice = createSlice({ + name: "auth", + initialState, + reducers: { + setCurrentUser(state, action: PayloadAction) { + state.user = action.payload + }, + clearCurrentUser(state) { + state.user = null + }, + }, +}) + +export const { setCurrentUser, clearCurrentUser } = authSlice.actions +export const authReducer = authSlice.reducer diff --git a/src/store/index.ts b/src/store/index.ts index 8e33ca8..aa18f6b 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -11,6 +11,7 @@ import { REGISTER, } from "redux-persist" import createWebStorage from "redux-persist/es/storage/createWebStorage" +import { authReducer } from "./auth-slice" import { firearmsReducer } from "./firearms-slice" const storage = createWebStorage(import.meta.env.VITE_REDUX_STORAGE ?? "local") @@ -18,10 +19,11 @@ const storage = createWebStorage(import.meta.env.VITE_REDUX_STORAGE ?? "local") const persistConfig = { key: "root", storage, - whitelist: ["firearms"], + whitelist: ["auth", "firearms"], } const rootReducer = combineReducers({ + auth: authReducer, firearms: firearmsReducer }) diff --git a/src/types/index.ts b/src/types/index.ts index 94c898b..76ccf4a 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -47,3 +47,14 @@ export interface PageQueryParams { sortBy?: string direction?: Direction } + +export interface LoginRequest { + principle: string + credential: string +} + +export interface User { + id: number + username: string + email: string +} diff --git a/vite.config.ts b/vite.config.ts index 45b6aba..4eec181 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -12,4 +12,13 @@ export default defineConfig({ "@": fileURLToPath(new URL("./src", import.meta.url)), }, }, + server: { + proxy: { + '/api': { + target: 'http://localhost:8080', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, '') + } + } + } })