mirror of
https://github.com/chaitin/MonkeyCode.git
synced 2026-02-01 22:33:30 +08:00
feat: 切换 ui
This commit is contained in:
@@ -44,7 +44,7 @@
|
||||
### UI框架与样式
|
||||
- **Material-UI (@mui)** - Google Material Design组件库
|
||||
- **Emotion** - CSS-in-JS样式库
|
||||
- **@c-x/ui** - 自定义组件库
|
||||
- **@ctzhian/ui** - 自定义组件库
|
||||
|
||||
### 状态管理与数据
|
||||
- **ahooks** - React Hooks工具库
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<%
|
||||
const { apiConfig, generateResponses, config } = it;
|
||||
%>
|
||||
import { message as Message } from '@c-x/ui'
|
||||
import { message as Message } from '@ctzhian/ui'
|
||||
import type { AxiosInstance, AxiosRequestConfig, HeadersDefaults, ResponseType, AxiosResponse } from "axios";
|
||||
import axios from "axios";
|
||||
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@c-x/ui": "^1.0.9",
|
||||
"@ctzhian/ui": "^7",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@hookform/resolvers": "^5.2.1",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@mui/icons-material": "^6.4.12",
|
||||
"@mui/lab": "6.0.0-beta.19",
|
||||
"@mui/material": "^6.4.12",
|
||||
"@mui/icons-material": "^7",
|
||||
"@mui/material": "^7",
|
||||
"@yokowu/modelkit-ui": "2.0.6",
|
||||
"@tailwindcss/vite": "^4.1.12",
|
||||
"ahooks": "^3.8.4",
|
||||
|
||||
243
ui/pnpm-lock.yaml
generated
243
ui/pnpm-lock.yaml
generated
@@ -8,9 +8,9 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@c-x/ui':
|
||||
specifier: ^1.0.9
|
||||
version: 1.0.9(87983aa74373e7bdff176d7db35e2938)
|
||||
'@ctzhian/ui':
|
||||
specifier: ^7
|
||||
version: 7.0.5(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/icons-material@7.3.2(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@emotion/react':
|
||||
specifier: ^11.14.0
|
||||
version: 11.14.0(@types/react@19.1.10)(react@19.1.1)
|
||||
@@ -24,20 +24,17 @@ importers:
|
||||
specifier: 4.7.0
|
||||
version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/icons-material':
|
||||
specifier: ^6.4.12
|
||||
version: 6.5.0(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/lab':
|
||||
specifier: 6.0.0-beta.19
|
||||
version: 6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
specifier: ^7
|
||||
version: 7.3.2(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/material':
|
||||
specifier: ^6.4.12
|
||||
version: 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
specifier: ^7
|
||||
version: 7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@tailwindcss/vite':
|
||||
specifier: ^4.1.12
|
||||
version: 4.1.12(vite@6.3.5(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1))
|
||||
'@yokowu/modelkit-ui':
|
||||
specifier: 2.0.6
|
||||
version: 2.0.6(@mui/lab@6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/utils@7.3.1(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(i18next@25.5.2(typescript@5.8.3))(typescript@5.8.3)
|
||||
version: 2.0.6(@mui/lab@6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(i18next@25.5.2(typescript@5.8.3))(typescript@5.8.3)
|
||||
ahooks:
|
||||
specifier: ^3.8.4
|
||||
version: 3.9.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
@@ -308,6 +305,17 @@ packages:
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
|
||||
'@ctzhian/ui@7.0.5':
|
||||
resolution: {integrity: sha512-BPeEePM9K4U9vV43qFGT/zOkRMfH6GlgBjeECUIZpAyv9D1kLNn7mPC1ldCdYxIYhMqyv1dz3jb5rkkNHt+OTg==}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11
|
||||
'@emotion/styled': ^11
|
||||
'@mui/icons-material': ^7
|
||||
'@mui/material': ^7
|
||||
'@mui/utils': ^7
|
||||
react: '>=16.9.0'
|
||||
react-dom: '>=16.9.0'
|
||||
|
||||
'@emotion/babel-plugin@11.13.5':
|
||||
resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==}
|
||||
|
||||
@@ -674,16 +682,8 @@ packages:
|
||||
'@mui/core-downloads-tracker@6.5.0':
|
||||
resolution: {integrity: sha512-LGb8t8i6M2ZtS3Drn3GbTI1DVhDY6FJ9crEey2lZ0aN2EMZo8IZBZj9wRf4vqbZHaWjsYgtbOnJw5V8UWbmK2Q==}
|
||||
|
||||
'@mui/icons-material@6.5.0':
|
||||
resolution: {integrity: sha512-VPuPqXqbBPlcVSA0BmnoE4knW4/xG6Thazo8vCLWkOKusko6DtwFV6B665MMWJ9j0KFohTIf3yx2zYtYacvG1g==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@mui/material': ^6.5.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@mui/core-downloads-tracker@7.3.2':
|
||||
resolution: {integrity: sha512-AOyfHjyDKVPGJJFtxOlept3EYEdLoar/RvssBTWVAvDJGIE676dLi2oT/Kx+FoVXFoA/JdV7DEMq/BVWV3KHRw==}
|
||||
|
||||
'@mui/icons-material@7.3.2':
|
||||
resolution: {integrity: sha512-TZWazBjWXBjR6iGcNkbKklnwodcwj0SrChCNHc9BhD9rBgET22J1eFhHsEmvSvru9+opDy3umqAimQjokhfJlQ==}
|
||||
@@ -737,6 +737,26 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/material@7.3.2':
|
||||
resolution: {integrity: sha512-qXvbnawQhqUVfH1LMgMaiytP+ZpGoYhnGl7yYq2x57GYzcFL/iPzSZ3L30tlbwEjSVKNYcbiKO8tANR1tadjUg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.5.0
|
||||
'@emotion/styled': ^11.3.0
|
||||
'@mui/material-pigment-css': ^7.3.2
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/react':
|
||||
optional: true
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
'@mui/material-pigment-css':
|
||||
optional: true
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/private-theming@6.4.9':
|
||||
resolution: {integrity: sha512-LktcVmI5X17/Q5SkwjCcdOLBzt1hXuc14jYa7NPShog0GBDCDvKtcnP0V7a2s6EiVRlv7BzbWEJzH6+l/zaCxw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -747,6 +767,16 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/private-theming@7.3.2':
|
||||
resolution: {integrity: sha512-ha7mFoOyZGJr75xeiO9lugS3joRROjc8tG1u4P50dH0KR7bwhHznVMcYg7MouochUy0OxooJm/OOSpJ7gKcMvg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/styled-engine@6.5.0':
|
||||
resolution: {integrity: sha512-8woC2zAqF4qUDSPIBZ8v3sakj+WgweolpyM/FXf8jAx6FMls+IE4Y8VDZc+zS805J7PRz31vz73n2SovKGaYgw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -760,6 +790,19 @@ packages:
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
|
||||
'@mui/styled-engine@7.3.2':
|
||||
resolution: {integrity: sha512-PkJzW+mTaek4e0nPYZ6qLnW5RGa0KN+eRTf5FA2nc7cFZTeM+qebmGibaTLrgQBy3UpcpemaqfzToBNkzuxqew==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.4.1
|
||||
'@emotion/styled': ^11.3.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/react':
|
||||
optional: true
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
|
||||
'@mui/system@6.5.0':
|
||||
resolution: {integrity: sha512-XcbBYxDS+h/lgsoGe78ExXFZXtuIlSBpn/KsZq8PtZcIkUNJInkuDqcLd2rVBQrDC1u+rvVovdaWPf2FHKJf3w==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -776,6 +819,22 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/system@7.3.2':
|
||||
resolution: {integrity: sha512-9d8JEvZW+H6cVkaZ+FK56R53vkJe3HsTpcjMUtH8v1xK6Y1TjzHdZ7Jck02mGXJsE6MQGWVs3ogRHTQmS9Q/rA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@emotion/react': ^11.5.0
|
||||
'@emotion/styled': ^11.3.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
'@emotion/react':
|
||||
optional: true
|
||||
'@emotion/styled':
|
||||
optional: true
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/types@7.2.24':
|
||||
resolution: {integrity: sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==}
|
||||
peerDependencies:
|
||||
@@ -784,8 +843,8 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/types@7.4.5':
|
||||
resolution: {integrity: sha512-ZPwlAOE3e8C0piCKbaabwrqZbW4QvWz0uapVPWya7fYj6PeDkl5sSJmomT7wjOcZGPB48G/a6Ubidqreptxz4g==}
|
||||
'@mui/types@7.4.6':
|
||||
resolution: {integrity: sha512-NVBbIw+4CDMMppNamVxyTccNv0WxtDb7motWDlMeSC8Oy95saj1TIZMGynPpFLePt3yOD8TskzumeqORCgRGWw==}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
@@ -802,8 +861,8 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@mui/utils@7.3.1':
|
||||
resolution: {integrity: sha512-/31y4wZqVWa0jzMnzo6JPjxwP6xXy4P3+iLbosFg/mJQowL1KIou0LC+lquWW60FKVbKz5ZUWBg2H3jausa0pw==}
|
||||
'@mui/utils@7.3.2':
|
||||
resolution: {integrity: sha512-4DMWQGenOdLnM3y/SdFQFwKsCLM+mqxzvoWp9+x2XdEzXapkznauHLiXtSohHs/mc0+5/9UACt1GdugCX2te5g==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
@@ -3260,26 +3319,23 @@ snapshots:
|
||||
- magicast
|
||||
- typescript
|
||||
|
||||
'@c-x/ui@1.0.9(87983aa74373e7bdff176d7db35e2938)':
|
||||
'@c-x/ui@1.0.9(2095097f83dff6549ba477ae9943cd74)':
|
||||
dependencies:
|
||||
'@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/icons-material': 6.5.0(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/lab': 6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/icons-material': 7.3.2(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/lab': 6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/material': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/utils': 7.3.1(@types/react@19.1.10)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
react-virtuoso: 4.14.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
|
||||
'@c-x/ui@1.0.9(9e5bbf95f65f6bba045b6e0e314ece93)':
|
||||
'@ctzhian/ui@7.0.5(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/icons-material@7.3.2(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/icons-material': 7.3.2(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/lab': 6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/material': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/utils': 7.3.1(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/icons-material': 7.3.2(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/material': 7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
react-virtuoso: 4.14.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
@@ -3611,9 +3667,9 @@ snapshots:
|
||||
|
||||
'@mui/base@5.0.0-beta.66(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
'@floating-ui/react-dom': 2.1.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/types': 7.4.5(@types/react@19.1.10)
|
||||
'@mui/types': 7.4.6(@types/react@19.1.10)
|
||||
'@mui/utils': 6.4.9(@types/react@19.1.10)(react@19.1.1)
|
||||
'@popperjs/core': 2.11.8
|
||||
clsx: 2.1.1
|
||||
@@ -3625,13 +3681,7 @@ snapshots:
|
||||
|
||||
'@mui/core-downloads-tracker@6.5.0': {}
|
||||
|
||||
'@mui/icons-material@6.5.0(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@mui/material': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
'@mui/core-downloads-tracker@7.3.2': {}
|
||||
|
||||
'@mui/icons-material@7.3.2(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
@@ -3641,13 +3691,21 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/lab@6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
'@mui/icons-material@7.3.2(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/material': 7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/lab@6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/base': 5.0.0-beta.66(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/material': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/material': 7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@mui/system': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/types': 7.4.5(@types/react@19.1.10)
|
||||
'@mui/types': 7.4.6(@types/react@19.1.10)
|
||||
'@mui/utils': 6.4.9(@types/react@19.1.10)(react@19.1.1)
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
@@ -3660,7 +3718,7 @@ snapshots:
|
||||
|
||||
'@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/core-downloads-tracker': 6.5.0
|
||||
'@mui/system': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/types': 7.2.24(@types/react@19.1.10)
|
||||
@@ -3679,18 +3737,61 @@ snapshots:
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/core-downloads-tracker': 7.3.2
|
||||
'@mui/system': 7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/types': 7.4.6(@types/react@19.1.10)
|
||||
'@mui/utils': 7.3.2(@types/react@19.1.10)(react@19.1.1)
|
||||
'@popperjs/core': 2.11.8
|
||||
'@types/react-transition-group': 4.4.12(@types/react@19.1.10)
|
||||
clsx: 2.1.1
|
||||
csstype: 3.1.3
|
||||
prop-types: 15.8.1
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
react-is: 19.1.1
|
||||
react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/private-theming@6.4.9(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/utils': 6.4.9(@types/react@19.1.10)(react@19.1.1)
|
||||
prop-types: 15.8.1
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/private-theming@7.3.2(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/utils': 7.3.2(@types/react@19.1.10)(react@19.1.1)
|
||||
prop-types: 15.8.1
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/styled-engine@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
'@emotion/cache': 11.14.0
|
||||
'@emotion/serialize': 1.3.3
|
||||
'@emotion/sheet': 1.4.0
|
||||
csstype: 3.1.3
|
||||
prop-types: 15.8.1
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
|
||||
'@mui/styled-engine@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.4
|
||||
'@emotion/cache': 11.14.0
|
||||
'@emotion/serialize': 1.3.3
|
||||
'@emotion/sheet': 1.4.0
|
||||
@@ -3703,7 +3804,7 @@ snapshots:
|
||||
|
||||
'@mui/system@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/private-theming': 6.4.9(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/styled-engine': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(react@19.1.1)
|
||||
'@mui/types': 7.2.24(@types/react@19.1.10)
|
||||
@@ -3717,19 +3818,35 @@ snapshots:
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/system@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/private-theming': 7.3.2(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/styled-engine': 7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(react@19.1.1)
|
||||
'@mui/types': 7.4.6(@types/react@19.1.10)
|
||||
'@mui/utils': 7.3.2(@types/react@19.1.10)(react@19.1.1)
|
||||
clsx: 2.1.1
|
||||
csstype: 3.1.3
|
||||
prop-types: 15.8.1
|
||||
react: 19.1.1
|
||||
optionalDependencies:
|
||||
'@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/types@7.2.24(@types/react@19.1.10)':
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/types@7.4.5(@types/react@19.1.10)':
|
||||
'@mui/types@7.4.6(@types/react@19.1.10)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/utils@6.4.9(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/types': 7.2.24(@types/react@19.1.10)
|
||||
'@types/prop-types': 15.7.15
|
||||
clsx: 2.1.1
|
||||
@@ -3739,10 +3856,10 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.10
|
||||
|
||||
'@mui/utils@7.3.1(@types/react@19.1.10)(react@19.1.1)':
|
||||
'@mui/utils@7.3.2(@types/react@19.1.10)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@mui/types': 7.4.5(@types/react@19.1.10)
|
||||
'@babel/runtime': 7.28.4
|
||||
'@mui/types': 7.4.6(@types/react@19.1.10)
|
||||
'@types/prop-types': 15.7.15
|
||||
clsx: 2.1.1
|
||||
prop-types: 15.8.1
|
||||
@@ -4212,9 +4329,9 @@ snapshots:
|
||||
|
||||
'@vue/shared@3.5.18': {}
|
||||
|
||||
'@yokowu/modelkit-ui@2.0.6(@mui/lab@6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/utils@7.3.1(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(i18next@25.5.2(typescript@5.8.3))(typescript@5.8.3)':
|
||||
'@yokowu/modelkit-ui@2.0.6(@mui/lab@6.0.0-beta.19(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@mui/material@7.3.2(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(i18next@25.5.2(typescript@5.8.3))(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@c-x/ui': 1.0.9(9e5bbf95f65f6bba045b6e0e314ece93)
|
||||
'@c-x/ui': 1.0.9(2095097f83dff6549ba477ae9943cd74)
|
||||
'@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
|
||||
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
'@mui/icons-material': 7.3.2(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
|
||||
@@ -4525,7 +4642,7 @@ snapshots:
|
||||
|
||||
dom-helpers@5.2.1:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
csstype: 3.1.3
|
||||
|
||||
dotenv@17.2.1: {}
|
||||
@@ -4956,7 +5073,7 @@ snapshots:
|
||||
|
||||
i18next@25.5.2(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
optionalDependencies:
|
||||
typescript: 5.8.3
|
||||
|
||||
@@ -5788,7 +5905,7 @@ snapshots:
|
||||
|
||||
react-i18next@15.7.3(i18next@25.5.2(typescript@5.8.3))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
html-parse-stringify: 3.0.1
|
||||
i18next: 25.5.2(typescript@5.8.3)
|
||||
react: 19.1.1
|
||||
@@ -5846,7 +5963,7 @@ snapshots:
|
||||
|
||||
react-transition-group@4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.2
|
||||
'@babel/runtime': 7.28.4
|
||||
dom-helpers: 5.2.1
|
||||
loose-envify: 1.4.0
|
||||
prop-types: 15.8.1
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
* ---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import { message as Message } from "@c-x/ui";
|
||||
import { message as Message } from '@ctzhian/ui';
|
||||
import type {
|
||||
AxiosInstance,
|
||||
AxiosRequestConfig,
|
||||
HeadersDefaults,
|
||||
ResponseType,
|
||||
} from "axios";
|
||||
import axios from "axios";
|
||||
} from 'axios';
|
||||
import axios from 'axios';
|
||||
|
||||
export type QueryParamsType = Record<string | number, any>;
|
||||
|
||||
export interface FullRequestParams
|
||||
extends Omit<AxiosRequestConfig, "data" | "params" | "url" | "responseType"> {
|
||||
extends Omit<AxiosRequestConfig, 'data' | 'params' | 'url' | 'responseType'> {
|
||||
/** set parameter to `true` for call `securityWorker` for this request */
|
||||
secure?: boolean;
|
||||
/** request path */
|
||||
@@ -39,34 +39,34 @@ export interface FullRequestParams
|
||||
|
||||
export type RequestParams = Omit<
|
||||
FullRequestParams,
|
||||
"body" | "method" | "query" | "path"
|
||||
'body' | 'method' | 'query' | 'path'
|
||||
>;
|
||||
|
||||
export interface ApiConfig<SecurityDataType = unknown>
|
||||
extends Omit<AxiosRequestConfig, "data" | "cancelToken"> {
|
||||
extends Omit<AxiosRequestConfig, 'data' | 'cancelToken'> {
|
||||
securityWorker?: (
|
||||
securityData: SecurityDataType | null,
|
||||
securityData: SecurityDataType | null
|
||||
) => Promise<AxiosRequestConfig | void> | AxiosRequestConfig | void;
|
||||
secure?: boolean;
|
||||
format?: ResponseType;
|
||||
}
|
||||
|
||||
export enum ContentType {
|
||||
Json = "application/json",
|
||||
FormData = "multipart/form-data",
|
||||
UrlEncoded = "application/x-www-form-urlencoded",
|
||||
Text = "text/plain",
|
||||
Json = 'application/json',
|
||||
FormData = 'multipart/form-data',
|
||||
UrlEncoded = 'application/x-www-form-urlencoded',
|
||||
Text = 'text/plain',
|
||||
}
|
||||
|
||||
const whitePathnameList = ["/user/login", "/login", "/auth", "/invite"];
|
||||
const whiteApiList = ["/api/v1/user/profile", "/api/v1/admin/profile"];
|
||||
const whitePathnameList = ['/user/login', '/login', '/auth', '/invite'];
|
||||
const whiteApiList = ['/api/v1/user/profile', '/api/v1/admin/profile'];
|
||||
|
||||
const redirectToLogin = () => {
|
||||
const redirectAfterLogin = encodeURIComponent(location.href);
|
||||
const search = `redirect=${redirectAfterLogin}`;
|
||||
const pathname = location.pathname.startsWith("/user")
|
||||
? "/login"
|
||||
: "/login/admin";
|
||||
const pathname = location.pathname.startsWith('/user')
|
||||
? '/login'
|
||||
: '/login/admin';
|
||||
window.location.href = `${pathname}`;
|
||||
};
|
||||
|
||||
@@ -75,7 +75,7 @@ type ExtractDataProp<T> = T extends { data?: infer U } ? U : never;
|
||||
export class HttpClient<SecurityDataType = unknown> {
|
||||
public instance: AxiosInstance;
|
||||
private securityData: SecurityDataType | null = null;
|
||||
private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
|
||||
private securityWorker?: ApiConfig<SecurityDataType>['securityWorker'];
|
||||
private secure?: boolean;
|
||||
private format?: ResponseType;
|
||||
|
||||
@@ -88,7 +88,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
this.instance = axios.create({
|
||||
withCredentials: true,
|
||||
...axiosConfig,
|
||||
baseURL: axiosConfig.baseURL || "",
|
||||
baseURL: axiosConfig.baseURL || '',
|
||||
});
|
||||
this.secure = secure;
|
||||
this.format = format;
|
||||
@@ -107,20 +107,20 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
if (
|
||||
whitePathnameList.find((item) => location.pathname.startsWith(item))
|
||||
) {
|
||||
return Promise.reject("尚未登录");
|
||||
return Promise.reject('尚未登录');
|
||||
}
|
||||
Message.error("尚未登录");
|
||||
Message.error('尚未登录');
|
||||
redirectToLogin();
|
||||
return Promise.reject("尚未登录");
|
||||
return Promise.reject('尚未登录');
|
||||
}
|
||||
// 手动取消请求
|
||||
if (err.code === "ERR_CANCELED") {
|
||||
if (err.code === 'ERR_CANCELED') {
|
||||
return;
|
||||
}
|
||||
const msg = err?.response?.data?.message || err?.message;
|
||||
Message.error(msg);
|
||||
return Promise.reject(msg);
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
|
||||
protected mergeRequestParams(
|
||||
params1: AxiosRequestConfig,
|
||||
params2?: AxiosRequestConfig,
|
||||
params2?: AxiosRequestConfig
|
||||
): AxiosRequestConfig {
|
||||
const method = params1.method || (params2 && params2.method);
|
||||
|
||||
@@ -151,7 +151,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
}
|
||||
|
||||
protected stringifyFormItem(formItem: unknown) {
|
||||
if (typeof formItem === "object" && formItem !== null) {
|
||||
if (typeof formItem === 'object' && formItem !== null) {
|
||||
return JSON.stringify(formItem);
|
||||
} else {
|
||||
return `${formItem}`;
|
||||
@@ -168,7 +168,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
const isFileType = formItem instanceof Blob || formItem instanceof File;
|
||||
formData.append(
|
||||
key,
|
||||
isFileType ? formItem : this.stringifyFormItem(formItem),
|
||||
isFileType ? formItem : this.stringifyFormItem(formItem)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
...params
|
||||
}: FullRequestParams): Promise<ExtractDataProp<T>> => {
|
||||
const secureParams =
|
||||
((typeof secure === "boolean" ? secure : this.secure) &&
|
||||
((typeof secure === 'boolean' ? secure : this.secure) &&
|
||||
this.securityWorker &&
|
||||
(await this.securityWorker(this.securityData))) ||
|
||||
{};
|
||||
@@ -197,7 +197,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
type === ContentType.FormData &&
|
||||
body &&
|
||||
body !== null &&
|
||||
typeof body === "object"
|
||||
typeof body === 'object'
|
||||
) {
|
||||
body = this.createFormData(body as Record<string, unknown>);
|
||||
}
|
||||
@@ -206,7 +206,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
type === ContentType.Text &&
|
||||
body &&
|
||||
body !== null &&
|
||||
typeof body !== "string"
|
||||
typeof body !== 'string'
|
||||
) {
|
||||
body = JSON.stringify(body);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
headers: {
|
||||
...(requestParams.headers || {}),
|
||||
...(type && type !== ContentType.FormData
|
||||
? { "Content-Type": type }
|
||||
? { 'Content-Type': type }
|
||||
: {}),
|
||||
},
|
||||
params: query,
|
||||
@@ -226,4 +226,4 @@ export class HttpClient<SecurityDataType = unknown> {
|
||||
});
|
||||
};
|
||||
}
|
||||
export default new HttpClient({ format: "json" }).request;
|
||||
export default new HttpClient({ format: 'json' }).request;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { styled } from '@mui/material';
|
||||
|
||||
const StyledCard = styled('div')(({ theme }) => ({
|
||||
padding: theme.spacing(2),
|
||||
borderRadius: theme.shape.borderRadius * 2.5,
|
||||
borderRadius: (theme.shape.borderRadius as number) * 2.5,
|
||||
backgroundColor: theme.palette.background.default,
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
import Card from '@/components/card';
|
||||
import { Ellipsis, Modal } from '@c-x/ui';
|
||||
import { Ellipsis, Modal } from '@ctzhian/ui';
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { DomainSecurityScanningResult, DomainSecurityScanningRiskDetail } from '@/api/types';
|
||||
import { getSecurityScanningDetail, getUserSecurityScanningDetail } from '@/api';
|
||||
import { Box, CircularProgress, Grid2 as Grid, List, ListItem, ListItemButton, Stack, ToggleButton, ToggleButtonGroup } from '@mui/material';
|
||||
import {
|
||||
DomainSecurityScanningResult,
|
||||
DomainSecurityScanningRiskDetail,
|
||||
} from '@/api/types';
|
||||
import {
|
||||
getSecurityScanningDetail,
|
||||
getUserSecurityScanningDetail,
|
||||
} from '@/api';
|
||||
import {
|
||||
Box,
|
||||
CircularProgress,
|
||||
Grid,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
Stack,
|
||||
ToggleButton,
|
||||
ToggleButtonGroup,
|
||||
} from '@mui/material';
|
||||
import ListAltIcon from '@mui/icons-material/ListAlt';
|
||||
import ViewSidebarOutlinedIcon from '@mui/icons-material/ViewSidebarOutlined';
|
||||
import MonacoEditor from '@monaco-editor/react';
|
||||
@@ -36,16 +52,18 @@ const RiskLevelBox = ({ level }: RiskLevelBoxProps) => {
|
||||
if (!config) return null;
|
||||
|
||||
return (
|
||||
<Box sx={{
|
||||
backgroundColor: config.color,
|
||||
color: '#fff',
|
||||
borderRadius: '4px',
|
||||
textAlign: 'center',
|
||||
width: '80px',
|
||||
minWidth: '80px',
|
||||
fontSize: '12px',
|
||||
lineHeight: '20px'
|
||||
}}>
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: config.color,
|
||||
color: '#fff',
|
||||
borderRadius: '4px',
|
||||
textAlign: 'center',
|
||||
width: '80px',
|
||||
minWidth: '80px',
|
||||
fontSize: '12px',
|
||||
lineHeight: '20px',
|
||||
}}
|
||||
>
|
||||
{config.text}
|
||||
</Box>
|
||||
);
|
||||
@@ -111,17 +129,21 @@ const TaskDetail = ({
|
||||
task?: DomainSecurityScanningResult;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
admin: boolean
|
||||
admin: boolean;
|
||||
}) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [vulns, setVulns] = useState<DomainSecurityScanningRiskDetail[]>([]);
|
||||
const [vulDetail, setVulDetail] = useState<DomainSecurityScanningRiskDetail | undefined>(undefined);
|
||||
const [vulDetail, setVulDetail] = useState<
|
||||
DomainSecurityScanningRiskDetail | undefined
|
||||
>(undefined);
|
||||
const [viewMode, setViewMode] = useState<'list' | 'detail'>('detail');
|
||||
|
||||
const fetchData = async () => {
|
||||
setLoading(true);
|
||||
const resp = await (admin ? getSecurityScanningDetail : getUserSecurityScanningDetail)({
|
||||
id: task?.id as string
|
||||
const resp = await (admin
|
||||
? getSecurityScanningDetail
|
||||
: getUserSecurityScanningDetail)({
|
||||
id: task?.id as string,
|
||||
});
|
||||
setVulns(resp);
|
||||
setLoading(false);
|
||||
@@ -131,10 +153,10 @@ const TaskDetail = ({
|
||||
setVulns([]);
|
||||
setVulDetail(undefined);
|
||||
setViewMode('detail');
|
||||
console.log(!!vulDetail)
|
||||
console.log(!!vulDetail);
|
||||
if (open) {
|
||||
fetchData();
|
||||
};
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [task, open]);
|
||||
|
||||
@@ -149,86 +171,103 @@ const TaskDetail = ({
|
||||
}, [vulDetail]);
|
||||
|
||||
// 高亮显示漏洞代码
|
||||
const highlightVulnerability = (editor: Monaco.editor.IStandaloneCodeEditor, vulDetail: DomainSecurityScanningRiskDetail | undefined) => {
|
||||
const highlightVulnerability = (
|
||||
editor: Monaco.editor.IStandaloneCodeEditor,
|
||||
vulDetail: DomainSecurityScanningRiskDetail | undefined
|
||||
) => {
|
||||
// 清除之前的装饰器
|
||||
editor.deltaDecorations(editor.getModel()?.getAllDecorations().map(d => d.id) || [], []);
|
||||
|
||||
editor.deltaDecorations(
|
||||
editor
|
||||
.getModel()
|
||||
?.getAllDecorations()
|
||||
.map((d) => d.id) || [],
|
||||
[]
|
||||
);
|
||||
|
||||
// 如果有 start 和 end 位置信息,则设置选区
|
||||
if (vulDetail?.start && vulDetail?.end) {
|
||||
const startLine = vulDetail.start.line ?? 1;
|
||||
const startColumn = vulDetail.start.col ?? 1;
|
||||
const endLine = vulDetail.end.line ?? startLine;
|
||||
const endColumn = vulDetail.end.col ?? startColumn;
|
||||
|
||||
|
||||
// 设置选区
|
||||
const selection = {
|
||||
startLineNumber: startLine,
|
||||
startColumn: startColumn,
|
||||
endLineNumber: endLine,
|
||||
endColumn: endColumn
|
||||
endColumn: endColumn,
|
||||
};
|
||||
|
||||
|
||||
editor.setSelection(selection);
|
||||
|
||||
|
||||
// 添加装饰器以增强高亮效果
|
||||
editor.deltaDecorations([], [
|
||||
{
|
||||
range: selection,
|
||||
options: {
|
||||
isWholeLine: false,
|
||||
className: 'highlighted-code',
|
||||
inlineClassName: 'highlighted-code-inline',
|
||||
overviewRuler: {
|
||||
color: 'rgba(255, 255, 0, 0.5)',
|
||||
position: 1 // Monaco.Editor.OverviewRulerLane.Center
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
editor.deltaDecorations(
|
||||
[],
|
||||
[
|
||||
{
|
||||
range: selection,
|
||||
options: {
|
||||
isWholeLine: false,
|
||||
className: 'highlighted-code',
|
||||
inlineClassName: 'highlighted-code-inline',
|
||||
overviewRuler: {
|
||||
color: 'rgba(255, 255, 0, 0.5)',
|
||||
position: 1, // Monaco.Editor.OverviewRulerLane.Center
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// 滚动到选区
|
||||
editor.revealLineInCenter(startLine);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditorDidMount = (editor: Monaco.editor.IStandaloneCodeEditor) => {
|
||||
const handleEditorDidMount = (
|
||||
editor: Monaco.editor.IStandaloneCodeEditor
|
||||
) => {
|
||||
// 保存编辑器实例
|
||||
editorRef.current = editor;
|
||||
|
||||
|
||||
// 初始高亮
|
||||
highlightVulnerability(editor, vulDetail);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal title={
|
||||
<Stack direction={'row'} >
|
||||
{vulDetail && <ToggleButtonGroup
|
||||
exclusive
|
||||
value={viewMode}
|
||||
size="small"
|
||||
onChange={(e, value) => {
|
||||
setViewMode(value)
|
||||
}}
|
||||
>
|
||||
<ToggleButton value="list">
|
||||
<ListAltIcon />
|
||||
</ToggleButton>
|
||||
<ToggleButton value="detail" disabled={!vulDetail}>
|
||||
<ViewSidebarOutlinedIcon sx={{ transform: 'rotate(180deg)' }} />
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>}
|
||||
<Ellipsis
|
||||
sx={{
|
||||
fontWeight: 'bold',
|
||||
fontSize: 20,
|
||||
lineHeight: '40px',
|
||||
width: 700,
|
||||
ml: '20px'
|
||||
}}
|
||||
>
|
||||
{task?.name} / {task?.project_name}
|
||||
</Ellipsis>
|
||||
</Stack>
|
||||
<Modal
|
||||
title={
|
||||
<Stack direction={'row'}>
|
||||
{vulDetail && (
|
||||
<ToggleButtonGroup
|
||||
exclusive
|
||||
value={viewMode}
|
||||
size='small'
|
||||
onChange={(e, value) => {
|
||||
setViewMode(value);
|
||||
}}
|
||||
>
|
||||
<ToggleButton value='list'>
|
||||
<ListAltIcon />
|
||||
</ToggleButton>
|
||||
<ToggleButton value='detail' disabled={!vulDetail}>
|
||||
<ViewSidebarOutlinedIcon sx={{ transform: 'rotate(180deg)' }} />
|
||||
</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
)}
|
||||
<Ellipsis
|
||||
sx={{
|
||||
fontWeight: 'bold',
|
||||
fontSize: 20,
|
||||
lineHeight: '40px',
|
||||
width: 700,
|
||||
ml: '20px',
|
||||
}}
|
||||
>
|
||||
{task?.name} / {task?.project_name}
|
||||
</Ellipsis>
|
||||
</Stack>
|
||||
}
|
||||
width={1200}
|
||||
open={open}
|
||||
@@ -237,23 +276,34 @@ const TaskDetail = ({
|
||||
>
|
||||
<Card sx={{ p: 0, background: 'transparent', boxShadow: 'none' }}>
|
||||
<Grid container sx={{ height: '70vh' }}>
|
||||
<Grid size={viewMode === 'detail' && !!vulDetail ? 5 : 12} sx={{
|
||||
height: '100%',
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
<Grid
|
||||
size={viewMode === 'detail' && !!vulDetail ? 5 : 12}
|
||||
sx={{
|
||||
height: '100%',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<List>
|
||||
{loading ? (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', padding: '20px' }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
padding: '20px',
|
||||
}}
|
||||
>
|
||||
<CircularProgress />
|
||||
</div>
|
||||
) : (
|
||||
vulns.map((vuln) => (
|
||||
<ListItem key={vuln.id}
|
||||
<ListItem
|
||||
key={vuln.id}
|
||||
sx={{
|
||||
padding: 0,
|
||||
width: '100%'
|
||||
}}>
|
||||
<ListItemButton
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<ListItemButton
|
||||
selected={vulDetail?.id === vuln.id}
|
||||
onClick={() => {
|
||||
setVulDetail(vuln);
|
||||
@@ -263,54 +313,90 @@ const TaskDetail = ({
|
||||
borderBottomStyle: 'solid',
|
||||
borderBottomColor: 'background.paper',
|
||||
fontSize: '14px',
|
||||
width: '100%'
|
||||
}}>
|
||||
<Stack direction={"column"} sx={{
|
||||
width: '100%'
|
||||
}}>
|
||||
<Stack direction={"row"}>
|
||||
<RiskLevelBox level={vuln.level as 'severe' | 'critical' | 'suggest'} />
|
||||
<Box sx={{
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
direction={'column'}
|
||||
sx={{
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Stack direction={'row'}>
|
||||
<RiskLevelBox
|
||||
level={
|
||||
vuln.level as 'severe' | 'critical' | 'suggest'
|
||||
}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: '14px',
|
||||
ml: '20px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
lineHeight: '20px',
|
||||
}}
|
||||
>
|
||||
{vuln.desc}
|
||||
</Box>
|
||||
</Stack>
|
||||
<Box
|
||||
sx={{
|
||||
color: 'text.tertiary',
|
||||
fontSize: '14px',
|
||||
ml: '20px',
|
||||
mt: '6px',
|
||||
width: '100%',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
lineHeight: '20px'
|
||||
}}>{vuln.desc}</Box>
|
||||
</Stack>
|
||||
<Box sx={{
|
||||
color: 'text.tertiary',
|
||||
fontSize: '14px',
|
||||
mt: '6px',
|
||||
width: '100%',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{vuln.filename}:{vuln?.start?.line}
|
||||
</Box>
|
||||
|
||||
{!!vulDetail && vulDetail?.id === vuln.id && <Box sx={{
|
||||
fontSize: '12px',
|
||||
mt: '6px',
|
||||
}}>关键代码位于第 {vulDetail?.start?.line} 行{vulDetail?.start?.line !== vulDetail?.end?.line && `至第 ${vulDetail?.end?.line} 行`}</Box>}
|
||||
{!!vulDetail && vulDetail?.id === vuln.id && <Box sx={{
|
||||
fontSize: '12px',
|
||||
mt: '6px',
|
||||
}}>
|
||||
<pre style={{
|
||||
backgroundColor: '#fff',
|
||||
padding: '10px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #ccc',
|
||||
overflow: 'hidden',
|
||||
}}>{vulDetail?.lines}</pre>
|
||||
</Box>}
|
||||
{!!vulDetail && vulDetail?.id === vuln.id && <Box sx={{
|
||||
fontSize: '12px',
|
||||
mt: '6px',
|
||||
}}>修改建议:{vulDetail?.fix}</Box>}
|
||||
|
||||
{!!vulDetail && vulDetail?.id === vuln.id && (
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: '12px',
|
||||
mt: '6px',
|
||||
}}
|
||||
>
|
||||
关键代码位于第 {vulDetail?.start?.line} 行
|
||||
{vulDetail?.start?.line !== vulDetail?.end?.line &&
|
||||
`至第 ${vulDetail?.end?.line} 行`}
|
||||
</Box>
|
||||
)}
|
||||
{!!vulDetail && vulDetail?.id === vuln.id && (
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: '12px',
|
||||
mt: '6px',
|
||||
}}
|
||||
>
|
||||
<pre
|
||||
style={{
|
||||
backgroundColor: '#fff',
|
||||
padding: '10px',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #ccc',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{vulDetail?.lines}
|
||||
</pre>
|
||||
</Box>
|
||||
)}
|
||||
{!!vulDetail && vulDetail?.id === vuln.id && (
|
||||
<Box
|
||||
sx={{
|
||||
fontSize: '12px',
|
||||
mt: '6px',
|
||||
}}
|
||||
>
|
||||
修改建议:{vulDetail?.fix}
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
@@ -318,30 +404,40 @@ const TaskDetail = ({
|
||||
)}
|
||||
</List>
|
||||
</Grid>
|
||||
{viewMode === 'detail' && !!vulDetail && <Grid size={7} sx={{
|
||||
height: '100%',
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
<Box sx={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}>
|
||||
<style> {`.monaco-editor.vs-dark .highlighted-code { background-color: rgba(255, 0, 0, 0.3) !important; }`} </style>
|
||||
<MonacoEditor
|
||||
height="100%"
|
||||
value={vulDetail?.content || ''}
|
||||
theme='vs-dark'
|
||||
language={getLanguageByFilename(vulDetail?.filename)}
|
||||
options={{
|
||||
readOnly: true,
|
||||
minimap: {
|
||||
enabled: false
|
||||
}
|
||||
{viewMode === 'detail' && !!vulDetail && (
|
||||
<Grid
|
||||
size={7}
|
||||
sx={{
|
||||
height: '100%',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
onMount={handleEditorDidMount}
|
||||
></MonacoEditor>
|
||||
</Box>
|
||||
</Grid>}
|
||||
>
|
||||
<style>
|
||||
{' '}
|
||||
{`.monaco-editor.vs-dark .highlighted-code { background-color: rgba(255, 0, 0, 0.3) !important; }`}{' '}
|
||||
</style>
|
||||
<MonacoEditor
|
||||
height='100%'
|
||||
value={vulDetail?.content || ''}
|
||||
theme='vs-dark'
|
||||
language={getLanguageByFilename(vulDetail?.filename)}
|
||||
options={{
|
||||
readOnly: true,
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
}}
|
||||
onMount={handleEditorDidMount}
|
||||
></MonacoEditor>
|
||||
</Box>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</Card>
|
||||
</Modal>
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Table } from '@c-x/ui';
|
||||
import { Table } from '@ctzhian/ui';
|
||||
import { getSecurityScanningList } from '@/api/SecurityScanning';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import Card from '@/components/card';
|
||||
import {
|
||||
Autocomplete,
|
||||
Box,
|
||||
Stack,
|
||||
TextField,
|
||||
Tooltip,
|
||||
} from '@mui/material';
|
||||
import { Autocomplete, Box, Stack, TextField, Tooltip } from '@mui/material';
|
||||
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { DomainSecurityScanningResult, DomainSecurityScanningRiskResult, DomainUser } from '@/api/types';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import {
|
||||
DomainSecurityScanningResult,
|
||||
DomainSecurityScanningRiskResult,
|
||||
DomainUser,
|
||||
} from '@/api/types';
|
||||
import User from '@/components/user';
|
||||
import TaskDetail from './taskDetail';
|
||||
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
|
||||
@@ -23,17 +21,21 @@ import { getUserSecurityScanningList } from '@/api';
|
||||
|
||||
const CodeScanTaskList = ({
|
||||
admin,
|
||||
users
|
||||
users,
|
||||
}: {
|
||||
admin: boolean,
|
||||
users: DomainUser[]
|
||||
admin: boolean;
|
||||
users: DomainUser[];
|
||||
}) => {
|
||||
const [page, setPage] = useState(1);
|
||||
const [size, setSize] = useState(20);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataSource, setDataSource] = useState<DomainSecurityScanningResult[]>([]);
|
||||
const [detail, setDetail] = useState<DomainSecurityScanningResult | undefined>();
|
||||
const [dataSource, setDataSource] = useState<DomainSecurityScanningResult[]>(
|
||||
[]
|
||||
);
|
||||
const [detail, setDetail] = useState<
|
||||
DomainSecurityScanningResult | undefined
|
||||
>();
|
||||
const [filterUser, setFilterUser] = useState('');
|
||||
|
||||
const fetchData = async (params: {
|
||||
@@ -43,7 +45,9 @@ const CodeScanTaskList = ({
|
||||
author?: string;
|
||||
}) => {
|
||||
setLoading(true);
|
||||
const res = await (admin ? getSecurityScanningList : getUserSecurityScanningList)({
|
||||
const res = await (admin
|
||||
? getSecurityScanningList
|
||||
: getUserSecurityScanningList)({
|
||||
page: params.page || page,
|
||||
size: params.size || size,
|
||||
author: params.author || filterUser,
|
||||
@@ -57,7 +61,7 @@ const CodeScanTaskList = ({
|
||||
setPage(1);
|
||||
fetchData({
|
||||
page: 1,
|
||||
author: filterUser
|
||||
author: filterUser,
|
||||
});
|
||||
}, [filterUser]);
|
||||
|
||||
@@ -69,71 +73,111 @@ const CodeScanTaskList = ({
|
||||
render: (project_name, record) => {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.name}
|
||||
</Box>
|
||||
<Box sx={{
|
||||
color: 'text.tertiary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
mt: '4px'
|
||||
}}>
|
||||
{(record.status === 'pending') && <Stack direction={'row'}>
|
||||
<AutoModeIcon sx={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
color: 'info.main'
|
||||
}} />
|
||||
<Box sx={{
|
||||
lineHeight: '16px',
|
||||
ml: '4px'
|
||||
}}>等待扫描</Box>
|
||||
</Stack>}
|
||||
{(record.status === 'running') && <Stack direction={'row'}>
|
||||
<AutoModeIcon sx={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
color: 'info.main',
|
||||
animation: 'spin 1s linear infinite',
|
||||
'@keyframes spin': {
|
||||
'0%': {
|
||||
transform: 'rotate(0deg)',
|
||||
},
|
||||
'100%': {
|
||||
transform: 'rotate(360deg)',
|
||||
},
|
||||
},
|
||||
}} />
|
||||
<Box sx={{
|
||||
lineHeight: '16px',
|
||||
ml: '4px'
|
||||
}}>正在扫描</Box>
|
||||
</Stack>}
|
||||
{(record.status === 'success') && <Stack direction={'row'}>
|
||||
<CheckCircleOutlineIcon sx={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
color: 'success.main'
|
||||
}} />
|
||||
<Box sx={{
|
||||
lineHeight: '16px',
|
||||
ml: '4px'
|
||||
}}>扫描完成</Box>
|
||||
</Stack>}
|
||||
{(record.status === 'failed') && <Tooltip title={record.error}>
|
||||
<Box
|
||||
sx={{
|
||||
color: 'text.tertiary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
mt: '4px',
|
||||
}}
|
||||
>
|
||||
{record.status === 'pending' && (
|
||||
<Stack direction={'row'}>
|
||||
<ErrorOutlineIcon sx={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
color: 'error.main'
|
||||
}} />
|
||||
<Box sx={{
|
||||
lineHeight: '16px',
|
||||
ml: '4px'
|
||||
}}>扫描失败</Box>
|
||||
<AutoModeIcon
|
||||
sx={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
color: 'info.main',
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
lineHeight: '16px',
|
||||
ml: '4px',
|
||||
}}
|
||||
>
|
||||
等待扫描
|
||||
</Box>
|
||||
</Stack>
|
||||
</Tooltip>}
|
||||
)}
|
||||
{record.status === 'running' && (
|
||||
<Stack direction={'row'}>
|
||||
<AutoModeIcon
|
||||
sx={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
color: 'info.main',
|
||||
animation: 'spin 1s linear infinite',
|
||||
'@keyframes spin': {
|
||||
'0%': {
|
||||
transform: 'rotate(0deg)',
|
||||
},
|
||||
'100%': {
|
||||
transform: 'rotate(360deg)',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
lineHeight: '16px',
|
||||
ml: '4px',
|
||||
}}
|
||||
>
|
||||
正在扫描
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
{record.status === 'success' && (
|
||||
<Stack direction={'row'}>
|
||||
<CheckCircleOutlineIcon
|
||||
sx={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
color: 'success.main',
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
lineHeight: '16px',
|
||||
ml: '4px',
|
||||
}}
|
||||
>
|
||||
扫描完成
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
{record.status === 'failed' && (
|
||||
<Tooltip title={record.error}>
|
||||
<Stack direction={'row'}>
|
||||
<ErrorOutlineIcon
|
||||
sx={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
color: 'error.main',
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
lineHeight: '16px',
|
||||
ml: '4px',
|
||||
}}
|
||||
>
|
||||
扫描失败
|
||||
</Box>
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
@@ -145,10 +189,23 @@ const CodeScanTaskList = ({
|
||||
render: (project_name, record) => {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.project_name}
|
||||
</Box>
|
||||
<Box sx={{ color: 'text.secondary', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.path}
|
||||
</Box>
|
||||
</Stack>
|
||||
@@ -160,28 +217,30 @@ const CodeScanTaskList = ({
|
||||
title: '扫描结果',
|
||||
width: 260,
|
||||
render(risk: DomainSecurityScanningRiskResult, record) {
|
||||
const hasNoRisk = record.status !== 'pending' &&
|
||||
const hasNoRisk =
|
||||
record.status !== 'pending' &&
|
||||
(!risk.severe_count || risk.severe_count <= 0) &&
|
||||
(!risk.critical_count || risk.critical_count <= 0) &&
|
||||
(!risk.suggest_count || risk.suggest_count <= 0);
|
||||
|
||||
const tip = []
|
||||
const tip = [];
|
||||
if (risk.severe_count && risk.severe_count > 0) {
|
||||
tip.push(`严重安全告警 ${risk.severe_count} 个`)
|
||||
}
|
||||
tip.push(`严重安全告警 ${risk.severe_count} 个`);
|
||||
}
|
||||
if (risk.critical_count && risk.critical_count > 0) {
|
||||
tip.push(`高风险安全提醒 ${risk.critical_count} 个`)
|
||||
tip.push(`高风险安全提醒 ${risk.critical_count} 个`);
|
||||
}
|
||||
if (risk.suggest_count && risk.suggest_count > 0) {
|
||||
tip.push(`低风险安全提醒 ${risk.suggest_count} 个`)
|
||||
tip.push(`低风险安全提醒 ${risk.suggest_count} 个`);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={ hasNoRisk ? '暂无风险' : tip.join(', ')}>
|
||||
<Stack direction='row'
|
||||
<Tooltip title={hasNoRisk ? '暂无风险' : tip.join(', ')}>
|
||||
<Stack
|
||||
direction='row'
|
||||
onClick={() => {
|
||||
if (!hasNoRisk) {
|
||||
setDetail(record)
|
||||
setDetail(record);
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
@@ -190,7 +249,10 @@ const CodeScanTaskList = ({
|
||||
width: '200px',
|
||||
height: '24px',
|
||||
lineHeight: '24px',
|
||||
background: (record.status === 'pending' || record.status === 'running') ? 'repeating-linear-gradient(45deg, #f0f0f0, #f0f0f0 10px, #e0e0e0 10px, #e0e0e0 20px)' : '#F1F2F8',
|
||||
background:
|
||||
record.status === 'pending' || record.status === 'running'
|
||||
? 'repeating-linear-gradient(45deg, #f0f0f0, #f0f0f0 10px, #e0e0e0 10px, #e0e0e0 20px)'
|
||||
: '#F1F2F8',
|
||||
backgroundSize: '30px 30px',
|
||||
animation: 'stripes 1s linear infinite',
|
||||
borderRadius: '4px',
|
||||
@@ -198,7 +260,7 @@ const CodeScanTaskList = ({
|
||||
transition: 'box-shadow 0.3s ease',
|
||||
userSelect: 'none',
|
||||
'&:hover': {
|
||||
cursor: "pointer",
|
||||
cursor: 'pointer',
|
||||
boxShadow: hasNoRisk ? '' : '0 0px 8px #FFCF62',
|
||||
},
|
||||
'@keyframes stripes': {
|
||||
@@ -209,45 +271,82 @@ const CodeScanTaskList = ({
|
||||
backgroundPosition: '30px 0',
|
||||
},
|
||||
},
|
||||
}}>
|
||||
{((record.status === 'success' || record.status === 'failed') && hasNoRisk) ? (
|
||||
}}
|
||||
>
|
||||
{(record.status === 'success' || record.status === 'failed') &&
|
||||
hasNoRisk ? (
|
||||
// 如果没有风险,显示"无风险"
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
color: 'disabled.main',
|
||||
}}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
color: 'disabled.main',
|
||||
}}
|
||||
>
|
||||
暂无风险
|
||||
</Box>
|
||||
) : (
|
||||
// 否则,显示原有的风险条
|
||||
<>
|
||||
{!!risk.severe_count && risk.severe_count > 0 && <Box sx={{
|
||||
backgroundColor: 'risk.severe',
|
||||
minWidth: '30px',
|
||||
width: (risk.severe_count || 0) * 100 / ((risk.critical_count || 0) + (risk.severe_count || 0) + (risk.suggest_count || 0)) + '%',
|
||||
textAlign: 'center'
|
||||
}}>{risk.severe_count}</Box>}
|
||||
{!!risk.critical_count && risk.critical_count > 0 && <Box sx={{
|
||||
backgroundColor: 'risk.critical',
|
||||
minWidth: '30px',
|
||||
width: (risk.critical_count || 0) * 100 / ((risk.critical_count || 0) + (risk.severe_count || 0) + (risk.suggest_count || 0)) + '%',
|
||||
textAlign: 'center'
|
||||
}}>{risk.critical_count}</Box>}
|
||||
{!!risk.suggest_count && risk.suggest_count > 0 && <Box sx={{
|
||||
backgroundColor: 'risk.suggest',
|
||||
minWidth: '30px',
|
||||
width: (risk.suggest_count || 0) * 100 / ((risk.critical_count || 0) + (risk.severe_count || 0) + (risk.suggest_count || 0)) + '%',
|
||||
textAlign: 'center'
|
||||
}}>{risk.suggest_count}</Box>}
|
||||
{!!risk.severe_count && risk.severe_count > 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: 'risk.severe',
|
||||
minWidth: '30px',
|
||||
width:
|
||||
((risk.severe_count || 0) * 100) /
|
||||
((risk.critical_count || 0) +
|
||||
(risk.severe_count || 0) +
|
||||
(risk.suggest_count || 0)) +
|
||||
'%',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{risk.severe_count}
|
||||
</Box>
|
||||
)}
|
||||
{!!risk.critical_count && risk.critical_count > 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: 'risk.critical',
|
||||
minWidth: '30px',
|
||||
width:
|
||||
((risk.critical_count || 0) * 100) /
|
||||
((risk.critical_count || 0) +
|
||||
(risk.severe_count || 0) +
|
||||
(risk.suggest_count || 0)) +
|
||||
'%',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{risk.critical_count}
|
||||
</Box>
|
||||
)}
|
||||
{!!risk.suggest_count && risk.suggest_count > 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: 'risk.suggest',
|
||||
minWidth: '30px',
|
||||
width:
|
||||
((risk.suggest_count || 0) * 100) /
|
||||
((risk.critical_count || 0) +
|
||||
(risk.severe_count || 0) +
|
||||
(risk.suggest_count || 0)) +
|
||||
'%',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{risk.suggest_count}
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Tooltip>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -273,39 +372,50 @@ const CodeScanTaskList = ({
|
||||
render: (text) => {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{dayjs.unix(text).format('YYYY-MM-DD')}
|
||||
</Box>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{dayjs.unix(text).format('HH:mm:ss')}
|
||||
</Box>
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Card sx={{ flex: 1, height: '100%' }}>
|
||||
{admin && <Stack direction='row' spacing={2} sx={{ mb: 2 }}>
|
||||
<Autocomplete
|
||||
size='small'
|
||||
sx={{ minWidth: 220 }}
|
||||
options={users || []}
|
||||
getOptionLabel={(option) => option.username || ''}
|
||||
value={
|
||||
users?.find((item) => item.username === filterUser) ||
|
||||
null
|
||||
}
|
||||
onChange={(_, newValue) =>
|
||||
setFilterUser(newValue ? newValue.username! : '')
|
||||
}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option.username === value.username
|
||||
}
|
||||
renderInput={(params) => <TextField {...params} label='成员' />}
|
||||
clearOnEscape
|
||||
/>
|
||||
</Stack>}
|
||||
{admin && (
|
||||
<Stack direction='row' spacing={2} sx={{ mb: 2 }}>
|
||||
<Autocomplete
|
||||
size='small'
|
||||
sx={{ minWidth: 220 }}
|
||||
options={users || []}
|
||||
getOptionLabel={(option) => option.username || ''}
|
||||
value={users?.find((item) => item.username === filterUser) || null}
|
||||
onChange={(_, newValue) =>
|
||||
setFilterUser(newValue ? newValue.username! : '')
|
||||
}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option.username === value.username
|
||||
}
|
||||
renderInput={(params) => <TextField {...params} label='成员' />}
|
||||
clearOnEscape
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
<Table
|
||||
height={admin ? 'calc(100% - 52px)' : '100%'}
|
||||
sx={{ mx: -2 }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button, IconButton, Stack, Tooltip } from '@mui/material';
|
||||
import { message } from '@c-x/ui';
|
||||
import { message } from '@ctzhian/ui';
|
||||
import { postLogout } from '@/api/User';
|
||||
import { postAdminLogout } from '@/api/Admin';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
|
||||
@@ -9,7 +9,9 @@ const StyledLabel = styled('div')<StyledLabelProps>(
|
||||
// 获取颜色值
|
||||
const getColor = (colorProp: string) => {
|
||||
// 如果是主题预设颜色
|
||||
if (['success', 'warning', 'error', 'info', 'disabled'].includes(colorProp)) {
|
||||
if (
|
||||
['success', 'warning', 'error', 'info', 'disabled'].includes(colorProp)
|
||||
) {
|
||||
return theme.palette[
|
||||
colorProp as 'success' | 'warning' | 'error' | 'info' | 'disabled'
|
||||
].main;
|
||||
@@ -26,10 +28,14 @@ const StyledLabel = styled('div')<StyledLabelProps>(
|
||||
|
||||
// 获取背景颜色(淡化版本)
|
||||
const getBackgroundColor = (colorProp: string) => {
|
||||
if (['success', 'warning', 'error', 'info', 'disabled'].includes(colorProp)) {
|
||||
if (
|
||||
['success', 'warning', 'error', 'info', 'disabled'].includes(colorProp)
|
||||
) {
|
||||
// 使用主题的 light 版本,如果没有则使用 alpha 透明度
|
||||
const palette =
|
||||
theme.palette[colorProp as 'success' | 'warning' | 'error' | 'info' | 'disabled'];
|
||||
theme.palette[
|
||||
colorProp as 'success' | 'warning' | 'error' | 'info' | 'disabled'
|
||||
];
|
||||
return alpha(palette.main, 0.15);
|
||||
}
|
||||
// 如果是 default,使用淡灰色背景
|
||||
@@ -42,7 +48,7 @@ const StyledLabel = styled('div')<StyledLabelProps>(
|
||||
|
||||
return {
|
||||
padding: theme.spacing(0.5, 1),
|
||||
borderRadius: theme.shape.borderRadius * 4,
|
||||
borderRadius: (theme.shape.borderRadius as number) * 4,
|
||||
color: textColor,
|
||||
backgroundColor: getBackgroundColor(color),
|
||||
border: `1px solid ${alpha(textColor, 0.3)}`,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { message } from '@c-x/ui';
|
||||
import { message } from '@ctzhian/ui';
|
||||
import { Box, useTheme } from '@mui/material';
|
||||
import React from 'react';
|
||||
import ReactMarkdown, { Components } from 'react-markdown';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { useState } from 'react';
|
||||
import { Modal } from '@c-x/ui';
|
||||
import { Modal } from '@ctzhian/ui';
|
||||
import HelpCenter from '@/assets/json/help-center.json';
|
||||
import Takeoff from '@/assets/json/takeoff.json';
|
||||
import IconUpgrade from '@/assets/json/upgrade.json';
|
||||
@@ -22,22 +22,21 @@ const AboutModal = ({
|
||||
onClose,
|
||||
curVersion,
|
||||
latestVersion,
|
||||
license
|
||||
license,
|
||||
}: LicenseModalProps) => {
|
||||
|
||||
const [openChangeLicense, setOpenChangeLicense] = useState(false);
|
||||
|
||||
const editionText = (edition: any) => {
|
||||
if (edition === 0) {
|
||||
return '开源版'
|
||||
return '开源版';
|
||||
} else if (edition === 1) {
|
||||
return '联创版'
|
||||
return '联创版';
|
||||
} else if (edition === 2) {
|
||||
return '企业版'
|
||||
return '企业版';
|
||||
} else {
|
||||
return '未知'
|
||||
return '未知';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -45,18 +44,31 @@ const AboutModal = ({
|
||||
width={600}
|
||||
open={open}
|
||||
onCancel={onClose}
|
||||
footer={null}>
|
||||
<Stack direction={'column'} gap={2} sx={{
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
footer={null}
|
||||
>
|
||||
<Stack
|
||||
direction={'column'}
|
||||
gap={2}
|
||||
sx={{
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
<Stack direction={'row'} gap={2} alignItems={'center'}>
|
||||
<Box sx={{
|
||||
width: '120px'
|
||||
}}>当前版本</Box>
|
||||
<Box sx={{
|
||||
width: '120px',
|
||||
fontWeight: 700
|
||||
}}>{curVersion}</Box>
|
||||
<Box
|
||||
sx={{
|
||||
width: '120px',
|
||||
}}
|
||||
>
|
||||
当前版本
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
width: '120px',
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{curVersion}
|
||||
</Box>
|
||||
|
||||
{latestVersion === `v${curVersion}` ? (
|
||||
<Box sx={{ color: 'text.auxiliary', fontSize: 12 }}>
|
||||
@@ -76,7 +88,7 @@ const AboutModal = ({
|
||||
}
|
||||
onClick={() => {
|
||||
window.open(
|
||||
'https://monkeycode.docs.baizhi.cloud/node/01980d22-db84-73b4-ae13-6a188e318048',
|
||||
'https://monkeycode.docs.baizhi.cloud/node/01980d22-db84-73b4-ae13-6a188e318048'
|
||||
);
|
||||
}}
|
||||
>
|
||||
@@ -86,9 +98,13 @@ const AboutModal = ({
|
||||
</Stack>
|
||||
|
||||
<Stack direction={'row'} gap={2} alignItems={'center'}>
|
||||
<Box sx={{
|
||||
width: '120px',
|
||||
}}>产品型号</Box>
|
||||
<Box
|
||||
sx={{
|
||||
width: '120px',
|
||||
}}
|
||||
>
|
||||
产品型号
|
||||
</Box>
|
||||
<Box>{editionText(license?.edition)}</Box>
|
||||
|
||||
<Button
|
||||
@@ -125,19 +141,30 @@ const AboutModal = ({
|
||||
商务咨询
|
||||
</Button>
|
||||
</Stack>
|
||||
{license && license?.edition !== 0 && <Stack direction={'row'} gap={2}>
|
||||
<Box sx={{
|
||||
width: '120px'
|
||||
}}>授权时间</Box>
|
||||
<Box sx={{
|
||||
}}>{dayjs.unix(license.started_at!).format('YYYY-MM-DD')} ~ {dayjs.unix(license.expired_at!).format('YYYY-MM-DD')}</Box>
|
||||
</Stack>}
|
||||
{license && license?.edition !== 0 && (
|
||||
<Stack direction={'row'} gap={2}>
|
||||
<Box
|
||||
sx={{
|
||||
width: '120px',
|
||||
}}
|
||||
>
|
||||
授权时间
|
||||
</Box>
|
||||
<Box sx={{}}>
|
||||
{dayjs.unix(license.started_at!).format('YYYY-MM-DD')} ~{' '}
|
||||
{dayjs.unix(license.expired_at!).format('YYYY-MM-DD')}
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
<ChangeLicense
|
||||
open={openChangeLicense}
|
||||
onClose={() => { setOpenChangeLicense(false) }} />
|
||||
onClose={() => {
|
||||
setOpenChangeLicense(false);
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default AboutModal;
|
||||
export default AboutModal;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { useState } from 'react';
|
||||
import { Ellipsis, message, Modal } from '@c-x/ui';
|
||||
import { Ellipsis, message, Modal } from '@ctzhian/ui';
|
||||
import { Box, Button, Link, Stack, TextField } from '@mui/material';
|
||||
import { DomainLicenseResp } from '@/api/types';
|
||||
import { v1LicenseCreate } from '@/api';
|
||||
@@ -10,73 +10,92 @@ interface LicenseModalProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const ChangeLicense = ({
|
||||
open,
|
||||
onClose
|
||||
}: LicenseModalProps) => {
|
||||
const ChangeLicense = ({ open, onClose }: LicenseModalProps) => {
|
||||
const [code, setCode] = useState('');
|
||||
const [verifing, setVerifing] = useState(false);
|
||||
|
||||
const updateLicense = () => {
|
||||
if (code.length === 0) {
|
||||
message.error("授权码不能为空");
|
||||
message.error('授权码不能为空');
|
||||
return;
|
||||
}
|
||||
setVerifing(true);
|
||||
v1LicenseCreate({
|
||||
license_type: 'code',
|
||||
license_code: code,
|
||||
license_file: '' as any
|
||||
}).then((resp: DomainLicenseResp) => {
|
||||
message.success("切换授权成功");
|
||||
console.log(resp)
|
||||
setVerifing(false);
|
||||
onClose();
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 1000)
|
||||
}).catch(() => {
|
||||
message.error("遇到一点意外,无法激活");
|
||||
setVerifing(false);
|
||||
license_file: '' as any,
|
||||
})
|
||||
}
|
||||
.then((resp: DomainLicenseResp) => {
|
||||
message.success('切换授权成功');
|
||||
console.log(resp);
|
||||
setVerifing(false);
|
||||
onClose();
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 1000);
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('遇到一点意外,无法激活');
|
||||
setVerifing(false);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
<Modal
|
||||
title='切换 MonkeyCode 授权'
|
||||
width={400}
|
||||
open={open}
|
||||
onCancel={onClose}
|
||||
footer={null}>
|
||||
<Stack direction={'column'} gap={2} sx={{
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
<Stack direction={'row'} gap={2} sx={{
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
<TextField label="授权码" variant="outlined" sx={{
|
||||
width: '100%'
|
||||
footer={null}
|
||||
>
|
||||
<Stack
|
||||
direction={'column'}
|
||||
gap={2}
|
||||
sx={{
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
direction={'row'}
|
||||
gap={2}
|
||||
sx={{
|
||||
fontSize: '14px',
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setCode(e.target.value);
|
||||
}} />
|
||||
|
||||
>
|
||||
<TextField
|
||||
label='授权码'
|
||||
variant='outlined'
|
||||
sx={{
|
||||
width: '100%',
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setCode(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack direction={'row'} gap={2} sx={{
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
<Button variant="contained"
|
||||
<Stack
|
||||
direction={'row'}
|
||||
gap={2}
|
||||
sx={{
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant='contained'
|
||||
loading={verifing}
|
||||
sx={{
|
||||
width: '100%'
|
||||
width: '100%',
|
||||
}}
|
||||
onClick={() => {
|
||||
updateLicense()
|
||||
}}>在线激活</Button>
|
||||
updateLicense();
|
||||
}}
|
||||
>
|
||||
在线激活
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChangeLicense;
|
||||
export default ChangeLicense;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Logo from '@/assets/images/logo.png';
|
||||
import { alpha, Box, Button, Stack, useTheme, styled } from '@mui/material';
|
||||
import { Icon } from '@c-x/ui';
|
||||
import { Icon } from '@ctzhian/ui';
|
||||
import { NavLink, useLocation } from 'react-router-dom';
|
||||
import { Modal } from '@c-x/ui';
|
||||
import { Modal } from '@ctzhian/ui';
|
||||
import { useMemo, useState } from 'react';
|
||||
import Qrcode from '@/assets/images/qrcode.png';
|
||||
import Version from './version';
|
||||
@@ -145,7 +145,10 @@ const Sidebar = () => {
|
||||
}
|
||||
return isConfigModel
|
||||
? ADMIN_MENUS.map((item) => ({ ...item, disabled: false }))
|
||||
: ADMIN_MENUS.map((item) => ({ ...item, disabled: item.pathname !== 'general-setting' }));
|
||||
: ADMIN_MENUS.map((item) => ({
|
||||
...item,
|
||||
disabled: item.pathname !== 'general-setting',
|
||||
}));
|
||||
}, [pathname, isConfigModel]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -6,7 +6,7 @@ import '@/assets/fonts/font.css';
|
||||
import '@/assets/fonts/iconfont';
|
||||
import './index.css';
|
||||
import '@/assets/styles/markdown.css';
|
||||
import { ThemeProvider } from '@c-x/ui';
|
||||
import { ThemeProvider } from '@ctzhian/ui';
|
||||
import { zhCN } from 'date-fns/locale/zh-CN';
|
||||
import { setDefaultOptions } from 'date-fns';
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ import {
|
||||
Paper,
|
||||
Alert,
|
||||
CircularProgress,
|
||||
Grid2 as Grid,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
Divider,
|
||||
Stack,
|
||||
} from '@mui/material';
|
||||
import { CusTabs, Icon, message } from '@c-x/ui';
|
||||
import { CusTabs, Icon, message } from '@ctzhian/ui';
|
||||
|
||||
// @ts-ignore
|
||||
import { AestheticFluidBg } from '@/assets/jsm/AestheticFluidBg.module.js';
|
||||
@@ -354,9 +354,9 @@ const AuthPage = () => {
|
||||
<CusTabs
|
||||
list={[
|
||||
{ label: '研发成员', value: 'user' },
|
||||
{ label: '管理员', value: 'admin', disabled: true},
|
||||
{ label: '管理员', value: 'admin', disabled: true },
|
||||
]}
|
||||
value={"user"}
|
||||
value={'user'}
|
||||
sx={{
|
||||
width: '100%',
|
||||
mb: 4,
|
||||
|
||||
@@ -2,7 +2,7 @@ import Avatar from '@/components/avatar';
|
||||
import Card from '@/components/card';
|
||||
import { getChatInfo } from '@/api/Billing';
|
||||
import MarkDown from '@/components/markDown';
|
||||
import { Ellipsis, Modal } from '@c-x/ui';
|
||||
import { Ellipsis, Modal } from '@ctzhian/ui';
|
||||
import { styled } from '@mui/material';
|
||||
import logo from '@/assets/images/logo.png';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Table } from '@c-x/ui';
|
||||
import { Table } from '@ctzhian/ui';
|
||||
import { getListChatRecord } from '@/api/Billing';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import StyledLabel from '@/components/label';
|
||||
|
||||
import ChatDetailModal from './chatDetailModal';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import { DomainChatRecord, DomainUser } from '@/api/types';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
import User from '@/components/user';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Card from '@/components/card';
|
||||
import { getCompletionInfo } from '@/api/Billing';
|
||||
import { Modal } from '@c-x/ui';
|
||||
import { Modal } from '@ctzhian/ui';
|
||||
import MonacoEditor from '@monaco-editor/react';
|
||||
import { loader } from '@monaco-editor/react';
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
||||
import { DomainCompletionRecord, DomainUser } from '@/api/types';
|
||||
import { getListCompletionRecord } from '@/api/Billing';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { Table } from '@c-x/ui';
|
||||
import { Table } from '@ctzhian/ui';
|
||||
import Card from '@/components/card';
|
||||
import {
|
||||
Box,
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import { getListUser } from '@/api/User';
|
||||
import dayjs from 'dayjs';
|
||||
import { useDebounceFn } from 'ahooks';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
import CompletionDetailModal from './completionDetailModal';
|
||||
import StyledLabel from '@/components/label';
|
||||
@@ -154,14 +154,26 @@ const Completion = () => {
|
||||
render(value: number) {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{dayjs.unix(value).format('YYYY-MM-DD')}
|
||||
</Box>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{dayjs.unix(value).format('HH:mm:ss')}
|
||||
</Box>
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Box, Stack } from '@mui/material';
|
||||
import { DomainUserCodeRank } from '@/api/types';
|
||||
import { Modal } from '@c-x/ui';
|
||||
import { Modal } from '@ctzhian/ui';
|
||||
import { StyledItem, StyledSerialNumber, StyledText } from './statisticCard';
|
||||
import User from '@/components/user';
|
||||
import Avatar from '@/components/avatar';
|
||||
@@ -49,13 +49,13 @@ const ContributionModal = ({
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
|
||||
<Avatar
|
||||
name={item.user?.username}
|
||||
src={item.user?.avatar_url}
|
||||
sx={{ width: 20, height: 20, fontSize: 12 }}
|
||||
/>
|
||||
<StyledText className='active-user-name'>{item.username}
|
||||
<StyledText className='active-user-name'>
|
||||
{item.username}
|
||||
</StyledText>
|
||||
</Stack>
|
||||
</StyledItem>
|
||||
|
||||
@@ -5,12 +5,8 @@ import {
|
||||
getUserCodeRankDashboard,
|
||||
} from '@/api/Dashboard';
|
||||
import { SecondTimeRange } from '@/components/ui/calendar';
|
||||
import {
|
||||
getRecent60MinutesData,
|
||||
getTimeRange,
|
||||
getRangeData,
|
||||
} from '@/utils';
|
||||
import { Grid2 as Grid, styled } from '@mui/material';
|
||||
import { getRecent60MinutesData, getTimeRange, getRangeData } from '@/utils';
|
||||
import { Grid, styled } from '@mui/material';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { useMemo } from 'react';
|
||||
import BarCharts from './barCharts';
|
||||
@@ -73,12 +69,32 @@ const GlobalStatistic = ({
|
||||
} = timeStatData || {};
|
||||
const label = { valueLabel: 'value' };
|
||||
return {
|
||||
userActiveChartData: getRangeData(timeDuration, active_users, precision, label),
|
||||
userActiveChartData: getRangeData(
|
||||
timeDuration,
|
||||
active_users,
|
||||
precision,
|
||||
label
|
||||
),
|
||||
chatChartData: getRangeData(timeDuration, chats, precision, label),
|
||||
codeCompletionChartData: getRangeData(timeDuration, code_completions, precision, label),
|
||||
codeLineChartData: getRangeData(timeDuration, lines_of_code, precision, label),
|
||||
codeCompletionChartData: getRangeData(
|
||||
timeDuration,
|
||||
code_completions,
|
||||
precision,
|
||||
label
|
||||
),
|
||||
codeLineChartData: getRangeData(
|
||||
timeDuration,
|
||||
lines_of_code,
|
||||
precision,
|
||||
label
|
||||
),
|
||||
realTimeTokenChartData: getRecent60MinutesData(real_time_tokens, label),
|
||||
acceptedPerChartData: getRangeData(timeDuration, accepted_per, precision, label),
|
||||
acceptedPerChartData: getRangeData(
|
||||
timeDuration,
|
||||
accepted_per,
|
||||
precision,
|
||||
label
|
||||
),
|
||||
};
|
||||
}, [timeStatData, precision]);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
} from '@/api/types';
|
||||
import Avatar from '@/components/avatar';
|
||||
import Card from '@/components/card';
|
||||
import { Icon } from '@c-x/ui';
|
||||
import { Icon } from '@ctzhian/ui';
|
||||
import {
|
||||
Box,
|
||||
IconButton,
|
||||
|
||||
@@ -5,8 +5,13 @@ import {
|
||||
} from '@/api/Dashboard';
|
||||
import { DomainUser } from '@/api/types';
|
||||
import { SecondTimeRange } from '@/components/ui/calendar';
|
||||
import { getRangeData, getRecent24HoursData, getRecentDaysData, getTimeRange } from '@/utils';
|
||||
import { Grid2 as Grid } from '@mui/material';
|
||||
import {
|
||||
getRangeData,
|
||||
getRecent24HoursData,
|
||||
getRecentDaysData,
|
||||
getTimeRange,
|
||||
} from '@/utils';
|
||||
import { Grid } from '@mui/material';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
@@ -85,8 +90,18 @@ const MemberStatistic = ({
|
||||
precision,
|
||||
label
|
||||
);
|
||||
const codeLineChartData = getRangeData(timeDuration, lines_of_code, precision, label);
|
||||
const acceptedPerChartData = getRangeData(timeDuration, accepted_per, precision, label);
|
||||
const codeLineChartData = getRangeData(
|
||||
timeDuration,
|
||||
lines_of_code,
|
||||
precision,
|
||||
label
|
||||
);
|
||||
const acceptedPerChartData = getRangeData(
|
||||
timeDuration,
|
||||
accepted_per,
|
||||
precision,
|
||||
label
|
||||
);
|
||||
return {
|
||||
chatChartData,
|
||||
codeCompletionChartData,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Empty } from '@c-x/ui';
|
||||
import { Empty } from '@ctzhian/ui';
|
||||
import { Box, Stack, styled } from '@mui/material';
|
||||
import dayjs from 'dayjs';
|
||||
import { useState } from 'react';
|
||||
@@ -117,7 +117,7 @@ export const ContributionCard = ({
|
||||
gap={1.5}
|
||||
sx={{
|
||||
flex: 1,
|
||||
minWidth: 0
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
@@ -125,7 +125,8 @@ export const ContributionCard = ({
|
||||
src={item.user?.avatar_url}
|
||||
sx={{ width: 20, height: 20, fontSize: 12 }}
|
||||
/>
|
||||
<StyledText className='active-user-name'>{item.username}
|
||||
<StyledText className='active-user-name'>
|
||||
{item.username}
|
||||
</StyledText>
|
||||
</Stack>
|
||||
</StyledItem>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { getListUser } from '@/api/User';
|
||||
import { Stack, Box } from '@mui/material';
|
||||
import { CusTabs } from '@c-x/ui';
|
||||
import { CusTabs } from '@ctzhian/ui';
|
||||
import GlobalStatistic from './components/globalStatistic';
|
||||
import { useRequest } from 'ahooks';
|
||||
import MemberStatistic from './components/memberStatistic';
|
||||
@@ -112,7 +112,7 @@ const Dashboard = () => {
|
||||
};
|
||||
const handleTimeRangeChange = (value: any) => {
|
||||
if (value) {
|
||||
console.log(value)
|
||||
console.log(value);
|
||||
setTimeRange(value);
|
||||
} else {
|
||||
setTimeRange(get24HoursRange());
|
||||
@@ -136,7 +136,12 @@ const Dashboard = () => {
|
||||
|
||||
return (
|
||||
<Stack gap={2} sx={{ height: '100%' }}>
|
||||
<Stack direction='row' gap={2} justifyContent='space-between' alignItems='center'>
|
||||
<Stack
|
||||
direction='row'
|
||||
gap={2}
|
||||
justifyContent='space-between'
|
||||
alignItems='center'
|
||||
>
|
||||
<CusTabs
|
||||
value={tabValue}
|
||||
onChange={onTabChange}
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
putAiemployeeUpdate,
|
||||
postUserAiemployeeCreate,
|
||||
putUserAiemployeeUpdate,
|
||||
} from "@/api";
|
||||
import { Ellipsis, message, Modal } from "@c-x/ui";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
|
||||
} from '@/api';
|
||||
import { Ellipsis, message, Modal } from '@ctzhian/ui';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
import {
|
||||
Box,
|
||||
Checkbox,
|
||||
@@ -22,13 +22,13 @@ import {
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Stack,
|
||||
TextField
|
||||
} from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import CopyToClipboard from "react-copy-to-clipboard";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { z } from "zod";
|
||||
TextField,
|
||||
} from '@mui/material';
|
||||
import { useEffect, useState } from 'react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { z } from 'zod';
|
||||
|
||||
const formSchema = z.object({
|
||||
issue_at_comment: z.boolean().default(false),
|
||||
@@ -38,15 +38,15 @@ const formSchema = z.object({
|
||||
mr_pr_at_comment: z.boolean().default(false),
|
||||
/** 是否处理全部新增PR/MR */
|
||||
mr_pr_open: z.boolean().default(false),
|
||||
name: z.string().min(1, "必填项").default(""),
|
||||
name: z.string().min(1, '必填项').default(''),
|
||||
platform: z
|
||||
.enum(ConstsRepoPlatform)
|
||||
.default(ConstsRepoPlatform.RepoPlatformGitLab),
|
||||
position: z
|
||||
.enum(ConstsAIEmployeePosition)
|
||||
.default(ConstsAIEmployeePosition.AIEmployeePositionEngineer),
|
||||
repo_url: z.string().min(1, "必填项").default(""),
|
||||
token: z.string().min(1, "必填项").default(""),
|
||||
repo_url: z.string().min(1, '必填项').default(''),
|
||||
token: z.string().min(1, '必填项').default(''),
|
||||
});
|
||||
|
||||
const EmloyeeModal = ({
|
||||
@@ -62,10 +62,10 @@ const EmloyeeModal = ({
|
||||
}) => {
|
||||
const [webhookOpen, setWebhookOpen] = useState(false);
|
||||
const [webhookUrl, setWebhookUrl] = useState<
|
||||
Pick<DomainAIEmployee, "webhook_url" | "webhook_secret"> | undefined
|
||||
Pick<DomainAIEmployee, 'webhook_url' | 'webhook_secret'> | undefined
|
||||
>();
|
||||
const { pathname } = useLocation();
|
||||
const isUser = pathname.startsWith("/user/");
|
||||
const isUser = pathname.startsWith('/user/');
|
||||
const {
|
||||
reset,
|
||||
register,
|
||||
@@ -79,7 +79,10 @@ const EmloyeeModal = ({
|
||||
const handleChange = handleSubmit(
|
||||
async (data) => {
|
||||
const res = await (record
|
||||
? (isUser ? putUserAiemployeeUpdate : putAiemployeeUpdate)({ ...data, id: record.id })
|
||||
? (isUser ? putUserAiemployeeUpdate : putAiemployeeUpdate)({
|
||||
...data,
|
||||
id: record.id,
|
||||
})
|
||||
: (isUser ? postUserAiemployeeCreate : postAiemployeeCreate)(data));
|
||||
onChanged?.(); // 调用回调函数,刷新列表
|
||||
setWebhookUrl(res);
|
||||
@@ -90,10 +93,10 @@ const EmloyeeModal = ({
|
||||
}
|
||||
);
|
||||
const checkitems = [
|
||||
{ key: "issue_open", label: "自动跟进所有的 Issue" },
|
||||
{ key: "mr_pr_open", label: "自动跟进所有的 Merge/Pull Request" },
|
||||
{ key: "issue_at_comment", label: "允许在 Issue 中被 @" },
|
||||
{ key: "mr_pr_at_comment", label: "允许在 Merge/Pull Request 中被 @" },
|
||||
{ key: 'issue_open', label: '自动跟进所有的 Issue' },
|
||||
{ key: 'mr_pr_open', label: '自动跟进所有的 Merge/Pull Request' },
|
||||
{ key: 'issue_at_comment', label: '允许在 Issue 中被 @' },
|
||||
{ key: 'mr_pr_at_comment', label: '允许在 Merge/Pull Request 中被 @' },
|
||||
] as const;
|
||||
useEffect(() => {
|
||||
if (open) reset(record || formSchema.parse({}));
|
||||
@@ -105,36 +108,36 @@ const EmloyeeModal = ({
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
title={record ? "编辑 AI 员工" : "创建 AI 员工"}
|
||||
title={record ? '编辑 AI 员工' : '创建 AI 员工'}
|
||||
width={600}
|
||||
open={open}
|
||||
// onOk={() => setOpenWebhook(true)}
|
||||
onOk={handleChange}
|
||||
onCancel={onClose}
|
||||
okText={record ? "更新" : "创建"}
|
||||
cancelText="取消"
|
||||
okText={record ? '更新' : '创建'}
|
||||
cancelText='取消'
|
||||
>
|
||||
<Stack spacing={2} sx={{ fontSize: "13px" }}>
|
||||
<Stack spacing={2} sx={{ fontSize: '13px' }}>
|
||||
<TextField
|
||||
label="AI 员工名称"
|
||||
label='AI 员工名称'
|
||||
fullWidth
|
||||
size="small"
|
||||
{...register("name")}
|
||||
size='small'
|
||||
{...register('name')}
|
||||
error={!!errors.name}
|
||||
helperText={errors.name?.message}
|
||||
/>
|
||||
<Stack
|
||||
direction={"row"}
|
||||
direction={'row'}
|
||||
component={FormControl}
|
||||
alignItems="center"
|
||||
alignItems='center'
|
||||
spacing={3}
|
||||
>
|
||||
<FormLabel id="demo-row-radio-buttons-group-label">
|
||||
<FormLabel id='demo-row-radio-buttons-group-label'>
|
||||
AI 员工角色
|
||||
</FormLabel>
|
||||
<Controller
|
||||
control={control}
|
||||
name="position"
|
||||
name='position'
|
||||
render={({ field }) => (
|
||||
<RadioGroup
|
||||
row
|
||||
@@ -180,25 +183,25 @@ const EmloyeeModal = ({
|
||||
))}
|
||||
</FormGroup>
|
||||
<TextField
|
||||
label="工作项目的 Git 仓库"
|
||||
label='工作项目的 Git 仓库'
|
||||
fullWidth
|
||||
size="small"
|
||||
{...register("repo_url")}
|
||||
size='small'
|
||||
{...register('repo_url')}
|
||||
error={!!errors.repo_url}
|
||||
helperText={errors.repo_url?.message}
|
||||
/>
|
||||
<Stack
|
||||
direction={"row"}
|
||||
direction={'row'}
|
||||
component={FormControl}
|
||||
alignItems="center"
|
||||
alignItems='center'
|
||||
spacing={3}
|
||||
>
|
||||
<FormLabel id="demo-row-radio-buttons-group-label">
|
||||
<FormLabel id='demo-row-radio-buttons-group-label'>
|
||||
Git 托管平台
|
||||
</FormLabel>
|
||||
<Controller
|
||||
control={control}
|
||||
name="platform"
|
||||
name='platform'
|
||||
render={({ field }) => (
|
||||
<RadioGroup
|
||||
row
|
||||
@@ -226,72 +229,72 @@ const EmloyeeModal = ({
|
||||
/>
|
||||
</Stack>
|
||||
<TextField
|
||||
label="Git 仓库的访问令牌"
|
||||
label='Git 仓库的访问令牌'
|
||||
fullWidth
|
||||
size="small"
|
||||
{...register("token")}
|
||||
size='small'
|
||||
{...register('token')}
|
||||
error={!!errors.token}
|
||||
helperText={errors.token?.message}
|
||||
/>
|
||||
</Stack>
|
||||
</Modal>
|
||||
<Modal
|
||||
title="Webhook 配置信息"
|
||||
title='Webhook 配置信息'
|
||||
width={830}
|
||||
open={webhookOpen}
|
||||
onOk={onCloseWebhook}
|
||||
onCancel={onCloseWebhook}
|
||||
showCancel={false}
|
||||
okText="确定"
|
||||
okText='确定'
|
||||
>
|
||||
{webhookUrl?.webhook_secret && (
|
||||
<Stack
|
||||
spacing={2}
|
||||
sx={{
|
||||
mt: 2,
|
||||
fontSize: "14px",
|
||||
"& > .MuiStack-root > div:nth-child(2)": {
|
||||
fontSize: '14px',
|
||||
'& > .MuiStack-root > div:nth-child(2)': {
|
||||
fontWeight: 600,
|
||||
bgcolor: "background.paper",
|
||||
bgcolor: 'background.paper',
|
||||
px: 1,
|
||||
py: 0.5,
|
||||
borderRadius: "4px",
|
||||
borderRadius: '4px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Stack direction="row" alignItems={"center"} spacing={2}>
|
||||
<Box sx={{ flexShrink: 0, minWidth: "130px" }}>Webhook URL: </Box>
|
||||
<Stack direction='row' alignItems={'center'} spacing={2}>
|
||||
<Box sx={{ flexShrink: 0, minWidth: '130px' }}>Webhook URL: </Box>
|
||||
<Ellipsis>{webhookUrl?.webhook_url}</Ellipsis>
|
||||
<CopyToClipboard
|
||||
text={webhookUrl?.webhook_url || ""}
|
||||
text={webhookUrl?.webhook_url || ''}
|
||||
onCopy={() => {
|
||||
message.success("复制成功");
|
||||
message.success('复制成功');
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
color="primary"
|
||||
size="small"
|
||||
sx={{ alignSelf: "flex-end" }}
|
||||
color='primary'
|
||||
size='small'
|
||||
sx={{ alignSelf: 'flex-end' }}
|
||||
>
|
||||
<ContentCopyIcon />
|
||||
</IconButton>
|
||||
</CopyToClipboard>
|
||||
</Stack>
|
||||
<Stack direction="row" alignItems={"center"} spacing={2}>
|
||||
<Box sx={{ flexShrink: 0, minWidth: "130px" }}>
|
||||
Webhook Secret:{" "}
|
||||
<Stack direction='row' alignItems={'center'} spacing={2}>
|
||||
<Box sx={{ flexShrink: 0, minWidth: '130px' }}>
|
||||
Webhook Secret:{' '}
|
||||
</Box>
|
||||
<Ellipsis>{webhookUrl?.webhook_secret}</Ellipsis>
|
||||
<CopyToClipboard
|
||||
text={webhookUrl?.webhook_secret || ""}
|
||||
text={webhookUrl?.webhook_secret || ''}
|
||||
onCopy={() => {
|
||||
message.success("复制成功");
|
||||
message.success('复制成功');
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
color="primary"
|
||||
size="small"
|
||||
sx={{ alignSelf: "flex-end" }}
|
||||
color='primary'
|
||||
size='small'
|
||||
sx={{ alignSelf: 'flex-end' }}
|
||||
>
|
||||
<ContentCopyIcon />
|
||||
</IconButton>
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import { Ellipsis, Icon, message, Modal, Table } from "@c-x/ui";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Ellipsis, Icon, message, Modal, Table } from '@ctzhian/ui';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import Card from "@/components/card";
|
||||
import { Box, Button, Stack } from "@mui/material";
|
||||
import Card from '@/components/card';
|
||||
import { Box, Button, Stack } from '@mui/material';
|
||||
|
||||
import { deleteAiemployeeDelete, getAiemployeeList } from "@/api/AiEmployee";
|
||||
import { deleteAiemployeeDelete, getAiemployeeList } from '@/api/AiEmployee';
|
||||
import {
|
||||
deleteUserAiemployeeDelete,
|
||||
getUserAiemployeeList,
|
||||
} from "@/api/UserAiEmployee";
|
||||
} from '@/api/UserAiEmployee';
|
||||
import {
|
||||
ConstsRepoPlatform,
|
||||
DomainAIEmployee,
|
||||
DomainUpdateAIEmployeeReq,
|
||||
} from "@/api/types";
|
||||
import { ColumnsType } from "@c-x/ui/dist/Table";
|
||||
import dayjs from "dayjs";
|
||||
import EmloyeeModal from "./emloyeeModal";
|
||||
import { useLocation } from "react-router-dom";
|
||||
} from '@/api/types';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import dayjs from 'dayjs';
|
||||
import EmloyeeModal from './emloyeeModal';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
const gitPlatformIcons = {
|
||||
[ConstsRepoPlatform.RepoPlatformGitHub]: "icon-github",
|
||||
[ConstsRepoPlatform.RepoPlatformGitLab]: "icon-gitlab",
|
||||
[ConstsRepoPlatform.RepoPlatformGitee]: "icon-gitee",
|
||||
[ConstsRepoPlatform.RepoPlatformGitea]: "icon-gitea",
|
||||
[ConstsRepoPlatform.RepoPlatformGitHub]: 'icon-github',
|
||||
[ConstsRepoPlatform.RepoPlatformGitLab]: 'icon-gitlab',
|
||||
[ConstsRepoPlatform.RepoPlatformGitee]: 'icon-gitee',
|
||||
[ConstsRepoPlatform.RepoPlatformGitea]: 'icon-gitea',
|
||||
} as const;
|
||||
const EmployeeTaskList = () => {
|
||||
const [page, setPage] = useState(1);
|
||||
@@ -33,7 +33,7 @@ const EmployeeTaskList = () => {
|
||||
const [dataSource, setDataSource] = useState<DomainAIEmployee[]>([]);
|
||||
const [detail, setDetail] = useState<DomainUpdateAIEmployeeReq | undefined>();
|
||||
const { pathname } = useLocation();
|
||||
const isUser = pathname.startsWith("/user/");
|
||||
const isUser = pathname.startsWith('/user/');
|
||||
const [open, setOpen] = useState(false);
|
||||
const onClose = () => {
|
||||
setOpen(false);
|
||||
@@ -71,17 +71,17 @@ const EmployeeTaskList = () => {
|
||||
};
|
||||
const handleDelete = (record: DomainAIEmployee) => {
|
||||
Modal.confirm({
|
||||
title: "提示",
|
||||
okText: "删除",
|
||||
title: '提示',
|
||||
okText: '删除',
|
||||
okButtonProps: {
|
||||
color: "error",
|
||||
color: 'error',
|
||||
},
|
||||
content: (
|
||||
<>
|
||||
确定要删除 AI 员工{" "}
|
||||
<Box component="span" sx={{ fontWeight: 700, color: "text.primary" }}>
|
||||
确定要删除 AI 员工{' '}
|
||||
<Box component='span' sx={{ fontWeight: 700, color: 'text.primary' }}>
|
||||
{record!.name}
|
||||
</Box>{" "}
|
||||
</Box>{' '}
|
||||
吗?
|
||||
</>
|
||||
),
|
||||
@@ -89,7 +89,7 @@ const EmployeeTaskList = () => {
|
||||
(isUser ? deleteUserAiemployeeDelete : deleteAiemployeeDelete)({
|
||||
id: record.id!,
|
||||
}).then(() => {
|
||||
message.success("删除成功");
|
||||
message.success('删除成功');
|
||||
fetchData({});
|
||||
});
|
||||
},
|
||||
@@ -97,22 +97,22 @@ const EmployeeTaskList = () => {
|
||||
};
|
||||
const columns: ColumnsType<DomainAIEmployee> = [
|
||||
{
|
||||
dataIndex: "name",
|
||||
title: "AI 员工",
|
||||
dataIndex: 'name',
|
||||
title: 'AI 员工',
|
||||
width: 240,
|
||||
render: (name, record) => {
|
||||
return (
|
||||
<Stack direction="column">
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Stack direction='column'>
|
||||
<Stack direction='row' alignItems='center' spacing={1}>
|
||||
<Icon
|
||||
type="icon-jiqiren"
|
||||
sx={{ fontSize: 20, color: "text.main" }}
|
||||
type='icon-jiqiren'
|
||||
sx={{ fontSize: 20, color: 'text.main' }}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.name}
|
||||
@@ -120,17 +120,17 @@ const EmployeeTaskList = () => {
|
||||
</Stack>
|
||||
<Box
|
||||
sx={{
|
||||
color: "text.tertiary",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
fontSize: "0.8rem",
|
||||
mt: "4px",
|
||||
color: 'text.tertiary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
fontSize: '0.8rem',
|
||||
mt: '4px',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
lineHeight: "16px",
|
||||
lineHeight: '16px',
|
||||
}}
|
||||
>
|
||||
{record?.position}
|
||||
@@ -141,36 +141,36 @@ const EmployeeTaskList = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "工作项目",
|
||||
dataIndex: "platform",
|
||||
title: '工作项目',
|
||||
dataIndex: 'platform',
|
||||
width: 300,
|
||||
render: (platform, record) => {
|
||||
return (
|
||||
<Stack direction="column">
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<Stack direction='column'>
|
||||
<Stack direction='row' alignItems='center' spacing={1}>
|
||||
<Icon
|
||||
type={gitPlatformIcons[record.platform as ConstsRepoPlatform]}
|
||||
sx={{ fontSize: 16, color: "text.main" }}
|
||||
sx={{ fontSize: 16, color: 'text.main' }}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.repository_url
|
||||
? record?.repository_url.split("/").pop()
|
||||
? record?.repository_url.split('/').pop()
|
||||
: record?.platform}
|
||||
</Box>
|
||||
</Stack>
|
||||
<Ellipsis
|
||||
sx={{
|
||||
color: "text.secondary",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
fontSize: "0.8rem",
|
||||
color: 'text.secondary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
{record?.repository_url}
|
||||
@@ -180,27 +180,27 @@ const EmployeeTaskList = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "创建者",
|
||||
dataIndex: "creater",
|
||||
title: '创建者',
|
||||
dataIndex: 'creater',
|
||||
render: (creater, record) => {
|
||||
return (
|
||||
<Stack direction="column">
|
||||
<Stack direction='column'>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.admin?.username}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
color: "text.secondary",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
fontSize: "0.8rem",
|
||||
color: 'text.secondary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
{dayjs(Number(record?.created_at) * 1000).fromNow()}创建
|
||||
@@ -210,27 +210,27 @@ const EmployeeTaskList = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "工作状态",
|
||||
dataIndex: "status",
|
||||
title: '工作状态',
|
||||
dataIndex: 'status',
|
||||
render: (status, record) => {
|
||||
return (
|
||||
<Stack direction="column">
|
||||
<Stack direction='column'>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
共完成 {record?.completed_count || 0} 个任务
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
color: "text.secondary",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
fontSize: "0.8rem",
|
||||
color: 'text.secondary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
fontSize: '0.8rem',
|
||||
}}
|
||||
>
|
||||
{dayjs(Number(record?.last_active_at) * 1000).fromNow()}活跃
|
||||
@@ -240,17 +240,17 @@ const EmployeeTaskList = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
dataIndex: "opt",
|
||||
title: '操作',
|
||||
dataIndex: 'opt',
|
||||
render: (status, record) => {
|
||||
return (
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button variant="text" onClick={() => handleEdit(record)}>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Button variant='text' onClick={() => handleEdit(record)}>
|
||||
修改
|
||||
</Button>
|
||||
<Button
|
||||
variant="text"
|
||||
color="error"
|
||||
variant='text'
|
||||
color='error'
|
||||
onClick={() => handleDelete(record)}
|
||||
>
|
||||
删除
|
||||
@@ -261,18 +261,18 @@ const EmployeeTaskList = () => {
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Card sx={{ flex: 1, height: "100%" }}>
|
||||
<Stack height="100%">
|
||||
<Card sx={{ flex: 1, height: '100%' }}>
|
||||
<Stack height='100%'>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
sx={{ mb: 2, alignSelf: "flex-end" }}
|
||||
variant='contained'
|
||||
size='small'
|
||||
sx={{ mb: 2, alignSelf: 'flex-end' }}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
创建 AI 员工
|
||||
</Button>
|
||||
<Table
|
||||
sx={{ mx: -2, flexGrow: 1, overflow: "auto" }}
|
||||
sx={{ mx: -2, flexGrow: 1, overflow: 'auto' }}
|
||||
PaginationProps={{
|
||||
sx: {
|
||||
pt: 2,
|
||||
@@ -282,7 +282,7 @@ const EmployeeTaskList = () => {
|
||||
loading={loading}
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
rowKey="id"
|
||||
rowKey='id'
|
||||
pagination={{
|
||||
page,
|
||||
pageSize: size,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import Card from '@/components/card';
|
||||
import { Stack, Box } from '@mui/material';
|
||||
import { Table } from '@c-x/ui';
|
||||
import { Table } from '@ctzhian/ui';
|
||||
import dayjs from 'dayjs';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { getAdminLoginHistory } from '@/api/Admin';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import { DomainListAdminLoginHistoryResp } from '@/api/types';
|
||||
import User from '@/components/user';
|
||||
|
||||
@@ -13,7 +13,9 @@ type LoginHistory = NonNullable<
|
||||
>[number];
|
||||
|
||||
const AdminLoginHistory = () => {
|
||||
const { data, loading } = useRequest(() => getAdminLoginHistory({page: 1, size: 50}));
|
||||
const { data, loading } = useRequest(() =>
|
||||
getAdminLoginHistory({ page: 1, size: 50 })
|
||||
);
|
||||
const columns: ColumnsType<LoginHistory> = [
|
||||
{
|
||||
title: '账号',
|
||||
@@ -30,7 +32,9 @@ const AdminLoginHistory = () => {
|
||||
<Stack direction='column'>
|
||||
<Box>{record?.ip_info?.ip}</Box>
|
||||
<Box sx={{ color: 'text.secondary' }}>
|
||||
{record?.ip_info?.country === '中国' ? ('' + record?.ip_info?.province + '-' + record?.ip_info?.city) : (record?.ip_info?.country || '未知')}
|
||||
{record?.ip_info?.country === '中国'
|
||||
? '' + record?.ip_info?.province + '-' + record?.ip_info?.city
|
||||
: record?.ip_info?.country || '未知'}
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
@@ -45,7 +49,7 @@ const AdminLoginHistory = () => {
|
||||
<Box>{dayjs.unix(text).format('YYYY-MM-DD')}</Box>
|
||||
<Box>{dayjs.unix(text).format('HH:mm:ss')}</Box>
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -55,23 +59,27 @@ const AdminLoginHistory = () => {
|
||||
direction='row'
|
||||
justifyContent='space-between'
|
||||
alignItems='center'
|
||||
sx={{
|
||||
sx={{
|
||||
mb: 2,
|
||||
height: 32,
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
}}
|
||||
>
|
||||
<Box sx={{
|
||||
'&::before': {
|
||||
content: '""',
|
||||
display: 'inline-block',
|
||||
width: 4,
|
||||
height: 12,
|
||||
bgcolor: 'common.black',
|
||||
borderRadius: '2px',
|
||||
mr: 1,
|
||||
},
|
||||
}}>管理员登录记录</Box>
|
||||
<Box
|
||||
sx={{
|
||||
'&::before': {
|
||||
content: '""',
|
||||
display: 'inline-block',
|
||||
width: 4,
|
||||
height: 12,
|
||||
bgcolor: 'common.black',
|
||||
borderRadius: '2px',
|
||||
mr: 1,
|
||||
},
|
||||
}}
|
||||
>
|
||||
管理员登录记录
|
||||
</Box>
|
||||
</Stack>
|
||||
<Table
|
||||
columns={columns}
|
||||
|
||||
@@ -14,9 +14,14 @@ import {
|
||||
import { AdminPanelSettings, Person } from '@mui/icons-material';
|
||||
import { postCreateAdmin } from '@/api/Admin';
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||
import { deleteDeleteAdmin, getAdminProfile, getListAdminUser, postGrantRole } from '@/api/Admin';
|
||||
import { Table, Modal, message } from '@c-x/ui';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import {
|
||||
deleteDeleteAdmin,
|
||||
getAdminProfile,
|
||||
getListAdminUser,
|
||||
postGrantRole,
|
||||
} from '@/api/Admin';
|
||||
import { Table, Modal, message } from '@ctzhian/ui';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import { useRequest } from 'ahooks';
|
||||
import dayjs from 'dayjs';
|
||||
import { DomainAdminUser } from '@/api/types';
|
||||
@@ -109,7 +114,9 @@ const AddAdminModal = ({
|
||||
<MenuItem value={2}>普通管理员</MenuItem>
|
||||
</Select>
|
||||
{errors.roleId && (
|
||||
<Box sx={{ color: 'error.main', fontSize: '0.75rem', mt: 0.5 }}>
|
||||
<Box
|
||||
sx={{ color: 'error.main', fontSize: '0.75rem', mt: 0.5 }}
|
||||
>
|
||||
{errors.roleId?.message as string}
|
||||
</Box>
|
||||
)}
|
||||
@@ -186,17 +193,19 @@ const AdminUser = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const { data, loading, refresh } = useRequest(() => getListAdminUser({}));
|
||||
const { data: currentAdmin } = useRequest(() => getAdminProfile({}));
|
||||
|
||||
|
||||
const handleRoleChange = (adminId: string, newRoleId: number) => {
|
||||
postGrantRole({
|
||||
admin_id: adminId,
|
||||
role_ids: [newRoleId],
|
||||
}).then(() => {
|
||||
message.success('角色更新成功');
|
||||
refresh();
|
||||
}).catch(() => {
|
||||
message.error('角色更新失败');
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
message.success('角色更新成功');
|
||||
refresh();
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('角色更新失败');
|
||||
});
|
||||
};
|
||||
|
||||
const onDeleteAdmin = (data: DomainAdminUser) => {
|
||||
@@ -240,40 +249,42 @@ const AdminUser = () => {
|
||||
<Select
|
||||
size='small'
|
||||
value={record.role?.id || ''}
|
||||
onChange={(e) => handleRoleChange(record.id!, Number(e.target.value))}
|
||||
onChange={(e) =>
|
||||
handleRoleChange(record.id!, Number(e.target.value))
|
||||
}
|
||||
displayEmpty
|
||||
disabled={record.id === currentAdmin?.id}
|
||||
renderValue={(value) => {
|
||||
if (value === 1) {
|
||||
return (
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
<AdminPanelSettings fontSize="small" />
|
||||
<Stack direction='row' alignItems='center' gap={1}>
|
||||
<AdminPanelSettings fontSize='small' />
|
||||
<span>超级管理员</span>
|
||||
</Stack>
|
||||
);
|
||||
} else if (value === 2) {
|
||||
return (
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
<Person fontSize="small" />
|
||||
<Stack direction='row' alignItems='center' gap={1}>
|
||||
<Person fontSize='small' />
|
||||
<span>普通管理员</span>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
return "请选择角色";
|
||||
return '请选择角色';
|
||||
}}
|
||||
sx={{
|
||||
mr: 1
|
||||
mr: 1,
|
||||
}}
|
||||
>
|
||||
<MenuItem value={1}>
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
<AdminPanelSettings fontSize="small" />
|
||||
<Stack direction='row' alignItems='center' gap={1}>
|
||||
<AdminPanelSettings fontSize='small' />
|
||||
<span>超级管理员</span>
|
||||
</Stack>
|
||||
</MenuItem>
|
||||
<MenuItem value={2}>
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
<Person fontSize="small" />
|
||||
<Stack direction='row' alignItems='center' gap={1}>
|
||||
<Person fontSize='small' />
|
||||
<span>普通管理员</span>
|
||||
</Stack>
|
||||
</MenuItem>
|
||||
@@ -287,10 +298,16 @@ const AdminUser = () => {
|
||||
dataIndex: 'created_at',
|
||||
width: 120,
|
||||
render: (text, record) => {
|
||||
return <Stack>
|
||||
<Box>{dayjs.unix(text).fromNow()}</Box>
|
||||
<Box>{record.last_active_at === 0 ? '从未使用' : dayjs.unix(text).fromNow()}</Box>
|
||||
</Stack>
|
||||
return (
|
||||
<Stack>
|
||||
<Box>{dayjs.unix(text).fromNow()}</Box>
|
||||
<Box>
|
||||
{record.last_active_at === 0
|
||||
? '从未使用'
|
||||
: dayjs.unix(text).fromNow()}
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -317,23 +334,27 @@ const AdminUser = () => {
|
||||
direction='row'
|
||||
justifyContent='space-between'
|
||||
alignItems='center'
|
||||
sx={{
|
||||
sx={{
|
||||
mb: 2,
|
||||
height: 32,
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
}}
|
||||
>
|
||||
<Box sx={{
|
||||
'&::before': {
|
||||
content: '""',
|
||||
display: 'inline-block',
|
||||
width: 4,
|
||||
height: 12,
|
||||
bgcolor: 'common.black',
|
||||
borderRadius: '2px',
|
||||
mr: 1,
|
||||
},
|
||||
}}>管理员清单</Box>
|
||||
<Box
|
||||
sx={{
|
||||
'&::before': {
|
||||
content: '""',
|
||||
display: 'inline-block',
|
||||
width: 4,
|
||||
height: 12,
|
||||
bgcolor: 'common.black',
|
||||
borderRadius: '2px',
|
||||
mr: 1,
|
||||
},
|
||||
}}
|
||||
>
|
||||
管理员清单
|
||||
</Box>
|
||||
<Button
|
||||
variant='contained'
|
||||
color='primary'
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import Card from "@/components/card";
|
||||
import { Box, Button, Stack, TextField } from "@mui/material";
|
||||
import { message } from "@c-x/ui";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getGetSetting, putUpdateSetting } from "@/api/Admin";
|
||||
import { DomainUpdateSettingReq } from "@/api/types";
|
||||
import Card from '@/components/card';
|
||||
import { Box, Button, Stack, TextField } from '@mui/material';
|
||||
import { message } from '@ctzhian/ui';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { getGetSetting, putUpdateSetting } from '@/api/Admin';
|
||||
import { DomainUpdateSettingReq } from '@/api/types';
|
||||
|
||||
const CardServiceSettings = () => {
|
||||
const [baseURL, setBaseURL] = useState("");
|
||||
const [initialBaseURL, setInitialBaseURL] = useState("");
|
||||
const [baseURL, setBaseURL] = useState('');
|
||||
const [initialBaseURL, setInitialBaseURL] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const fetchInitialBaseURL = async () => {
|
||||
try {
|
||||
const response = await getGetSetting();
|
||||
const initialValue = response.base_url || "";
|
||||
const initialValue = response.base_url || '';
|
||||
setBaseURL(initialValue);
|
||||
setInitialBaseURL(initialValue);
|
||||
} catch (err: any) {
|
||||
message.error("Failed to fetch initial base URL:", err);
|
||||
message.error('Failed to fetch initial base URL:', err);
|
||||
// 如果获取失败,可以设置一个默认值或者保持空字符串
|
||||
setBaseURL("");
|
||||
setInitialBaseURL("");
|
||||
setBaseURL('');
|
||||
setInitialBaseURL('');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -35,11 +35,11 @@ const CardServiceSettings = () => {
|
||||
try {
|
||||
const parsedURL = new URL(url);
|
||||
// Check if the protocol is either http or https
|
||||
if (parsedURL.protocol !== "http:" && parsedURL.protocol !== "https:") {
|
||||
if (parsedURL.protocol !== 'http:' && parsedURL.protocol !== 'https:') {
|
||||
return false;
|
||||
}
|
||||
// Check if the URL is a base URL (no path or only root path)
|
||||
if (parsedURL.pathname !== "/" && parsedURL.pathname !== "") {
|
||||
if (parsedURL.pathname !== '/' && parsedURL.pathname !== '') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -51,7 +51,7 @@ const CardServiceSettings = () => {
|
||||
const handleSave = async () => {
|
||||
// Check if the baseURL is valid before saving
|
||||
if (baseURL && !isValidURL(baseURL)) {
|
||||
message.error("请输入一个有效的 URL 地址");
|
||||
message.error('请输入一个有效的 URL 地址');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,50 +60,50 @@ const CardServiceSettings = () => {
|
||||
base_url: baseURL,
|
||||
};
|
||||
await putUpdateSetting(setting);
|
||||
message.success("保存成功");
|
||||
message.success('保存成功');
|
||||
setInitialBaseURL(baseURL);
|
||||
} catch (err: any) {
|
||||
message.error("保存失败:", err);
|
||||
message.error('保存失败:', err);
|
||||
}
|
||||
};
|
||||
|
||||
const hasValueChanged = baseURL !== initialBaseURL;
|
||||
|
||||
return (
|
||||
<Card sx={{ p: 0, mb: 2, borderBottom: "1px solid #e0e0e0" }}>
|
||||
<Card sx={{ p: 0, mb: 2, borderBottom: '1px solid #e0e0e0' }}>
|
||||
<Box
|
||||
sx={{
|
||||
fontWeight: "bold",
|
||||
fontWeight: 'bold',
|
||||
px: 2,
|
||||
py: 1.5,
|
||||
bgcolor: "rgb(248, 249, 250)",
|
||||
borderTopLeftRadius: "10px",
|
||||
borderTopRightRadius: "10px",
|
||||
bgcolor: 'rgb(248, 249, 250)',
|
||||
borderTopLeftRadius: '10px',
|
||||
borderTopRightRadius: '10px',
|
||||
}}
|
||||
>
|
||||
MonkeyCode 服务配置
|
||||
</Box>
|
||||
<Stack direction="column">
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems={"center"}
|
||||
justifyContent={"space-between"}
|
||||
direction='row'
|
||||
alignItems={'center'}
|
||||
justifyContent={'space-between'}
|
||||
sx={{
|
||||
m: 2,
|
||||
height: 32,
|
||||
fontWeight: "bold",
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
"&::before": {
|
||||
'&::before': {
|
||||
content: '""',
|
||||
display: "inline-block",
|
||||
display: 'inline-block',
|
||||
width: 4,
|
||||
height: 12,
|
||||
bgcolor: "common.black",
|
||||
borderRadius: "2px",
|
||||
bgcolor: 'common.black',
|
||||
borderRadius: '2px',
|
||||
mr: 1,
|
||||
},
|
||||
}}
|
||||
@@ -111,7 +111,7 @@ const CardServiceSettings = () => {
|
||||
MonkeyCode 服务连接地址
|
||||
</Box>
|
||||
{hasValueChanged && (
|
||||
<Button variant="contained" size="small" onClick={handleSave}>
|
||||
<Button variant='contained' size='small' onClick={handleSave}>
|
||||
保存
|
||||
</Button>
|
||||
)}
|
||||
@@ -121,14 +121,14 @@ const CardServiceSettings = () => {
|
||||
fullWidth
|
||||
value={baseURL}
|
||||
onChange={handleBaseURLChange}
|
||||
placeholder={baseURL ? "" : window.location.origin}
|
||||
placeholder={baseURL ? '' : window.location.origin}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
mt: 1,
|
||||
fontSize: "0.75rem",
|
||||
color: "warning.main",
|
||||
fontWeight: "normal",
|
||||
fontSize: '0.75rem',
|
||||
color: 'warning.main',
|
||||
fontWeight: 'normal',
|
||||
}}
|
||||
>
|
||||
用于解决 VSCode 插件无法连接 MonkeyCode 服务的问题
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import CardServiceSettings from "./components/cardServiceSettings";
|
||||
import { Grid2 as Grid } from "@mui/material";
|
||||
import CardAdminUser from "./components/cardAdminUser";
|
||||
import Model from "@/pages/model";
|
||||
import CardServiceSettings from './components/cardServiceSettings';
|
||||
import { Grid } from '@mui/material';
|
||||
import CardAdminUser from './components/cardAdminUser';
|
||||
import Model from '@/pages/model';
|
||||
|
||||
const GeneralSetting = () => {
|
||||
return (
|
||||
<Grid container spacing={2} sx={{ height: "100%" }}>
|
||||
<Grid container spacing={2} sx={{ height: '100%' }}>
|
||||
<Grid size={6}>
|
||||
<CardServiceSettings />
|
||||
<Model />
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
Typography,
|
||||
Container,
|
||||
Paper,
|
||||
Grid2 as Grid,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
CircularProgress,
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
import { useRequest } from 'ahooks';
|
||||
import { postRegister, getUserOauthSignupOrIn } from '@/api/User';
|
||||
import { getGetSetting } from '@/api/Admin';
|
||||
import { Icon } from '@c-x/ui';
|
||||
import { Icon } from '@ctzhian/ui';
|
||||
import { ConstsLoginSource, DomainSetting } from '@/api/types';
|
||||
|
||||
import DownloadIcon from '@mui/icons-material/Download';
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
Container,
|
||||
Paper,
|
||||
CircularProgress,
|
||||
Grid2 as Grid,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
Stack,
|
||||
@@ -18,7 +18,7 @@ import { postAdminLogin } from '@/api/Admin';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { ConstsLoginSource, DomainSetting } from '@/api/types';
|
||||
import { Icon, CusTabs } from '@c-x/ui';
|
||||
import { Icon, CusTabs } from '@ctzhian/ui';
|
||||
import Logo from '@/assets/images/logo.png';
|
||||
import { getRedirectUrl } from '@/utils';
|
||||
import { getGetSetting } from '@/api/Admin';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Modal, message } from '@c-x/ui';
|
||||
import { Modal, message } from '@ctzhian/ui';
|
||||
import { Box, TextField } from '@mui/material';
|
||||
import { postCreateGroup } from '@/api/UserGroup';
|
||||
|
||||
|
||||
@@ -17,23 +17,40 @@ import {
|
||||
SelectChangeEvent,
|
||||
TextField,
|
||||
} from '@mui/material';
|
||||
import { Table, Modal, message } from '@c-x/ui';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { DomainAdminUser, DomainLicenseEdition, DomainUser, DomainUserGroup } from '@/api/types';
|
||||
import { deleteDeleteGroup, getListAdminUser, getListUserGroup, v1LicenseList } from '@/api';
|
||||
import { deleteRemoveAdminFromGroup, postGrantGroup, postAddUserToGroup, deleteRemoveUserFromGroup, putUpdateUserGroup } from '@/api/UserGroup';
|
||||
import { Table, Modal, message } from '@ctzhian/ui';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import {
|
||||
DomainAdminUser,
|
||||
DomainLicenseEdition,
|
||||
DomainUser,
|
||||
DomainUserGroup,
|
||||
} from '@/api/types';
|
||||
import {
|
||||
deleteDeleteGroup,
|
||||
getListAdminUser,
|
||||
getListUserGroup,
|
||||
v1LicenseList,
|
||||
} from '@/api';
|
||||
import {
|
||||
deleteRemoveAdminFromGroup,
|
||||
postGrantGroup,
|
||||
postAddUserToGroup,
|
||||
deleteRemoveUserFromGroup,
|
||||
putUpdateUserGroup,
|
||||
} from '@/api/UserGroup';
|
||||
import CreateGroupModal from './createGroupModal';
|
||||
import UpdateGroupModal from './updateGroupModal';
|
||||
import { Check } from '@mui/icons-material';
|
||||
|
||||
|
||||
const GroupList = () => {
|
||||
const [openCreateGroupModal, setOpenCreateGroupModal] = useState(false);
|
||||
const [openUpdateGroupModal, setOpenUpdateGroupModal] = useState(false);
|
||||
const [currentGroup, setCurrentGroup] = useState<DomainUserGroup | null>(null);
|
||||
const groupData = useRequest(() => getListUserGroup({page: 1, size: 9999}));
|
||||
const userData = useRequest(() => getListUser({page: 1, size: 9999}));
|
||||
const adminData = useRequest(() => getListAdminUser({page: 1, size: 9999}));
|
||||
const [currentGroup, setCurrentGroup] = useState<DomainUserGroup | null>(
|
||||
null
|
||||
);
|
||||
const groupData = useRequest(() => getListUserGroup({ page: 1, size: 9999 }));
|
||||
const userData = useRequest(() => getListUser({ page: 1, size: 9999 }));
|
||||
const adminData = useRequest(() => getListAdminUser({ page: 1, size: 9999 }));
|
||||
const [searchUser, setSearchUser] = useState('');
|
||||
const [memberSearchText, setMemberSearchText] = useState('');
|
||||
const [adminSearchText, setAdminSearchText] = useState('');
|
||||
@@ -41,8 +58,8 @@ const GroupList = () => {
|
||||
const memberInputRef = useRef<HTMLInputElement>(null);
|
||||
const adminInputRef = useRef<HTMLInputElement>(null);
|
||||
const license = useRequest(() => {
|
||||
return v1LicenseList({})
|
||||
}).data
|
||||
return v1LicenseList({});
|
||||
}).data;
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!groupData?.data?.groups) return [];
|
||||
@@ -56,12 +73,20 @@ const GroupList = () => {
|
||||
|
||||
const filteredSelectUsers = useMemo(() => {
|
||||
if (!userData.data?.users) return [];
|
||||
return userData.data.users.filter(user => (user.username || '').toLowerCase().includes(memberSearchText.toLowerCase()));
|
||||
return userData.data.users.filter((user) =>
|
||||
(user.username || '')
|
||||
.toLowerCase()
|
||||
.includes(memberSearchText.toLowerCase())
|
||||
);
|
||||
}, [userData.data?.users, memberSearchText]);
|
||||
|
||||
const filteredSelectAdmins = useMemo(() => {
|
||||
if (!adminData.data?.users) return [];
|
||||
return adminData.data.users.filter(user => (user.username || '').toLowerCase().includes(adminSearchText.toLowerCase()));
|
||||
return adminData.data.users.filter((user) =>
|
||||
(user.username || '')
|
||||
.toLowerCase()
|
||||
.includes(adminSearchText.toLowerCase())
|
||||
);
|
||||
}, [adminData.data?.users, adminSearchText]);
|
||||
|
||||
const handleClick = (
|
||||
@@ -120,196 +145,239 @@ const GroupList = () => {
|
||||
title: '成员',
|
||||
dataIndex: 'users',
|
||||
render: (users, record) => {
|
||||
return <FormControl sx={{ width: '100%' }}>
|
||||
<InputLabel size='small'>成员</InputLabel>
|
||||
<Select
|
||||
multiple
|
||||
value={(users || []).map((u: DomainUser) => u.id)}
|
||||
label='成员'
|
||||
size='small'
|
||||
onClose={() => setMemberSearchText('')}
|
||||
onOpen={() => {
|
||||
setTimeout(() => {
|
||||
memberInputRef.current?.focus();
|
||||
}, 100);
|
||||
}}
|
||||
MenuProps={{
|
||||
autoFocus: false,
|
||||
}}
|
||||
renderValue={(selectedIds: string[]) => {
|
||||
if (!Array.isArray(selectedIds)) return null;
|
||||
const selectedUsers = (userData.data?.users || []).filter((user: DomainUser) =>
|
||||
user.id && selectedIds.includes(user.id)
|
||||
);
|
||||
return selectedUsers.map((u: DomainUser) => (
|
||||
<Chip size='small' key={u.id} label={u.username}></Chip>
|
||||
));
|
||||
}}
|
||||
onChange={(event: SelectChangeEvent<string[]>) => {
|
||||
console.log(event.target)
|
||||
// 获取当前分组的成员ID列表
|
||||
const currentUserIds = (users || []).map((user: DomainUser) => user.id!);
|
||||
// 获取选择的成员ID列表
|
||||
const selectedUserIds = event.target.value as string[];
|
||||
|
||||
// 计算新增的成员ID
|
||||
const addedUserIds = selectedUserIds.filter(id => !currentUserIds.includes(id));
|
||||
// 计算移除的成员ID
|
||||
const removedUserIds = currentUserIds.filter((id: string) => !selectedUserIds.includes(id));
|
||||
|
||||
// 调用API添加成员
|
||||
if (addedUserIds.length > 0) {
|
||||
postAddUserToGroup({
|
||||
user_ids: addedUserIds,
|
||||
group_ids: [record.id!]
|
||||
}).then(() => {
|
||||
message.success('成员添加成功');
|
||||
groupData.refresh();
|
||||
}).catch(() => {
|
||||
message.error('成员添加失败');
|
||||
});
|
||||
}
|
||||
|
||||
// 调用API移除成员
|
||||
if (removedUserIds.length > 0) {
|
||||
deleteRemoveUserFromGroup({
|
||||
user_ids: removedUserIds,
|
||||
group_id: record.id!
|
||||
}).then(() => {
|
||||
message.success('成员移除成功');
|
||||
groupData.refresh();
|
||||
}).catch(() => {
|
||||
message.error('成员移除失败');
|
||||
});
|
||||
}
|
||||
setMemberSearchText('');
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
sx={{ p: 1, position: 'sticky', top: -8, zIndex: 1, backgroundColor: 'background.paper' }}
|
||||
return (
|
||||
<FormControl sx={{ width: '100%' }}>
|
||||
<InputLabel size='small'>成员</InputLabel>
|
||||
<Select
|
||||
multiple
|
||||
value={(users || []).map((u: DomainUser) => u.id)}
|
||||
label='成员'
|
||||
size='small'
|
||||
onClose={() => setMemberSearchText('')}
|
||||
onOpen={() => {
|
||||
setTimeout(() => {
|
||||
memberInputRef.current?.focus();
|
||||
}, 100);
|
||||
}}
|
||||
MenuProps={{
|
||||
autoFocus: false,
|
||||
}}
|
||||
renderValue={(selectedIds: string[]) => {
|
||||
if (!Array.isArray(selectedIds)) return null;
|
||||
const selectedUsers = (userData.data?.users || []).filter(
|
||||
(user: DomainUser) => user.id && selectedIds.includes(user.id)
|
||||
);
|
||||
return selectedUsers.map((u: DomainUser) => (
|
||||
<Chip size='small' key={u.id} label={u.username}></Chip>
|
||||
));
|
||||
}}
|
||||
onChange={(event: SelectChangeEvent<string[]>) => {
|
||||
console.log(event.target);
|
||||
// 获取当前分组的成员ID列表
|
||||
const currentUserIds = (users || []).map(
|
||||
(user: DomainUser) => user.id!
|
||||
);
|
||||
// 获取选择的成员ID列表
|
||||
const selectedUserIds = event.target.value as string[];
|
||||
|
||||
// 计算新增的成员ID
|
||||
const addedUserIds = selectedUserIds.filter(
|
||||
(id) => !currentUserIds.includes(id)
|
||||
);
|
||||
// 计算移除的成员ID
|
||||
const removedUserIds = currentUserIds.filter(
|
||||
(id: string) => !selectedUserIds.includes(id)
|
||||
);
|
||||
|
||||
// 调用API添加成员
|
||||
if (addedUserIds.length > 0) {
|
||||
postAddUserToGroup({
|
||||
user_ids: addedUserIds,
|
||||
group_ids: [record.id!],
|
||||
})
|
||||
.then(() => {
|
||||
message.success('成员添加成功');
|
||||
groupData.refresh();
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('成员添加失败');
|
||||
});
|
||||
}
|
||||
|
||||
// 调用API移除成员
|
||||
if (removedUserIds.length > 0) {
|
||||
deleteRemoveUserFromGroup({
|
||||
user_ids: removedUserIds,
|
||||
group_id: record.id!,
|
||||
})
|
||||
.then(() => {
|
||||
message.success('成员移除成功');
|
||||
groupData.refresh();
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('成员移除失败');
|
||||
});
|
||||
}
|
||||
setMemberSearchText('');
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
size="small"
|
||||
fullWidth
|
||||
inputRef={memberInputRef}
|
||||
placeholder="搜索成员"
|
||||
onChange={(e) => setMemberSearchText(e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
{filteredSelectUsers?.map((user) => (
|
||||
<MenuItem key={user.username} value={user.id}>
|
||||
{(users.some((u: DomainUser) => {
|
||||
return u.id === user.id
|
||||
})) ? <>
|
||||
{user.username}<Check sx={{ ml: 2, width: '16px' }} />
|
||||
</> : <>
|
||||
{user.username}
|
||||
</>}
|
||||
</MenuItem>)
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>;
|
||||
<Box
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
sx={{
|
||||
p: 1,
|
||||
position: 'sticky',
|
||||
top: -8,
|
||||
zIndex: 1,
|
||||
backgroundColor: 'background.paper',
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
size='small'
|
||||
fullWidth
|
||||
inputRef={memberInputRef}
|
||||
placeholder='搜索成员'
|
||||
onChange={(e) => setMemberSearchText(e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
{filteredSelectUsers?.map((user) => (
|
||||
<MenuItem key={user.username} value={user.id}>
|
||||
{users.some((u: DomainUser) => {
|
||||
return u.id === user.id;
|
||||
}) ? (
|
||||
<>
|
||||
{user.username}
|
||||
<Check sx={{ ml: 2, width: '16px' }} />
|
||||
</>
|
||||
) : (
|
||||
<>{user.username}</>
|
||||
)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '管理员',
|
||||
dataIndex: 'admins',
|
||||
render: (admins, record) => {
|
||||
return <FormControl sx={{ width: '100%' }}>
|
||||
<InputLabel size='small'>管理员</InputLabel>
|
||||
<Select
|
||||
multiple
|
||||
value={(admins || []).map((u: DomainAdminUser) => u.id)}
|
||||
label='管理员'
|
||||
size='small'
|
||||
onClose={() => setAdminSearchText('')}
|
||||
onOpen={() => {
|
||||
setTimeout(() => {
|
||||
adminInputRef.current?.focus();
|
||||
}, 100);
|
||||
}}
|
||||
MenuProps={{
|
||||
autoFocus: false,
|
||||
}}
|
||||
renderValue={(selectedIds: string[]) => {
|
||||
if (!Array.isArray(selectedIds)) return null;
|
||||
const selectedAdmins = (adminData.data?.users || []).filter((user: DomainAdminUser) =>
|
||||
user.id && selectedIds.includes(user.id)
|
||||
);
|
||||
return selectedAdmins.map((u: DomainAdminUser) => (
|
||||
<Chip size='small' key={u.id} label={u.username}></Chip>
|
||||
));
|
||||
}}
|
||||
onChange={(event: SelectChangeEvent<string[]>) => {
|
||||
console.log(event.target)
|
||||
// 获取当前分组的管理员ID列表
|
||||
const currentAdminIds = (admins || []).map((user: DomainAdminUser) => user.id!);
|
||||
// 获取选择的管理员ID列表
|
||||
const selectedAdminIds = event.target.value as string[];
|
||||
|
||||
// 计算新增的管理员ID
|
||||
const addedAdminIds = selectedAdminIds.filter(id => !currentAdminIds.includes(id));
|
||||
// 计算移除的管理员ID
|
||||
const removedAdminIds = currentAdminIds.filter((id: string) => !selectedAdminIds.includes(id));
|
||||
|
||||
// 调用API添加管理员
|
||||
if (addedAdminIds.length > 0) {
|
||||
postGrantGroup({
|
||||
admin_ids: addedAdminIds,
|
||||
group_ids: [record.id!]
|
||||
}).then(() => {
|
||||
message.success('管理员添加成功');
|
||||
groupData.refresh();
|
||||
}).catch(() => {
|
||||
message.error('管理员添加失败');
|
||||
});
|
||||
}
|
||||
|
||||
// 调用API移除管理员
|
||||
if (removedAdminIds.length > 0) {
|
||||
deleteRemoveAdminFromGroup({
|
||||
admin_ids: removedAdminIds,
|
||||
group_id: record.id!
|
||||
}).then(() => {
|
||||
message.success('管理员移除成功');
|
||||
groupData.refresh();
|
||||
}).catch(() => {
|
||||
message.error('管理员移除失败');
|
||||
});
|
||||
}
|
||||
setAdminSearchText('');
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
sx={{ p: 1, position: 'sticky', top: -8, zIndex: 1, backgroundColor: 'background.paper' }}
|
||||
return (
|
||||
<FormControl sx={{ width: '100%' }}>
|
||||
<InputLabel size='small'>管理员</InputLabel>
|
||||
<Select
|
||||
multiple
|
||||
value={(admins || []).map((u: DomainAdminUser) => u.id)}
|
||||
label='管理员'
|
||||
size='small'
|
||||
onClose={() => setAdminSearchText('')}
|
||||
onOpen={() => {
|
||||
setTimeout(() => {
|
||||
adminInputRef.current?.focus();
|
||||
}, 100);
|
||||
}}
|
||||
MenuProps={{
|
||||
autoFocus: false,
|
||||
}}
|
||||
renderValue={(selectedIds: string[]) => {
|
||||
if (!Array.isArray(selectedIds)) return null;
|
||||
const selectedAdmins = (adminData.data?.users || []).filter(
|
||||
(user: DomainAdminUser) =>
|
||||
user.id && selectedIds.includes(user.id)
|
||||
);
|
||||
return selectedAdmins.map((u: DomainAdminUser) => (
|
||||
<Chip size='small' key={u.id} label={u.username}></Chip>
|
||||
));
|
||||
}}
|
||||
onChange={(event: SelectChangeEvent<string[]>) => {
|
||||
console.log(event.target);
|
||||
// 获取当前分组的管理员ID列表
|
||||
const currentAdminIds = (admins || []).map(
|
||||
(user: DomainAdminUser) => user.id!
|
||||
);
|
||||
// 获取选择的管理员ID列表
|
||||
const selectedAdminIds = event.target.value as string[];
|
||||
|
||||
// 计算新增的管理员ID
|
||||
const addedAdminIds = selectedAdminIds.filter(
|
||||
(id) => !currentAdminIds.includes(id)
|
||||
);
|
||||
// 计算移除的管理员ID
|
||||
const removedAdminIds = currentAdminIds.filter(
|
||||
(id: string) => !selectedAdminIds.includes(id)
|
||||
);
|
||||
|
||||
// 调用API添加管理员
|
||||
if (addedAdminIds.length > 0) {
|
||||
postGrantGroup({
|
||||
admin_ids: addedAdminIds,
|
||||
group_ids: [record.id!],
|
||||
})
|
||||
.then(() => {
|
||||
message.success('管理员添加成功');
|
||||
groupData.refresh();
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('管理员添加失败');
|
||||
});
|
||||
}
|
||||
|
||||
// 调用API移除管理员
|
||||
if (removedAdminIds.length > 0) {
|
||||
deleteRemoveAdminFromGroup({
|
||||
admin_ids: removedAdminIds,
|
||||
group_id: record.id!,
|
||||
})
|
||||
.then(() => {
|
||||
message.success('管理员移除成功');
|
||||
groupData.refresh();
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('管理员移除失败');
|
||||
});
|
||||
}
|
||||
setAdminSearchText('');
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
size="small"
|
||||
fullWidth
|
||||
inputRef={adminInputRef}
|
||||
placeholder="搜索管理员"
|
||||
onChange={(e) => setAdminSearchText(e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
{filteredSelectAdmins?.map((user) => (
|
||||
<MenuItem key={user.username} value={user.id}>
|
||||
{(admins.some((u: DomainAdminUser) => {
|
||||
return u.id === user.id
|
||||
})) ? <>
|
||||
{user.username}<Check sx={{ ml: 2, width: '16px' }} />
|
||||
</> : <>
|
||||
{user.username}
|
||||
</>}
|
||||
</MenuItem>)
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>;
|
||||
<Box
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
sx={{
|
||||
p: 1,
|
||||
position: 'sticky',
|
||||
top: -8,
|
||||
zIndex: 1,
|
||||
backgroundColor: 'background.paper',
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
size='small'
|
||||
fullWidth
|
||||
inputRef={adminInputRef}
|
||||
placeholder='搜索管理员'
|
||||
onChange={(e) => setAdminSearchText(e.target.value)}
|
||||
/>
|
||||
</Box>
|
||||
{filteredSelectAdmins?.map((user) => (
|
||||
<MenuItem key={user.username} value={user.id}>
|
||||
{admins.some((u: DomainAdminUser) => {
|
||||
return u.id === user.id;
|
||||
}) ? (
|
||||
<>
|
||||
{user.username}
|
||||
<Check sx={{ ml: 2, width: '16px' }} />
|
||||
</>
|
||||
) : (
|
||||
<>{user.username}</>
|
||||
)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -335,9 +403,7 @@ const GroupList = () => {
|
||||
return (
|
||||
<Card sx={{ maxHeight: '500px' }}>
|
||||
<Menu anchorEl={anchorEl} open={!!anchorEl} onClose={handleClose}>
|
||||
<MenuItem onClick={onUpdateGroup}>
|
||||
修改成员组名称
|
||||
</MenuItem>
|
||||
<MenuItem onClick={onUpdateGroup}>修改成员组名称</MenuItem>
|
||||
<MenuItem sx={{ color: 'error.main' }} onClick={onDeleteGroup}>
|
||||
删除成员组
|
||||
</MenuItem>
|
||||
@@ -351,13 +417,21 @@ const GroupList = () => {
|
||||
>
|
||||
<Box sx={{ fontWeight: 700 }}>成员组</Box>
|
||||
<Stack direction='row' gap={1}>
|
||||
<TextField label='搜索' size='small' onChange={(e)=>setSearchUser(e.target.value)} />
|
||||
<TextField
|
||||
label='搜索'
|
||||
size='small'
|
||||
onChange={(e) => setSearchUser(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant='contained'
|
||||
color='primary'
|
||||
onClick={() => setOpenCreateGroupModal(true)}
|
||||
disabled={license?.edition !== DomainLicenseEdition.LicenseEditionEnterprise}
|
||||
>创建成员组</Button>
|
||||
disabled={
|
||||
license?.edition !== DomainLicenseEdition.LicenseEditionEnterprise
|
||||
}
|
||||
>
|
||||
创建成员组
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Table
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import Card from '@/components/card';
|
||||
import {
|
||||
Grid2 as Grid,
|
||||
Stack,
|
||||
styled,
|
||||
Switch,
|
||||
Button,
|
||||
Box,
|
||||
} from '@mui/material';
|
||||
import { Grid, Stack, styled, Switch, Button, Box } from '@mui/material';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { getGetSetting, putUpdateSetting } from '@/api/Admin';
|
||||
import MemberManage from './memberManage';
|
||||
import LoginHistory from './loginHistory';
|
||||
import { DomainLicenseEdition, v1LicenseList } from '@/api';
|
||||
import { message } from '@c-x/ui';
|
||||
import { message } from '@ctzhian/ui';
|
||||
import ThirdPartyLoginSettingModal from './thirdPartyLoginSettingModal';
|
||||
import GroupList from './groupList';
|
||||
|
||||
@@ -124,7 +117,10 @@ const User = () => {
|
||||
color='info'
|
||||
sx={{ gap: 2 }}
|
||||
onClick={() => setThirdPartyLoginSettingModalOpen(true)}
|
||||
disabled={license?.edition !== DomainLicenseEdition.LicenseEditionEnterprise}
|
||||
disabled={
|
||||
license?.edition !==
|
||||
DomainLicenseEdition.LicenseEditionEnterprise
|
||||
}
|
||||
>
|
||||
配置
|
||||
</Button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Modal, message, Loading } from '@c-x/ui';
|
||||
import { Modal, message, Loading } from '@ctzhian/ui';
|
||||
import { Box, Typography, IconButton, Paper } from '@mui/material';
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||
|
||||
@@ -2,9 +2,9 @@ import Card from '@/components/card';
|
||||
import { Stack, Box } from '@mui/material';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { getLoginHistory } from '@/api/User';
|
||||
import { Table } from '@c-x/ui';
|
||||
import { Table } from '@ctzhian/ui';
|
||||
import dayjs from 'dayjs';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import { DomainListLoginHistoryResp } from '@/api/types';
|
||||
import User from '@/components/user';
|
||||
|
||||
@@ -20,7 +20,13 @@ const LoginHistory = () => {
|
||||
dataIndex: 'user',
|
||||
render: (user, record) => {
|
||||
return (
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
<User
|
||||
username={record.user!.username!}
|
||||
id={record.user!.id!}
|
||||
@@ -38,10 +44,23 @@ const LoginHistory = () => {
|
||||
render: (ip, record) => {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.device}
|
||||
</Box>
|
||||
<Box sx={{ color: 'text.secondary', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.hostname}
|
||||
</Box>
|
||||
</Stack>
|
||||
@@ -54,10 +73,23 @@ const LoginHistory = () => {
|
||||
render: (ip, record) => {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.client_id}
|
||||
</Box>
|
||||
<Box sx={{ color: 'text.secondary', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.client_version}
|
||||
</Box>
|
||||
</Stack>
|
||||
@@ -70,11 +102,26 @@ const LoginHistory = () => {
|
||||
render: (ip, record) => {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.ip_info?.ip}
|
||||
</Box>
|
||||
<Box sx={{ color: 'text.secondary', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
{record?.ip_info?.country === '中国' ? ('' + record?.ip_info?.province + '-' + record?.ip_info?.city) : (record?.ip_info?.country || '未知')}
|
||||
<Box
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{record?.ip_info?.country === '中国'
|
||||
? '' + record?.ip_info?.province + '-' + record?.ip_info?.city
|
||||
: record?.ip_info?.country || '未知'}
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
@@ -86,14 +133,26 @@ const LoginHistory = () => {
|
||||
render: (text) => {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{dayjs.unix(text).format('YYYY-MM-DD')}
|
||||
</Box>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{dayjs.unix(text).format('HH:mm:ss')}
|
||||
</Box>
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -17,9 +17,9 @@ import {
|
||||
MenuItem,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import { Table, MenuSelect, Modal, message } from '@c-x/ui';
|
||||
import { Table, MenuSelect, Modal, message } from '@ctzhian/ui';
|
||||
import InviteUserModal from './inviteUserModal';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import { ConstsUserStatus, DomainUser } from '@/api/types';
|
||||
import dayjs from 'dayjs';
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||
@@ -150,22 +150,28 @@ const MemberManage = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [resetPasswordOpen, setResetPasswordOpen] = useState(false);
|
||||
const [currentUser, setCurrentUser] = useState<DomainUser | null>(null);
|
||||
const { data: originData, loading, refresh } = useRequest(() => getListUser({page: 1, size: 999}));
|
||||
const {
|
||||
data: originData,
|
||||
loading,
|
||||
refresh,
|
||||
} = useRequest(() => getListUser({ page: 1, size: 999 }));
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const [searchUser, setSearchUser] = useState('');
|
||||
const [data, setData] = useState<DomainUser[]>([]);
|
||||
useEffect(()=>{
|
||||
if(searchUser){
|
||||
setData(originData?.users?.filter((item) => {
|
||||
const searchTerm = searchUser.toLowerCase();
|
||||
const username = (item.username || '').toLowerCase();
|
||||
const email = (item.email || '').toLowerCase();
|
||||
return username.includes(searchTerm) || email.includes(searchTerm);
|
||||
}) || []);
|
||||
}else {
|
||||
useEffect(() => {
|
||||
if (searchUser) {
|
||||
setData(
|
||||
originData?.users?.filter((item) => {
|
||||
const searchTerm = searchUser.toLowerCase();
|
||||
const username = (item.username || '').toLowerCase();
|
||||
const email = (item.email || '').toLowerCase();
|
||||
return username.includes(searchTerm) || email.includes(searchTerm);
|
||||
}) || []
|
||||
);
|
||||
} else {
|
||||
setData(originData?.users || []);
|
||||
}
|
||||
},[searchUser, originData])
|
||||
}, [searchUser, originData]);
|
||||
const handleClick = (
|
||||
event: React.MouseEvent<HTMLButtonElement>,
|
||||
record: DomainUser
|
||||
@@ -344,7 +350,11 @@ const MemberManage = () => {
|
||||
>
|
||||
<Box sx={{ fontWeight: 700 }}>成员列表</Box>
|
||||
<Stack direction='row' gap={1}>
|
||||
<TextField label='搜索' size='small' onChange={(e)=>setSearchUser(e.target.value)} />
|
||||
<TextField
|
||||
label='搜索'
|
||||
size='small'
|
||||
onChange={(e) => setSearchUser(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant='contained'
|
||||
color='primary'
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
Autocomplete,
|
||||
Chip,
|
||||
} from '@mui/material';
|
||||
import { Modal, message } from '@c-x/ui';
|
||||
import { Modal, message } from '@ctzhian/ui';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { FormItem } from '@/components/form';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Modal, message } from '@c-x/ui';
|
||||
import { Modal, message } from '@ctzhian/ui';
|
||||
import { Box, TextField } from '@mui/material';
|
||||
import { putUpdateUserGroup } from '@/api/UserGroup';
|
||||
import { DomainUserGroup } from '@/api/types';
|
||||
@@ -11,7 +11,12 @@ interface UpdateGroupModalProps {
|
||||
group: DomainUserGroup | null;
|
||||
}
|
||||
|
||||
const UpdateGroupModal = ({ open, onClose, onUpdated, group }: UpdateGroupModalProps) => {
|
||||
const UpdateGroupModal = ({
|
||||
open,
|
||||
onClose,
|
||||
onUpdated,
|
||||
group,
|
||||
}: UpdateGroupModalProps) => {
|
||||
const [groupName, setGroupName] = useState('');
|
||||
|
||||
// 当group变化时,更新表单中的组名
|
||||
@@ -67,4 +72,4 @@ const UpdateGroupModal = ({ open, onClose, onUpdated, group }: UpdateGroupModalP
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateGroupModal;
|
||||
export default UpdateGroupModal;
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import React, { useState } from 'react';
|
||||
import Card from '@/components/card';
|
||||
import { deleteDeleteModel, putUpdateModel } from '@/api/Model';
|
||||
import {
|
||||
deleteDeleteModel,
|
||||
putUpdateModel,
|
||||
} from '@/api/Model';
|
||||
import { DomainModel, GithubComChaitinMonkeyCodeBackendConstsModelStatus, GithubComChaitinMonkeyCodeBackendConstsModelType, } from '@/api/types';
|
||||
import { Stack, Box, Button, Grid2 as Grid, ButtonBase } from '@mui/material';
|
||||
import { Icon, Modal, message } from '@c-x/ui';
|
||||
DomainModel,
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus,
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelType,
|
||||
} from '@/api/types';
|
||||
import { Stack, Box, Button, Grid, ButtonBase } from '@mui/material';
|
||||
import { Icon, Modal, message } from '@ctzhian/ui';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
import NoData from '@/assets/images/nodata.png';
|
||||
import { ModelModal, DEFAULT_MODEL_PROVIDERS} from '@yokowu/modelkit-ui';
|
||||
import { localModelToModelKitModel, modelService } from '@/pages/model/components/services/modelService';
|
||||
import { ModelModal, DEFAULT_MODEL_PROVIDERS } from '@yokowu/modelkit-ui';
|
||||
import {
|
||||
localModelToModelKitModel,
|
||||
modelService,
|
||||
} from '@/pages/model/components/services/modelService';
|
||||
|
||||
const ModelItem = ({
|
||||
data,
|
||||
@@ -40,7 +44,8 @@ const ModelItem = ({
|
||||
onOk: () => {
|
||||
putUpdateModel({
|
||||
id: data.id,
|
||||
status: GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusInactive,
|
||||
status:
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusInactive,
|
||||
provider: data.provider!,
|
||||
}).then(() => {
|
||||
message.success('停用成功');
|
||||
@@ -90,7 +95,8 @@ const ModelItem = ({
|
||||
onOk: () => {
|
||||
putUpdateModel({
|
||||
id: data.id,
|
||||
status: GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusDefault,
|
||||
status:
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusDefault,
|
||||
provider: data.provider!,
|
||||
}).then(() => {
|
||||
message.success('设为默认模型成功');
|
||||
@@ -115,7 +121,8 @@ const ModelItem = ({
|
||||
onOk: () => {
|
||||
putUpdateModel({
|
||||
id: data.id,
|
||||
status: GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusActive,
|
||||
status:
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusActive,
|
||||
provider: data.provider!,
|
||||
}).then(() => {
|
||||
message.success('激活成功');
|
||||
@@ -128,7 +135,11 @@ const ModelItem = ({
|
||||
// 添加状态标签渲染函数
|
||||
const renderStatusLabel = () => {
|
||||
// 根据 is_active 和 status 字段判断状态
|
||||
if (data.is_active && data.status === GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusActive) {
|
||||
if (
|
||||
data.is_active &&
|
||||
data.status ===
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusActive
|
||||
) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@@ -151,13 +162,16 @@ const ModelItem = ({
|
||||
borderLeft: '6px solid transparent',
|
||||
borderTop: '6px solid',
|
||||
borderTopColor: 'success.dark',
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
可选
|
||||
</Box>
|
||||
);
|
||||
} else if (data.status === GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusInactive) {
|
||||
} else if (
|
||||
data.status ===
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusInactive
|
||||
) {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@@ -180,7 +194,7 @@ const ModelItem = ({
|
||||
borderLeft: '6px solid transparent',
|
||||
borderTop: '6px solid',
|
||||
borderTopColor: 'grey.600',
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
未激活
|
||||
@@ -210,7 +224,7 @@ const ModelItem = ({
|
||||
borderLeft: '6px solid transparent',
|
||||
borderTop: '6px solid',
|
||||
borderTopColor: 'primary.dark',
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
默认
|
||||
@@ -257,9 +271,14 @@ const ModelItem = ({
|
||||
<Stack direction='row' alignItems='center' gap={1}>
|
||||
<Icon
|
||||
type={
|
||||
DEFAULT_MODEL_PROVIDERS[data.provider as keyof typeof DEFAULT_MODEL_PROVIDERS]?.icon
|
||||
DEFAULT_MODEL_PROVIDERS[
|
||||
data.provider as keyof typeof DEFAULT_MODEL_PROVIDERS
|
||||
]?.icon
|
||||
}
|
||||
sx={{ fontSize: 24, color: data.is_active ? 'inherit' : 'grey.400' }}
|
||||
sx={{
|
||||
fontSize: 24,
|
||||
color: data.is_active ? 'inherit' : 'grey.400',
|
||||
}}
|
||||
/>
|
||||
<Stack
|
||||
direction='row'
|
||||
@@ -326,16 +345,20 @@ const ModelItem = ({
|
||||
gap={2}
|
||||
sx={{ mt: 2 }}
|
||||
>
|
||||
<Stack direction='row' alignItems='center'> </Stack>
|
||||
<Stack direction='row' alignItems='center'>
|
||||
{' '}
|
||||
</Stack>
|
||||
<Stack direction='row' sx={{ button: { minWidth: 0 } }} gap={2}>
|
||||
{(data.status === GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusActive ||
|
||||
data.status === GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusInactive) && (
|
||||
{(data.status ===
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusActive ||
|
||||
data.status ===
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusInactive) && (
|
||||
<ButtonBase
|
||||
disableRipple
|
||||
sx={{
|
||||
color: 'text.primary',
|
||||
'&:hover': {
|
||||
fontWeight: 700
|
||||
fontWeight: 700,
|
||||
},
|
||||
}}
|
||||
onClick={onSetDefaultModel}
|
||||
@@ -344,22 +367,23 @@ const ModelItem = ({
|
||||
</ButtonBase>
|
||||
)}
|
||||
|
||||
{data.status === GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusInactive &&
|
||||
data.model_type !== GithubComChaitinMonkeyCodeBackendConstsModelType.ModelTypeCoder &&
|
||||
(
|
||||
<ButtonBase
|
||||
disableRipple
|
||||
sx={{
|
||||
color: 'success.main',
|
||||
'&:hover': {
|
||||
fontWeight: 700
|
||||
},
|
||||
}}
|
||||
onClick={onActiveModel}
|
||||
>
|
||||
激活
|
||||
</ButtonBase>
|
||||
)}
|
||||
{data.status ===
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelStatus.ModelStatusInactive &&
|
||||
data.model_type !==
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelType.ModelTypeCoder && (
|
||||
<ButtonBase
|
||||
disableRipple
|
||||
sx={{
|
||||
color: 'success.main',
|
||||
'&:hover': {
|
||||
fontWeight: 700,
|
||||
},
|
||||
}}
|
||||
onClick={onActiveModel}
|
||||
>
|
||||
激活
|
||||
</ButtonBase>
|
||||
)}
|
||||
|
||||
{!data.is_internal && (
|
||||
<ButtonBase
|
||||
@@ -367,7 +391,7 @@ const ModelItem = ({
|
||||
sx={{
|
||||
color: 'info.main',
|
||||
'&:hover': {
|
||||
fontWeight: 700
|
||||
fontWeight: 700,
|
||||
},
|
||||
}}
|
||||
onClick={() => onEdit(data)}
|
||||
@@ -382,7 +406,7 @@ const ModelItem = ({
|
||||
sx={{
|
||||
color: 'error.main',
|
||||
'&:hover': {
|
||||
fontWeight: 700
|
||||
fontWeight: 700,
|
||||
},
|
||||
}}
|
||||
onClick={onInactiveModel}
|
||||
@@ -397,7 +421,7 @@ const ModelItem = ({
|
||||
sx={{
|
||||
color: 'error.main',
|
||||
'&:hover': {
|
||||
fontWeight: 700
|
||||
fontWeight: 700,
|
||||
},
|
||||
}}
|
||||
onClick={onRemoveModel}
|
||||
@@ -471,7 +495,7 @@ const ModelCard: React.FC<IModelCardProps> = ({
|
||||
data={editData ? localModelToModelKitModel(editData) : null}
|
||||
model_type={modelType}
|
||||
modelService={modelService}
|
||||
language="zh-CN"
|
||||
language='zh-CN'
|
||||
messageComponent={message}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -4,7 +4,7 @@ import ModelCard from './components/modelCard';
|
||||
import { Stack } from '@mui/material';
|
||||
import { GithubComChaitinMonkeyCodeBackendConstsModelType } from '@/api/types';
|
||||
import { useCommonContext } from '@/hooks/context';
|
||||
import { Modal } from '@c-x/ui';
|
||||
import { Modal } from '@ctzhian/ui';
|
||||
|
||||
const Model = () => {
|
||||
const { coderModel, llmModel, refreshModel, isConfigModel, modelLoading } =
|
||||
@@ -43,13 +43,17 @@ const Model = () => {
|
||||
title='对话模型'
|
||||
data={llmModel}
|
||||
refreshModel={refreshModel}
|
||||
modelType={GithubComChaitinMonkeyCodeBackendConstsModelType.ModelTypeLLM}
|
||||
modelType={
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelType.ModelTypeLLM
|
||||
}
|
||||
/>
|
||||
<ModelCard
|
||||
title='代码补全模型'
|
||||
data={coderModel}
|
||||
refreshModel={refreshModel}
|
||||
modelType={GithubComChaitinMonkeyCodeBackendConstsModelType.ModelTypeCoder}
|
||||
modelType={
|
||||
GithubComChaitinMonkeyCodeBackendConstsModelType.ModelTypeCoder
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import Avatar from '@/components/avatar';
|
||||
import Card from '@/components/card';
|
||||
import { getUserChatInfo } from '@/api/UserRecord';
|
||||
import MarkDown from '@/components/markDown';
|
||||
import { Ellipsis, Modal } from '@c-x/ui';
|
||||
import { Ellipsis, Modal } from '@ctzhian/ui';
|
||||
import { styled } from '@mui/material';
|
||||
import logo from '@/assets/images/logo.png';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Table } from '@c-x/ui';
|
||||
import { Table } from '@ctzhian/ui';
|
||||
import { getUserListChatRecord } from '@/api/UserRecord';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
import StyledLabel from '@/components/label';
|
||||
|
||||
import ChatDetailModal from './chatDetailModal';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import { DomainChatRecord, DomainUser } from '@/api/types';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
import User from '@/components/user';
|
||||
@@ -153,14 +153,26 @@ const Chat = () => {
|
||||
render(value: number) {
|
||||
return (
|
||||
<Stack direction='column'>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{dayjs.unix(value).format('YYYY-MM-DD')}
|
||||
</Box>
|
||||
<Box sx={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||
<Box
|
||||
sx={{
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{dayjs.unix(value).format('HH:mm:ss')}
|
||||
</Box>
|
||||
</Stack>
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Card from '@/components/card';
|
||||
import { getUserCompletionInfo } from '@/api/UserRecord';
|
||||
import { Modal } from '@c-x/ui';
|
||||
import { Modal } from '@ctzhian/ui';
|
||||
import MonacoEditor from '@monaco-editor/react';
|
||||
import { loader } from '@monaco-editor/react';
|
||||
import * as monaco from 'monaco-editor';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { DomainCompletionRecord, DomainUser } from '@/api/types';
|
||||
import { getUserListCompletionRecord } from '@/api/UserRecord';
|
||||
import { Table } from '@c-x/ui';
|
||||
import { Table } from '@ctzhian/ui';
|
||||
import Card from '@/components/card';
|
||||
import {
|
||||
Box,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from '@mui/material';
|
||||
import dayjs from 'dayjs';
|
||||
import { useDebounceFn } from 'ahooks';
|
||||
import { ColumnsType } from '@c-x/ui/dist/Table';
|
||||
import { ColumnsType } from '@ctzhian/ui/dist/Table';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
import CompletionDetailModal from './completionDetailModal';
|
||||
import StyledLabel from '@/components/label';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Grid2 as Grid } from '@mui/material';
|
||||
import { Grid } from '@mui/material';
|
||||
import MemberInfo from '@/pages/dashboard/components/memberInfo';
|
||||
import PieCharts from '@/pages/dashboard/components/pieCharts';
|
||||
import LineCharts from '@/pages/dashboard/components/lineCharts';
|
||||
|
||||
@@ -8,13 +8,13 @@ import {
|
||||
Container,
|
||||
Paper,
|
||||
CircularProgress,
|
||||
Grid2 as Grid,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
Divider,
|
||||
Stack,
|
||||
} from '@mui/material';
|
||||
import { Icon, message } from '@c-x/ui';
|
||||
import { Icon, message } from '@ctzhian/ui';
|
||||
|
||||
import { getRedirectUrl } from '@/utils';
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from '@mui/material';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import PhotoCameraIcon from '@mui/icons-material/PhotoCamera';
|
||||
import { message, Modal } from '@c-x/ui';
|
||||
import { message, Modal } from '@ctzhian/ui';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { useRequest } from 'ahooks';
|
||||
import Card from '@/components/card';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { createTheme, Paper } from '@mui/material';
|
||||
import type { Shadows } from '@mui/material';
|
||||
import { zhCN } from '@mui/material/locale';
|
||||
import { zhCN as CuiZhCN } from '@c-x/ui/dist/local';
|
||||
import { zhCN as CuiZhCN } from '@ctzhian/ui/dist/local';
|
||||
import onData from '@/assets/images/nodata.png';
|
||||
import { common } from '@mui/material/colors';
|
||||
|
||||
@@ -34,7 +34,7 @@ const lightTheme = createTheme(
|
||||
risk: {
|
||||
severe: '#FF6262',
|
||||
critical: '#FFA762',
|
||||
suggest: '#FFCF62'
|
||||
suggest: '#FFCF62',
|
||||
},
|
||||
disabled: {
|
||||
main: '#666',
|
||||
@@ -179,7 +179,7 @@ const lightTheme = createTheme(
|
||||
styleOverrides: {
|
||||
root: {
|
||||
color: 'unset',
|
||||
fontSize: '0.8rem',
|
||||
fontSize: '0.8rem',
|
||||
fontFamily: 'var(--font-gilory), var(--font-HarmonyOS)',
|
||||
},
|
||||
asterisk: {
|
||||
@@ -197,14 +197,14 @@ const lightTheme = createTheme(
|
||||
MuiRadio: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontSize: '0.8rem',
|
||||
fontSize: '0.8rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiFormControlLabel: {
|
||||
styleOverrides: {
|
||||
label: {
|
||||
fontSize: '0.8rem',
|
||||
fontSize: '0.8rem',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user