From 3dfab449f793276f0bf8372df2531ec5a3a1eb22 Mon Sep 17 00:00:00 2001 From: Slowlyo <1821725017@qq.com> Date: Fri, 1 Sep 2023 23:58:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=A1=86=E6=9E=B6=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin-views/.env | 8 + admin-views/index.html | 1 + admin-views/package.json | 71 ++--- admin-views/pnpm-lock.yaml | 249 +++++++++++++++++- admin-views/src/hooks/useApp.ts | 50 ++++ admin-views/src/hooks/useAuth.ts | 27 ++ admin-views/src/hooks/useSettings.ts | 14 + admin-views/src/hooks/useStorage.ts | 27 ++ .../src/layouts/DefaultLayout/index.tsx | 2 +- admin-views/src/layouts/index.tsx | 3 - admin-views/src/main.tsx | 26 +- admin-views/src/pages/login/index.tsx | 5 + admin-views/src/service/api/auth.ts | 27 ++ admin-views/src/service/api/base.ts | 26 ++ admin-views/src/service/api/index.ts | 2 + admin-views/src/service/index.ts | 1 + admin-views/src/service/request/config.ts | 15 ++ admin-views/src/service/request/index.ts | 5 + admin-views/src/service/request/instance.ts | 76 ++++++ admin-views/src/store/index.ts | 75 ++++++ admin-views/src/utils/common.ts | 9 + admin-views/src/utils/dynamicAssets.ts | 35 +++ admin-views/src/utils/proxy.ts | 18 ++ admin-views/src/vite-env.d.ts | 12 + admin-views/tsconfig.json | 62 +++-- admin-views/vite.config.ts | 32 ++- 26 files changed, 808 insertions(+), 70 deletions(-) create mode 100644 admin-views/.env create mode 100644 admin-views/src/hooks/useApp.ts create mode 100644 admin-views/src/hooks/useAuth.ts create mode 100644 admin-views/src/hooks/useSettings.ts create mode 100644 admin-views/src/hooks/useStorage.ts create mode 100644 admin-views/src/pages/login/index.tsx create mode 100644 admin-views/src/service/api/auth.ts create mode 100644 admin-views/src/service/api/base.ts create mode 100644 admin-views/src/service/api/index.ts create mode 100644 admin-views/src/service/index.ts create mode 100644 admin-views/src/service/request/config.ts create mode 100644 admin-views/src/service/request/index.ts create mode 100644 admin-views/src/service/request/instance.ts create mode 100644 admin-views/src/store/index.ts create mode 100644 admin-views/src/utils/dynamicAssets.ts create mode 100644 admin-views/src/utils/proxy.ts diff --git a/admin-views/.env b/admin-views/.env new file mode 100644 index 00000000..75d671ad --- /dev/null +++ b/admin-views/.env @@ -0,0 +1,8 @@ +# 公共基础路径 +VITE_BASE_URL=/admin +# 接口前缀 (默认) +VITE_API_PREFIX=/admin-api +# 代理地址, mode != production 时生效 +VITE_PROXY_URL=http://owl-admin.test +# 代理地址是否更改origin +VITE_PROXY_CHANGE_ORIGIN=Y diff --git a/admin-views/index.html b/admin-views/index.html index 87f2a12c..68e132d1 100644 --- a/admin-views/index.html +++ b/admin-views/index.html @@ -35,6 +35,7 @@
+ diff --git a/admin-views/package.json b/admin-views/package.json index 70134978..c19e7634 100644 --- a/admin-views/package.json +++ b/admin-views/package.json @@ -1,34 +1,41 @@ { - "name": "admin-views", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "preview": "vite preview" - }, - "dependencies": { - "ahooks": "^3.7.8", - "antd": "^5.8.5", - "dayjs": "^1.11.9", - "react": "^18.2.0", - "react-dom": "^18.2.0" - }, - "devDependencies": { - "@types/react": "^18.2.15", - "@types/react-dom": "^18.2.7", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "@vitejs/plugin-react": "^4.0.3", - "autoprefixer": "^10.4.15", - "eslint": "^8.45.0", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.4.3", - "postcss": "^8.4.29", - "tailwindcss": "^3.3.3", - "typescript": "^5.0.2", - "vite": "^4.4.5" - } + "name": "admin-views", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build --mode production", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "ahooks": "^3.7.8", + "antd": "^5.8.5", + "axios": "^1.5.0", + "dayjs": "^1.11.9", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-redux": "^8.1.2", + "react-router": "^6.15.0", + "react-router-dom": "^6.15.0", + "redux": "^4.2.1" + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "@vitejs/plugin-react": "^4.0.3", + "autoprefixer": "^10.4.15", + "eslint": "^8.45.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "postcss": "^8.4.29", + "tailwindcss": "^3.3.3", + "typescript": "^5.0.2", + "vite": "^4.4.5", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-progress": "^0.0.7" + } } diff --git a/admin-views/pnpm-lock.yaml b/admin-views/pnpm-lock.yaml index 5470f835..5ee7b02d 100644 --- a/admin-views/pnpm-lock.yaml +++ b/admin-views/pnpm-lock.yaml @@ -11,6 +11,9 @@ dependencies: antd: specifier: ^5.8.5 version: 5.8.5(react-dom@18.2.0)(react@18.2.0) + axios: + specifier: ^1.5.0 + version: 1.5.0 dayjs: specifier: ^1.11.9 version: 1.11.9 @@ -20,6 +23,18 @@ dependencies: react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + react-redux: + specifier: ^8.1.2 + version: 8.1.2(@types/react-dom@18.2.7)(@types/react@18.2.15)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1) + react-router: + specifier: ^6.15.0 + version: 6.15.0(react@18.2.0) + react-router-dom: + specifier: ^6.15.0 + version: 6.15.0(react-dom@18.2.0)(react@18.2.0) + redux: + specifier: ^4.2.1 + version: 4.2.1 devDependencies: '@types/react': @@ -61,6 +76,12 @@ devDependencies: vite: specifier: ^4.4.5 version: 4.4.5 + vite-plugin-compression: + specifier: ^0.5.1 + version: 0.5.1(vite@4.4.5) + vite-plugin-progress: + specifier: ^0.0.7 + version: 0.0.7(vite@4.4.5) packages: @@ -776,6 +797,18 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@remix-run/router@1.8.0: + resolution: {integrity: sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg==} + engines: {node: '>=14.0.0'} + dev: false + + /@types/hoist-non-react-statics@3.3.1: + resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==} + dependencies: + '@types/react': 18.2.15 + hoist-non-react-statics: 3.3.2 + dev: false + /@types/js-cookie@2.2.7: resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} dev: false @@ -784,15 +817,17 @@ packages: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true + /@types/node@10.17.60: + resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} + dev: true + /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - dev: true /@types/react-dom@18.2.7: resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==} dependencies: '@types/react': 18.2.15 - dev: true /@types/react@18.2.15: resolution: {integrity: sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==} @@ -800,16 +835,18 @@ packages: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.3 csstype: 3.1.2 - dev: true /@types/scheduler@0.16.3: resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} - dev: true /@types/semver@7.5.1: resolution: {integrity: sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==} dev: true + /@types/use-sync-external-store@0.0.3: + resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} + dev: false + /@typescript-eslint/eslint-plugin@6.0.0(@typescript-eslint/parser@6.0.0)(eslint@8.45.0)(typescript@5.0.2): resolution: {integrity: sha512-xuv6ghKGoiq856Bww/yVYnXGsKa588kY3M0XK7uUW/3fJNNULKRfZfSBkMTSpqGG/8ZCXCadfh8G/z/B4aqS/A==} engines: {node: ^16.0.0 || >=18.0.0} @@ -1119,6 +1156,10 @@ packages: resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} dev: false + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + /autoprefixer@10.4.15(postcss@8.4.29): resolution: {integrity: sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==} engines: {node: ^10 || ^12 || >=14} @@ -1135,6 +1176,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /axios@1.5.0: + resolution: {integrity: sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -1240,6 +1291,13 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1301,6 +1359,11 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} dev: true @@ -1562,10 +1625,38 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true + /follow-redirects@1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /fraction.js@4.3.4: resolution: {integrity: sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q==} dev: true + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: true + /fs.realpath@1.0.0: resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} dev: true @@ -1647,6 +1738,10 @@ packages: slash: 3.0.0 dev: true + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + /grapheme-splitter@1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: true @@ -1672,6 +1767,12 @@ packages: function-bind: 1.1.1 dev: true + /hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + dependencies: + react-is: 16.13.1 + dev: false + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -1793,6 +1894,14 @@ packages: hasBin: true dev: true + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.11 + dev: true + /keyv@4.5.3: resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} dependencies: @@ -1868,6 +1977,18 @@ packages: picomatch: 2.3.1 dev: true + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -2081,6 +2202,15 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: true + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -2622,6 +2752,12 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /rd@2.0.1: + resolution: {integrity: sha512-/XdKU4UazUZTXFmI0dpABt8jSXPWcEyaGdk340KdHnsEOdkTctlX23aAK7ChQDn39YGNlAJr1M5uvaKt4QnpNw==} + dependencies: + '@types/node': 10.17.60 + dev: true + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -2636,11 +2772,72 @@ packages: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: false + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: false + + /react-redux@8.1.2(@types/react-dom@18.2.7)(@types/react@18.2.15)(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1): + resolution: {integrity: sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==} + peerDependencies: + '@types/react': ^16.8 || ^17.0 || ^18.0 + '@types/react-dom': ^16.8 || ^17.0 || ^18.0 + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + react-native: '>=0.59' + redux: ^4 || ^5.0.0-beta.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + react-dom: + optional: true + react-native: + optional: true + redux: + optional: true + dependencies: + '@babel/runtime': 7.22.11 + '@types/hoist-non-react-statics': 3.3.1 + '@types/react': 18.2.15 + '@types/react-dom': 18.2.7 + '@types/use-sync-external-store': 0.0.3 + hoist-non-react-statics: 3.3.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-is: 18.2.0 + redux: 4.2.1 + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false + /react-refresh@0.14.0: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} engines: {node: '>=0.10.0'} dev: true + /react-router-dom@6.15.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.8.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-router: 6.15.0(react@18.2.0) + dev: false + + /react-router@6.15.0(react@18.2.0): + resolution: {integrity: sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.8.0 + react: 18.2.0 + dev: false + /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -2661,6 +2858,12 @@ packages: picomatch: 2.3.1 dev: true + /redux@4.2.1: + resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + dependencies: + '@babel/runtime': 7.22.11 + dev: false + /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} dev: false @@ -2918,6 +3121,11 @@ packages: hasBin: true dev: true + /universalify@2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + dev: true + /update-browserslist-db@1.0.11(browserslist@4.21.10): resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} hasBin: true @@ -2935,10 +3143,43 @@ packages: punycode: 2.3.0 dev: true + /use-sync-external-store@1.2.0(react@18.2.0): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /util-deprecate@1.0.2: resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} dev: true + /vite-plugin-compression@0.5.1(vite@4.4.5): + resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} + peerDependencies: + vite: '>=2.0.0' + dependencies: + chalk: 4.1.2 + debug: 4.3.4 + fs-extra: 10.1.0 + vite: 4.4.5 + transitivePeerDependencies: + - supports-color + dev: true + + /vite-plugin-progress@0.0.7(vite@4.4.5): + resolution: {integrity: sha512-zyvKdcc/X+6hnw3J1HVV1TKrlFKC4Rh8GnDnWG/2qhRXjqytTcM++xZ+SAPnoDsSyWl8O93ymK0wZRgHAoglEQ==} + engines: {node: '>=14', pnpm: '>=7.0.0'} + peerDependencies: + vite: '>2.0.0-0' + dependencies: + picocolors: 1.0.0 + progress: 2.0.3 + rd: 2.0.1 + vite: 4.4.5 + dev: true + /vite@4.4.5: resolution: {integrity: sha512-4m5kEtAWHYr0O1Fu7rZp64CfO1PsRGZlD3TAB32UmQlpd7qg15VF7ROqGN5CyqN7HFuwr7ICNM2+fDWRqFEKaA==} engines: {node: ^14.18.0 || >=16.0.0} diff --git a/admin-views/src/hooks/useApp.ts b/admin-views/src/hooks/useApp.ts new file mode 100644 index 00000000..660b7d50 --- /dev/null +++ b/admin-views/src/hooks/useApp.ts @@ -0,0 +1,50 @@ +import {appLoaded} from '@/utils/common.ts' +import {useSelector} from 'react-redux' +import {GlobalState} from '@/store' +import useStorage from '@/hooks/useStorage.ts' +import zhCN from 'antd/locale/zh_CN' +import enUS from 'antd/locale/en_US' +import {dynamicAssetsHandler} from '@/utils/dynamicAssets.ts' +import {useSettings} from '@/hooks/useSettings.ts' +import {useAuth} from '@/hooks/useAuth.ts' + +export const useApp = () => { + const [lang, setLang] = useStorage('arco-lang', 'zh-CN') + const settings = useSettings() + const auth = useAuth() + + const getStore = () => useSelector((state: GlobalState) => state) + + const getLocale = () => { + switch (lang) { + case 'zh-CN': + return zhCN + case 'en-US': + return enUS + default: + return zhCN + } + } + + const init = async (store = null) => { + const {data} = await settings.initSettings.runAsync() + + setLang(data.locale == 'zh_CN' ? 'zh-CN' : 'en-US') + dynamicAssetsHandler(data.assets) + + store.dispatch({ + type: 'update-settings', + payload: {settings: data}, + }) + + auth.checkLogin() + + appLoaded() + } + + return { + init, + getStore, + getLocale + } +} diff --git a/admin-views/src/hooks/useAuth.ts b/admin-views/src/hooks/useAuth.ts new file mode 100644 index 00000000..d20135b7 --- /dev/null +++ b/admin-views/src/hooks/useAuth.ts @@ -0,0 +1,27 @@ +import useStorage from '@/hooks/useStorage.ts' + +const TokenKey = window.$adminApiPrefix.replace(/^\//, '') + '-token' + +export const useAuth = () => { + const [token, setToken, removeToken] = useStorage(TokenKey, '') + + const logout = () => { + removeToken() + + if (window.location.hash !== '#/login') { + window.location.hash = '#/login' + } + } + + const checkLogin = () => { + console.log(token) + if (!token) { + logout() + } + } + + return { + token, + checkLogin + } +} diff --git a/admin-views/src/hooks/useSettings.ts b/admin-views/src/hooks/useSettings.ts new file mode 100644 index 00000000..5e42371b --- /dev/null +++ b/admin-views/src/hooks/useSettings.ts @@ -0,0 +1,14 @@ +import {useRequest} from 'ahooks' +import {fetchSettings} from '@/service' + +export const useSettings = () => { + const initSettings = useRequest(fetchSettings, { + manual: true, + retryCount: 3, + cacheKey: 'app-settings', + }) + + return { + initSettings + } +} diff --git a/admin-views/src/hooks/useStorage.ts b/admin-views/src/hooks/useStorage.ts new file mode 100644 index 00000000..bcd70aba --- /dev/null +++ b/admin-views/src/hooks/useStorage.ts @@ -0,0 +1,27 @@ +import {useEffect, useState} from 'react' + +const getDefaultStorage = (key) => localStorage.getItem(key) + +function useStorage(key: string, defaultValue?: string): [string, (string) => void, () => void] { + const [storedValue, setStoredValue] = useState(getDefaultStorage(key) || defaultValue) + + const setStorageValue = (value: string) => { + localStorage.setItem(key, value) + if (value !== storedValue) { + setStoredValue(value) + } + } + + const removeStorage = () => localStorage.removeItem(key) + + useEffect(() => { + const storageValue = localStorage.getItem(key) + if (storageValue) { + setStoredValue(storageValue) + } + }, []) + + return [storedValue, setStorageValue, removeStorage] +} + +export default useStorage diff --git a/admin-views/src/layouts/DefaultLayout/index.tsx b/admin-views/src/layouts/DefaultLayout/index.tsx index d5dd5e75..3dd9d859 100644 --- a/admin-views/src/layouts/DefaultLayout/index.tsx +++ b/admin-views/src/layouts/DefaultLayout/index.tsx @@ -8,7 +8,7 @@ export const DefaultLayout = () => { Sider -
11111111Header
+
11111111Header
Content
diff --git a/admin-views/src/layouts/index.tsx b/admin-views/src/layouts/index.tsx index dcaea1b1..84c4529b 100644 --- a/admin-views/src/layouts/index.tsx +++ b/admin-views/src/layouts/index.tsx @@ -1,7 +1,6 @@ import {DefaultLayout} from './DefaultLayout' import {useEffect, useState} from 'react' import {SmLayout} from './SmLayout' -import {appLoaded} from '../utils/common.ts' import {useSmallScreen} from '../hooks/useSmallScreen.ts' export const Layout = () => { @@ -10,7 +9,5 @@ export const Layout = () => { useEffect(() => setLayout(isSmallScreen ? : ), [isSmallScreen]) - appLoaded() - return layout } diff --git a/admin-views/src/main.tsx b/admin-views/src/main.tsx index 8d36ae18..d83a73db 100644 --- a/admin-views/src/main.tsx +++ b/admin-views/src/main.tsx @@ -2,19 +2,37 @@ import React from 'react' import ReactDOM from 'react-dom/client' import './index.css' import {ConfigProvider} from 'antd' -import zhCN from 'antd/locale/zh_CN' import 'dayjs/locale/zh-cn' import dayjs from 'dayjs' import {Layout} from './layouts' +import {useApp} from '@/hooks/useApp.ts' +import {useMount} from 'ahooks' +import {Provider} from 'react-redux' +import {createStore} from 'redux' +import rootReducer from '@/store' +import {HashRouter, Route, Routes} from 'react-router-dom' +import {Login} from '@/pages/login' dayjs.locale('zh-cn') +const store = createStore(rootReducer) + const App = () => { + const app = useApp() + + useMount(() => app.init(store)) return ( - - - + + + + + }/> + }/> + + + + ) } diff --git a/admin-views/src/pages/login/index.tsx b/admin-views/src/pages/login/index.tsx new file mode 100644 index 00000000..84b13941 --- /dev/null +++ b/admin-views/src/pages/login/index.tsx @@ -0,0 +1,5 @@ +export const Login = () => { + return ( +
login
+ ) +} diff --git a/admin-views/src/service/api/auth.ts b/admin-views/src/service/api/auth.ts new file mode 100644 index 00000000..1337f4d1 --- /dev/null +++ b/admin-views/src/service/api/auth.ts @@ -0,0 +1,27 @@ +import {request} from '../request'; + +/** + * 登录 + * @param data - 登录数据 + */ +export const fetchLogin = (data: any) => request.post('/login', data); + +/** + * 获取用户信息 + */ +export const fetchUserInfo = () => request.get('/current-user'); + +/** + * 获取用户路由数据 + */ +export const fetchUserRoutes = () => request.get('/menus') + +/** + * 登出 + */ +export const fetchLogout = () => request.get('/logout') + +/** + * 获取验证码 + */ +export const fetchCaptcha = () => request.get('/captcha'); diff --git a/admin-views/src/service/api/base.ts b/admin-views/src/service/api/base.ts new file mode 100644 index 00000000..a4ffe98d --- /dev/null +++ b/admin-views/src/service/api/base.ts @@ -0,0 +1,26 @@ +import {request} from "../request" + +/** + * 初始化页面结构 + * @param path + */ +export const fetchPageSchema = (path: string) => request.get(path) + +/** + * amis请求 + * @param url + * @param method + * @param data + */ +export const amisRequest = (url, method, data) => request[method](url, data) + +/** + * 获取设置 + */ +export const fetchSettings = () => request.get("/_settings") + +/** + * 保存设置 + * @param data 格式:{key1: value1, key2: value2, ...} + */ +export const saveSettings = (data: any) => request.post("/_settings", data) diff --git a/admin-views/src/service/api/index.ts b/admin-views/src/service/api/index.ts new file mode 100644 index 00000000..7326de9c --- /dev/null +++ b/admin-views/src/service/api/index.ts @@ -0,0 +1,2 @@ +export * from "./base" +export * from "./auth" \ No newline at end of file diff --git a/admin-views/src/service/index.ts b/admin-views/src/service/index.ts new file mode 100644 index 00000000..3318fdbc --- /dev/null +++ b/admin-views/src/service/index.ts @@ -0,0 +1 @@ +export * from './api' diff --git a/admin-views/src/service/request/config.ts b/admin-views/src/service/request/config.ts new file mode 100644 index 00000000..023c6c97 --- /dev/null +++ b/admin-views/src/service/request/config.ts @@ -0,0 +1,15 @@ +import {AxiosRequestConfig} from "axios" + +interface RequestConfig extends AxiosRequestConfig { + // 代理路径 + proxyURL: string, + // 是否跨域 + changeOrigin: boolean, +} + +export default { + // @ts-ignore + baseURL: window.$adminApiPrefix || import.meta.env.VITE_API_PREFIX, + proxyURL: import.meta.env.VITE_PROXY_URL, + changeOrigin: import.meta.env.VITE_PROXY_CHANGE_ORIGIN === "Y", +} diff --git a/admin-views/src/service/request/index.ts b/admin-views/src/service/request/index.ts new file mode 100644 index 00000000..41878810 --- /dev/null +++ b/admin-views/src/service/request/index.ts @@ -0,0 +1,5 @@ +import CustomAxiosInstance from "@/service/request/instance" +import config from "./config" + + +export const request = new CustomAxiosInstance(config).instance \ No newline at end of file diff --git a/admin-views/src/service/request/instance.ts b/admin-views/src/service/request/instance.ts new file mode 100644 index 00000000..d81da24b --- /dev/null +++ b/admin-views/src/service/request/instance.ts @@ -0,0 +1,76 @@ +import axios, {AxiosError, AxiosInstance, AxiosRequestConfig} from "axios" +// import {getToken, removeToken} from "@/utils/checkLogin" +// import {Message} from "@arco-design/web-react" + +export default class CustomAxiosInstance { + instance: AxiosInstance + + constructor(axiosConfig: AxiosRequestConfig) { + this.instance = axios.create(axiosConfig) + this.setInterceptor() + } + + setInterceptor() { + // 请求拦截器 + this.instance.interceptors.request.use( + async config => { + const handleConfig = {...config} + // 设置token + // const token = getToken() + const token = '' + + handleConfig.headers.Authorization = `Bearer ${token}` + + return handleConfig + }, + (axiosError: AxiosError | any) => { + return { + data: { + status: 1, + msg: axiosError.response?.data?.message || axiosError.message + } + } + } + ) + // 响应拦截器 + this.instance.interceptors.response.use( + async response => { + const {status} = response + if (status === 200 || status < 300 || status === 304) { + const backend = response.data + // 请求成功 + if (backend.status === 0) { + if (backend?.msg && backend?.doNotDisplayToast == 0) { + // Message.success(backend.msg) + } + + return backend + }else{ + if (backend?.msg && backend?.doNotDisplayToast == 0) { + // Message.error(backend.msg) + } + } + + // token失效 + if (backend?.code == 401 && window.location.hash != "#/login") { + // removeToken() + + window.location.hash = "#/login" + } + + return response + } + + return response + }, + (axiosError: AxiosError | any) => { + return { + data: { + status: 1, + msg: axiosError.response?.data?.message || axiosError.message + } + } + } + ) + } +} diff --git a/admin-views/src/store/index.ts b/admin-views/src/store/index.ts new file mode 100644 index 00000000..7dc14fb1 --- /dev/null +++ b/admin-views/src/store/index.ts @@ -0,0 +1,75 @@ +const defaultSettings = { + footer: false, + breadcrumb: true, + breadcrumbIcon: false, + themeColor: '#4080FF', + menuWidth: 220, + layoutMode: 'default', + siderTheme: 'light', + topTheme: 'light', + animateInType: 'alpha', + animateInDuration: 600, + animateOutType: 'alpha', + animateOutDuration: 600, + loginTemplate: 'default', + keepAlive: false, + enableTab: false, + tabIcon: true +} + +export interface GlobalState { + settings?: {}; + userInfo?: { + name?: string; + avatar?: string; + }; + breadcrumb?: [], + routes?: any[]; +} + +const initialState: GlobalState = { + settings: {}, + userInfo: {}, + routes: [], +} + +export default function store(state = initialState, action) { + switch (action.type) { + case 'update-settings': { + const {settings} = action.payload + + settings.system_theme_setting = { + ...settings.system_theme_setting, + ...defaultSettings, + } + + return { + ...state, + settings, + } + } + case 'update-userInfo': { + const {userInfo = initialState.userInfo} = action.payload + return { + ...state, + userInfo, + } + } + case 'update-breadcrumb': { + const {breadcrumb} = action.payload + return { + ...state, + breadcrumb, + } + } + case 'update-routes': { + const {routes} = action.payload + return { + ...state, + routes, + } + } + default: + return state + } +} diff --git a/admin-views/src/utils/common.ts b/admin-views/src/utils/common.ts index 71b4a74d..5b13466b 100644 --- a/admin-views/src/utils/common.ts +++ b/admin-views/src/utils/common.ts @@ -2,3 +2,12 @@ * 应用加载完成 */ export const appLoaded = () => setTimeout(() => document.getElementById('app-loader')?.remove(), 300) + +/** + * 注册全局函数 + * @param name + * @param fn + */ +export const registerGlobalFunction = (name, fn) => { + window.$owl = {...window.$owl, [name]: fn} +} diff --git a/admin-views/src/utils/dynamicAssets.ts b/admin-views/src/utils/dynamicAssets.ts new file mode 100644 index 00000000..0d64ae99 --- /dev/null +++ b/admin-views/src/utils/dynamicAssets.ts @@ -0,0 +1,35 @@ +export function dynamicAssetsHandler({js = [], css = [], styles = [], scripts = []}) { + const appendToHead = (element: any) => document.getElementsByTagName("head")[0].appendChild(element) + + const loadJS = (src: string) => { + const script = document.createElement("script") + script.src = src + script.type = "text/javascript" + appendToHead(script) + } + + const loadCSS = (href: string) => { + const link = document.createElement("link") + link.href = href + link.rel = "stylesheet" + appendToHead(link) + } + + const loadScripts = (arr: string[]) => { + const script = document.createElement("script") + script.innerHTML = arr.join("") + script.type = "text/javascript" + appendToHead(script) + } + + const loadStyles = (arr: string[]) => { + const style = document.createElement("style") + style.innerHTML = arr.join("") + appendToHead(style) + } + + js.forEach(js => loadJS(js)) + css.forEach(css => loadCSS(css)) + scripts.length && loadScripts(scripts) + styles.length && loadStyles(styles) +} diff --git a/admin-views/src/utils/proxy.ts b/admin-views/src/utils/proxy.ts new file mode 100644 index 00000000..238b57f2 --- /dev/null +++ b/admin-views/src/utils/proxy.ts @@ -0,0 +1,18 @@ +import type {ProxyOptions} from "vite" + +/** + * 设置网络代理 + */ +export function createViteProxy(env) { + if (env.PROD) return undefined + if (env.VITE_PROXY_CHANGE_ORIGIN !== "Y") return undefined + + const proxy: Record = { + [env.VITE_API_PREFIX]: { + target: env.VITE_PROXY_URL, + changeOrigin: env.VITE_PROXY_CHANGE_ORIGIN === "Y", + }, + } + + return proxy +} diff --git a/admin-views/src/vite-env.d.ts b/admin-views/src/vite-env.d.ts index 11f02fe2..f645d40a 100644 --- a/admin-views/src/vite-env.d.ts +++ b/admin-views/src/vite-env.d.ts @@ -1 +1,13 @@ /// + +interface Window { + $adminApiPrefix: string, + $owl: any +} + +interface ImportMetaEnv { + VITE_PROXY_URL: string, + VITE_PROXY_CHANGE_ORIGIN: string, + VITE_API_PREFIX: string, + VITE_BASE_URL: string, +} diff --git a/admin-views/tsconfig.json b/admin-views/tsconfig.json index a09e9b7e..21bf8713 100644 --- a/admin-views/tsconfig.json +++ b/admin-views/tsconfig.json @@ -1,25 +1,41 @@ { - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": false, - "noUnusedLocals": false, - "noUnusedParameters": false, - "noFallthroughCasesInSwitch": false - }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ], + "module": "ESNext", + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + /* Linting */ + "strict": false, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": false, + "noImplicitAny": false, + "noImplicitThis": false, + "baseUrl": ".", + "paths": { + "@/*": [ + "src/*" + ] + }, + }, + "include": [ + "src" + ], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] } diff --git a/admin-views/vite.config.ts b/admin-views/vite.config.ts index 5a33944a..8254a53c 100644 --- a/admin-views/vite.config.ts +++ b/admin-views/vite.config.ts @@ -1,7 +1,33 @@ -import { defineConfig } from 'vite' +import {defineConfig, loadEnv} from 'vite' import react from '@vitejs/plugin-react' +import compression from 'vite-plugin-compression' +import progress from 'vite-plugin-progress' +import {createViteProxy} from "./src/utils/proxy" // https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], +export default defineConfig(configEnv => { + const viteEnv = loadEnv(configEnv.mode, process.cwd()) + return { + base: viteEnv.VITE_BASE_URL, + plugins: [ + react(), + compression(), + progress() + ], + resolve: { + alias: [ + {find: '@', replacement: '/src'}, + ], + }, + server: { + host: '0.0.0.0', + port: 3200, + open: true, + proxy: createViteProxy(viteEnv), + }, + build: { + sourcemap: false, + reportCompressedSize: false, + } + } })