├── .browserslistrc ├── .editorconfig ├── .github └── workflows │ ├── lint-ci.yml │ └── sync.yml ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .huxy └── app.configs.js ├── .npmrc ├── .prettierignore ├── .versionrc.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __tests__ └── add.test.js ├── app ├── apis │ ├── apiList.js │ ├── fetcher.js │ ├── getApis.js │ ├── report │ │ ├── browserInfo.js │ │ ├── fetchError.js │ │ ├── pageError.js │ │ ├── report.js │ │ ├── reportButtom.jsx │ │ └── routeChange.js │ └── userMock.js ├── app.jsx ├── assets │ ├── icons │ │ ├── agile.png │ │ ├── algorithm.png │ │ ├── analysis.png │ │ ├── api.png │ │ ├── basketball.png │ │ ├── bigdata.png │ │ ├── brain.png │ │ ├── chat.png │ │ ├── checkup.png │ │ ├── code.png │ │ ├── coder.png │ │ ├── cogwheel.png │ │ ├── control.png │ │ ├── css.png │ │ ├── dashboard.png │ │ ├── data-analysis.png │ │ ├── data-modelling.png │ │ ├── debug.png │ │ ├── diagram.png │ │ ├── digital.png │ │ ├── flow.png │ │ ├── html.png │ │ ├── js.png │ │ ├── light.png │ │ ├── line-chart.png │ │ ├── manufacturing.png │ │ ├── map.png │ │ ├── monitoring.png │ │ ├── not-found.png │ │ ├── organization.png │ │ ├── production.png │ │ ├── programming.png │ │ ├── screen.png │ │ ├── setting.png │ │ ├── simulation.png │ │ ├── time.png │ │ ├── trend.png │ │ ├── web-analysis.png │ │ ├── work-home.png │ │ └── write.png │ ├── images │ │ ├── github.svg │ │ ├── logo.png │ │ ├── metamask.svg │ │ ├── user │ │ │ ├── 1.png │ │ │ ├── 2.png │ │ │ ├── 3.png │ │ │ ├── 4.png │ │ │ ├── 5.png │ │ │ ├── 6.png │ │ │ ├── 7.png │ │ │ └── 8.png │ │ ├── wx.jpg │ │ └── zys.svg │ ├── lang │ │ ├── en.png │ │ └── zh.png │ ├── styles.less │ └── var.less ├── build │ ├── .spa │ ├── favicon.png │ ├── img │ │ ├── img_00ed15c3.png │ │ ├── img_05d91403.png │ │ ├── img_0bd8fceb.png │ │ ├── img_11f7f8e1.png │ │ ├── img_18156581.png │ │ ├── img_1bf88407.png │ │ ├── img_2bc2ed04.png │ │ ├── img_3b260126.png │ │ ├── img_4512a22a.png │ │ ├── img_4542f85f.png │ │ ├── img_47f2615a.png │ │ ├── img_4a88e074.png │ │ ├── img_4c3443c3.png │ │ ├── img_534c19b0.png │ │ ├── img_67c69369.png │ │ ├── img_80fa61e6.png │ │ ├── img_85dda956.png │ │ ├── img_8c276863.png │ │ ├── img_987c0fad.png │ │ ├── img_98c65923.jpg │ │ ├── img_ac6bf8c0.jpg │ │ ├── img_b8ad20df.png │ │ ├── img_bb332316.png │ │ ├── img_bdef7b6c.png │ │ ├── img_c50c8ae6.png │ │ ├── img_c8f41c35.png │ │ ├── img_cb9d1666.png │ │ ├── img_cdbb0313.png │ │ ├── img_d9039ae8.png │ │ ├── img_d9a29b56.png │ │ ├── img_dc353f92.png │ │ ├── img_dc6d2254.png │ │ ├── img_e4fdac22.png │ │ ├── img_eed84d91.png │ │ ├── img_f2223441.png │ │ └── img_f98c79fb.png │ ├── index.html │ ├── manifest.json │ ├── robots.txt │ ├── service-worker.js │ └── src │ │ └── images │ │ ├── 144.png │ │ ├── 192.png │ │ ├── 512.png │ │ └── 96.png ├── commons │ ├── layout │ │ ├── README.md │ │ ├── components │ │ │ ├── footer │ │ │ │ ├── index.jsx │ │ │ │ └── index.less │ │ │ ├── mainTop │ │ │ │ ├── index.jsx │ │ │ │ └── index.less │ │ │ ├── menuBottom │ │ │ │ ├── index.jsx │ │ │ │ └── index.less │ │ │ ├── uiI18n │ │ │ │ └── index.jsx │ │ │ └── useFormatMenu │ │ │ │ └── index.jsx │ │ ├── configs.js │ │ ├── index.jsx │ │ ├── layout.jsx │ │ └── utils │ │ │ └── handleNavClick.js │ └── styles │ │ ├── base.less │ │ ├── block.less │ │ ├── common │ │ ├── default.css │ │ ├── icons.css │ │ ├── resets.css │ │ ├── style-block.less │ │ ├── style-icon.less │ │ └── tokens.css │ │ ├── func │ │ ├── angle.less │ │ ├── arrow.less │ │ ├── follow.less │ │ └── tooltip.less │ │ ├── global │ │ └── index.less │ │ └── index.less ├── components │ ├── base │ │ ├── button │ │ │ ├── index.jsx │ │ │ └── index.less │ │ ├── checkbox │ │ │ └── index.jsx │ │ ├── input │ │ │ ├── index.jsx │ │ │ └── index.less │ │ ├── menu │ │ │ ├── index.jsx │ │ │ └── index.less │ │ ├── radio │ │ │ └── index.jsx │ │ ├── select │ │ │ └── index.jsx │ │ ├── textarea │ │ │ ├── index.jsx │ │ │ └── index.less │ │ └── tooltip │ │ │ └── index.jsx │ ├── custom │ │ ├── form.jsx │ │ └── table.jsx │ ├── customCollapse.jsx │ ├── ellipsis.jsx │ ├── fullScreen.jsx │ ├── goBack.jsx │ ├── icon.jsx │ ├── icons │ │ ├── add.jsx │ │ ├── audio0.jsx │ │ ├── audio1.jsx │ │ ├── broom.jsx │ │ ├── github.jsx │ │ ├── image.jsx │ │ ├── lock.jsx │ │ ├── moon.jsx │ │ ├── send.jsx │ │ ├── sun.jsx │ │ ├── user.jsx │ │ ├── video.jsx │ │ └── wechat.jsx │ ├── intl.jsx │ ├── maxSize.jsx │ ├── notify.jsx │ ├── panel │ │ └── index.jsx │ ├── row │ │ └── index.jsx │ ├── search.jsx │ ├── searchForm │ │ └── index.jsx │ ├── settings │ │ └── index.jsx │ ├── skeletonContent │ │ ├── index.jsx │ │ └── index.less │ └── themeModel.jsx ├── configs │ ├── appTools.jsx │ ├── index.js │ ├── langList.jsx │ ├── nav.jsx │ ├── project.jsx │ ├── router.js │ ├── theme.js │ └── themes │ │ ├── dark.js │ │ ├── dark1.js │ │ ├── index.js │ │ ├── light.js │ │ ├── light1.js │ │ ├── portal.js │ │ ├── portal1.js │ │ └── themes.js ├── globals │ ├── getRouterAuth.js │ └── registerPwa.js ├── hooks │ ├── useFetchList.jsx │ ├── useGetI18ns.jsx │ ├── useGetProfile.jsx │ └── useHandleList.jsx ├── i18ns │ ├── en │ │ ├── index.js │ │ ├── login.js │ │ ├── main.js │ │ ├── nav.js │ │ ├── router.js │ │ └── theme.js │ └── zh │ │ ├── index.js │ │ ├── login.js │ │ ├── main.js │ │ ├── nav.js │ │ ├── router.js │ │ └── theme.js ├── index.jsx ├── models │ ├── animateObjs.js │ ├── circleRing.jsx │ ├── cssModels.js │ ├── icons.js │ ├── icons │ │ ├── agile.png │ │ ├── algorithm.png │ │ ├── analysis.png │ │ ├── api.png │ │ ├── brain.png │ │ ├── chat.png │ │ ├── coder.png │ │ ├── control.png │ │ ├── dashboard.png │ │ ├── data-analysis.png │ │ ├── debug.png │ │ ├── diagram.png │ │ ├── digital.png │ │ ├── light.png │ │ ├── manufacturing.png │ │ ├── monitoring.png │ │ ├── not-found.png │ │ ├── programming.png │ │ ├── screen.png │ │ ├── simulation.png │ │ ├── trend.png │ │ ├── web-analysis.png │ │ └── write.png │ ├── models.js │ └── objs.js ├── public │ ├── .spa │ ├── favicon.png │ ├── index.html │ ├── manifest.json │ ├── robots.txt │ └── src │ │ └── images │ │ ├── 144.png │ │ ├── 192.png │ │ ├── 512.png │ │ └── 96.png ├── routes │ ├── defaultPermList.js │ ├── index.js │ ├── routerComp │ │ ├── dynamicRoutes.js │ │ └── staticRoutes.js │ └── whiteList.js ├── store │ ├── index.js │ ├── names.js │ └── stores.js ├── sw │ └── index.js ├── utils │ ├── configs.js │ ├── confirmDesignPage.js │ ├── formatTree.js │ ├── getI18n.js │ ├── getLang.js │ ├── getRouterCfgs.js │ ├── getTheme.js │ ├── icons.js │ ├── isAdmin.js │ ├── patterns.js │ ├── rules.js │ ├── setStyleVar.js │ ├── sizeRules.js │ ├── sysThemeMode.js │ └── utils.js └── views │ ├── 404 │ ├── index.jsx │ └── index.less │ ├── layout │ ├── routes.js │ └── src │ │ └── index.jsx │ ├── message │ ├── routes.js │ └── src │ │ └── index.jsx │ ├── payer │ ├── routes.js │ └── src │ │ └── count │ │ ├── ali.png │ │ ├── member.jsx │ │ ├── member.less │ │ ├── order.jsx │ │ ├── pay.jsx │ │ ├── pay.less │ │ └── wechat.png │ ├── playground │ ├── routes.js │ └── src │ │ ├── canvas │ │ ├── 1.jpg │ │ ├── draw.js │ │ ├── drawText.js │ │ ├── index.jsx │ │ └── index.less │ │ ├── configList │ │ ├── configs.js │ │ ├── getColumns.jsx │ │ ├── mock │ │ │ ├── data.js │ │ │ ├── index.js │ │ │ └── utils.js │ │ ├── routes.js │ │ └── src │ │ │ ├── add.jsx │ │ │ ├── auth.jsx │ │ │ ├── index.jsx │ │ │ ├── index.less │ │ │ └── searchList │ │ │ ├── formList.jsx │ │ │ ├── index.jsx │ │ │ └── list │ │ │ ├── autoSizeList.jsx │ │ │ ├── wrapList.jsx │ │ │ └── wrapTable.jsx │ │ ├── functions │ │ ├── icons │ │ │ ├── index.jsx │ │ │ └── index.less │ │ ├── modal │ │ │ └── index.jsx │ │ ├── panel │ │ │ ├── index.jsx │ │ │ └── index.less │ │ ├── styles │ │ │ ├── config.js │ │ │ └── index.jsx │ │ └── tools │ │ │ └── index.jsx │ │ ├── materials │ │ ├── animation │ │ │ └── index.jsx │ │ ├── border │ │ │ └── index.jsx │ │ ├── chart │ │ │ └── index.jsx │ │ ├── shape │ │ │ ├── index.jsx │ │ │ └── taiji │ │ │ │ ├── bagua │ │ │ │ ├── gua │ │ │ │ │ ├── configs.js │ │ │ │ │ ├── index.jsx │ │ │ │ │ └── index.less │ │ │ │ ├── index.jsx │ │ │ │ └── yao │ │ │ │ │ ├── index.jsx │ │ │ │ │ └── index.less │ │ │ │ ├── index.jsx │ │ │ │ └── index.less │ │ └── text │ │ │ └── index.jsx │ │ ├── page │ │ ├── routes.js │ │ └── src │ │ │ └── index.jsx │ │ └── suspense │ │ ├── errorboundary.jsx │ │ ├── index.jsx │ │ └── suspenseFns.js │ └── user │ ├── configs.js │ ├── routes.js │ └── src │ ├── index.jsx │ ├── index.less │ ├── login.jsx │ ├── profile.jsx │ ├── setNewPwd.jsx │ ├── signup.jsx │ └── verifyEmail.jsx ├── babel.config.js ├── commitlint.config.js ├── doc ├── functions.md ├── src │ ├── api.png │ ├── apiTest.png │ ├── auth.png │ ├── demand.png │ ├── doc.png │ ├── editDemand.png │ ├── email.png │ ├── file.png │ ├── lang.png │ ├── layout.png │ ├── log.png │ ├── member.png │ ├── message.png │ ├── monitor.png │ ├── order.png │ ├── pageDesign.png │ ├── pageView.png │ ├── profile.png │ ├── project.png │ ├── router.png │ ├── theme.png │ └── user.png └── tools.md ├── eslint.config.js ├── jest.config.js ├── package.json ├── postcss.config.js ├── prettier.config.js └── stylelint.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | not ie < 11 3 | last 2 versions 4 | > 1% 5 | last 2 iOS versions 6 | not dead -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.github/workflows/lint-ci.yml: -------------------------------------------------------------------------------- 1 | name: Lint CI 2 | on: 3 | push: 4 | branches: 5 | - develop 6 | jobs: 7 | lint: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - name: Install 12 | run: npm i 13 | - name: Lint 14 | run: npm run lint && npm run test -------------------------------------------------------------------------------- /.github/workflows/sync.yml: -------------------------------------------------------------------------------- 1 | name: Sync to gitee 2 | on: 3 | push: 4 | branches: 5 | - develop 6 | jobs: 7 | sync: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: 同步到 gitee 11 | uses: wearerequired/git-mirror-action@master 12 | env: 13 | SSH_PRIVATE_KEY: ${{ secrets.GITEE_SERVER_KEY }} 14 | with: 15 | source-repo: git@github.com:ahyiru/huxy-admin.git 16 | destination-repo: git@gitee.com:yiru/huxy-admin.git 17 | - name: 部署到 Gitee Pages 18 | uses: yanglbme/gitee-pages-action@main 19 | with: 20 | gitee-username: yiru 21 | gitee-password: ${{ secrets.GITEE_SERVER_PASSWORD }} 22 | gitee-repo: yiru/huxy-admin 23 | branch: develop 24 | directory: app/build 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Optional npm cache directory 24 | .npm 25 | 26 | # Optional REPL history 27 | .node_repl_history 28 | 29 | # Compiled binary addons (http://nodejs.org/api/addons.html) 30 | build/Release 31 | 32 | # Dependency directories 33 | node_modules 34 | jspm_packages 35 | bower_components 36 | typings 37 | 38 | # Editors 39 | .idea 40 | *.iml 41 | 42 | # OS metadata 43 | .DS_Store 44 | Thumbs.db 45 | 46 | # test 47 | __snapshots__ 48 | 49 | # package-lock.json 50 | package-lock.json 51 | 52 | # pnpm-lock.yaml 53 | pnpm-lock.yaml 54 | 55 | # build 56 | dist 57 | build 58 | 59 | # redis 60 | *.rdb 61 | 62 | deadcode.json 63 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx commitlint -e $1 -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | 6 | npm run test -------------------------------------------------------------------------------- /.huxy/app.configs.js: -------------------------------------------------------------------------------- 1 | import DeadCodePlugin from 'webpack-deadcode-plugin'; 2 | 3 | const app = { 4 | // HOST: 'http://localhost', 5 | PORT: 3000, 6 | PROD_PORT: 3001, 7 | PUBLIC_DIR: 'public', 8 | BUILD_DIR: 'build', 9 | DEV_ROOT_DIR: '/', 10 | PROD_ROOT_DIR: '/huxy-admin', 11 | projectName: '...', 12 | /* PROXY: { 13 | url: 'http://api.ihuxy.com', 14 | prefix: '/api', 15 | }, */ 16 | envConfigs: { 17 | // 全局环境变量 18 | name: '项目名', 19 | _id: '其它属性', 20 | }, 21 | }; 22 | 23 | export default { 24 | app, 25 | webpack: (rootPath, appPath) => ({ 26 | dev: { 27 | plugins: [ 28 | new DeadCodePlugin({ 29 | patterns: [`${appPath}/**/*.(js|jsx|css|less|json|png|jpg|jpeg)`], 30 | exclude: ['**/node_modules/**', '**/build/**', '**/draft/**'], 31 | log: 'none', 32 | exportJSON: rootPath, 33 | }), 34 | ], 35 | }, 36 | prod: { 37 | copy: [ 38 | { 39 | from: `${appPath}/public/.spa`, 40 | to: `${appPath}/build/.spa`, 41 | }, 42 | ], 43 | }, 44 | }), 45 | }; 46 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps = true -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/coverage 3 | **/build 4 | **/draft 5 | -------------------------------------------------------------------------------- /.versionrc.js: -------------------------------------------------------------------------------- 1 | import configs from '@huxy/pack/config/version'; 2 | 3 | export default configs({ 4 | // customCfgs 5 | }); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 yiru 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /__tests__/add.test.js: -------------------------------------------------------------------------------- 1 | const sum = (a, b) => a + b; 2 | 3 | describe('add', () => { 4 | it ('adds 1 + 2 to equal 3', () => { 5 | expect(sum(1, 2)).toBe(3); 6 | }); 7 | }); 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/apis/apiList.js: -------------------------------------------------------------------------------- 1 | import fetcher from '@app/apis/report/fetchError'; 2 | import {dlApi, suspense} from '@app/apis/fetcher'; 3 | import getApis from '@app/apis/getApis'; 4 | import {allUserMock, allUserSuspenseMock} from '@app/apis/userMock'; 5 | 6 | const apiList = { 7 | allUserMock, 8 | }; 9 | 10 | const suspenseApis = { 11 | allUserSuspenseMock, 12 | }; 13 | 14 | const getSuspense = apis => { 15 | const susList = apis.filter(api => ['profile', 'allUser'].includes(api.name)); 16 | susList.map(sus => { 17 | const {name, fnName, dataType, url, isDl, ...restApi} = sus; 18 | const fetchFn = isDl ? dlApi : suspense; 19 | const funcName = fnName ?? `${name}Suspense`; 20 | const paramsKey = dataType || restApi.method === 'post' ? 'data' : 'params'; 21 | suspenseApis[funcName] = (data, ...rest) => fetchFn({...restApi, url: typeof url === 'function' ? url(data) : url, [paramsKey]: data, ...rest}); 22 | }); 23 | }; 24 | 25 | export {suspenseApis}; 26 | 27 | const getList = async () => { 28 | const {result} = await getApis(); 29 | return result?.list ?? []; 30 | }; 31 | 32 | export const getApiFn = async () => { 33 | let apis = []; 34 | try { 35 | apis = await getList(); 36 | } catch (err) {} 37 | apis.map(api => { 38 | const {name, fnName, dataType, url, isDl, ...restApi} = api; 39 | const fetchFn = isDl ? dlApi : fetcher; 40 | const funcName = fnName ?? `${name}Fn`; 41 | const paramsKey = dataType || (restApi.method === 'post' ? 'data' : 'params'); 42 | apiList[funcName] = (data, ...rest) => fetchFn({...restApi, url: typeof url === 'function' ? url(data) : url, [paramsKey]: data, ...rest}); 43 | }); 44 | getSuspense(apis); 45 | return apiList; 46 | }; 47 | 48 | export default apiList; 49 | -------------------------------------------------------------------------------- /app/apis/getApis.js: -------------------------------------------------------------------------------- 1 | import fetcher from './fetcher'; 2 | import {defProject} from '@app/configs'; 3 | 4 | // const getApis = () => fetcher({url: '/api/list', params: {projectId: defProject?._id, current: 1, size: 100}}); 5 | 6 | const apiList = projectId => [ 7 | { 8 | name: 'login', 9 | url: '/auth/login', 10 | method: 'post', 11 | }, 12 | { 13 | name: 'logout', 14 | url: '/auth/logout', 15 | }, 16 | { 17 | name: 'signup', 18 | url: '/auth/signup', 19 | method: 'post', 20 | }, 21 | { 22 | name: 'profile', 23 | url: '/users/profile', 24 | method: 'get', 25 | }, 26 | { 27 | name: 'allUser', 28 | url: '/users/allUser', 29 | }, 30 | ]; 31 | 32 | const getApis = () => ({result: {list: apiList(defProject?._id)}}); 33 | 34 | export default getApis; 35 | -------------------------------------------------------------------------------- /app/apis/report/browserInfo.js: -------------------------------------------------------------------------------- 1 | import {getOsInfo, getExplore} from '@huxy/utils'; 2 | import {browserRouter} from '@app/configs'; 3 | 4 | import pkg from '../../../package.json'; 5 | 6 | const {type: osType, version: osVersion, model: osModel} = getOsInfo(); 7 | const {type: browserType, version: browserVersion} = getExplore(); 8 | 9 | const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; 10 | 11 | const info = { 12 | osType, 13 | osVersion, 14 | osModel, 15 | browserType, 16 | browserVersion, 17 | language: window.navigator.language, 18 | netType: connection?.type, 19 | evn: browserRouter ? 'prod' : 'dev', 20 | appName: pkg.name, 21 | appVersion: pkg.version, 22 | }; 23 | 24 | export default info; 25 | -------------------------------------------------------------------------------- /app/apis/report/fetchError.js: -------------------------------------------------------------------------------- 1 | import fetcher from '@app/apis/fetcher'; 2 | 3 | import report from './report'; 4 | 5 | const whiteCode = [401, 403, 429]; 6 | const whitePath = ['/report', '/auth']; 7 | 8 | const fetch = props => 9 | fetcher(props).catch(err => { 10 | const {url} = props; 11 | const isPermission = !whiteCode.includes(err.code); 12 | const authedPath = !whitePath.find(path => url.includes(`${path}/`)); 13 | if (isPermission && authedPath) { 14 | report({actionType: 'fetchError', text: err.message, value: url}); 15 | } 16 | throw Error(err.message); 17 | }); 18 | 19 | export default fetch; 20 | -------------------------------------------------------------------------------- /app/apis/report/pageError.js: -------------------------------------------------------------------------------- 1 | import {HandleError} from '@huxy/components'; 2 | 3 | import report from './report'; 4 | 5 | const pageError = ({error}) => { 6 | const errStack = error?.message?.slice(0, 120).split('. ').slice(0, 2).join('. '); 7 | report({actionType: 'pageError', text: errStack}); 8 | }; 9 | 10 | const errorBoundary = props => ; 11 | 12 | export default errorBoundary; 13 | -------------------------------------------------------------------------------- /app/apis/report/report.js: -------------------------------------------------------------------------------- 1 | import {getRoute} from '@huxy/router'; 2 | 3 | import {browserRouter} from '@app/configs'; 4 | 5 | import {isAuthed} from '@app/utils/utils'; 6 | 7 | import apiList from '@app/apis/apiList'; 8 | 9 | import info from './browserInfo'; 10 | 11 | const report = params => { 12 | if (!browserRouter || !isAuthed()) { 13 | return; 14 | } 15 | const routeInfo = getRoute(); 16 | const routes = routeInfo ? routeInfo.current.slice(-1)[0] ?? {} : {}; 17 | const {path, name, ...restParams} = params; 18 | const currentPath = routes.path ?? path ?? ''; 19 | const reportInfo = { 20 | ...info, 21 | ...restParams, 22 | route: browserRouter ? currentPath : currentPath.slice(1), 23 | routeName: routes.name ?? name, 24 | }; 25 | apiList.addReportFn?.(reportInfo); 26 | }; 27 | 28 | export default report; 29 | -------------------------------------------------------------------------------- /app/apis/report/reportButtom.jsx: -------------------------------------------------------------------------------- 1 | import Button from '@app/components/base/button'; 2 | 3 | import report from './report'; 4 | 5 | const ReportButton = props => { 6 | const {value, label, text, description, onClick, ...rest} = props; 7 | const handleClick = e => { 8 | report({ 9 | text: text || props.children, 10 | value, 11 | label, 12 | description, 13 | type: 'click', 14 | }); 15 | onClick?.(e); 16 | }; 17 | return