From 45443709afd7b35e6cbf19fee6f102c416206b8b Mon Sep 17 00:00:00 2001 From: xion Date: Tue, 25 Mar 2025 15:51:15 +0800 Subject: [PATCH] feat: change center-component to components --- package.json | 4 +- packages/codemirror/package.json | 2 +- packages/codemirror/src/global.css | 2 +- packages/codemirror/src/pages/App.tsx | 2 +- packages/components/package.json | 2 +- packages/components/src/theme/wind-theme.css | 11 +- packages/components/tsconfig.json | 2 +- packages/resources/package.json | 2 +- packages/resources/src/global.css | 2 +- packages/resources/src/pages/App.tsx | 2 +- .../src/pages/file/draw/modules/MetaForm.tsx | 4 +- packages/resources/src/pages/file/index.tsx | 2 +- .../src/pages/file/list/FileTable.tsx | 2 +- .../pages/file/modules/PermissionManager.tsx | 2 +- pnpm-lock.yaml | 189 +++++++++++++++++- src/App.tsx | 5 +- src/globals.css | 5 +- src/modules/layout/index.tsx | 2 +- src/modules/message.ts | 22 +- src/pages/app/edit/AppVersionList.tsx | 4 +- src/pages/app/edit/List.tsx | 42 +++- src/pages/config/edit/List.tsx | 29 ++- src/pages/container/edit/List.tsx | 6 +- src/pages/container/module/DrawEdit.tsx | 25 ++- src/pages/container/store/index.ts | 9 +- src/pages/file/edit/List.tsx | 2 +- src/pages/org/edit/List.tsx | 4 +- src/pages/org/edit/UserList.tsx | 6 +- src/pages/pay/index.tsx | 91 +++++++++ src/pages/pay/modules/create-qrcode.ts | 27 +++ src/pages/pay/store/pay.ts | 46 +++++ src/pages/user/edit/List.tsx | 6 +- submodules/query-config | 2 +- vite.config.ts | 29 ++- 34 files changed, 504 insertions(+), 88 deletions(-) create mode 100644 src/pages/pay/index.tsx create mode 100644 src/pages/pay/modules/create-qrcode.ts create mode 100644 src/pages/pay/store/pay.ts diff --git a/package.json b/package.json index 1d33256..de1979d 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "@ant-design/icons": "^6.0.0", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", - "@kevisual/center-components": "workspace:*", "@kevisual/codemirror": "workspace:*", + "@kevisual/components": "workspace:*", "@kevisual/container": "1.0.0", "@kevisual/query": "^0.0.14", "@kevisual/query-config": "workspace:*", @@ -43,6 +43,7 @@ "lodash-es": "^4.17.21", "marked": "^15.0.7", "nanoid": "^5.1.5", + "qrcode": "^1.5.4", "react": "19.0.0", "react-dom": "19.0.0", "react-hook-form": "^7.54.2", @@ -60,6 +61,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^22.13.11", "@types/path-browserify": "^1.0.3", + "@types/qrcode": "^1.5.5", "@types/react": "^19.0.12", "@types/react-dom": "^19.0.4", "@vitejs/plugin-basic-ssl": "^2.0.0", diff --git a/packages/codemirror/package.json b/packages/codemirror/package.json index cd1e298..bcb4d5f 100644 --- a/packages/codemirror/package.json +++ b/packages/codemirror/package.json @@ -30,7 +30,7 @@ "@codemirror/view": "^6.36.4", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", - "@kevisual/center-components": "workspace:*", + "@kevisual/components": "workspace:*", "@kevisual/router": "^0.0.9", "@kevisual/store": "^0.0.2", "@mui/material": "^6.4.8", diff --git a/packages/codemirror/src/global.css b/packages/codemirror/src/global.css index 5920072..d8a2f70 100644 --- a/packages/codemirror/src/global.css +++ b/packages/codemirror/src/global.css @@ -1,3 +1,3 @@ @import 'tailwindcss'; -@import '@kevisual/center-components/theme/wind-theme.css'; +@import '@kevisual/components/theme/wind-theme.css'; @import './style.css'; diff --git a/packages/codemirror/src/pages/App.tsx b/packages/codemirror/src/pages/App.tsx index f3c823d..f4e9275 100644 --- a/packages/codemirror/src/pages/App.tsx +++ b/packages/codemirror/src/pages/App.tsx @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { CustomThemeProvider } from '@kevisual/center-components/theme/index.tsx'; +import { CustomThemeProvider } from '@kevisual/components/theme/index.tsx'; import { ToastContainer } from 'react-toastify'; import { FileEditor } from './file-editor/FileEditor'; diff --git a/packages/components/package.json b/packages/components/package.json index e97eef8..bdf66ed 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,5 +1,5 @@ { - "name": "@kevisual/center-components", + "name": "@kevisual/components", "version": "0.0.1", "description": "center components", "scripts": { diff --git a/packages/components/src/theme/wind-theme.css b/packages/components/src/theme/wind-theme.css index c15e3cd..859b3d1 100644 --- a/packages/components/src/theme/wind-theme.css +++ b/packages/components/src/theme/wind-theme.css @@ -4,6 +4,9 @@ --color-primary: #ffc107; --color-secondary: #ffa000; --color-success: #28a745; + --color-scrollbar-thumb: #999999; + --color-scrollbar-track: rgba(0, 0, 0, 0.1); + --color-scrollbar-thumb-hover: #666666; --scrollbar-color: #ffc107; /* 滚动条颜色 */ } @@ -45,7 +48,9 @@ body { width: 3px; height: 3px; } - + &::-webkit-scrollbar-track { + background-color: var(--color-scrollbar-track); + } /* 滚动条有滑块的轨道部分 */ &::-webkit-scrollbar-track-piece { background-color: transparent; @@ -55,13 +60,13 @@ body { /* 滚动条滑块(竖向:vertical 横向:horizontal) */ &::-webkit-scrollbar-thumb { cursor: pointer; - background-color: #c1c1c1; + background-color: var(--color-scrollbar-thumb); border-radius: 5px; } /* 滚动条滑块hover */ &::-webkit-scrollbar-thumb:hover { - background-color: #999999; + background-color: var(--color-scrollbar-thumb-hover); } /* 同时有垂直和水平滚动条时交汇的部分 */ diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 421486f..c63af6e 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -22,7 +22,7 @@ "node_modules/@kevisual/types", ], "paths": { - "@kevisual/center-components/*": [ + "@kevisual/components/*": [ "src/*" ] }, diff --git a/packages/resources/package.json b/packages/resources/package.json index b9e6919..1cd7675 100644 --- a/packages/resources/package.json +++ b/packages/resources/package.json @@ -19,7 +19,7 @@ "dependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", - "@kevisual/center-components": "workspace:*", + "@kevisual/components": "workspace:*", "@kevisual/router": "^0.0.9", "@kevisual/store": "^0.0.2", "@mui/material": "^6.4.8", diff --git a/packages/resources/src/global.css b/packages/resources/src/global.css index cf92229..5c2a690 100644 --- a/packages/resources/src/global.css +++ b/packages/resources/src/global.css @@ -1,4 +1,4 @@ @import 'tailwindcss'; -@import '@kevisual/center-components/theme/wind-theme.css'; +@import '@kevisual/components/theme/wind-theme.css'; @import './style.css'; diff --git a/packages/resources/src/pages/App.tsx b/packages/resources/src/pages/App.tsx index 5a5f306..0f55091 100644 --- a/packages/resources/src/pages/App.tsx +++ b/packages/resources/src/pages/App.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo } from 'react'; -import { CustomThemeProvider } from '@kevisual/center-components/theme/index.tsx'; +import { CustomThemeProvider } from '@kevisual/components/theme/index.tsx'; import { Left } from './layout/Left'; import { Main } from './main/index'; import { ToastContainer } from 'react-toastify'; diff --git a/packages/resources/src/pages/file/draw/modules/MetaForm.tsx b/packages/resources/src/pages/file/draw/modules/MetaForm.tsx index a43e226..a01e16d 100644 --- a/packages/resources/src/pages/file/draw/modules/MetaForm.tsx +++ b/packages/resources/src/pages/file/draw/modules/MetaForm.tsx @@ -1,6 +1,6 @@ import { useResourceFileStore } from '@kevisual/resources/pages/store/resource-file'; import { FormControlLabel, Box, ButtonGroup, Tooltip, Typography } from '@mui/material'; -import { IconButton } from '@kevisual/center-components/button/index.tsx'; +import { IconButton } from '@kevisual/components/button/index.tsx'; import { Info, Plus, Save, Share, Shuffle, Trash } from 'lucide-react'; import { useState, useEffect } from 'react'; import { toast } from 'react-toastify'; @@ -10,7 +10,7 @@ import { DatePicker } from './DatePicker'; import { DialogKey } from './DialogKey'; import { keysTips, KeyParse } from '../../modules/key-parse'; import { KeyShareSelect, KeyTextField } from '../../modules/PermissionManager'; -import { TagsInput } from '@kevisual/center-components/select/TagsInput.tsx'; +import { TagsInput } from '@kevisual/components/select/TagsInput.tsx'; export const setShareKeysOperate = (value: 'public' | 'protected' | 'private') => { const keys = ['password', 'usernames', 'expiration-time']; const deleteKeys = keys.map((item) => { diff --git a/packages/resources/src/pages/file/index.tsx b/packages/resources/src/pages/file/index.tsx index e3401c3..d82e64e 100644 --- a/packages/resources/src/pages/file/index.tsx +++ b/packages/resources/src/pages/file/index.tsx @@ -8,7 +8,7 @@ import { PrefixRedirect } from './modules/PrefixRedirect'; import { UploadButton } from '../upload'; import { FileDrawer } from './draw/FileDrawer'; import { useResourceFileStore } from '../store/resource-file'; -import { IconButtonItem } from '@kevisual/center-components/button/index.tsx'; +import { IconButtonItem } from '@kevisual/components/button/index.tsx'; export const FileApp = () => { const { getList, prefix, setListType, listType } = useResourceStore(); const { getStatFile, prefix: statPrefix, openDrawer } = useResourceFileStore(); diff --git a/packages/resources/src/pages/file/list/FileTable.tsx b/packages/resources/src/pages/file/list/FileTable.tsx index 456bfd4..364536d 100644 --- a/packages/resources/src/pages/file/list/FileTable.tsx +++ b/packages/resources/src/pages/file/list/FileTable.tsx @@ -6,7 +6,7 @@ import { getIcon } from '../FileIcon'; import { Download, Trash } from 'lucide-react'; import clsx from 'clsx'; import { useResourceFileStore } from '@kevisual/resources/pages/store/resource-file'; -import { useModal } from '@kevisual/center-components/modal/Confirm.tsx'; +import { useModal } from '@kevisual/components/modal/Confirm.tsx'; export const FileTable = () => { const { list, prefix, download, onOpenPrefix, getList } = useResourceStore(); diff --git a/packages/resources/src/pages/file/modules/PermissionManager.tsx b/packages/resources/src/pages/file/modules/PermissionManager.tsx index 1711502..feae375 100644 --- a/packages/resources/src/pages/file/modules/PermissionManager.tsx +++ b/packages/resources/src/pages/file/modules/PermissionManager.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import { KeyParse, getTips } from './key-parse'; import { FormControlLabel, TextField, Select, MenuItem, Tooltip } from '@mui/material'; import { DatePicker } from '../draw/modules/DatePicker'; -import { TagsInput } from '@kevisual/center-components/select/TagsInput.tsx'; +import { TagsInput } from '@kevisual/components/select/TagsInput.tsx'; import { HelpCircle } from 'lucide-react'; import clsx from 'clsx'; import { useTranslation } from 'react-i18next'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 834598f..4845875 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,12 +17,12 @@ importers: '@emotion/styled': specifier: ^11.14.0 version: 11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0) - '@kevisual/center-components': - specifier: workspace:* - version: link:packages/components '@kevisual/codemirror': specifier: workspace:* version: link:packages/codemirror + '@kevisual/components': + specifier: workspace:* + version: link:packages/components '@kevisual/container': specifier: 1.0.0 version: 1.0.0(@emotion/css@11.13.4)(@types/react@19.0.12)(crypto-js@4.2.0)(eventemitter3@5.0.1)(immer@10.1.1)(react@19.0.0)(rollup@4.36.0)(typescript@5.8.2) @@ -86,6 +86,9 @@ importers: nanoid: specifier: ^5.1.5 version: 5.1.5 + qrcode: + specifier: ^1.5.4 + version: 1.5.4 react: specifier: 19.0.0 version: 19.0.0 @@ -132,6 +135,9 @@ importers: '@types/path-browserify': specifier: ^1.0.3 version: 1.0.3 + '@types/qrcode': + specifier: ^1.5.5 + version: 1.5.5 '@types/react': specifier: ^19.0.12 version: 19.0.12 @@ -240,7 +246,7 @@ importers: '@emotion/styled': specifier: ^11.14.0 version: 11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0) - '@kevisual/center-components': + '@kevisual/components': specifier: workspace:* version: link:../components '@kevisual/router': @@ -362,7 +368,7 @@ importers: '@emotion/styled': specifier: ^11.14.0 version: 11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0) - '@kevisual/center-components': + '@kevisual/components': specifier: workspace:* version: link:../components '@kevisual/router': @@ -452,8 +458,8 @@ importers: specifier: ^0.0.1 version: 0.0.1(rollup@4.36.0)(tslib@2.8.1)(typescript@5.8.2) '@kevisual/query': - specifier: ^0.0.14 - version: 0.0.14(ws@8.18.1) + specifier: ^0.0.15 + version: 0.0.15(ws@8.18.1) dotenv: specifier: ^16.4.7 version: 16.4.7 @@ -978,6 +984,9 @@ packages: '@kevisual/query@0.0.14': resolution: {integrity: sha512-/bcyaR9sf9buAUoUHuW/8ZLgTcs8MANympoz2xkusFsxsy/rDQGeKdNl66LWhTZ687oBbI9KUcVhKajQS5NUog==} + '@kevisual/query@0.0.15': + resolution: {integrity: sha512-DK41qvyOiJMmlj70QyVP/48M0gszA39DdnBLtgU94YwAe6OqKrr9tYXHLjZrOROmUVMezIIBQuWMLedSAvb54A==} + '@kevisual/router@0.0.7': resolution: {integrity: sha512-4n1Tp4YLoraJv7jtfy7jbuLGyAj0B2QkTlnlEDHCUTlEUOvOkjtf7DHAe2SL92fTgXhSbod0I/0vUcDF85oj/w==} @@ -1561,6 +1570,9 @@ packages: '@types/prop-types@15.7.14': resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} + '@types/qrcode@1.5.5': + resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==} + '@types/react-dom@19.0.4': resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==} peerDependencies: @@ -1777,6 +1789,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + caniuse-lite@1.0.30001706: resolution: {integrity: sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==} @@ -1806,6 +1822,9 @@ packages: classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -1909,6 +1928,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decode-named-character-reference@1.1.0: resolution: {integrity: sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==} @@ -1934,6 +1957,9 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} @@ -2109,6 +2135,10 @@ packages: find-root@1.1.0: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -2150,6 +2180,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -2453,6 +2487,10 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -2622,14 +2660,26 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -2695,6 +2745,10 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + postcss-import@16.1.0: resolution: {integrity: sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==} engines: {node: '>=18.0.0'} @@ -2752,6 +2806,11 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -3099,6 +3158,13 @@ packages: rehype@13.0.2: resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} @@ -3162,6 +3228,9 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-cookie-parser@2.7.1: resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} @@ -3535,6 +3604,9 @@ packages: whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -3544,6 +3616,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -3580,6 +3656,9 @@ packages: resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} engines: {node: '>=0.4.0'} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -3592,6 +3671,14 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -4250,6 +4337,14 @@ snapshots: - ws - zod + '@kevisual/query@0.0.15(ws@8.18.1)': + dependencies: + openai: 4.89.0(ws@8.18.1) + transitivePeerDependencies: + - encoding + - ws + - zod + '@kevisual/router@0.0.7': dependencies: path-to-regexp: 8.2.0 @@ -4826,6 +4921,10 @@ snapshots: '@types/prop-types@15.7.14': {} + '@types/qrcode@1.5.5': + dependencies: + '@types/node': 22.13.11 + '@types/react-dom@19.0.4(@types/react@19.0.12)': dependencies: '@types/react': 19.0.12 @@ -5123,6 +5222,8 @@ snapshots: callsites@3.1.0: {} + camelcase@5.3.1: {} + caniuse-lite@1.0.30001706: {} ccount@2.0.1: {} @@ -5146,6 +5247,12 @@ snapshots: classnames@2.5.1: {} + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + clsx@2.1.1: {} codemirror@6.0.1: @@ -5234,6 +5341,8 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decode-named-character-reference@1.1.0: dependencies: character-entities: 2.0.2 @@ -5252,6 +5361,8 @@ snapshots: dependencies: dequal: 2.0.3 + dijkstrajs@1.0.3: {} + dom-helpers@5.2.1: dependencies: '@babel/runtime': 7.26.10 @@ -5466,6 +5577,11 @@ snapshots: find-root@1.1.0: {} + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -5506,6 +5622,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -5801,6 +5919,10 @@ snapshots: load-tsconfig@0.2.5: {} + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -5950,14 +6072,24 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} parent-module@1.0.1: @@ -6014,6 +6146,8 @@ snapshots: pirates@4.0.6: {} + pngjs@5.0.0: {} + postcss-import@16.1.0(postcss@8.5.3): dependencies: postcss: 8.5.3 @@ -6055,6 +6189,12 @@ snapshots: punycode@2.3.1: {} + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + queue-microtask@1.2.3: {} randombytes@2.1.0: @@ -6503,6 +6643,10 @@ snapshots: rehype-stringify: 10.0.1 unified: 11.0.5 + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + resize-observer-polyfill@1.5.1: {} resolve-from@4.0.0: {} @@ -6579,6 +6723,8 @@ snapshots: dependencies: randombytes: 2.1.0 + set-blocking@2.0.0: {} + set-cookie-parser@2.7.1: {} shebang-command@2.0.0: @@ -6932,12 +7078,20 @@ snapshots: tr46: 1.0.1 webidl-conversions: 4.0.2 + which-module@2.0.1: {} + which@2.0.2: dependencies: isexe: 2.0.0 word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -6956,6 +7110,8 @@ snapshots: xmlhttprequest-ssl@2.1.2: {} + y18n@4.0.3: {} + yallist@3.1.1: {} yaml@1.10.2: {} @@ -6963,6 +7119,25 @@ snapshots: yaml@2.5.1: optional: true + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yocto-queue@0.1.0: {} zustand@4.5.6(@types/react@19.0.12)(immer@10.1.1)(react@19.0.0): diff --git a/src/App.tsx b/src/App.tsx index 741b8ed..d5c89da 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,9 +6,10 @@ import { App as UserAppApp } from './pages/app'; import { App as FileApp } from './pages/file'; import { App as OrgApp } from './pages/org'; import { App as ConfigApp } from './pages/config'; +import { App as PayApp } from './pages/pay'; import { basename } from './modules/basename'; import { Redirect } from './modules/Redirect'; -import { CustomThemeProvider } from '@kevisual/center-components/theme/index.tsx'; +import { CustomThemeProvider } from '@kevisual/components/theme/index.tsx'; import { useTheme } from '@mui/material/styles'; import { ToastContainer } from 'react-toastify'; import 'dayjs/locale/zh-cn'; @@ -78,7 +79,7 @@ export const App = () => { } /> } /> } /> - + } /> 404} /> 404} /> diff --git a/src/globals.css b/src/globals.css index 2eb8f33..6179474 100644 --- a/src/globals.css +++ b/src/globals.css @@ -1,7 +1,7 @@ @import 'tailwindcss'; @import './assets/styles.css'; @import './index.css'; -@import '@kevisual/center-components/theme/wind-theme.css'; +@import '@kevisual/components/theme/wind-theme.css'; h1 { @apply text-2xl font-bold; @@ -60,6 +60,9 @@ h3 { .cm-editor { @apply h-full; } +.cm-scroller { + @apply scrollbar; +} #for-message { z-index: 9999 !important; } \ No newline at end of file diff --git a/src/modules/layout/index.tsx b/src/modules/layout/index.tsx index 129b7eb..266b215 100644 --- a/src/modules/layout/index.tsx +++ b/src/modules/layout/index.tsx @@ -12,7 +12,7 @@ import clsx from 'clsx'; import { Button, Menu, MenuItem } from '@mui/material'; import i18n from 'i18next'; -import { IconButton } from '@kevisual/center-components/button/index.tsx'; +import { IconButton } from '@kevisual/components/button/index.tsx'; import { Languages } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; diff --git a/src/modules/message.ts b/src/modules/message.ts index 38edff4..419977c 100644 --- a/src/modules/message.ts +++ b/src/modules/message.ts @@ -1,20 +1,20 @@ -import { toast } from 'react-toastify'; +import { toast, ToastOptions } from 'react-toastify'; export const message = { - success: (message: string) => { - toast.success(message); + success: (message: string, opts?: ToastOptions) => { + toast.success(message, opts); }, - error: (message: string) => { - toast.error(message); + error: (message: string, opts?: ToastOptions) => { + toast.error(message, opts); }, - warning: (message: string) => { - toast.warning(message); + warning: (message: string, opts?: ToastOptions) => { + toast.warning(message, opts); }, - info: (message: string) => { - toast.info(message); + info: (message: string, opts?: ToastOptions) => { + toast.info(message, opts); }, - loading: (message: string) => { - const toastId = toast.loading(message); + loading: (message: string, opts?: ToastOptions) => { + const toastId = toast.loading(message, opts); return () => { toast.dismiss(toastId); }; diff --git a/src/pages/app/edit/AppVersionList.tsx b/src/pages/app/edit/AppVersionList.tsx index fa444e6..3613aae 100644 --- a/src/pages/app/edit/AppVersionList.tsx +++ b/src/pages/app/edit/AppVersionList.tsx @@ -8,7 +8,7 @@ import FileOutlined from '@ant-design/icons/FileOutlined'; import LeftOutlined from '@ant-design/icons/LeftOutlined'; import LinkOutlined from '@ant-design/icons/LinkOutlined'; import PlusOutlined from '@ant-design/icons/PlusOutlined'; -import { useModal } from '@kevisual/center-components/modal/Confirm.tsx'; +import { useModal } from '@kevisual/components/modal/Confirm.tsx'; import { Tooltip } from '@mui/material'; import { isObjectNull } from '@/utils/is-null'; import { FileUpload } from '../modules/FileUpload'; @@ -18,7 +18,7 @@ import { useNewNavigate } from '@/modules'; import { Button } from '@mui/material'; import { Dialog, DialogContent, DialogTitle, ButtonGroup } from '@mui/material'; import { useTranslation } from 'react-i18next'; -import { IconButton } from '@kevisual/center-components/button/index.tsx'; +import { IconButton } from '@kevisual/components/button/index.tsx'; import { useForm, Controller } from 'react-hook-form'; import { TextField } from '@mui/material'; import { pick } from 'lodash-es'; diff --git a/src/pages/app/edit/List.tsx b/src/pages/app/edit/List.tsx index 058a6cc..784c8e6 100644 --- a/src/pages/app/edit/List.tsx +++ b/src/pages/app/edit/List.tsx @@ -1,7 +1,7 @@ import { useShallow } from 'zustand/react/shallow'; import { useUserAppStore } from '../store'; import { useEffect, useState } from 'react'; -import { useModal } from '@kevisual/center-components/modal/Confirm.tsx'; +import { useModal } from '@kevisual/components/modal/Confirm.tsx'; import DeleteOutlined from '@ant-design/icons/DeleteOutlined'; import EditOutlined from '@ant-design/icons/EditOutlined'; @@ -10,14 +10,14 @@ import PlusOutlined from '@ant-design/icons/PlusOutlined'; import UnorderedListOutlined from '@ant-design/icons/UnorderedListOutlined'; import CodeOutlined from '@ant-design/icons/CodeOutlined'; import ShareAltOutlined from '@ant-design/icons/ShareAltOutlined'; -import { FormControlLabel, Switch } from '@mui/material'; +import { FormControlLabel, Switch, useTheme } from '@mui/material'; import { isObjectNull } from '@/utils/is-null'; import { useNewNavigate } from '@/modules'; import { DialogActions, Tooltip } from '@mui/material'; import { marked } from 'marked'; import clsx from 'clsx'; -import { IconButton } from '@kevisual/center-components/button/index.tsx'; -import { Select } from '@kevisual/center-components/select/index.tsx'; +import { IconButton } from '@kevisual/components/button/index.tsx'; +import { Select } from '@kevisual/components/select/index.tsx'; import { iText } from '@kevisual/resources/index.ts'; import { PermissionManager } from '@kevisual/resources/pages/file/modules/PermissionManager.tsx'; import { Button } from '@mui/material'; @@ -72,6 +72,8 @@ const FormModal = () => { reset(); }; const isEdit = containerStore?.userApp?.id; + const theme = useTheme(); + const defaultProps = theme.components?.MuiTextField?.defaultProps as any; return ( { {isEdit ? 'Edit' : 'Add'}
- } /> + } /> } + render={({ field }) => } /> - } /> - } /> - } /> + } /> + } + /> + } /> ( setIsAgreed(e.target.checked)} className='w-3 h-3 accent-pink-500' /> + + + + + + ); +}; diff --git a/src/pages/pay/modules/create-qrcode.ts b/src/pages/pay/modules/create-qrcode.ts new file mode 100644 index 0000000..6b82a25 --- /dev/null +++ b/src/pages/pay/modules/create-qrcode.ts @@ -0,0 +1,27 @@ +import QRCode from 'qrcode'; + +export const createQrcode = (url: string, element: HTMLImageElement) => { + if (!url) return; + console.log('pay url', url); + QRCode.toDataURL( + url, + { + errorCorrectionLevel: 'H', + type: 'image/jpeg', + margin: 1, + + width: 300, + color: { + dark: '#000000', + light: '#ffffff', + }, + }, + function (err, url) { + if (err) { + console.log('err', err); + throw err; + } + element.src = url; + }, + ); +}; diff --git a/src/pages/pay/store/pay.ts b/src/pages/pay/store/pay.ts new file mode 100644 index 0000000..e2a3428 --- /dev/null +++ b/src/pages/pay/store/pay.ts @@ -0,0 +1,46 @@ +import { create } from 'zustand'; +import { query, queryLogin } from '@/modules/query'; +import { toast } from 'react-toastify'; +interface PayState { + getPayUrl: (data: { money: number; subject: string }) => Promise; + codeUrl: string; + setCodeUrl: (url: string) => void; + user: any; + money: number; + subject: string; + setMoney: (money: number) => void; + setSubject: (subject: string) => void; + init: () => Promise; +} + +export const usePayStore = create((set) => ({ + money: 12800, + setMoney: (money) => set({ money }), + subject: 'kevisual 会员', + setSubject: (subject) => set({ subject }), + getPayUrl: async (data) => { + const res = await query.post({ + path: 'alipay', + key: 'pay', + data, + }); + if (res.code === 200) { + if (res.data?.form) { + set({ codeUrl: res.data?.form }); + } + } else { + toast.error(res.message); + } + return res; + }, + codeUrl: '', + setCodeUrl: (url) => set({ codeUrl: url }), + user: null, + init: async () => { + const res = await queryLogin.cacheStore.getCurrentUser(); + console.log(res); + if (res) { + set({ user: res }); + } + }, +})); diff --git a/src/pages/user/edit/List.tsx b/src/pages/user/edit/List.tsx index fca3cab..563ecf3 100644 --- a/src/pages/user/edit/List.tsx +++ b/src/pages/user/edit/List.tsx @@ -8,11 +8,11 @@ import LeftOutlined from '@ant-design/icons/LeftOutlined'; import PlusOutlined from '@ant-design/icons/PlusOutlined'; import clsx from 'clsx'; import { isObjectNull } from '@/utils/is-null'; -import { CardBlank } from '@kevisual/center-components/card/CardBlank.tsx'; +import { CardBlank } from '@kevisual/components/card/CardBlank.tsx'; import { Dialog, ButtonGroup, Button, DialogContent, DialogTitle } from '@mui/material'; -import { IconButton } from '@kevisual/center-components/button/index.tsx'; +import { IconButton } from '@kevisual/components/button/index.tsx'; import { useTranslation } from 'react-i18next'; -import { useModal } from '@kevisual/center-components/modal/Confirm.tsx'; +import { useModal } from '@kevisual/components/modal/Confirm.tsx'; import { TextField } from '@mui/material'; import { useForm, Controller } from 'react-hook-form'; import { pick } from 'lodash-es'; diff --git a/submodules/query-config b/submodules/query-config index 93cd7cf..2068892 160000 --- a/submodules/query-config +++ b/submodules/query-config @@ -1 +1 @@ -Subproject commit 93cd7cf979b4a695bb582fb5eb490a10f51746c8 +Subproject commit 20688920b8be1e25de032fc9e20499ca03a470f7 diff --git a/vite.config.ts b/vite.config.ts index 955018a..6d95953 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -21,10 +21,11 @@ if (!isDev) { plugins.push(tailwindcss()); const devBackend = 'https://kevisual.silkyai.cn'; -const meBackend = 'https://kevisual.xiongxiao.me'; +// const meBackend = 'https://kevisual.xiongxiao.me'; +const meBackend = 'https://kevisual.cn'; // const backend = isDev ? devBackend : meBackend; const backendWss = devBackend.replace(/^https:/, 'wss:'); -const backend = devBackend; +const backend = meBackend; let proxy = {}; if (true) { proxy = { @@ -46,6 +47,15 @@ if (true) { }, }; } + +function processImageName(fileName: string): string { + if (fileName.includes('panda')) { + return fileName; // 保留原名 + } + // 其他图片文件名处理逻辑 + return `${fileName}.jpg`; // 示例:添加后缀 +} + // https://vitejs.dev/config/ export default defineConfig({ plugins: [react(), ...plugins], @@ -62,6 +72,21 @@ export default defineConfig({ DEV_SERVER: JSON.stringify(process.env.NODE_ENV === 'development'), }, base: isDev ? '/' : '/root/center/', + build: { + rollupOptions: { + output: { + // 控制输出 + // 在rollup里面, hash代表将你的文件名和文件内容进行组合计算得来的结果 + assetFileNames: (chunkInfo) => { + console.log(chunkInfo.names); + if (chunkInfo.names?.includes('panda.png')) { + return '[name].[ext]'; + } + return '[name].[hash].[ext]'; + }, + }, + }, + }, server: { port: 6020, host: '0.0.0.0',