update
This commit is contained in:
parent
521255c1af
commit
9add82dc7e
@ -20,12 +20,14 @@
|
|||||||
"@ant-design/icons": "^6.0.0",
|
"@ant-design/icons": "^6.0.0",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
|
"@kevisual/cache": "^0.0.1",
|
||||||
"@kevisual/codemirror": "workspace:*",
|
"@kevisual/codemirror": "workspace:*",
|
||||||
"@kevisual/components": "workspace:*",
|
"@kevisual/components": "workspace:*",
|
||||||
"@kevisual/container": "1.0.0",
|
"@kevisual/container": "1.0.0",
|
||||||
"@kevisual/query": "^0.0.15",
|
"@kevisual/query": "^0.0.15",
|
||||||
"@kevisual/query-config": "workspace:*",
|
"@kevisual/query-config": "workspace:*",
|
||||||
"@kevisual/query-login": "workspace:*",
|
"@kevisual/query-login": "workspace:*",
|
||||||
|
"@kevisual/query-upload": "workspace:*",
|
||||||
"@kevisual/resources": "workspace:*",
|
"@kevisual/resources": "workspace:*",
|
||||||
"@monaco-editor/react": "^4.7.0",
|
"@monaco-editor/react": "^4.7.0",
|
||||||
"@mui/material": "^7.0.1",
|
"@mui/material": "^7.0.1",
|
||||||
@ -47,6 +49,7 @@
|
|||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
|
"react-dropzone": "^14.3.8",
|
||||||
"react-hook-form": "^7.55.0",
|
"react-hook-form": "^7.55.0",
|
||||||
"react-i18next": "^15.4.1",
|
"react-i18next": "^15.4.1",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^2.1.7",
|
||||||
|
@ -20,6 +20,7 @@ type BaseEditorOpts = {
|
|||||||
open?: boolean;
|
open?: boolean;
|
||||||
overrideList?: Completion[];
|
overrideList?: Completion[];
|
||||||
};
|
};
|
||||||
|
onChange?: (value: string) => void;
|
||||||
};
|
};
|
||||||
export class BaseEditor {
|
export class BaseEditor {
|
||||||
editor?: EditorView;
|
editor?: EditorView;
|
||||||
@ -32,7 +33,7 @@ export class BaseEditor {
|
|||||||
open?: boolean;
|
open?: boolean;
|
||||||
overrideList?: Completion[];
|
overrideList?: Completion[];
|
||||||
};
|
};
|
||||||
|
onChange?: (value: string) => void;
|
||||||
constructor(opts?: BaseEditorOpts) {
|
constructor(opts?: BaseEditorOpts) {
|
||||||
this.filename = opts?.filename || '';
|
this.filename = opts?.filename || '';
|
||||||
this.language = opts?.language || 'typescript';
|
this.language = opts?.language || 'typescript';
|
||||||
@ -43,6 +44,7 @@ export class BaseEditor {
|
|||||||
}
|
}
|
||||||
this.autoComplete = opts?.autoComplete || { open: true, overrideList: [] };
|
this.autoComplete = opts?.autoComplete || { open: true, overrideList: [] };
|
||||||
this.onChangeCompartment = new Compartment(); // 创建一个用于 onChange 的独立扩展
|
this.onChangeCompartment = new Compartment(); // 创建一个用于 onChange 的独立扩展
|
||||||
|
this.onChange = opts?.onChange;
|
||||||
}
|
}
|
||||||
onEditorChange(view: EditorView) {
|
onEditorChange(view: EditorView) {
|
||||||
console.log('onChange', view);
|
console.log('onChange', view);
|
||||||
@ -54,6 +56,7 @@ export class BaseEditor {
|
|||||||
this.el = el;
|
this.el = el;
|
||||||
const onChangeCompartment = this.onChangeCompartment!;
|
const onChangeCompartment = this.onChangeCompartment!;
|
||||||
const language = this.language;
|
const language = this.language;
|
||||||
|
const onChange = this.onChange;
|
||||||
const extensions: Extension[] = [
|
const extensions: Extension[] = [
|
||||||
vscodeLight,
|
vscodeLight,
|
||||||
formatKeymap,
|
formatKeymap,
|
||||||
@ -91,7 +94,15 @@ export class BaseEditor {
|
|||||||
parent: el,
|
parent: el,
|
||||||
extensions: [
|
extensions: [
|
||||||
...extensions, //
|
...extensions, //
|
||||||
onChangeCompartment.of([]),
|
onChangeCompartment.of([
|
||||||
|
[
|
||||||
|
EditorView.updateListener.of((update) => {
|
||||||
|
if (update.changes.length > 0) {
|
||||||
|
onChange?.(update.state.doc.toString());
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
]),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ export { PermissionManager } from './pages/file/modules/PermissionManager.tsx';
|
|||||||
export { PermissionModal, usePermissionModal } from './pages/file/modules/PermissionModal.tsx';
|
export { PermissionModal, usePermissionModal } from './pages/file/modules/PermissionModal.tsx';
|
||||||
export { iText } from './i-text/index.ts';
|
export { iText } from './i-text/index.ts';
|
||||||
|
|
||||||
export { uploadFiles, uploadFileChunked, getDirectoryAndName, toFile, createDirectory } from './pages/upload/app';
|
export { uploadFiles, uploadFileChunked, getDirectoryAndName, createDirectory } from './pages/upload/app';
|
||||||
export { DialogDirectory, DialogDeleteDirectory } from './pages/upload/DialogDirectory';
|
export { DialogDirectory, DialogDeleteDirectory } from './pages/upload/DialogDirectory';
|
||||||
|
|
||||||
export { uploadChunkV2 } from './pages/upload/v2/upload-chunk';
|
export { uploadChunkV2, toFile } from './pages/upload/v2/upload-chunk';
|
||||||
|
@ -4,7 +4,7 @@ import { Id, toast } from 'react-toastify';
|
|||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { toastLogin } from '@kevisual/resources/pages/message/ToastLogin';
|
import { toastLogin } from '@kevisual/resources/pages/message/ToastLogin';
|
||||||
import { uploadFileChunked, UploadProgress } from '@kevisual/query-upload/query-upload';
|
import { uploadFileChunked, UploadProgress } from '@kevisual/query-upload/query-upload';
|
||||||
|
import { toFile } from '@kevisual/query-upload/query-upload';
|
||||||
export type ConvertOpts = {
|
export type ConvertOpts = {
|
||||||
appKey?: string;
|
appKey?: string;
|
||||||
version?: string;
|
version?: string;
|
||||||
@ -12,6 +12,10 @@ export type ConvertOpts = {
|
|||||||
directory?: string;
|
directory?: string;
|
||||||
isPublic?: boolean;
|
isPublic?: boolean;
|
||||||
filename?: string;
|
filename?: string;
|
||||||
|
/**
|
||||||
|
* 是否不检查应用文件, 默认 true,默认不检测
|
||||||
|
*/
|
||||||
|
noCheckAppFiles?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const uploadChunkV2 = async (file: File, opts: ConvertOpts) => {
|
export const uploadChunkV2 = async (file: File, opts: ConvertOpts) => {
|
||||||
@ -53,3 +57,4 @@ export const uploadChunkV2 = async (file: File, opts: ConvertOpts) => {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
export { toFile };
|
||||||
|
197
pnpm-lock.yaml
generated
197
pnpm-lock.yaml
generated
@ -17,6 +17,9 @@ importers:
|
|||||||
'@emotion/styled':
|
'@emotion/styled':
|
||||||
specifier: ^11.14.0
|
specifier: ^11.14.0
|
||||||
version: 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
version: 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
||||||
|
'@kevisual/cache':
|
||||||
|
specifier: ^0.0.1
|
||||||
|
version: 0.0.1(rollup@4.37.0)(tslib@2.8.1)(typescript@5.8.2)
|
||||||
'@kevisual/codemirror':
|
'@kevisual/codemirror':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:packages/codemirror
|
version: link:packages/codemirror
|
||||||
@ -35,6 +38,9 @@ importers:
|
|||||||
'@kevisual/query-login':
|
'@kevisual/query-login':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:submodules/query-login
|
version: link:submodules/query-login
|
||||||
|
'@kevisual/query-upload':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:submodules/query-upload
|
||||||
'@kevisual/resources':
|
'@kevisual/resources':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:packages/resources
|
version: link:packages/resources
|
||||||
@ -98,6 +104,9 @@ importers:
|
|||||||
react-dom:
|
react-dom:
|
||||||
specifier: 19.1.0
|
specifier: 19.1.0
|
||||||
version: 19.1.0(react@19.1.0)
|
version: 19.1.0(react@19.1.0)
|
||||||
|
react-dropzone:
|
||||||
|
specifier: ^14.3.8
|
||||||
|
version: 14.3.8(react@19.1.0)
|
||||||
react-hook-form:
|
react-hook-form:
|
||||||
specifier: ^7.55.0
|
specifier: ^7.55.0
|
||||||
version: 7.55.0(react@19.1.0)
|
version: 7.55.0(react@19.1.0)
|
||||||
@ -339,29 +348,29 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@emotion/react':
|
'@emotion/react':
|
||||||
specifier: ^11.14.0
|
specifier: ^11.14.0
|
||||||
version: 11.14.0(@types/react@19.1.0)(react@19.0.0)
|
version: 11.14.0(@types/react@19.1.0)(react@19.1.0)
|
||||||
'@emotion/styled':
|
'@emotion/styled':
|
||||||
specifier: ^11.14.0
|
specifier: ^11.14.0
|
||||||
version: 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0)
|
version: 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
||||||
'@mui/material':
|
'@mui/material':
|
||||||
specifier: ^6.4.7
|
specifier: ^7.0.1
|
||||||
version: 6.4.7(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
version: 7.0.1(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
react:
|
react:
|
||||||
specifier: 19.0.0
|
specifier: 19.1.0
|
||||||
version: 19.0.0
|
version: 19.1.0
|
||||||
react-dom:
|
react-dom:
|
||||||
specifier: 19.0.0
|
specifier: 19.1.0
|
||||||
version: 19.0.0(react@19.0.0)
|
version: 19.1.0(react@19.1.0)
|
||||||
react-hook-form:
|
react-hook-form:
|
||||||
specifier: ^7.54.2
|
specifier: ^7.55.0
|
||||||
version: 7.54.2(react@19.0.0)
|
version: 7.55.0(react@19.1.0)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
clsx:
|
clsx:
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 2.1.1
|
version: 2.1.1
|
||||||
tailwind-merge:
|
tailwind-merge:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.1.0
|
||||||
version: 3.0.2
|
version: 3.1.0
|
||||||
|
|
||||||
packages/kevisual-official:
|
packages/kevisual-official:
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1548,35 +1557,12 @@ packages:
|
|||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
'@mui/core-downloads-tracker@6.4.7':
|
|
||||||
resolution: {integrity: sha512-XjJrKFNt9zAKvcnoIIBquXyFyhfrHYuttqMsoDS7lM7VwufYG4fAPw4kINjBFg++fqXM2BNAuWR9J7XVIuKIKg==}
|
|
||||||
|
|
||||||
'@mui/core-downloads-tracker@6.4.8':
|
'@mui/core-downloads-tracker@6.4.8':
|
||||||
resolution: {integrity: sha512-vjP4+A1ybyCRhDZC7r5EPWu/gLseFZxaGyPdDl94vzVvk6Yj6gahdaqcjbhkaCrJjdZj90m3VioltWPAnWF/zw==}
|
resolution: {integrity: sha512-vjP4+A1ybyCRhDZC7r5EPWu/gLseFZxaGyPdDl94vzVvk6Yj6gahdaqcjbhkaCrJjdZj90m3VioltWPAnWF/zw==}
|
||||||
|
|
||||||
'@mui/core-downloads-tracker@7.0.1':
|
'@mui/core-downloads-tracker@7.0.1':
|
||||||
resolution: {integrity: sha512-T5DNVnSD9pMbj4Jk/Uphz+yvj9dfpl2+EqsOuJtG12HxEihNG5pd3qzX5yM1Id4dDwKRvM3dPVcxyzavTFhJeA==}
|
resolution: {integrity: sha512-T5DNVnSD9pMbj4Jk/Uphz+yvj9dfpl2+EqsOuJtG12HxEihNG5pd3qzX5yM1Id4dDwKRvM3dPVcxyzavTFhJeA==}
|
||||||
|
|
||||||
'@mui/material@6.4.7':
|
|
||||||
resolution: {integrity: sha512-K65StXUeGAtFJ4ikvHKtmDCO5Ab7g0FZUu2J5VpoKD+O6Y3CjLYzRi+TMlI3kaL4CL158+FccMoOd/eaddmeRQ==}
|
|
||||||
engines: {node: '>=14.0.0'}
|
|
||||||
peerDependencies:
|
|
||||||
'@emotion/react': ^11.5.0
|
|
||||||
'@emotion/styled': ^11.3.0
|
|
||||||
'@mui/material-pigment-css': ^6.4.7
|
|
||||||
'@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/material@6.4.8':
|
'@mui/material@6.4.8':
|
||||||
resolution: {integrity: sha512-5S9UTjKZZBd9GfbcYh/nYfD9cv6OXmj5Y7NgKYfk7JcSoshp8/pW5zP4wecRiroBSZX8wcrywSgogpVNO+5W0Q==}
|
resolution: {integrity: sha512-5S9UTjKZZBd9GfbcYh/nYfD9cv6OXmj5Y7NgKYfk7JcSoshp8/pW5zP4wecRiroBSZX8wcrywSgogpVNO+5W0Q==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -1617,16 +1603,6 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@mui/private-theming@6.4.6':
|
|
||||||
resolution: {integrity: sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==}
|
|
||||||
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/private-theming@6.4.8':
|
'@mui/private-theming@6.4.8':
|
||||||
resolution: {integrity: sha512-sWwQoNSn6elsPTAtSqCf+w5aaGoh7AASURNmpy+QTTD/zwJ0Jgwt0ZaaP6mXq2IcgHxYnYloM/+vJgHPMkRKTQ==}
|
resolution: {integrity: sha512-sWwQoNSn6elsPTAtSqCf+w5aaGoh7AASURNmpy+QTTD/zwJ0Jgwt0ZaaP6mXq2IcgHxYnYloM/+vJgHPMkRKTQ==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -1647,19 +1623,6 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@mui/styled-engine@6.4.6':
|
|
||||||
resolution: {integrity: sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==}
|
|
||||||
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/styled-engine@6.4.8':
|
'@mui/styled-engine@6.4.8':
|
||||||
resolution: {integrity: sha512-oyjx1b1FvUCI85ZMO4trrjNxGm90eLN3Ohy0AP/SqK5gWvRQg1677UjNf7t6iETOKAleHctJjuq0B3aXO2gtmw==}
|
resolution: {integrity: sha512-oyjx1b1FvUCI85ZMO4trrjNxGm90eLN3Ohy0AP/SqK5gWvRQg1677UjNf7t6iETOKAleHctJjuq0B3aXO2gtmw==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -1686,22 +1649,6 @@ packages:
|
|||||||
'@emotion/styled':
|
'@emotion/styled':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@mui/system@6.4.7':
|
|
||||||
resolution: {integrity: sha512-7wwc4++Ak6tGIooEVA9AY7FhH2p9fvBMORT4vNLMAysH3Yus/9B9RYMbrn3ANgsOyvT3Z7nE+SP8/+3FimQmcg==}
|
|
||||||
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/system@6.4.8':
|
'@mui/system@6.4.8':
|
||||||
resolution: {integrity: sha512-gV7iBHoqlsIenU2BP0wq14BefRoZcASZ/4LeyuQglayBl+DfLX5rEd3EYR3J409V2EZpR0NOM1LATAGlNk2cyA==}
|
resolution: {integrity: sha512-gV7iBHoqlsIenU2BP0wq14BefRoZcASZ/4LeyuQglayBl+DfLX5rEd3EYR3J409V2EZpR0NOM1LATAGlNk2cyA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -1734,14 +1681,6 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@mui/types@7.2.21':
|
|
||||||
resolution: {integrity: sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==}
|
|
||||||
peerDependencies:
|
|
||||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
|
||||||
peerDependenciesMeta:
|
|
||||||
'@types/react':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@mui/types@7.2.24':
|
'@mui/types@7.2.24':
|
||||||
resolution: {integrity: sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==}
|
resolution: {integrity: sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1758,16 +1697,6 @@ packages:
|
|||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@mui/utils@6.4.6':
|
|
||||||
resolution: {integrity: sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==}
|
|
||||||
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/utils@6.4.8':
|
'@mui/utils@6.4.8':
|
||||||
resolution: {integrity: sha512-C86gfiZ5BfZ51KqzqoHi1WuuM2QdSKoFhbkZeAfQRB+jCc4YNhhj11UXFVMMsqBgZ+Zy8IHNJW3M9Wj/LOwRXQ==}
|
resolution: {integrity: sha512-C86gfiZ5BfZ51KqzqoHi1WuuM2QdSKoFhbkZeAfQRB+jCc4YNhhj11UXFVMMsqBgZ+Zy8IHNJW3M9Wj/LOwRXQ==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@ -6280,33 +6209,10 @@ snapshots:
|
|||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-dom: 19.1.0(react@19.1.0)
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
|
||||||
'@mui/core-downloads-tracker@6.4.7': {}
|
|
||||||
|
|
||||||
'@mui/core-downloads-tracker@6.4.8': {}
|
'@mui/core-downloads-tracker@6.4.8': {}
|
||||||
|
|
||||||
'@mui/core-downloads-tracker@7.0.1': {}
|
'@mui/core-downloads-tracker@7.0.1': {}
|
||||||
|
|
||||||
'@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.26.0
|
|
||||||
'@mui/core-downloads-tracker': 6.4.7
|
|
||||||
'@mui/system': 6.4.7(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
'@mui/types': 7.2.21(@types/react@19.1.0)
|
|
||||||
'@mui/utils': 6.4.6(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
'@popperjs/core': 2.11.8
|
|
||||||
'@types/react-transition-group': 4.4.12(@types/react@19.1.0)
|
|
||||||
clsx: 2.1.1
|
|
||||||
csstype: 3.1.3
|
|
||||||
prop-types: 15.8.1
|
|
||||||
react: 19.0.0
|
|
||||||
react-dom: 19.0.0(react@19.0.0)
|
|
||||||
react-is: 19.1.0
|
|
||||||
react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
|
||||||
optionalDependencies:
|
|
||||||
'@emotion/react': 11.14.0(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
'@types/react': 19.1.0
|
|
||||||
|
|
||||||
'@mui/material@6.4.8(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
'@mui/material@6.4.8(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.10
|
'@babel/runtime': 7.26.10
|
||||||
@ -6370,15 +6276,6 @@ snapshots:
|
|||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
||||||
'@types/react': 19.1.0
|
'@types/react': 19.1.0
|
||||||
|
|
||||||
'@mui/private-theming@6.4.6(@types/react@19.1.0)(react@19.0.0)':
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.26.10
|
|
||||||
'@mui/utils': 6.4.8(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
prop-types: 15.8.1
|
|
||||||
react: 19.0.0
|
|
||||||
optionalDependencies:
|
|
||||||
'@types/react': 19.1.0
|
|
||||||
|
|
||||||
'@mui/private-theming@6.4.8(@types/react@19.0.12)(react@19.0.0)':
|
'@mui/private-theming@6.4.8(@types/react@19.0.12)(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.10
|
'@babel/runtime': 7.26.10
|
||||||
@ -6406,19 +6303,6 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.1.0
|
'@types/react': 19.1.0
|
||||||
|
|
||||||
'@mui/styled-engine@6.4.6(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0))(react@19.0.0)':
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.26.10
|
|
||||||
'@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.0.0
|
|
||||||
optionalDependencies:
|
|
||||||
'@emotion/react': 11.14.0(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
|
|
||||||
'@mui/styled-engine@6.4.8(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0))(react@19.0.0)':
|
'@mui/styled-engine@6.4.8(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0))(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.10
|
'@babel/runtime': 7.26.10
|
||||||
@ -6458,22 +6342,6 @@ snapshots:
|
|||||||
'@emotion/react': 11.14.0(@types/react@19.1.0)(react@19.1.0)
|
'@emotion/react': 11.14.0(@types/react@19.1.0)(react@19.1.0)
|
||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
||||||
|
|
||||||
'@mui/system@6.4.7(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0)':
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.26.10
|
|
||||||
'@mui/private-theming': 6.4.6(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
'@mui/styled-engine': 6.4.6(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0))(react@19.0.0)
|
|
||||||
'@mui/types': 7.2.24(@types/react@19.1.0)
|
|
||||||
'@mui/utils': 6.4.8(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
clsx: 2.1.1
|
|
||||||
csstype: 3.1.3
|
|
||||||
prop-types: 15.8.1
|
|
||||||
react: 19.0.0
|
|
||||||
optionalDependencies:
|
|
||||||
'@emotion/react': 11.14.0(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.0.0))(@types/react@19.1.0)(react@19.0.0)
|
|
||||||
'@types/react': 19.1.0
|
|
||||||
|
|
||||||
'@mui/system@6.4.8(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0)':
|
'@mui/system@6.4.8(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0))(@types/react@19.0.12)(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.10
|
'@babel/runtime': 7.26.10
|
||||||
@ -6522,10 +6390,6 @@ snapshots:
|
|||||||
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0)
|
||||||
'@types/react': 19.1.0
|
'@types/react': 19.1.0
|
||||||
|
|
||||||
'@mui/types@7.2.21(@types/react@19.1.0)':
|
|
||||||
optionalDependencies:
|
|
||||||
'@types/react': 19.1.0
|
|
||||||
|
|
||||||
'@mui/types@7.2.24(@types/react@19.0.12)':
|
'@mui/types@7.2.24(@types/react@19.0.12)':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.0.12
|
'@types/react': 19.0.12
|
||||||
@ -6540,18 +6404,6 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/react': 19.1.0
|
'@types/react': 19.1.0
|
||||||
|
|
||||||
'@mui/utils@6.4.6(@types/react@19.1.0)(react@19.0.0)':
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.26.10
|
|
||||||
'@mui/types': 7.2.24(@types/react@19.1.0)
|
|
||||||
'@types/prop-types': 15.7.14
|
|
||||||
clsx: 2.1.1
|
|
||||||
prop-types: 15.8.1
|
|
||||||
react: 19.0.0
|
|
||||||
react-is: 19.1.0
|
|
||||||
optionalDependencies:
|
|
||||||
'@types/react': 19.1.0
|
|
||||||
|
|
||||||
'@mui/utils@6.4.8(@types/react@19.0.12)(react@19.0.0)':
|
'@mui/utils@6.4.8(@types/react@19.0.12)(react@19.0.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.26.10
|
'@babel/runtime': 7.26.10
|
||||||
@ -9603,6 +9455,13 @@ snapshots:
|
|||||||
prop-types: 15.8.1
|
prop-types: 15.8.1
|
||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
|
|
||||||
|
react-dropzone@14.3.8(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
attr-accept: 2.2.5
|
||||||
|
file-selector: 2.1.2
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 19.1.0
|
||||||
|
|
||||||
react-hook-form@7.54.2(react@19.0.0):
|
react-hook-form@7.54.2(react@19.0.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
|
@ -87,5 +87,9 @@
|
|||||||
"delete_directory_success": "Delete directory success",
|
"delete_directory_success": "Delete directory success",
|
||||||
"create_directory": "Create Directory",
|
"create_directory": "Create Directory",
|
||||||
"create_directory_success": "Create directory success",
|
"create_directory_success": "Create directory success",
|
||||||
"Apply Change Name": "Apply Change Name"
|
"Apply Change Name": "Apply Change Name",
|
||||||
|
"Tips": "Tips",
|
||||||
|
"Check username introduction": "Check your username, if the username is not available, you can contact the customer service to modify.",
|
||||||
|
"Delete and remove file": "Delete and remove file",
|
||||||
|
"Delete App Introduce": "Delete App, when you click the delete button, the file will be deleted from the file management system."
|
||||||
}
|
}
|
@ -87,5 +87,9 @@
|
|||||||
"delete_directory_success": "删除目录成功",
|
"delete_directory_success": "删除目录成功",
|
||||||
"create_directory": "创建目录",
|
"create_directory": "创建目录",
|
||||||
"create_directory_success": "创建目录成功",
|
"create_directory_success": "创建目录成功",
|
||||||
"Apply Change Name": "申请修改名称"
|
"Apply Change Name": "申请修改名称",
|
||||||
|
"Tips": "提示",
|
||||||
|
"Check username introduction": "查看是否可以取名,如果当前用户名已存在,请更换其他用户名。其中用户名以@开头",
|
||||||
|
"Delete and remove file": "删除并删除文件",
|
||||||
|
"Delete App Introduce": "删除应用, 当点击同时删除文件,会把文件管理中,应用相关的存储的资源同步删除。"
|
||||||
}
|
}
|
@ -8,6 +8,7 @@ import { App as OrgApp } from './pages/org';
|
|||||||
import { App as ConfigApp } from './pages/config';
|
import { App as ConfigApp } from './pages/config';
|
||||||
import { App as PayApp } from './pages/pay';
|
import { App as PayApp } from './pages/pay';
|
||||||
import { App as DomainApp } from './pages/domain';
|
import { App as DomainApp } from './pages/domain';
|
||||||
|
import { App as HomeApp } from './pages/home';
|
||||||
import { basename } from './modules/basename';
|
import { basename } from './modules/basename';
|
||||||
import { Redirect } from './modules/Redirect';
|
import { Redirect } from './modules/Redirect';
|
||||||
import { CustomThemeProvider } from '@kevisual/components/theme/index.tsx';
|
import { CustomThemeProvider } from '@kevisual/components/theme/index.tsx';
|
||||||
@ -82,6 +83,7 @@ export const App = () => {
|
|||||||
<Route path='/file/*' element={<FileApp />} />
|
<Route path='/file/*' element={<FileApp />} />
|
||||||
<Route path='/pay/*' element={<PayApp />} />
|
<Route path='/pay/*' element={<PayApp />} />
|
||||||
<Route path='/domain/*' element={<DomainApp />} />
|
<Route path='/domain/*' element={<DomainApp />} />
|
||||||
|
<Route path='/home/*' element={<HomeApp />} />
|
||||||
<Route path='/404' element={<div>404</div>} />
|
<Route path='/404' element={<div>404</div>} />
|
||||||
<Route path='*' element={<div>404</div>} />
|
<Route path='*' element={<div>404</div>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
@ -12,6 +12,7 @@ import { useNewNavigate } from '../navicate';
|
|||||||
import { LogOut, Map, SquareUser, Users, X, ArrowDownLeftFromSquareIcon } from 'lucide-react';
|
import { LogOut, Map, SquareUser, Users, X, ArrowDownLeftFromSquareIcon } from 'lucide-react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useQuickMenu } from './Menu';
|
||||||
|
|
||||||
export const LayoutUser = () => {
|
export const LayoutUser = () => {
|
||||||
const { open, setOpen, isAdmin, ...store } = useLayoutStore(
|
const { open, setOpen, isAdmin, ...store } = useLayoutStore(
|
||||||
@ -77,7 +78,6 @@ export const LayoutUser = () => {
|
|||||||
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
};
|
};
|
||||||
|
@ -12,14 +12,29 @@ import SmileOutlined from '@ant-design/icons/SmileOutlined';
|
|||||||
import { X, Settings } from 'lucide-react';
|
import { X, Settings } from 'lucide-react';
|
||||||
import { useNewNavigate } from '../navicate';
|
import { useNewNavigate } from '../navicate';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Map } from 'lucide-react';
|
||||||
|
export const useQuickMenu = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: t('User App'),
|
||||||
|
icon: <AppstoreOutlined />,
|
||||||
|
link: '/app/edit/list',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('File App'),
|
||||||
|
icon: <FolderOutlined />,
|
||||||
|
link: '/file/edit/list',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
export const LayoutMenu = () => {
|
export const LayoutMenu = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const meun = [
|
const meun = [
|
||||||
{
|
{
|
||||||
title: t('Home'),
|
title: t('Home'),
|
||||||
icon: <HomeOutlined />,
|
icon: <HomeOutlined />,
|
||||||
link: '/map',
|
link: '/home',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('User App'),
|
title: t('User App'),
|
||||||
@ -37,6 +52,7 @@ export const LayoutMenu = () => {
|
|||||||
link: '/container/edit/list',
|
link: '/container/edit/list',
|
||||||
},
|
},
|
||||||
{ title: t('Config'), icon: <Settings size={16} />, link: '/config/edit/list' },
|
{ title: t('Config'), icon: <Settings size={16} />, link: '/config/edit/list' },
|
||||||
|
{ title: t('Map'), icon: <Map size={16} />, link: '/map' },
|
||||||
{
|
{
|
||||||
title: t('About'),
|
title: t('About'),
|
||||||
icon: <SmileOutlined />,
|
icon: <SmileOutlined />,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { MenuOutlined, SwapOutlined } from '@ant-design/icons';
|
import { MenuOutlined, SwapOutlined } from '@ant-design/icons';
|
||||||
import { Tooltip } from '@mui/material';
|
import { Tooltip } from '@mui/material';
|
||||||
import { Outlet } from 'react-router-dom';
|
import { Outlet, useNavigate } from 'react-router-dom';
|
||||||
import { LayoutMenu } from './Menu';
|
import { LayoutMenu, useQuickMenu } from './Menu';
|
||||||
import { useLayoutStore, usePlatformStore } from './store';
|
import { useLayoutStore, usePlatformStore } from './store';
|
||||||
import { useShallow } from 'zustand/react/shallow';
|
import { useShallow } from 'zustand/react/shallow';
|
||||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||||
@ -46,6 +46,8 @@ export const LayoutMain = (props: LayoutMainProps) => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const { isMac, mount, isElectron } = platformStore;
|
const { isMac, mount, isElectron } = platformStore;
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const quickMenu = useQuickMenu();
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
platformStore.init();
|
platformStore.init();
|
||||||
@ -88,7 +90,26 @@ export const LayoutMain = (props: LayoutMainProps) => {
|
|||||||
<MenuOutlined />
|
<MenuOutlined />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<div className='flex grow justify-between pl-4 items-center'>
|
<div className='flex grow justify-between pl-4 items-center'>
|
||||||
{props.title}
|
<div className='flex items-center gap-2'>
|
||||||
|
<div className='text-xl font-bold'>{props.title}</div>
|
||||||
|
<div className='ml-4 flex items-center gap-2 text-sm '>
|
||||||
|
{quickMenu.map((item, index) => {
|
||||||
|
const isActive = location.pathname.includes(item.link);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={clsx('flex items-center gap-2 px-1', isActive && 'border border-white')}
|
||||||
|
onClick={() => {
|
||||||
|
navigate(item.link);
|
||||||
|
}}>
|
||||||
|
<Tooltip title={item.title}>
|
||||||
|
<div className='cursor-pointer'>{item.icon}</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className='mr-4 flex gap-4 items-center no-drag'>
|
<div className='mr-4 flex gap-4 items-center no-drag'>
|
||||||
<div className='group relative'>
|
<div className='group relative'>
|
||||||
<IconButton>
|
<IconButton>
|
||||||
|
@ -64,8 +64,9 @@ export type LayoutStore = {
|
|||||||
switchOrg: (username?: string, type?: 'user' | 'org') => Promise<void>;
|
switchOrg: (username?: string, type?: 'user' | 'org') => Promise<void>;
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
setIsAdmin: (isAdmin: boolean) => void;
|
setIsAdmin: (isAdmin: boolean) => void;
|
||||||
|
checkHasOrg: () => boolean;
|
||||||
};
|
};
|
||||||
export const useLayoutStore = create<LayoutStore>((set) => ({
|
export const useLayoutStore = create<LayoutStore>((set, get) => ({
|
||||||
open: false,
|
open: false,
|
||||||
setOpen: (open) => set({ open }),
|
setOpen: (open) => set({ open }),
|
||||||
me: {},
|
me: {},
|
||||||
@ -92,4 +93,11 @@ export const useLayoutStore = create<LayoutStore>((set) => ({
|
|||||||
},
|
},
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
setIsAdmin: (isAdmin) => set({ isAdmin }),
|
setIsAdmin: (isAdmin) => set({ isAdmin }),
|
||||||
|
checkHasOrg: () => {
|
||||||
|
const user = get().me || {};
|
||||||
|
if (!user.orgs) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return user?.orgs?.length > 0;
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -8,7 +8,6 @@ import FileOutlined from '@ant-design/icons/FileOutlined';
|
|||||||
import LeftOutlined from '@ant-design/icons/LeftOutlined';
|
import LeftOutlined from '@ant-design/icons/LeftOutlined';
|
||||||
import LinkOutlined from '@ant-design/icons/LinkOutlined';
|
import LinkOutlined from '@ant-design/icons/LinkOutlined';
|
||||||
import PlusOutlined from '@ant-design/icons/PlusOutlined';
|
import PlusOutlined from '@ant-design/icons/PlusOutlined';
|
||||||
import { useModal } from '@kevisual/components/modal/Confirm.tsx';
|
|
||||||
import { Tooltip } from '@mui/material';
|
import { Tooltip } from '@mui/material';
|
||||||
import { isObjectNull } from '@/utils/is-null';
|
import { isObjectNull } from '@/utils/is-null';
|
||||||
import { FileUpload } from '../modules/FileUpload';
|
import { FileUpload } from '../modules/FileUpload';
|
||||||
@ -22,6 +21,7 @@ import { IconButton } from '@kevisual/components/button/index.tsx';
|
|||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
import { TextField } from '@mui/material';
|
import { TextField } from '@mui/material';
|
||||||
import { pick } from 'lodash-es';
|
import { pick } from 'lodash-es';
|
||||||
|
import { useAppDeleteModalStore, AppDeleteModal } from '../modules/AppDeleteModal';
|
||||||
|
|
||||||
const FormModal = () => {
|
const FormModal = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -108,8 +108,14 @@ export const AppVersionList = () => {
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const appDeleteModalStore = useAppDeleteModalStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
return {
|
||||||
|
onClickDelete: state.onClickDelete,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
const navigate = useNewNavigate();
|
const navigate = useNewNavigate();
|
||||||
const [modal, contextHolder] = useModal();
|
|
||||||
const [isUpload, setIsUpload] = useState(false);
|
const [isUpload, setIsUpload] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// fetch app version list
|
// fetch app version list
|
||||||
@ -178,13 +184,7 @@ export const AppVersionList = () => {
|
|||||||
<Tooltip title='Delete'>
|
<Tooltip title='Delete'>
|
||||||
<Button
|
<Button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
modal.confirm({
|
appDeleteModalStore.onClickDelete('app-version', item);
|
||||||
title: 'Delete',
|
|
||||||
content: 'Are you sure delete this data?',
|
|
||||||
onOk: () => {
|
|
||||||
versionStore.deleteData(item.id);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}>
|
}}>
|
||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
@ -229,7 +229,6 @@ export const AppVersionList = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{contextHolder}
|
|
||||||
<div className='shark h-full'>
|
<div className='shark h-full'>
|
||||||
{isUpload && (
|
{isUpload && (
|
||||||
<div className='bg-white p-2 w-[600px] h-full flex flex-col'>
|
<div className='bg-white p-2 w-[600px] h-full flex flex-col'>
|
||||||
@ -249,6 +248,7 @@ export const AppVersionList = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<FormModal />
|
<FormModal />
|
||||||
|
<AppDeleteModal />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -268,8 +268,8 @@ export const AppVersionFile = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>version: {versionStore.formData.version}</div>
|
<div>version: {versionStore.formData.version}</div>
|
||||||
<div className='border rounded-md my-2 grow overflow-hidden'>
|
<div className='border border-gray-200 rounded-md my-2 grow overflow-hidden'>
|
||||||
<div className='flex gap-2 items-center border-b py-2 px-2'>
|
<div className='flex gap-2 items-center border-b border-b-gray-200 py-2 px-2'>
|
||||||
Files
|
Files
|
||||||
<FileUpload />
|
<FileUpload />
|
||||||
</div>
|
</div>
|
||||||
@ -284,7 +284,7 @@ export const AppVersionFile = () => {
|
|||||||
const _path = file.path || '';
|
const _path = file.path || '';
|
||||||
const path = _path.replace(prefix, '');
|
const path = _path.replace(prefix, '');
|
||||||
return (
|
return (
|
||||||
<div className='flex gap-2 px-4 py-2 border-b' key={index}>
|
<div className='flex gap-2 px-4 py-2 border-b border-b-gray-200' key={index}>
|
||||||
{/* <div className='w-[100px] truncate'>{file.name}</div> */}
|
{/* <div className='w-[100px] truncate'>{file.name}</div> */}
|
||||||
<div>
|
<div>
|
||||||
<FileOutlined />
|
<FileOutlined />
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
import { useShallow } from 'zustand/react/shallow';
|
import { useShallow } from 'zustand/react/shallow';
|
||||||
import { useUserAppStore } from '../store';
|
import { useAppVersionStore, useUserAppStore } from '../store';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { useModal } from '@kevisual/components/modal/Confirm.tsx';
|
import { useModal } from '@kevisual/components/modal/Confirm.tsx';
|
||||||
|
|
||||||
import DeleteOutlined from '@ant-design/icons/DeleteOutlined';
|
|
||||||
import EditOutlined from '@ant-design/icons/EditOutlined';
|
|
||||||
import LinkOutlined from '@ant-design/icons/LinkOutlined';
|
import LinkOutlined from '@ant-design/icons/LinkOutlined';
|
||||||
import PlusOutlined from '@ant-design/icons/PlusOutlined';
|
import PlusOutlined from '@ant-design/icons/PlusOutlined';
|
||||||
import UnorderedListOutlined from '@ant-design/icons/UnorderedListOutlined';
|
|
||||||
import CodeOutlined from '@ant-design/icons/CodeOutlined';
|
import CodeOutlined from '@ant-design/icons/CodeOutlined';
|
||||||
import ShareAltOutlined from '@ant-design/icons/ShareAltOutlined';
|
|
||||||
import { FormControlLabel, Switch, useTheme } from '@mui/material';
|
import { FormControlLabel, Switch, useTheme } from '@mui/material';
|
||||||
import { isObjectNull } from '@/utils/is-null';
|
import { isObjectNull } from '@/utils/is-null';
|
||||||
import { queryLogin, useNewNavigate } from '@/modules';
|
import { queryLogin, useNewNavigate } from '@/modules';
|
||||||
@ -29,6 +25,8 @@ import { useForm, Controller } from 'react-hook-form';
|
|||||||
import { pick } from 'lodash-es';
|
import { pick } from 'lodash-es';
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import { useLayoutStore } from '@/modules/layout/store';
|
import { useLayoutStore } from '@/modules/layout/store';
|
||||||
|
import { useAppDeleteModalStore, AppDeleteModal } from '../modules/AppDeleteModal';
|
||||||
|
import { AppWindow, Edit, Link, RefreshCcw, Share2, Trash } from 'lucide-react';
|
||||||
|
|
||||||
const FormModal = () => {
|
const FormModal = () => {
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
@ -57,7 +55,6 @@ const FormModal = () => {
|
|||||||
const open = containerStore.showEdit;
|
const open = containerStore.showEdit;
|
||||||
if (open) {
|
if (open) {
|
||||||
const isNull = isObjectNull(containerStore.userApp);
|
const isNull = isObjectNull(containerStore.userApp);
|
||||||
console.log('isNull', containerStore.userApp);
|
|
||||||
if (isNull) {
|
if (isNull) {
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
} else {
|
} else {
|
||||||
@ -152,7 +149,7 @@ const ShareModal = () => {
|
|||||||
const permission = containerStore.userApp?.data?.permission || {};
|
const permission = containerStore.userApp?.data?.permission || {};
|
||||||
const runtime = containerStore.userApp?.data?.runtime || [];
|
const runtime = containerStore.userApp?.data?.runtime || [];
|
||||||
if (isObjectNull(permission)) {
|
if (isObjectNull(permission)) {
|
||||||
setPermission(null);
|
setPermission({ share: 'private' });
|
||||||
} else {
|
} else {
|
||||||
setPermission(permission);
|
setPermission(permission);
|
||||||
}
|
}
|
||||||
@ -173,9 +170,9 @@ const ShareModal = () => {
|
|||||||
containerStore.setShowEdit(false);
|
containerStore.setShowEdit(false);
|
||||||
};
|
};
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
console.log('runtime', runtime);
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const defaultProps = theme.components?.MuiTextField?.defaultProps as any;
|
const defaultProps = theme.components?.MuiTextField?.defaultProps as any;
|
||||||
|
const isAdmin = useLayoutStore(useShallow((state) => state.isAdmin));
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={containerStore.showEdit}
|
open={containerStore.showEdit}
|
||||||
@ -191,35 +188,37 @@ const ShareModal = () => {
|
|||||||
setPermission(value);
|
setPermission(value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormControlLabel
|
{isAdmin && (
|
||||||
label={t('app.runtime')}
|
<FormControlLabel
|
||||||
labelPlacement='top'
|
label={t('app.runtime')}
|
||||||
sx={{
|
labelPlacement='top'
|
||||||
'& .MuiFormControlLabel-label': {
|
sx={{
|
||||||
width: '100%',
|
'& .MuiFormControlLabel-label': {
|
||||||
},
|
width: '100%',
|
||||||
}}
|
},
|
||||||
control={
|
}}
|
||||||
<Select
|
control={
|
||||||
multiple
|
<Select
|
||||||
size='small'
|
multiple
|
||||||
value={runtime}
|
size='small'
|
||||||
onChange={(e) => {
|
value={runtime}
|
||||||
setRuntime(e.target.value as string[]);
|
onChange={(e) => {
|
||||||
}}
|
setRuntime(e.target.value as string[]);
|
||||||
options={[
|
}}
|
||||||
{
|
options={[
|
||||||
label: 'Node',
|
{
|
||||||
value: 'node',
|
label: 'Node',
|
||||||
},
|
value: 'node',
|
||||||
{
|
},
|
||||||
label: 'Browser',
|
{
|
||||||
value: 'browser',
|
label: 'Browser',
|
||||||
},
|
value: 'browser',
|
||||||
]}
|
},
|
||||||
/>
|
]}
|
||||||
}
|
/>
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
@ -250,6 +249,20 @@ export const List = () => {
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const appVersionStore = useAppVersionStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
return {
|
||||||
|
publishVersion: state.publishVersion,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const appDeleteModalStore = useAppDeleteModalStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
return {
|
||||||
|
onClickDelete: state.onClickDelete,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
const navicate = useNewNavigate();
|
const navicate = useNewNavigate();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
userAppStore.getList();
|
userAppStore.getList();
|
||||||
@ -299,11 +312,22 @@ export const List = () => {
|
|||||||
{userAppStore.list.map((item) => {
|
{userAppStore.list.map((item) => {
|
||||||
const isRunning = item.status === 'running';
|
const isRunning = item.status === 'running';
|
||||||
const hasDescription = !!item.description;
|
const hasDescription = !!item.description;
|
||||||
const content = marked.parse(item.description);
|
// const content = marked.parse(item.description);
|
||||||
|
const content = item.description;
|
||||||
return (
|
return (
|
||||||
<div className='card w-[300px] relative pb-10 ' key={item.id}>
|
<div className='card w-[300px] relative pb-10 ' key={item.id}>
|
||||||
<div className='card-title flex font-bold justify-between' onClick={() => {}}>
|
<div className='card-title flex font-bold justify-between' onClick={() => {}}>
|
||||||
{item.title}
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<pre className=''>
|
||||||
|
<span className='text-sm'>{item.title}</span>
|
||||||
|
<i className='text-xs text-white ml-4'>{item.key}</i>
|
||||||
|
</pre>
|
||||||
|
}>
|
||||||
|
<div>
|
||||||
|
{item.title} <i className='text-xs text-gray-400'>{item.key}</i>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
<div>
|
<div>
|
||||||
<Tooltip title={isRunning ? '网页可正常访问' : '网页被关闭'}>
|
<Tooltip title={isRunning ? '网页可正常访问' : '网页被关闭'}>
|
||||||
<div className={`${isRunning ? 'bg-green-500' : 'bg-red-500'} w-4 h-4 rounded-full`}></div>
|
<div className={`${isRunning ? 'bg-green-500' : 'bg-red-500'} w-4 h-4 rounded-full`}></div>
|
||||||
@ -329,8 +353,10 @@ export const List = () => {
|
|||||||
<div className='text-xs'>
|
<div className='text-xs'>
|
||||||
{t('app.version')}: {item.version}
|
{t('app.version')}: {item.version}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={clsx('text-sm border border-gray-200 p-2 max-h-[140px] scrollbar my-1', !hasDescription && 'hidden')}>
|
<div className={clsx('text-sm border border-gray-200 p-2 max-h-[140px] scrollbar my-1', !hasDescription && 'hidden')}>
|
||||||
<div dangerouslySetInnerHTML={{ __html: content }}></div>
|
{/* <div dangerouslySetInnerHTML={{ __html: content }}></div> */}
|
||||||
|
<div className='text-sm whitespace-pre-wrap'>{content}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='py-4'></div>
|
<div className='py-4'></div>
|
||||||
@ -346,7 +372,7 @@ export const List = () => {
|
|||||||
userAppStore.setFormData(item);
|
userAppStore.setFormData(item);
|
||||||
userAppStore.setShowEdit(true);
|
userAppStore.setShowEdit(true);
|
||||||
}}>
|
}}>
|
||||||
<EditOutlined />
|
<Edit size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={'App Version List'}>
|
<Tooltip title={'App Version List'}>
|
||||||
@ -354,7 +380,7 @@ export const List = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
navicate(`/app/${item.key}/version/list`);
|
navicate(`/app/${item.key}/version/list`);
|
||||||
}}>
|
}}>
|
||||||
<UnorderedListOutlined />
|
<AppWindow size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={iText.share.tips}>
|
<Tooltip title={iText.share.tips}>
|
||||||
@ -364,7 +390,15 @@ export const List = () => {
|
|||||||
userAppStore.setFormData(item);
|
userAppStore.setFormData(item);
|
||||||
userAppStore.setShowShareEdit(true);
|
userAppStore.setShowShareEdit(true);
|
||||||
}}>
|
}}>
|
||||||
<ShareAltOutlined />
|
<Share2 size={16} />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title={'reload'}>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
appVersionStore.publishVersion({ appKey: item.key, version: item.version }, { showToast: false });
|
||||||
|
}}>
|
||||||
|
<RefreshCcw size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={'To App'}>
|
<Tooltip title={'To App'}>
|
||||||
@ -396,23 +430,16 @@ export const List = () => {
|
|||||||
message.error('The app is not running');
|
message.error('The app is not running');
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<LinkOutlined />
|
<Link size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={'Delete'}>
|
<Tooltip title={'Delete'}>
|
||||||
<Button
|
<Button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
console.log('delete', item);
|
appDeleteModalStore.onClickDelete('user-app', item);
|
||||||
modal.confirm({
|
|
||||||
title: 'Delete',
|
|
||||||
content: 'Are you sure delete this data?',
|
|
||||||
onOk: () => {
|
|
||||||
userAppStore.deleteData(item.id);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}}>
|
}}>
|
||||||
<DeleteOutlined />
|
<Trash size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
@ -427,6 +454,7 @@ export const List = () => {
|
|||||||
{contextHolder}
|
{contextHolder}
|
||||||
<FormModal />
|
<FormModal />
|
||||||
<ShareModal />
|
<ShareModal />
|
||||||
|
<AppDeleteModal />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
79
src/pages/app/modules/AppDeleteModal.tsx
Normal file
79
src/pages/app/modules/AppDeleteModal.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { Button, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { create } from 'zustand';
|
||||||
|
import { useAppVersionStore, useUserAppStore } from '../store';
|
||||||
|
import { useShallow } from 'zustand/shallow';
|
||||||
|
|
||||||
|
type AppDeleteModalStore = {
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (open: boolean) => void;
|
||||||
|
app: any;
|
||||||
|
setApp: (app: any) => void;
|
||||||
|
type: 'user-app' | 'app-version';
|
||||||
|
setType: (type: 'user-app' | 'app-version') => void;
|
||||||
|
onClickDelete: (type: 'user-app' | 'app-version', data: any) => void;
|
||||||
|
};
|
||||||
|
export const useAppDeleteModalStore = create<AppDeleteModalStore>((set) => ({
|
||||||
|
open: false,
|
||||||
|
setOpen: (open) => set({ open }),
|
||||||
|
app: null,
|
||||||
|
setApp: (app) => set({ app }),
|
||||||
|
type: 'user-app',
|
||||||
|
setType: (type) => set({ type }),
|
||||||
|
onClickDelete: (type, data) => {
|
||||||
|
set({ open: true, type, app: data });
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const AppDeleteModal = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { open, setOpen, app, type, setType } = useAppDeleteModalStore();
|
||||||
|
const userAppStore = useUserAppStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
return {
|
||||||
|
deleteData: state.deleteData,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const appVersionStore = useAppVersionStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
return {
|
||||||
|
deleteData: state.deleteData,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const onClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
const onDelete = (deleteFile = false) => {
|
||||||
|
if (type === 'user-app') {
|
||||||
|
userAppStore.deleteData(app.id, deleteFile);
|
||||||
|
} else {
|
||||||
|
appVersionStore.deleteData(app.id, deleteFile);
|
||||||
|
}
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onClose={onClose}>
|
||||||
|
<DialogTitle>{t('Tips')}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<div className='w-[400px]'>
|
||||||
|
<p className='text-sm text-gray-500'>{t('Delete App Introduce')}</p>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button variant='contained' onClick={() => onDelete()}>{t('Delete')}</Button>
|
||||||
|
<Button onClick={onClose}>{t('Cancel')}</Button>
|
||||||
|
<Button
|
||||||
|
color='error'
|
||||||
|
onClick={() => {
|
||||||
|
onDelete(true);
|
||||||
|
}}>
|
||||||
|
{t('Delete and remove file')}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
@ -17,8 +17,14 @@ type AppVersionStore = {
|
|||||||
app: any;
|
app: any;
|
||||||
getApp: (key: string, force?: boolean) => Promise<void>;
|
getApp: (key: string, force?: boolean) => Promise<void>;
|
||||||
updateData: (data: any) => Promise<void>;
|
updateData: (data: any) => Promise<void>;
|
||||||
deleteData: (id: string) => Promise<void>;
|
/**
|
||||||
publishVersion: (data: any) => Promise<void>;
|
* 删除应用版本
|
||||||
|
* @param id 应用版本id
|
||||||
|
* @param deleteFile 是否删除文件
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
deleteData: (id: string, deleteFile?: boolean) => Promise<void>;
|
||||||
|
publishVersion: (data: { id?: string; appKey?: string; version?: string }, opts?: { showToast?: boolean }) => Promise<any>;
|
||||||
};
|
};
|
||||||
export const useAppVersionStore = create<AppVersionStore>((set, get) => {
|
export const useAppVersionStore = create<AppVersionStore>((set, get) => {
|
||||||
return {
|
return {
|
||||||
@ -94,12 +100,13 @@ export const useAppVersionStore = create<AppVersionStore>((set, get) => {
|
|||||||
message.error(res.message || 'Request failed');
|
message.error(res.message || 'Request failed');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteData: async (id) => {
|
deleteData: async (id, deleteFile = false) => {
|
||||||
const { getList } = get();
|
const { getList } = get();
|
||||||
const res = await query.post({
|
const res = await query.post({
|
||||||
path: 'app',
|
path: 'app',
|
||||||
key: 'delete',
|
key: 'delete',
|
||||||
id,
|
id,
|
||||||
|
deleteFile,
|
||||||
});
|
});
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
getList();
|
getList();
|
||||||
@ -108,18 +115,24 @@ export const useAppVersionStore = create<AppVersionStore>((set, get) => {
|
|||||||
message.error(res.message || 'Request failed');
|
message.error(res.message || 'Request failed');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
publishVersion: async (data) => {
|
publishVersion: async (data, opts) => {
|
||||||
|
const showToast = opts?.showToast ?? true;
|
||||||
const res = await query.post({
|
const res = await query.post({
|
||||||
path: 'app',
|
path: 'app',
|
||||||
key: 'publish',
|
key: 'publish',
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
message.success('Success');
|
if (showToast) {
|
||||||
get().getApp(get().key, true);
|
message.success('Success');
|
||||||
|
get().getApp(get().key, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
message.error(res.message || 'Request failed');
|
if (showToast) {
|
||||||
|
message.error(res.message || 'Request failed');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,13 @@ type UserAppStore = {
|
|||||||
list: any[];
|
list: any[];
|
||||||
getList: () => Promise<void>;
|
getList: () => Promise<void>;
|
||||||
updateData: (data: any) => Promise<void>;
|
updateData: (data: any) => Promise<void>;
|
||||||
deleteData: (id: string) => Promise<void>;
|
/**
|
||||||
|
* 删除用户应用
|
||||||
|
* @param id 用户应用id
|
||||||
|
* @param deleteFile 是否删除文件
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
deleteData: (id: string, deleteFile?: boolean) => Promise<void>;
|
||||||
showShareEdit: boolean;
|
showShareEdit: boolean;
|
||||||
setShowShareEdit: (showShareEdit: boolean) => void;
|
setShowShareEdit: (showShareEdit: boolean) => void;
|
||||||
userApp: any;
|
userApp: any;
|
||||||
@ -56,12 +62,13 @@ export const useUserAppStore = create<UserAppStore>((set, get) => {
|
|||||||
message.error(res.message || 'Request failed');
|
message.error(res.message || 'Request failed');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteData: async (id) => {
|
deleteData: async (id, deleteFile = false) => {
|
||||||
const { getList } = get();
|
const { getList } = get();
|
||||||
const res = await query.post({
|
const res = await query.post({
|
||||||
path: 'user-app',
|
path: 'user-app',
|
||||||
key: 'delete',
|
key: 'delete',
|
||||||
id,
|
id,
|
||||||
|
deleteFile,
|
||||||
});
|
});
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
getList();
|
getList();
|
||||||
|
107
src/pages/home/Home.tsx
Normal file
107
src/pages/home/Home.tsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import CloudUploadOutlined from '@ant-design/icons/CloudUploadOutlined';
|
||||||
|
|
||||||
|
import { BaseEditor } from '@kevisual/codemirror/editor/editor.ts';
|
||||||
|
import { IconButton } from '@kevisual/components/button/index.tsx';
|
||||||
|
import { Button, Tooltip } from 'antd';
|
||||||
|
import { UploadIcon } from 'lucide-react';
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { useDropzone } from 'react-dropzone';
|
||||||
|
import { CacheWorkspace } from '@kevisual/cache';
|
||||||
|
import { useHomeStore } from './store/index.ts';
|
||||||
|
import { UploadModal } from './module/UploadModal.tsx';
|
||||||
|
import { useShallow } from 'zustand/shallow';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { SuccessModal } from './module/SuccessModal.tsx';
|
||||||
|
|
||||||
|
export const Home = () => {
|
||||||
|
const editorElRef = useRef<HTMLDivElement>(null);
|
||||||
|
const editorRef = useRef<BaseEditor>(null);
|
||||||
|
const { initApp, setOpenUploadModal, setText, filename } = useHomeStore(
|
||||||
|
useShallow((state) => ({ initApp: state.initApp, setOpenUploadModal: state.setOpenUploadModal, setText: state.setText, filename: state.filename })),
|
||||||
|
);
|
||||||
|
const onDrop = (acceptedFiles) => {
|
||||||
|
console.log(acceptedFiles);
|
||||||
|
const file = acceptedFiles[0];
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
const content = e.target?.result as string;
|
||||||
|
editorRef.current!.setContent(content);
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
const { getRootProps, getInputProps } = useDropzone({ onDrop, accept: { 'text/html': ['.html'], 'text/javascript': ['.js'], 'text/css': ['.css'] } });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
initApp();
|
||||||
|
initEditor();
|
||||||
|
return () => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
editorRef.current.destroyEditor();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const initEditor = async () => {
|
||||||
|
if (!editorElRef.current) return;
|
||||||
|
const cache = new CacheWorkspace();
|
||||||
|
let cacheData = '';
|
||||||
|
try {
|
||||||
|
cacheData = (await cache.storage.get('html-editor')) || '';
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
editorRef.current = new BaseEditor({
|
||||||
|
filename: filename || 'index.html',
|
||||||
|
onChange: (value) => {
|
||||||
|
cache.storage.set('html-editor', value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
editorRef.current.createEditor(editorElRef.current);
|
||||||
|
setTimeout(() => {
|
||||||
|
editorRef.current!.setContent(cacheData);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex flex-row w-full h-full'>
|
||||||
|
<div className='flex flex-col text-primary border-r border-gray-200 px-2 pt-2'>
|
||||||
|
<div>
|
||||||
|
<Tooltip title='部署应用' placement='right'>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
const editorContent = editorRef.current?.getContent();
|
||||||
|
if (editorContent) {
|
||||||
|
setOpenUploadModal(true);
|
||||||
|
setText(editorContent);
|
||||||
|
} else {
|
||||||
|
toast.error('请先输入代码');
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<CloudUploadOutlined />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div className=' mt-2' {...getRootProps()}>
|
||||||
|
<Tooltip title='点击上传html或者js文件 ' placement='right'>
|
||||||
|
<IconButton>
|
||||||
|
<UploadIcon size={16} />
|
||||||
|
</IconButton>
|
||||||
|
<input type='file' style={{ display: 'none' }} {...getInputProps()} />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='h-full grow px-2'>
|
||||||
|
<div className=' py-1'>
|
||||||
|
<i className=' text-gray-500' style={{ fontSize: 10 }}>
|
||||||
|
{'>'} 快速部署html小应用, 粘贴前端html代码。点击部署。(这个页面内容自动缓存到本地)
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
<div className=' border rounded-md border-gray-200 scrollbar' style={{ height: 'calc(100% - 50px)' }}>
|
||||||
|
<div className='w-full h-full ' ref={editorElRef}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<UploadModal />
|
||||||
|
<SuccessModal />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
12
src/pages/home/index.tsx
Normal file
12
src/pages/home/index.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Route, Routes } from 'react-router-dom';
|
||||||
|
import { Main } from './layouts';
|
||||||
|
import { Home } from './Home';
|
||||||
|
export const App = () => {
|
||||||
|
return (
|
||||||
|
<Routes>
|
||||||
|
<Route element={<Main />}>
|
||||||
|
<Route path='/' element={<Home />}></Route>
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
);
|
||||||
|
};
|
5
src/pages/home/layouts/index.tsx
Normal file
5
src/pages/home/layouts/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { LayoutMain } from '@/modules/layout';
|
||||||
|
|
||||||
|
export const Main = () => {
|
||||||
|
return <LayoutMain title='Home' />;
|
||||||
|
};
|
55
src/pages/home/module/SuccessModal.tsx
Normal file
55
src/pages/home/module/SuccessModal.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { Dialog, DialogContent, DialogTitle } from '@mui/material';
|
||||||
|
import { useShallow } from 'zustand/shallow';
|
||||||
|
import { useHomeStore } from '../store';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useLayoutStore } from '@/modules/layout/store';
|
||||||
|
export const Label = ({ label, children }: { label: string; children: React.ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<div className='text-sm text-gray-500 w-full flex gap-2'>
|
||||||
|
<div className='min-w-[60px]'>{label}</div>
|
||||||
|
<div className=''>{children}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const SuccessModal = () => {
|
||||||
|
const { openSuccessModal, setOpenSuccessModal, appKey, version, filename } = useHomeStore(
|
||||||
|
useShallow((state) => ({
|
||||||
|
openSuccessModal: state.openSuccessModal,
|
||||||
|
setOpenSuccessModal: state.setOpenSuccessModal,
|
||||||
|
appKey: state.appKey, //
|
||||||
|
version: state.version, //
|
||||||
|
filename: state.filename, //
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
const { me } = useLayoutStore(useShallow((state) => ({ me: state.me })));
|
||||||
|
const link = useMemo(() => {
|
||||||
|
const _currentHref = new URL(window.location.href);
|
||||||
|
const username = me?.username;
|
||||||
|
const newHref = new URL(`/${username}/${appKey}/`, _currentHref.origin);
|
||||||
|
return newHref.toString();
|
||||||
|
}, [me, appKey]);
|
||||||
|
return (
|
||||||
|
<Dialog open={openSuccessModal} onClose={() => setOpenSuccessModal(false)}>
|
||||||
|
<DialogTitle className='text-black'>部署成功</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<div className='flex flex-col gap-2 w-[400px] min-h-[100px] text-black'>
|
||||||
|
<Label label='应用 Key: '>{appKey}</Label>
|
||||||
|
<Label label='版本:'>{version}</Label>
|
||||||
|
<Label label='访问地址:'>
|
||||||
|
<a href={link} className='text-blue-500' target='_blank' rel='noreferrer'>
|
||||||
|
{link}
|
||||||
|
</a>
|
||||||
|
</Label>
|
||||||
|
<Label label='配置地址:'>
|
||||||
|
<a href={`/app/edit/list`} className='text-blue-500' target='_self' rel='noreferrer'>
|
||||||
|
{`/app/edit/list`}
|
||||||
|
</a>
|
||||||
|
</Label>
|
||||||
|
<div className='mt-1 text-gray-500 italic' style={{ fontSize: 10 }}>
|
||||||
|
注: 如果需要其他人访问,需要设置共享。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
98
src/pages/home/module/UploadModal.tsx
Normal file
98
src/pages/home/module/UploadModal.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { Button, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material';
|
||||||
|
import { useHomeStore } from '../store';
|
||||||
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
|
import { TextField } from '@mui/material';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
import { uploadFile } from './upload-file';
|
||||||
|
import { useAppVersionStore } from '@/pages/app/store';
|
||||||
|
import { useShallow } from 'zustand/shallow';
|
||||||
|
|
||||||
|
export const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10);
|
||||||
|
export const UploadModal = () => {
|
||||||
|
const { appKey, version, filename, openUploadModal, text, setOpenUploadModal, setAppKey, setVersion, setFilename, setOpenSuccessModal } = useHomeStore();
|
||||||
|
const { control, handleSubmit, reset } = useForm();
|
||||||
|
const { publishVersion } = useAppVersionStore(useShallow((state) => ({ publishVersion: state.publishVersion })));
|
||||||
|
useEffect(() => {
|
||||||
|
if (openUploadModal) {
|
||||||
|
const randomAppKey = nanoid(4) + nanoid(4);
|
||||||
|
reset({ appKey: appKey || randomAppKey, version: version || '1.0.0', filename: filename || 'index.html' });
|
||||||
|
}
|
||||||
|
}, [openUploadModal]);
|
||||||
|
const onSubmit = async (data: any) => {
|
||||||
|
console.log(data);
|
||||||
|
if (!text) {
|
||||||
|
toast.error('代码不能为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!data.appKey) {
|
||||||
|
toast.error('应用key不能为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!data.version) {
|
||||||
|
toast.error('版本不能为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!data.filename) {
|
||||||
|
toast.error('文件名不能为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setAppKey(data.appKey);
|
||||||
|
setVersion(data.version);
|
||||||
|
setFilename(data.filename);
|
||||||
|
const res = await uploadFile({
|
||||||
|
appKey: data.appKey,
|
||||||
|
version: data.version,
|
||||||
|
filename: data.filename,
|
||||||
|
text,
|
||||||
|
});
|
||||||
|
if (res?.code === 200) {
|
||||||
|
toast.success('部署成功');
|
||||||
|
const toastId = toast.loading('发布中...');
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
const res = await publishVersion({ appKey: data.appKey, version: data.version }, { showToast: false });
|
||||||
|
toast.dismiss(toastId);
|
||||||
|
if (res?.code === 200) {
|
||||||
|
toast.success('发布成功');
|
||||||
|
setOpenSuccessModal(true);
|
||||||
|
} else {
|
||||||
|
toast.error(res?.message || '发布失败');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toast.error(res?.message || '部署失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<Dialog open={openUploadModal} onClose={() => setOpenUploadModal(false)}>
|
||||||
|
<DialogTitle>部署页面</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<form className='flex flex-col gap-3 pt-1 w-[500px]' onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<div className='flex flex-col gap-1'>
|
||||||
|
<label className='text-sm'>应用key</label>
|
||||||
|
<Controller control={control} name='appKey' render={({ field }) => <TextField {...field} />} />
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-col gap-1'>
|
||||||
|
<label className='text-sm'>版本</label>
|
||||||
|
<Controller control={control} name='version' render={({ field }) => <TextField {...field} />} />
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-col gap-1'>
|
||||||
|
<label className='text-sm'>文件名</label>
|
||||||
|
<Controller control={control} name='filename' render={({ field }) => <TextField {...field} />} />
|
||||||
|
</div>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setOpenUploadModal(false);
|
||||||
|
}}>
|
||||||
|
{t('Cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button type='submit'>{t('Submit')}</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
29
src/pages/home/module/upload-file.ts
Normal file
29
src/pages/home/module/upload-file.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { uploadChunkV2, toFile } from '@kevisual/resources/index.ts';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
type UploadFileOpts = {
|
||||||
|
appKey: string;
|
||||||
|
version: string;
|
||||||
|
filename: string;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
const getFilenameExtension = (filename: string) => {
|
||||||
|
return filename.split('.').pop() || '';
|
||||||
|
};
|
||||||
|
const allowFilesName = ['js', 'css', 'json', 'html'];
|
||||||
|
export const uploadFile = async (uploadFileOpts: UploadFileOpts) => {
|
||||||
|
const { appKey, version, filename, text } = uploadFileOpts;
|
||||||
|
const extension = getFilenameExtension(filename);
|
||||||
|
if (!allowFilesName.includes(extension)) {
|
||||||
|
toast.error('文件类型不支持');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const file = toFile(text, filename);
|
||||||
|
const res = await uploadChunkV2(file, {
|
||||||
|
appKey,
|
||||||
|
version,
|
||||||
|
filename,
|
||||||
|
noCheckAppFiles: false,
|
||||||
|
});
|
||||||
|
return res as any;
|
||||||
|
};
|
51
src/pages/home/store/index.ts
Normal file
51
src/pages/home/store/index.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
export type HomeStore = {
|
||||||
|
appKey: string;
|
||||||
|
version: string;
|
||||||
|
setAppKey: (appKey: string) => void;
|
||||||
|
setVersion: (version: string) => void;
|
||||||
|
filename: string;
|
||||||
|
setFilename: (filename: string) => void;
|
||||||
|
initApp: () => void;
|
||||||
|
openUploadModal: boolean;
|
||||||
|
setOpenUploadModal: (open: boolean) => void;
|
||||||
|
text: string;
|
||||||
|
setText: (text: string) => void;
|
||||||
|
openSuccessModal: boolean;
|
||||||
|
setOpenSuccessModal: (open: boolean) => void;
|
||||||
|
};
|
||||||
|
export const useHomeStore = create<HomeStore>((set) => ({
|
||||||
|
appKey: '',
|
||||||
|
version: '',
|
||||||
|
setAppKey: (appKey: string) => {
|
||||||
|
set({ appKey });
|
||||||
|
localStorage.setItem('home-app-key', appKey);
|
||||||
|
},
|
||||||
|
setVersion: (version: string) => {
|
||||||
|
set({ version });
|
||||||
|
localStorage.setItem('home-app-version', version);
|
||||||
|
},
|
||||||
|
filename: '',
|
||||||
|
setFilename: (filename: string) => {
|
||||||
|
set({ filename });
|
||||||
|
localStorage.setItem('home-file-name', filename);
|
||||||
|
},
|
||||||
|
initApp: () => {
|
||||||
|
const appKey = localStorage.getItem('home-app-key') || '';
|
||||||
|
const version = localStorage.getItem('home-app-version') || '';
|
||||||
|
const filename = localStorage.getItem('home-file-name') || '';
|
||||||
|
set({ appKey, version, filename });
|
||||||
|
},
|
||||||
|
openUploadModal: false,
|
||||||
|
setOpenUploadModal: (open: boolean) => {
|
||||||
|
set({ openUploadModal: open });
|
||||||
|
},
|
||||||
|
text: '',
|
||||||
|
setText: (text: string) => {
|
||||||
|
set({ text });
|
||||||
|
},
|
||||||
|
openSuccessModal: false,
|
||||||
|
setOpenSuccessModal: (open: boolean) => {
|
||||||
|
set({ openSuccessModal: open });
|
||||||
|
},
|
||||||
|
}));
|
@ -1,10 +1,21 @@
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useNewNavigate } from '@/modules';
|
import { useNewNavigate } from '@/modules';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useLayoutStore } from '@/modules/layout/store';
|
||||||
|
import { useShallow } from 'zustand/shallow';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
const ServerPath = () => {
|
const ServerPath = () => {
|
||||||
const navigate = useNewNavigate();
|
const navigate = useNewNavigate();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const layoutStore = useLayoutStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
return {
|
||||||
|
isAdmin: state.isAdmin,
|
||||||
|
checkHasOrg: state.checkHasOrg,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
const serverPath = [
|
const serverPath = [
|
||||||
{
|
{
|
||||||
path: 'container',
|
path: 'container',
|
||||||
@ -28,9 +39,9 @@ const ServerPath = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<div className='p-2 w-full h-full bg-gray-200'>
|
<div className='p-2 w-full h-full bg-gray-200 '>
|
||||||
<h1 className='p-4 w-1/2 m-auto h1'>{t('Site Map')}</h1>
|
<h1 className='py-4 w-1/2 m-auto h1 text-primary'>{t('Site Map')}</h1>
|
||||||
<div className='w-1/2 m-auto bg-white p-4 border rounded-md shadow-md min-w-[700px] max-h-[80vh] overflow-auto scrollbar'>
|
<div className='w-1/2 m-auto bg-white p-4 border border-gray-200 rounded-md shadow-md min-w-[700px] max-h-[80vh] overflow-auto scrollbar'>
|
||||||
<div className='flex flex-col w-full'>
|
<div className='flex flex-col w-full'>
|
||||||
{serverPath.map((item) => {
|
{serverPath.map((item) => {
|
||||||
const links = item.links.map((link) => {
|
const links = item.links.map((link) => {
|
||||||
@ -54,7 +65,7 @@ const ServerPath = () => {
|
|||||||
navigate(`/${item.path}`);
|
navigate(`/${item.path}`);
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<div className={clsx('border rounded-md p-2 m-2', hasId && 'bg-gray-200')}>{_path}</div>
|
<div className={clsx('border border-gray-200 rounded-md p-2 m-2', hasId && 'bg-gray-200')}>{_path}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { LayoutMain } from '@/modules/layout';
|
import { LayoutMain } from '@/modules/layout';
|
||||||
export const Main = () => {
|
export const Main = () => {
|
||||||
return <LayoutMain title='User' />;
|
return <LayoutMain title='User Org' />;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { InputAdornment, TextField, Tooltip } from '@mui/material';
|
import { Dialog, DialogContent, DialogTitle, InputAdornment, TextField, Tooltip } from '@mui/material';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import { useUserStore } from '../store';
|
import { useUserStore } from '../store';
|
||||||
@ -12,6 +12,56 @@ import { FileUpload } from '../module/FileUpload';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Edit } from 'lucide-react';
|
import { Edit } from 'lucide-react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { useAdminStore } from '../admin/store/admin-store';
|
||||||
|
export const CheckUserExistModal = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const userStore = useUserStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
return {
|
||||||
|
showCheckUserExist: state.showCheckUserExist,
|
||||||
|
setShowCheckUserExist: state.setShowCheckUserExist,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const adminStore = useAdminStore(
|
||||||
|
useShallow((state) => {
|
||||||
|
return {
|
||||||
|
checkUserExist: state.checkUserExist,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const onClose = () => {
|
||||||
|
userStore.setShowCheckUserExist(false);
|
||||||
|
};
|
||||||
|
const [username, setUsername] = useState('@');
|
||||||
|
|
||||||
|
const onCheck = async () => {
|
||||||
|
const res = await adminStore.checkUserExist(username);
|
||||||
|
console.log(res);
|
||||||
|
if (res === false) {
|
||||||
|
toast.info('当前用户名可以修改,点击右上角关注公众号联系客服修改。', {
|
||||||
|
autoClose: 20000,
|
||||||
|
});
|
||||||
|
// toast.success(t('Check success'));
|
||||||
|
} else {
|
||||||
|
toast.error('当前用户名已存在,请更换其他用户名。');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Dialog open={userStore.showCheckUserExist} onClose={onClose}>
|
||||||
|
<DialogTitle>{t('Tips')}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<div className='flex flex-col pt-4 gap-6 w-[400px]'>
|
||||||
|
<div className='text-sm text-secondary'>{t('Check username introduction')}</div>
|
||||||
|
<TextField label='username' value={username} onChange={(e) => setUsername(e.target.value)} />
|
||||||
|
<Button variant='contained' color='primary' onClick={onCheck}>
|
||||||
|
{t('Submit')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const Profile = () => {
|
export const Profile = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -32,6 +82,7 @@ export const Profile = () => {
|
|||||||
updateData: state.updateData,
|
updateData: state.updateData,
|
||||||
setFormData: state.setFormData,
|
setFormData: state.setFormData,
|
||||||
updateSelf: state.updateSelf,
|
updateSelf: state.updateSelf,
|
||||||
|
setShowCheckUserExist: state.setShowCheckUserExist,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -104,9 +155,7 @@ export const Profile = () => {
|
|||||||
className='w-4 h-4 cursor-pointer text-primary'
|
className='w-4 h-4 cursor-pointer text-primary'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log('onClick edit');
|
console.log('onClick edit');
|
||||||
toast.info('联系客服修改,因为名称和上传文件绑定了。', {
|
userStore.setShowCheckUserExist(true);
|
||||||
autoClose: 20000,
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
@ -153,6 +202,7 @@ export const Profile = () => {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<CheckUserExistModal />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -6,6 +6,8 @@ type UserStore = {
|
|||||||
setShowEdit: (showEdit: boolean) => void;
|
setShowEdit: (showEdit: boolean) => void;
|
||||||
showNameEdit: boolean;
|
showNameEdit: boolean;
|
||||||
setShowNameEdit: (showNameEdit: boolean) => void;
|
setShowNameEdit: (showNameEdit: boolean) => void;
|
||||||
|
showCheckUserExist: boolean;
|
||||||
|
setShowCheckUserExist: (showCheckUserExist: boolean) => void;
|
||||||
formData: any;
|
formData: any;
|
||||||
setFormData: (formData: any) => void;
|
setFormData: (formData: any) => void;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@ -22,6 +24,8 @@ export const useUserStore = create<UserStore>((set, get) => {
|
|||||||
setShowEdit: (showEdit) => set({ showEdit }),
|
setShowEdit: (showEdit) => set({ showEdit }),
|
||||||
showNameEdit: false,
|
showNameEdit: false,
|
||||||
setShowNameEdit: (showNameEdit) => set({ showNameEdit }),
|
setShowNameEdit: (showNameEdit) => set({ showNameEdit }),
|
||||||
|
showCheckUserExist: false,
|
||||||
|
setShowCheckUserExist: (showCheckUserExist) => set({ showCheckUserExist }),
|
||||||
formData: {},
|
formData: {},
|
||||||
setFormData: (formData) => set({ formData }),
|
setFormData: (formData) => set({ formData }),
|
||||||
loading: false,
|
loading: false,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user