@qlover/create-app 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/package.json +2 -2
- package/templates/react-app/README.md +311 -120
- package/templates/react-app/config/Identifier.I18n.ts +170 -0
- package/templates/react-app/config/common.ts +13 -0
- package/templates/react-app/package.json +6 -2
- package/templates/react-app/public/locales/en/common.json +25 -1
- package/templates/react-app/public/locales/zh/common.json +25 -1
- package/templates/react-app/src/App.tsx +5 -4
- package/templates/react-app/src/base/apis/AiApi.ts +4 -4
- package/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +2 -2
- package/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +2 -2
- package/templates/react-app/src/base/cases/AppConfig.ts +103 -0
- package/templates/react-app/src/base/cases/{appError/AppError.ts → AppError.ts} +0 -3
- package/templates/react-app/src/base/cases/DialogHandler.ts +86 -0
- package/templates/react-app/src/base/cases/RouterLoader.ts +166 -0
- package/templates/react-app/src/base/port/InteractionHubInterface.ts +94 -0
- package/templates/react-app/src/base/services/I18nService.ts +19 -0
- package/templates/react-app/src/base/types/deprecated-antd.d.ts +60 -0
- package/templates/react-app/src/core/IOC.ts +6 -1
- package/templates/react-app/src/core/bootstrap.ts +21 -31
- package/templates/react-app/src/core/globals.ts +8 -1
- package/templates/react-app/src/core/registers/RegisterGlobals.ts +11 -7
- package/templates/react-app/src/core/registers/index.ts +1 -2
- package/templates/react-app/src/pages/base/About.tsx +114 -1
- package/templates/react-app/src/pages/base/Executor.tsx +10 -15
- package/templates/react-app/src/styles/css/antd-themes/_default.css +239 -0
- package/templates/react-app/src/styles/css/antd-themes/dark.css +176 -0
- package/templates/react-app/src/styles/css/antd-themes/index.css +3 -0
- package/templates/react-app/src/styles/css/antd-themes/no-context.css +34 -0
- package/templates/react-app/src/styles/css/antd-themes/pink.css +199 -0
- package/templates/react-app/src/styles/css/index.css +3 -0
- package/templates/react-app/src/styles/css/themes/_default.css +10 -181
- package/templates/react-app/src/styles/css/themes/dark.css +10 -135
- package/templates/react-app/src/styles/css/themes/pink.css +10 -141
- package/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +1 -1
- package/templates/react-app/src/uikit/controllers/RouterController.ts +1 -1
- package/templates/react-app/src/uikit/controllers/UserController.ts +1 -1
- package/templates/react-app/tsconfig.json +3 -2
- package/templates/react-app/tsconfig.node.json +2 -1
- package/templates/react-app/vite.config.ts +70 -2
- package/templates/react-app/src/base/cases/router-loader/index.ts +0 -90
- package/templates/react-app/src/core/AppConfig.ts +0 -36
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { ComponentType, LazyExoticComponent, ReactNode } from 'react';
|
|
2
|
+
import { RouteObject } from 'react-router-dom';
|
|
3
|
+
import isString from 'lodash/isString';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Component mapping type for lazy-loaded components
|
|
7
|
+
* @description Maps component identifiers to their lazy-loaded implementations
|
|
8
|
+
*/
|
|
9
|
+
export type ComponentValue = Record<string, () => unknown>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Route component type definition supporting both regular and lazy-loaded components
|
|
13
|
+
*/
|
|
14
|
+
type RouteComponentType<T = unknown> =
|
|
15
|
+
| ComponentType<T>
|
|
16
|
+
| LazyExoticComponent<ComponentType<T>>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Extended route configuration interface
|
|
20
|
+
* @description Extends React Router's RouteObject with additional meta information
|
|
21
|
+
*/
|
|
22
|
+
export type RouteConfigValue = Omit<RouteObject, 'element' | 'children'> & {
|
|
23
|
+
/**
|
|
24
|
+
* Component identifier string that maps to a component in componentMaps
|
|
25
|
+
*
|
|
26
|
+
* TODO: support `ReactNode`
|
|
27
|
+
*
|
|
28
|
+
* @description Used to lookup the actual component implementation
|
|
29
|
+
*/
|
|
30
|
+
element?: string;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Nested route configurations
|
|
34
|
+
*/
|
|
35
|
+
children?: RouteConfigValue[];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Additional metadata for the route
|
|
39
|
+
* @description Can store any route-specific data like permissions, titles, etc.
|
|
40
|
+
*/
|
|
41
|
+
meta?: Record<string, unknown>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Route rendering function type
|
|
46
|
+
* @description Function to customize how route components are rendered
|
|
47
|
+
*/
|
|
48
|
+
export type RouterLoaderRender = (
|
|
49
|
+
route: Omit<RouteConfigValue, 'element'> & {
|
|
50
|
+
element: () => RouteComponentType;
|
|
51
|
+
}
|
|
52
|
+
) => ReactNode;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Router loader configuration options
|
|
56
|
+
*/
|
|
57
|
+
export type RouterLoaderOptions = {
|
|
58
|
+
/**
|
|
59
|
+
* Route configuration array
|
|
60
|
+
* @description Defines the application's routing structure
|
|
61
|
+
*/
|
|
62
|
+
routes?: RouteConfigValue[];
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Component mapping object
|
|
66
|
+
* @description Maps component identifiers to their actual implementations
|
|
67
|
+
* @example
|
|
68
|
+
* {
|
|
69
|
+
* 'Home': () => import('./pages/Home'),
|
|
70
|
+
* 'About': () => import('./pages/About')
|
|
71
|
+
* }
|
|
72
|
+
*/
|
|
73
|
+
componentMaps?: ComponentValue;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Custom route rendering function
|
|
77
|
+
* @description Controls how route components are rendered
|
|
78
|
+
* @required
|
|
79
|
+
*/
|
|
80
|
+
render: RouterLoaderRender;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Router Configuration Loader
|
|
85
|
+
*
|
|
86
|
+
* Significance: Manages dynamic route configuration and component loading
|
|
87
|
+
* Core idea: Separate route definitions from component implementations
|
|
88
|
+
* Main function: Transform route configurations into React Router compatible routes
|
|
89
|
+
* Main purpose: Enable dynamic and code-split routing with lazy loading
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* const loader = new RouterLoader({
|
|
93
|
+
* routes: [{
|
|
94
|
+
* path: '/',
|
|
95
|
+
* element: 'Home',
|
|
96
|
+
* children: [{
|
|
97
|
+
* path: 'about',
|
|
98
|
+
* element: 'About'
|
|
99
|
+
* }]
|
|
100
|
+
* }],
|
|
101
|
+
* componentMaps: {
|
|
102
|
+
* 'Home': () => import('./pages/Home'),
|
|
103
|
+
* 'About': () => import('./pages/About')
|
|
104
|
+
* },
|
|
105
|
+
* render: (route) => <Suspense><route.element /></Suspense>
|
|
106
|
+
* });
|
|
107
|
+
*/
|
|
108
|
+
export class RouterLoader {
|
|
109
|
+
constructor(private readonly options: RouterLoaderOptions) {
|
|
110
|
+
if (!options.render) {
|
|
111
|
+
throw new Error('RouterLoader render is required');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get the component mapping object
|
|
117
|
+
* @returns Component mapping dictionary
|
|
118
|
+
*/
|
|
119
|
+
getComponentMaps(): ComponentValue {
|
|
120
|
+
const { componentMaps = {} } = this.options;
|
|
121
|
+
return componentMaps;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Retrieve a component implementation by its identifier
|
|
126
|
+
* @param element Component identifier string
|
|
127
|
+
* @returns Component loader function
|
|
128
|
+
* @throws Error if component is not found in componentMaps
|
|
129
|
+
*/
|
|
130
|
+
getComponent(element: string): () => RouteComponentType {
|
|
131
|
+
const maps = this.getComponentMaps();
|
|
132
|
+
const component = maps[element];
|
|
133
|
+
|
|
134
|
+
if (!component) {
|
|
135
|
+
throw new Error(`Component not found: ${element}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return component as () => RouteComponentType;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Transform a route configuration into a React Router compatible route
|
|
143
|
+
* @param route Route configuration object
|
|
144
|
+
* @returns React Router route object
|
|
145
|
+
*/
|
|
146
|
+
toRoute(route: RouteConfigValue): RouteObject {
|
|
147
|
+
const { render } = this.options;
|
|
148
|
+
const { element, children, ...rest } = route;
|
|
149
|
+
|
|
150
|
+
if (!element || !isString(element)) {
|
|
151
|
+
console.warn(
|
|
152
|
+
`Invalid route, path is: ${route.path}, element is: ${element}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const componet = this.getComponent(element || '404');
|
|
157
|
+
const Element = render({ ...rest, element: componet });
|
|
158
|
+
|
|
159
|
+
// @ts-expect-error
|
|
160
|
+
return {
|
|
161
|
+
...rest,
|
|
162
|
+
element: Element,
|
|
163
|
+
children: children?.map((child) => this.toRoute(child))
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ModalFuncProps } from 'antd';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Confirmation dialog configuration options
|
|
5
|
+
* Extends Ant Design's ModalFuncProps and requires a title
|
|
6
|
+
*/
|
|
7
|
+
export interface ConfirmOptions extends ModalFuncProps {
|
|
8
|
+
content: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Basic dialog configuration options
|
|
13
|
+
*/
|
|
14
|
+
export interface InteractionOptions {
|
|
15
|
+
/** Display duration (milliseconds) */
|
|
16
|
+
duration?: number;
|
|
17
|
+
/** Close callback function */
|
|
18
|
+
onClose?: () => void;
|
|
19
|
+
/** Error object */
|
|
20
|
+
error?: unknown;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Interaction Hub Interface
|
|
25
|
+
*
|
|
26
|
+
* This interface serves as the central interaction layer for the application,
|
|
27
|
+
* managing all user interface interactions, notifications, and feedback functionality.
|
|
28
|
+
* Main responsibilities include:
|
|
29
|
+
* 1. Providing a unified message notification mechanism (success/error/info/warn)
|
|
30
|
+
* 2. Handling user interaction confirmation scenarios (confirm)
|
|
31
|
+
* 3. Unified error display and handling approach
|
|
32
|
+
*
|
|
33
|
+
* Design Goals:
|
|
34
|
+
* - Uniformity: Provide consistent user interaction experience
|
|
35
|
+
* - Extensibility: Easy to add new interaction types
|
|
36
|
+
* - Configurability: Support custom interaction behaviors
|
|
37
|
+
* - Decoupling: Separate UI interaction layer from business logic
|
|
38
|
+
*
|
|
39
|
+
* Use Cases:
|
|
40
|
+
* - Operation success/failure feedback
|
|
41
|
+
* - Important operation confirmation prompts
|
|
42
|
+
* - System message notifications
|
|
43
|
+
* - Warning message display
|
|
44
|
+
*
|
|
45
|
+
* Implementation Notes:
|
|
46
|
+
* - Currently implemented based on Ant Design component library
|
|
47
|
+
* - Supports other UI libraries through different adapters
|
|
48
|
+
* - Supports global configuration of default behaviors
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* // Success notification
|
|
52
|
+
* interactionHub.success("Operation successful", { duration: 3000 });
|
|
53
|
+
*
|
|
54
|
+
* // Confirmation dialog
|
|
55
|
+
* interactionHub.confirm({
|
|
56
|
+
* content: "Are you sure you want to delete?",
|
|
57
|
+
* onOk: () => handleDelete()
|
|
58
|
+
* });
|
|
59
|
+
*/
|
|
60
|
+
export interface InteractionHubInterface {
|
|
61
|
+
/**
|
|
62
|
+
* Display success notification
|
|
63
|
+
* @param message Notification message
|
|
64
|
+
* @param options Configuration options
|
|
65
|
+
*/
|
|
66
|
+
success(message: string, options?: InteractionOptions): void;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Display error notification
|
|
70
|
+
* @param message Error message
|
|
71
|
+
* @param options Configuration options
|
|
72
|
+
*/
|
|
73
|
+
error(message: string, options?: InteractionOptions): void;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Display information notification
|
|
77
|
+
* @param message Information message
|
|
78
|
+
* @param options Configuration options
|
|
79
|
+
*/
|
|
80
|
+
info(message: string, options?: InteractionOptions): void;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Display warning notification
|
|
84
|
+
* @param message Warning message
|
|
85
|
+
* @param options Configuration options
|
|
86
|
+
*/
|
|
87
|
+
warn(message: string, options?: InteractionOptions): void;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Display confirmation dialog
|
|
91
|
+
* @param options Confirmation dialog configuration options
|
|
92
|
+
*/
|
|
93
|
+
confirm(options: ConfirmOptions): void;
|
|
94
|
+
}
|
|
@@ -88,4 +88,23 @@ export class I18nService
|
|
|
88
88
|
static isValidLanguage(language: string): language is I18nServiceLocale {
|
|
89
89
|
return supportedLngs.includes(language as I18nServiceLocale);
|
|
90
90
|
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* translate the key
|
|
94
|
+
* @param key - key to translate
|
|
95
|
+
* @param params - params to pass to the translation
|
|
96
|
+
* @returns translated value
|
|
97
|
+
*/
|
|
98
|
+
t(key: string, params?: Record<string, unknown>): string {
|
|
99
|
+
const i18nValue = i18n.t(key, {
|
|
100
|
+
lng: i18n.language,
|
|
101
|
+
...params
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (!i18nValue || i18nValue === key) {
|
|
105
|
+
return key;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return i18nValue;
|
|
109
|
+
}
|
|
91
110
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import AntdMessageStatic from 'antd/es/message';
|
|
2
|
+
import { TypeOpen } from 'antd/es/message/interface';
|
|
3
|
+
import AntdModalStatic from 'antd/es/modal';
|
|
4
|
+
|
|
5
|
+
import { ModalFunc } from 'antd/es/modal/confirm';
|
|
6
|
+
|
|
7
|
+
declare module 'antd' {
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Please use alternative message implementation instead
|
|
10
|
+
*/
|
|
11
|
+
export const message: typeof AntdMessageStatic & {
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated Please use alternative message implementation instead
|
|
14
|
+
*/
|
|
15
|
+
info: TypeOpen;
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Please use alternative message implementation instead
|
|
18
|
+
*/
|
|
19
|
+
success: TypeOpen;
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated Please use alternative message implementation instead
|
|
22
|
+
*/
|
|
23
|
+
error: TypeOpen;
|
|
24
|
+
/**
|
|
25
|
+
* @deprecated Please use alternative message implementation instead
|
|
26
|
+
*/
|
|
27
|
+
warning: TypeOpen;
|
|
28
|
+
/**
|
|
29
|
+
* @deprecated Please use alternative message implementation instead
|
|
30
|
+
*/
|
|
31
|
+
loading: TypeOpen;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Modal: typeof AntdModalStatic & {
|
|
35
|
+
/**
|
|
36
|
+
* @deprecated Please use alternative message implementation instead
|
|
37
|
+
*/
|
|
38
|
+
confirm: ModalFunc;
|
|
39
|
+
/**
|
|
40
|
+
* @deprecated Please use alternative message implementation instead
|
|
41
|
+
*/
|
|
42
|
+
info: ModalFunc;
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated Please use alternative message implementation instead
|
|
45
|
+
*/
|
|
46
|
+
success: ModalFunc;
|
|
47
|
+
/**
|
|
48
|
+
* @deprecated Please use alternative message implementation instead
|
|
49
|
+
*/
|
|
50
|
+
error: ModalFunc;
|
|
51
|
+
/**
|
|
52
|
+
* @deprecated Please use alternative message implementation instead
|
|
53
|
+
*/
|
|
54
|
+
warn: ModalFunc;
|
|
55
|
+
/**
|
|
56
|
+
* @deprecated Please use alternative message implementation instead
|
|
57
|
+
*/
|
|
58
|
+
warning: ModalFunc;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -11,11 +11,14 @@ import {
|
|
|
11
11
|
} from '@qlover/corekit-bridge';
|
|
12
12
|
import type { JSONSerializer, JSONStorage } from '@qlover/fe-corekit';
|
|
13
13
|
import type { LoggerInterface } from '@qlover/logger';
|
|
14
|
+
import type { AppConfig } from '@/base/cases/AppConfig';
|
|
14
15
|
import { Container } from 'inversify';
|
|
15
16
|
import { IOCRegisterInterface } from '@qlover/corekit-bridge';
|
|
17
|
+
import { DialogHandler } from '@/base/cases/DialogHandler';
|
|
16
18
|
|
|
17
19
|
export type IocRegisterOptions = {
|
|
18
20
|
pathname: string;
|
|
21
|
+
appConfig: AppConfig;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
export type InversifyRegisterContainer = Container;
|
|
@@ -72,7 +75,8 @@ export const IOCIdentifier = Object.freeze({
|
|
|
72
75
|
FeApiCommonPlugin: 'FeApiCommonPlugin',
|
|
73
76
|
AppConfig: 'AppConfig',
|
|
74
77
|
ApiMockPlugin: 'ApiMockPlugin',
|
|
75
|
-
ApiCatchPlugin: 'ApiCatchPlugin'
|
|
78
|
+
ApiCatchPlugin: 'ApiCatchPlugin',
|
|
79
|
+
DialogHandler: 'DialogHandler'
|
|
76
80
|
});
|
|
77
81
|
|
|
78
82
|
/**
|
|
@@ -87,6 +91,7 @@ export interface IOCIdentifierMap {
|
|
|
87
91
|
[IOCIdentifier.AppConfig]: EnvConfigInterface;
|
|
88
92
|
[IOCIdentifier.ApiMockPlugin]: ApiMockPlugin;
|
|
89
93
|
[IOCIdentifier.ApiCatchPlugin]: ApiCatchPlugin;
|
|
94
|
+
[IOCIdentifier.DialogHandler]: DialogHandler;
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
export const IOC = createIOCFunction<IOCIdentifierMap>(
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Bootstrap,
|
|
3
|
-
type InjectGlobalConfig,
|
|
4
|
-
type InjectIOCOptions,
|
|
5
|
-
type IOCContainerInterface,
|
|
6
|
-
type InjectEnvConfig
|
|
7
|
-
} from '@qlover/corekit-bridge';
|
|
8
|
-
import AppConfig from '@/core/AppConfig';
|
|
1
|
+
import { Bootstrap } from '@qlover/corekit-bridge';
|
|
9
2
|
import { envBlackList, envPrefix, browserGlobalsName } from '@config/common';
|
|
10
3
|
import { IOC } from './IOC';
|
|
11
4
|
import * as globals from '@/core/globals';
|
|
@@ -24,33 +17,30 @@ export default async function startup({
|
|
|
24
17
|
throw new Error(GLOBAL_NO_WINDOW);
|
|
25
18
|
}
|
|
26
19
|
|
|
27
|
-
const { logger } = globals;
|
|
20
|
+
const { logger, appConfig } = globals;
|
|
28
21
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
blackList: envBlackList
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const iocOptions: InjectIOCOptions<IOCContainerInterface> = {
|
|
37
|
-
manager: IOC,
|
|
38
|
-
register: new IocRegister({
|
|
39
|
-
pathname: root.location.pathname
|
|
40
|
-
})
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const globalOptions: InjectGlobalConfig = {
|
|
44
|
-
sources: globals,
|
|
45
|
-
target: browserGlobalsName
|
|
46
|
-
};
|
|
22
|
+
const iocRegister = new IocRegister({
|
|
23
|
+
pathname: root.location.pathname,
|
|
24
|
+
appConfig
|
|
25
|
+
});
|
|
47
26
|
|
|
48
27
|
const bootstrap = new Bootstrap({
|
|
49
28
|
root,
|
|
50
29
|
logger,
|
|
51
|
-
ioc:
|
|
52
|
-
|
|
53
|
-
|
|
30
|
+
ioc: {
|
|
31
|
+
manager: IOC,
|
|
32
|
+
register: iocRegister
|
|
33
|
+
},
|
|
34
|
+
envOptions: {
|
|
35
|
+
target: appConfig,
|
|
36
|
+
source: envSource,
|
|
37
|
+
prefix: envPrefix,
|
|
38
|
+
blackList: envBlackList
|
|
39
|
+
},
|
|
40
|
+
globalOptions: {
|
|
41
|
+
sources: globals,
|
|
42
|
+
target: browserGlobalsName
|
|
43
|
+
}
|
|
54
44
|
});
|
|
55
45
|
|
|
56
46
|
try {
|
|
@@ -63,6 +53,6 @@ export default async function startup({
|
|
|
63
53
|
|
|
64
54
|
await bootstrap.use(bootstrapsRegistry.register()).start();
|
|
65
55
|
} catch (error) {
|
|
66
|
-
logger.error(`${
|
|
56
|
+
logger.error(`${appConfig.appName} starup error:`, error);
|
|
67
57
|
}
|
|
68
58
|
}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
// ! global variables, don't import any dependencies and don't have side effects
|
|
2
2
|
import { JSONStorage, JSONSerializer, SyncStorage } from '@qlover/fe-corekit';
|
|
3
3
|
import { ColorFormatter, ConsoleHandler, Logger } from '@qlover/corekit-bridge';
|
|
4
|
+
import { DialogHandler } from '@/base/cases/DialogHandler';
|
|
5
|
+
import { loggerStyles } from '@config/common';
|
|
6
|
+
import { AppConfig } from '@/base/cases/AppConfig';
|
|
4
7
|
|
|
5
8
|
const isProduction = import.meta.env.VITE_USER_NODE_ENV === 'production';
|
|
6
9
|
|
|
10
|
+
export const appConfig = new AppConfig();
|
|
11
|
+
|
|
12
|
+
export const dialogHandler = new DialogHandler();
|
|
13
|
+
|
|
7
14
|
/**
|
|
8
15
|
* Global logger
|
|
9
16
|
*/
|
|
10
17
|
export const logger = new Logger({
|
|
11
|
-
handlers: new ConsoleHandler(new ColorFormatter()),
|
|
18
|
+
handlers: new ConsoleHandler(new ColorFormatter(loggerStyles)),
|
|
12
19
|
silent: isProduction
|
|
13
20
|
});
|
|
14
21
|
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { JSONSerializer, JSONStorage } from '@qlover/fe-corekit';
|
|
2
|
-
import type {
|
|
3
|
-
import { JSON, localJsonStorage, logger } from '../globals';
|
|
2
|
+
import type { IOCManagerInterface } from '@qlover/corekit-bridge';
|
|
3
|
+
import { dialogHandler, JSON, localJsonStorage, logger } from '../globals';
|
|
4
4
|
import {
|
|
5
5
|
type InversifyContainer,
|
|
6
6
|
type InversifyRegisterInterface,
|
|
7
|
-
IOCIdentifier
|
|
7
|
+
IOCIdentifier,
|
|
8
|
+
IocRegisterOptions
|
|
8
9
|
} from '@/core/IOC';
|
|
9
10
|
import { Logger } from '@qlover/logger';
|
|
10
11
|
|
|
11
12
|
export class RegisterGlobals implements InversifyRegisterInterface {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
register(
|
|
14
|
+
container: InversifyContainer,
|
|
15
|
+
_: IOCManagerInterface<InversifyContainer>,
|
|
16
|
+
options: IocRegisterOptions
|
|
17
|
+
): void {
|
|
15
18
|
// inject AppConfig to IOC
|
|
16
|
-
container.bind(IOCIdentifier.AppConfig,
|
|
19
|
+
container.bind(IOCIdentifier.AppConfig, options.appConfig);
|
|
20
|
+
container.bind(IOCIdentifier.DialogHandler, dialogHandler);
|
|
17
21
|
|
|
18
22
|
container.bind(JSONSerializer, JSON);
|
|
19
23
|
container.bind(IOCIdentifier.JSON, JSON);
|
|
@@ -2,7 +2,6 @@ import { RegisterGlobals } from './RegisterGlobals';
|
|
|
2
2
|
import { RegisterCommon } from './RegisterCommon';
|
|
3
3
|
import { RegisterApi } from './RegisterApi';
|
|
4
4
|
import { RegisterControllers } from './RegisterControllers';
|
|
5
|
-
import AppConfig from '../AppConfig';
|
|
6
5
|
import {
|
|
7
6
|
InversifyContainer,
|
|
8
7
|
InversifyRegisterInterface,
|
|
@@ -15,7 +14,7 @@ export class IocRegister implements InversifyRegisterInterface {
|
|
|
15
14
|
|
|
16
15
|
getRegisterList(): InversifyRegisterInterface[] {
|
|
17
16
|
return [
|
|
18
|
-
new RegisterGlobals(
|
|
17
|
+
new RegisterGlobals(),
|
|
19
18
|
new RegisterCommon(),
|
|
20
19
|
new RegisterApi(),
|
|
21
20
|
new RegisterControllers()
|
|
@@ -1,14 +1,127 @@
|
|
|
1
1
|
import { useBaseRoutePage } from '@/uikit/contexts/BaseRouteContext';
|
|
2
2
|
import * as i18nKeys from '@config/Identifier.I18n';
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
Tooltip,
|
|
6
|
+
message,
|
|
7
|
+
notification,
|
|
8
|
+
Modal,
|
|
9
|
+
Drawer,
|
|
10
|
+
Popover,
|
|
11
|
+
Popconfirm,
|
|
12
|
+
Alert
|
|
13
|
+
} from 'antd';
|
|
14
|
+
import { useState } from 'react';
|
|
3
15
|
|
|
4
16
|
export default function About() {
|
|
5
17
|
const { t } = useBaseRoutePage();
|
|
18
|
+
const [messageApi, contextHolder] = message.useMessage();
|
|
19
|
+
const [notificationApi, contextHolder2] = notification.useNotification();
|
|
20
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
21
|
+
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
|
22
|
+
|
|
23
|
+
const showMessage = () => {
|
|
24
|
+
messageApi.info(t(i18nKeys.ABOUT_MESSAGE_TEST), 2000);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const showNotification = () => {
|
|
28
|
+
notificationApi.open({
|
|
29
|
+
message: t(i18nKeys.ABOUT_NOTIFICATION_TITLE),
|
|
30
|
+
description: t(i18nKeys.ABOUT_NOTIFICATION_DESC),
|
|
31
|
+
duration: 2000
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
const showNotification2 = () => {
|
|
35
|
+
notification.open({
|
|
36
|
+
message: t(i18nKeys.ABOUT_NOTIFICATION_TITLE),
|
|
37
|
+
description: t(i18nKeys.ABOUT_NOTIFICATION_DESC),
|
|
38
|
+
duration: 2000
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const showModal = () => {
|
|
43
|
+
setIsModalOpen(true);
|
|
44
|
+
};
|
|
45
|
+
const showMessage2 = () => {
|
|
46
|
+
message.info(t(i18nKeys.ABOUT_MESSAGE_TEST), 200);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const showDrawer = () => {
|
|
50
|
+
setIsDrawerOpen(true);
|
|
51
|
+
};
|
|
52
|
+
|
|
6
53
|
return (
|
|
7
54
|
<div className="min-h-screen bg-primary py-6 flex flex-col justify-center sm:py-12">
|
|
55
|
+
{contextHolder}
|
|
56
|
+
{contextHolder2}
|
|
8
57
|
<div className="relative py-3 sm:max-w-xl sm:mx-auto">
|
|
9
|
-
<h1 className="text-2xl font-bold text-center text-text">
|
|
58
|
+
<h1 className="text-2xl font-bold text-center text-text mb-8">
|
|
10
59
|
{t(i18nKeys.PAGE_ABOUT_TITLE)}
|
|
11
60
|
</h1>
|
|
61
|
+
|
|
62
|
+
<div className="space-x-4 flex justify-center flex-wrap gap-4">
|
|
63
|
+
<Button onClick={showMessage}>{t(i18nKeys.ABOUT_BTN_MESSAGE)}</Button>
|
|
64
|
+
<Button onClick={showMessage2}>
|
|
65
|
+
{t(i18nKeys.ABOUT_BTN_MESSAGE2)}
|
|
66
|
+
</Button>
|
|
67
|
+
|
|
68
|
+
<Button onClick={showNotification}>
|
|
69
|
+
{t(i18nKeys.ABOUT_BTN_NOTIFICATION)}
|
|
70
|
+
</Button>
|
|
71
|
+
|
|
72
|
+
<Button onClick={showNotification2}>
|
|
73
|
+
{t(i18nKeys.ABOUT_BTN_NOTIFICATION2)}
|
|
74
|
+
</Button>
|
|
75
|
+
|
|
76
|
+
<Tooltip title={t(i18nKeys.ABOUT_TOOLTIP_TEXT)}>
|
|
77
|
+
<Button>{t(i18nKeys.ABOUT_BTN_TOOLTIP)}</Button>
|
|
78
|
+
</Tooltip>
|
|
79
|
+
|
|
80
|
+
<Modal
|
|
81
|
+
title={t(i18nKeys.ABOUT_MODAL_TITLE)}
|
|
82
|
+
open={isModalOpen}
|
|
83
|
+
onOk={() => setIsModalOpen(false)}
|
|
84
|
+
onCancel={() => setIsModalOpen(false)}
|
|
85
|
+
>
|
|
86
|
+
<p>{t(i18nKeys.ABOUT_MODAL_CONTENT)}</p>
|
|
87
|
+
</Modal>
|
|
88
|
+
|
|
89
|
+
<Button onClick={showModal}>{t(i18nKeys.ABOUT_BTN_MODAL)}</Button>
|
|
90
|
+
|
|
91
|
+
<Drawer
|
|
92
|
+
title={t(i18nKeys.ABOUT_DRAWER_TITLE)}
|
|
93
|
+
open={isDrawerOpen}
|
|
94
|
+
onClose={() => setIsDrawerOpen(false)}
|
|
95
|
+
>
|
|
96
|
+
<p>{t(i18nKeys.ABOUT_DRAWER_CONTENT)}</p>
|
|
97
|
+
</Drawer>
|
|
98
|
+
|
|
99
|
+
<Button onClick={showDrawer}>{t(i18nKeys.ABOUT_BTN_DRAWER)}</Button>
|
|
100
|
+
|
|
101
|
+
<Popover
|
|
102
|
+
content={t(i18nKeys.ABOUT_POPOVER_CONTENT)}
|
|
103
|
+
title={t(i18nKeys.ABOUT_POPOVER_TITLE)}
|
|
104
|
+
>
|
|
105
|
+
<Button>{t(i18nKeys.ABOUT_BTN_POPOVER)}</Button>
|
|
106
|
+
</Popover>
|
|
107
|
+
|
|
108
|
+
<Popconfirm
|
|
109
|
+
title={t(i18nKeys.ABOUT_POPCONFIRM_TITLE)}
|
|
110
|
+
description={t(i18nKeys.ABOUT_POPCONFIRM_DESC)}
|
|
111
|
+
okText={t(i18nKeys.COMMON_OK)}
|
|
112
|
+
cancelText={t(i18nKeys.COMMON_CANCEL)}
|
|
113
|
+
>
|
|
114
|
+
<Button>{t(i18nKeys.ABOUT_BTN_POPCONFIRM)}</Button>
|
|
115
|
+
</Popconfirm>
|
|
116
|
+
|
|
117
|
+
<Alert
|
|
118
|
+
message={t(i18nKeys.ABOUT_ALERT_MESSAGE)}
|
|
119
|
+
type="warning"
|
|
120
|
+
showIcon
|
|
121
|
+
closable
|
|
122
|
+
className="mt-4"
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
12
125
|
</div>
|
|
13
126
|
</div>
|
|
14
127
|
);
|