@qlover/create-app 0.8.0 → 0.10.0
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 +32 -0
- package/dist/configs/_common/.github/workflows/general-check.yml +1 -1
- package/dist/configs/_common/.github/workflows/release.yml +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/next-app/.env.template +9 -10
- package/dist/templates/next-app/eslint.config.mjs +5 -0
- package/dist/templates/next-app/next.config.ts +1 -1
- package/dist/templates/next-app/src/app/[locale]/login/page.tsx +1 -1
- package/dist/templates/next-app/src/app/[locale]/page.tsx +1 -1
- package/dist/templates/next-app/src/app/[locale]/register/page.tsx +1 -1
- package/dist/templates/next-app/src/app/api/locales/json/route.ts +2 -1
- package/dist/templates/next-app/src/i18n/request.ts +2 -2
- package/dist/templates/react-app/__tests__/__mocks__/{MockAppConfit.ts → MockAppConfig.ts} +1 -1
- package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +10 -17
- package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +27 -8
- package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -1
- package/dist/templates/react-app/__tests__/__mocks__/i18nextHttpBackend.ts +110 -0
- package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +3 -2
- package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +13 -0
- package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +3 -1
- package/dist/templates/react-app/__tests__/src/uikit/components/chatMessage/ChatRoot.test.tsx +274 -0
- package/dist/templates/react-app/config/IOCIdentifier.ts +9 -3
- package/dist/templates/react-app/config/Identifier/components/component.chatMessage.ts +56 -0
- package/dist/templates/react-app/config/Identifier/components/component.messageBaseList.ts +103 -0
- package/dist/templates/react-app/config/Identifier/pages/index.ts +1 -0
- package/dist/templates/react-app/config/Identifier/pages/page.message.ts +20 -0
- package/dist/templates/react-app/config/app.router.ts +23 -0
- package/dist/templates/react-app/config/common.ts +38 -0
- package/dist/templates/react-app/config/feapi.mock.json +5 -12
- package/dist/templates/react-app/config/i18n/chatMessageI18n.ts +17 -0
- package/dist/templates/react-app/config/i18n/messageBaseListI18n.ts +22 -0
- package/dist/templates/react-app/config/i18n/messageI18n.ts +14 -0
- package/dist/templates/react-app/docs/en/components/chat-message-component.md +314 -0
- package/dist/templates/react-app/docs/en/components/chat-message-refactor.md +270 -0
- package/dist/templates/react-app/docs/en/components/message-base-list-component.md +172 -0
- package/dist/templates/react-app/docs/zh/components/chat-message-component.md +314 -0
- package/dist/templates/react-app/docs/zh/components/chat-message-refactor.md +270 -0
- package/dist/templates/react-app/docs/zh/components/message-base-list-component.md +172 -0
- package/dist/templates/react-app/eslint.config.mjs +6 -5
- package/dist/templates/react-app/package.json +1 -1
- package/dist/templates/react-app/playwright.config.ts +6 -6
- package/dist/templates/react-app/public/locales/en/common.json +44 -1
- package/dist/templates/react-app/public/locales/zh/common.json +44 -1
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +22 -13
- package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +3 -3
- package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +17 -12
- package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +19 -2
- package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +2 -4
- package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +15 -9
- package/dist/templates/react-app/src/base/services/BaseLayoutService.ts +55 -0
- package/dist/templates/react-app/src/base/services/I18nService.ts +1 -0
- package/dist/templates/react-app/src/base/services/UserBootstrap.ts +43 -0
- package/dist/templates/react-app/src/base/services/UserGatewayPlugin.ts +16 -0
- package/dist/templates/react-app/src/base/services/UserService.ts +51 -80
- package/dist/templates/react-app/src/core/bootstraps/BootstrapClient.ts +8 -3
- package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +6 -6
- package/dist/templates/react-app/src/core/bootstraps/SaveAppInfo.ts +28 -0
- package/dist/templates/react-app/src/core/clientIoc/ClientIOCRegister.ts +24 -18
- package/dist/templates/react-app/src/core/globals.ts +10 -11
- package/dist/templates/react-app/src/main.tsx +1 -1
- package/dist/templates/react-app/src/pages/auth/Layout.tsx +4 -4
- package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +1 -1
- package/dist/templates/react-app/src/pages/base/Layout.tsx +3 -3
- package/dist/templates/react-app/src/pages/base/MessagePage.tsx +40 -0
- package/dist/templates/react-app/src/uikit/components/BaseLayoutProvider.tsx +44 -0
- package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +1 -3
- package/dist/templates/react-app/src/uikit/components/MessageBaseList.tsx +240 -0
- package/dist/templates/react-app/src/uikit/components/chatMessage/ChatMessageBridge.ts +176 -0
- package/dist/templates/react-app/src/uikit/components/chatMessage/ChatRoot.tsx +21 -0
- package/dist/templates/react-app/src/uikit/components/chatMessage/FocusBar.tsx +106 -0
- package/dist/templates/react-app/src/uikit/components/chatMessage/MessageApi.ts +271 -0
- package/dist/templates/react-app/src/uikit/components/chatMessage/MessageItem.tsx +102 -0
- package/dist/templates/react-app/src/uikit/components/chatMessage/MessagesList.tsx +86 -0
- package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +9 -0
- package/dist/templates/react-app/src/uikit/hooks/{useI18nGuard.ts → useRouterI18nGuard.ts} +7 -4
- package/dist/templates/react-app/tsconfig.app.json +4 -2
- package/dist/templates/react-app/tsconfig.node.json +4 -0
- package/dist/templates/react-app/tsconfig.test.json +3 -1
- package/package.json +3 -3
- package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +0 -102
- package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +0 -61
- package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +0 -57
- package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +0 -28
- package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +0 -16
|
@@ -6,20 +6,20 @@ import {
|
|
|
6
6
|
} from '@qlover/fe-corekit';
|
|
7
7
|
import { inject, injectable } from 'inversify';
|
|
8
8
|
import { AppError } from '@/base/cases/AppError';
|
|
9
|
-
import { RegisterFormData } from '@/base/services/UserService';
|
|
10
9
|
import { UserApiAdapter } from './UserApiAdapter';
|
|
11
10
|
import { UserApiConfig } from './UserApiBootstarp';
|
|
12
11
|
import {
|
|
13
12
|
GetIpInfoTransaction,
|
|
14
13
|
UserApiGetUserInfoTransaction,
|
|
15
14
|
UserApiLoginTransaction,
|
|
15
|
+
UserApiRegisterTransaction,
|
|
16
16
|
UserApiTestApiCatchResultTransaction,
|
|
17
|
-
UserInfo
|
|
17
|
+
UserInfo,
|
|
18
|
+
UserCredential
|
|
18
19
|
} from './UserApiType';
|
|
19
20
|
import type {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
UserAuthStoreInterface
|
|
21
|
+
UserAuthStoreInterface,
|
|
22
|
+
UserServiceGateway
|
|
23
23
|
} from '@qlover/corekit-bridge';
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -32,7 +32,7 @@ import type {
|
|
|
32
32
|
@injectable()
|
|
33
33
|
export class UserApi
|
|
34
34
|
extends RequestTransaction<UserApiConfig>
|
|
35
|
-
implements
|
|
35
|
+
implements UserServiceGateway<UserInfo, UserCredential>
|
|
36
36
|
{
|
|
37
37
|
protected store: UserAuthStoreInterface<UserInfo> | null = null;
|
|
38
38
|
|
|
@@ -85,7 +85,7 @@ export class UserApi
|
|
|
85
85
|
*/
|
|
86
86
|
async login(
|
|
87
87
|
params: UserApiLoginTransaction['data']
|
|
88
|
-
): Promise<
|
|
88
|
+
): Promise<UserCredential> {
|
|
89
89
|
const response = await this.post<UserApiLoginTransaction>(
|
|
90
90
|
'/api/login',
|
|
91
91
|
params
|
|
@@ -108,24 +108,33 @@ export class UserApi
|
|
|
108
108
|
* @returns
|
|
109
109
|
*/
|
|
110
110
|
register(
|
|
111
|
-
params:
|
|
112
|
-
): Promise<
|
|
113
|
-
|
|
111
|
+
params: UserApiRegisterTransaction['data']
|
|
112
|
+
): Promise<UserApiRegisterTransaction['response']['data']> {
|
|
113
|
+
// @ts-expect-error - TODO: implement
|
|
114
|
+
return this.post<UserApiRegisterTransaction>('/api/register', params);
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
/**
|
|
117
118
|
* @override
|
|
118
119
|
* @returns
|
|
119
120
|
*/
|
|
120
|
-
|
|
121
|
-
return
|
|
121
|
+
async refreshUserInfo(): Promise<UserInfo> {
|
|
122
|
+
return this.getUserInfo();
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
/**
|
|
125
126
|
* @override
|
|
126
127
|
* @returns
|
|
127
128
|
*/
|
|
128
|
-
|
|
129
|
+
logout(): Promise<any> {
|
|
130
|
+
return this.post('/api/logout');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @override
|
|
135
|
+
* @returns
|
|
136
|
+
*/
|
|
137
|
+
async getUserInfo(_credential?: UserCredential): Promise<UserInfo> {
|
|
129
138
|
const response =
|
|
130
139
|
await this.get<UserApiGetUserInfoTransaction>('/api/userinfo');
|
|
131
140
|
|
|
@@ -2,7 +2,7 @@ import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
|
2
2
|
import {
|
|
3
3
|
type BootstrapContext,
|
|
4
4
|
type BootstrapExecutorPlugin,
|
|
5
|
-
type
|
|
5
|
+
type ApiMockPluginOptions,
|
|
6
6
|
type ApiCatchPluginConfig,
|
|
7
7
|
type ApiCatchPluginResponse
|
|
8
8
|
} from '@qlover/corekit-bridge';
|
|
@@ -23,12 +23,12 @@ import type {
|
|
|
23
23
|
* UserApiConfig is the config for the UserApi.
|
|
24
24
|
*
|
|
25
25
|
* extends:
|
|
26
|
-
* -
|
|
26
|
+
* - ApiMockPluginOptions
|
|
27
27
|
* - ApiCatchPluginConfig
|
|
28
28
|
*/
|
|
29
29
|
export interface UserApiConfig<Request = unknown>
|
|
30
30
|
extends RequestAdapterConfig<Request>,
|
|
31
|
-
|
|
31
|
+
ApiMockPluginOptions,
|
|
32
32
|
ApiCatchPluginConfig {}
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UserApiTransaction } from './UserApiBootstarp';
|
|
2
|
+
import type { LoginParams } from '@qlover/corekit-bridge';
|
|
2
3
|
|
|
3
4
|
export type UserInfo = {
|
|
4
5
|
name: string;
|
|
@@ -44,22 +45,26 @@ export type UserApiGetUserInfoTransaction = UserApiTransaction<
|
|
|
44
45
|
UserInfo
|
|
45
46
|
>;
|
|
46
47
|
|
|
48
|
+
export type UserCredential = {
|
|
49
|
+
token: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
47
52
|
export type UserApiLoginTransaction = UserApiTransaction<
|
|
48
|
-
{ username
|
|
49
|
-
|
|
50
|
-
token: string;
|
|
51
|
-
}
|
|
53
|
+
LoginParams & { username?: string },
|
|
54
|
+
UserCredential
|
|
52
55
|
>;
|
|
53
56
|
|
|
54
57
|
export type UserApiTestApiCatchResultTransaction = UserApiGetRandomUser;
|
|
55
58
|
|
|
59
|
+
export interface RegisterFormData {
|
|
60
|
+
username: string;
|
|
61
|
+
email: string;
|
|
62
|
+
password: string;
|
|
63
|
+
confirmPassword: string;
|
|
64
|
+
agreeToTerms: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
56
67
|
export type UserApiRegisterTransaction = UserApiTransaction<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
email: string;
|
|
60
|
-
password: string;
|
|
61
|
-
confirmPassword: string;
|
|
62
|
-
agreeToTerms: boolean;
|
|
63
|
-
},
|
|
64
|
-
UserApiTransaction['response']['data']
|
|
68
|
+
RegisterFormData,
|
|
69
|
+
UserInfo
|
|
65
70
|
>;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
2
|
+
import {
|
|
3
|
+
ExecutorError,
|
|
4
|
+
type ExecutorContext,
|
|
5
|
+
type ExecutorPlugin
|
|
6
|
+
} from '@qlover/fe-corekit';
|
|
2
7
|
import { inject, injectable } from 'inversify';
|
|
3
8
|
import type { I18nServiceInterface } from '../port/I18nServiceInterface';
|
|
4
|
-
import type { ExecutorContext, ExecutorPlugin } from '@qlover/fe-corekit';
|
|
5
9
|
import type { LoggerInterface } from '@qlover/logger';
|
|
6
10
|
|
|
7
11
|
/**
|
|
@@ -19,14 +23,27 @@ export class I18nKeyErrorPlugin implements ExecutorPlugin {
|
|
|
19
23
|
protected i18nService: I18nServiceInterface
|
|
20
24
|
) {}
|
|
21
25
|
|
|
26
|
+
protected translateById(id: string): string {
|
|
27
|
+
return this.i18nService.t(id);
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
onError(context: ExecutorContext<unknown>): Error | void {
|
|
23
31
|
const { error } = context;
|
|
24
32
|
|
|
33
|
+
if (!error) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (error instanceof ExecutorError) {
|
|
38
|
+
const i18nText = this.translateById(error.id);
|
|
39
|
+
return new ExecutorError(error.id, i18nText);
|
|
40
|
+
}
|
|
41
|
+
|
|
25
42
|
if (error instanceof Error) {
|
|
26
43
|
const i18nKey = error.message;
|
|
27
44
|
|
|
28
45
|
if (i18nKey && typeof i18nKey === 'string') {
|
|
29
|
-
const i18nText = this.
|
|
46
|
+
const i18nText = this.translateById(i18nKey);
|
|
30
47
|
|
|
31
48
|
if (i18nText && i18nText !== i18nKey) {
|
|
32
49
|
this.logger.debug('I18nKeyErrorPlugin Error:', i18nText);
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { StoreInterface } from '@qlover/corekit-bridge';
|
|
2
2
|
import type { RouteConfigValue } from '../cases/RouterLoader';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
StoreStateInterface
|
|
6
|
-
} from '@qlover/corekit-bridge';
|
|
3
|
+
import type { StoreStateInterface } from '@qlover/corekit-bridge';
|
|
4
|
+
import type { LoggerInterface } from '@qlover/logger';
|
|
7
5
|
import type { NavigateFunction, NavigateOptions } from 'react-router-dom';
|
|
8
6
|
|
|
9
7
|
export interface RouteServiceStateInterface extends StoreStateInterface {
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
import type { ExecutorPlugin } from '@qlover/fe-corekit';
|
|
1
|
+
import type { UserInfo, UserCredential } from '@/base/apis/userApi/UserApiType';
|
|
2
|
+
import type { UserServiceInterface as CorekitBridgeUserServiceInterface } from '@qlover/corekit-bridge';
|
|
4
3
|
|
|
5
|
-
export
|
|
6
|
-
extends
|
|
7
|
-
|
|
8
|
-
{
|
|
9
|
-
readonly pluginName = 'UserService';
|
|
4
|
+
export interface UserServiceInterface
|
|
5
|
+
extends CorekitBridgeUserServiceInterface<UserInfo, UserCredential> {
|
|
6
|
+
// You can add your own methods here
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Get the user token
|
|
10
|
+
*
|
|
11
|
+
* This is a extends method from the corekit-bridge UserServiceInterface.
|
|
12
|
+
*/
|
|
13
|
+
getToken(): string;
|
|
14
|
+
|
|
15
|
+
isUserInfo(value: unknown): value is UserInfo;
|
|
16
|
+
|
|
17
|
+
isUserCredential(value: unknown): value is UserCredential;
|
|
12
18
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { I } from '@config/IOCIdentifier';
|
|
2
|
+
import { AsyncExecutor, ExecutorPlugin } from '@qlover/fe-corekit';
|
|
3
|
+
import { injectable, inject } from 'inversify';
|
|
4
|
+
import { UserBootstrap } from './UserBootstrap';
|
|
5
|
+
import type { RouteServiceInterface } from '../port/RouteServiceInterface';
|
|
6
|
+
import type { UserServiceInterface } from '../port/UserServiceInterface';
|
|
7
|
+
import type {
|
|
8
|
+
BootstrapContextValue,
|
|
9
|
+
IOCContainerInterface
|
|
10
|
+
} from '@qlover/corekit-bridge';
|
|
11
|
+
import type { LoggerInterface } from '@qlover/logger';
|
|
12
|
+
|
|
13
|
+
@injectable()
|
|
14
|
+
export class BaseLayoutService {
|
|
15
|
+
protected executor: AsyncExecutor = new AsyncExecutor();
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
@inject(I.Logger) protected logger: LoggerInterface,
|
|
19
|
+
@inject(I.RouteServiceInterface)
|
|
20
|
+
protected routeService: RouteServiceInterface,
|
|
21
|
+
@inject(I.UserServiceInterface)
|
|
22
|
+
protected userService: UserServiceInterface
|
|
23
|
+
) {
|
|
24
|
+
this.use(new UserBootstrap(userService));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
use(plugin: ExecutorPlugin): this {
|
|
28
|
+
this.executor.use(plugin);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
handler(): Promise<{ success: boolean }> {
|
|
33
|
+
return Promise.resolve({
|
|
34
|
+
success: true
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async starup(ioc: IOCContainerInterface): Promise<unknown> {
|
|
39
|
+
const context: BootstrapContextValue = {
|
|
40
|
+
root: {},
|
|
41
|
+
logger: this.logger,
|
|
42
|
+
ioc: ioc
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const result = await this.executor.exec(context, this.handler.bind(this));
|
|
47
|
+
this.logger.info('BaseLayoutService starup success!');
|
|
48
|
+
return result;
|
|
49
|
+
} catch (err) {
|
|
50
|
+
this.logger.error('BaseLayoutService starup failed!', err);
|
|
51
|
+
|
|
52
|
+
this.routeService.gotoLogin();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { LOCAL_NO_USER_TOKEN } from '@config/Identifier';
|
|
2
|
+
import { I } from '@config/IOCIdentifier';
|
|
3
|
+
import { inject, injectable } from 'inversify';
|
|
4
|
+
import { AppError } from '../cases/AppError';
|
|
5
|
+
import type { UserServiceInterface } from '../port/UserServiceInterface';
|
|
6
|
+
import type { BootstrapExecutorPlugin } from '@qlover/corekit-bridge';
|
|
7
|
+
|
|
8
|
+
@injectable()
|
|
9
|
+
export class UserBootstrap implements BootstrapExecutorPlugin {
|
|
10
|
+
readonly pluginName = 'UserBootstrap';
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
@inject(I.UserServiceInterface)
|
|
14
|
+
protected userService: UserServiceInterface
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
async onBefore(): Promise<void> {
|
|
18
|
+
const userService = this.userService;
|
|
19
|
+
|
|
20
|
+
if (userService.isAuthenticated()) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 如果用户凭证存在,则刷新用户信息, 更新状态
|
|
25
|
+
const credential = userService.getCredential();
|
|
26
|
+
if (userService.isUserCredential(credential)) {
|
|
27
|
+
userService.getStore().start();
|
|
28
|
+
|
|
29
|
+
const user = await userService.refreshUserInfo();
|
|
30
|
+
|
|
31
|
+
userService.getStore().success(user);
|
|
32
|
+
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const newError = new AppError(LOCAL_NO_USER_TOKEN);
|
|
37
|
+
|
|
38
|
+
userService.getStore().failed(newError);
|
|
39
|
+
|
|
40
|
+
// 否则还是抛出错误
|
|
41
|
+
throw newError;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { UserInfo, UserCredential } from '@/base/apis/userApi/UserApiType';
|
|
2
|
+
import type { RouteServiceInterface } from '../port/RouteServiceInterface';
|
|
3
|
+
import type { UserServicePluginInterface } from '@qlover/corekit-bridge';
|
|
4
|
+
|
|
5
|
+
export class UserGatewayPlugin
|
|
6
|
+
implements UserServicePluginInterface<UserInfo, UserCredential>
|
|
7
|
+
{
|
|
8
|
+
readonly pluginName = 'UserGatewayPlugin';
|
|
9
|
+
|
|
10
|
+
constructor(protected routerService: RouteServiceInterface) {}
|
|
11
|
+
|
|
12
|
+
onLogoutSuccess(): void {
|
|
13
|
+
this.routerService.reset();
|
|
14
|
+
this.routerService.gotoLogin();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,51 +1,41 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
1
|
+
import { I } from '@config/IOCIdentifier';
|
|
3
2
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
LoginResponseData,
|
|
7
|
-
UserAuthStore
|
|
3
|
+
UserService as CorekitBridgeUserService,
|
|
4
|
+
GatewayExecutor
|
|
8
5
|
} from '@qlover/corekit-bridge';
|
|
9
|
-
import { type SyncStorageInterface } from '@qlover/fe-corekit';
|
|
10
6
|
import { inject, injectable } from 'inversify';
|
|
7
|
+
import { isObject, isString } from 'lodash';
|
|
11
8
|
import { UserApi } from '@/base/apis/userApi/UserApi';
|
|
12
|
-
import type {
|
|
13
|
-
UserApiLoginTransaction,
|
|
14
|
-
UserInfo
|
|
15
|
-
} from '@/base/apis/userApi/UserApiType';
|
|
16
|
-
import { AppError } from '@/base/cases/AppError';
|
|
9
|
+
import type { UserInfo, UserCredential } from '@/base/apis/userApi/UserApiType';
|
|
17
10
|
import { AppConfig } from '../cases/AppConfig';
|
|
18
|
-
import { RouteServiceInterface } from '../port/RouteServiceInterface';
|
|
19
11
|
import { UserServiceInterface } from '../port/UserServiceInterface';
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export interface RegisterFormData {
|
|
24
|
-
username: string;
|
|
25
|
-
email: string;
|
|
26
|
-
password: string;
|
|
27
|
-
confirmPassword: string;
|
|
28
|
-
agreeToTerms: boolean;
|
|
29
|
-
}
|
|
12
|
+
import type { UserServiceGateway } from '@qlover/corekit-bridge';
|
|
13
|
+
import type { SyncStorageInterface } from '@qlover/fe-corekit';
|
|
14
|
+
import type { LoggerInterface } from '@qlover/logger';
|
|
30
15
|
|
|
31
16
|
@injectable()
|
|
32
|
-
export class UserService
|
|
17
|
+
export class UserService
|
|
18
|
+
extends CorekitBridgeUserService<UserInfo, UserCredential>
|
|
19
|
+
implements UserServiceInterface
|
|
20
|
+
{
|
|
33
21
|
constructor(
|
|
34
|
-
@inject(IOCIdentifier.RouteServiceInterface)
|
|
35
|
-
protected routerService: RouteServiceInterface,
|
|
36
22
|
@inject(UserApi)
|
|
37
|
-
userApi:
|
|
38
|
-
@inject(
|
|
39
|
-
@inject(
|
|
40
|
-
storage: SyncStorageInterface<string
|
|
23
|
+
userApi: UserServiceGateway<UserInfo, UserCredential>,
|
|
24
|
+
@inject(I.AppConfig) appConfig: AppConfig,
|
|
25
|
+
@inject(I.LocalStorageEncrypt)
|
|
26
|
+
storage: SyncStorageInterface<string>,
|
|
27
|
+
@inject(I.Logger)
|
|
28
|
+
logger: LoggerInterface
|
|
41
29
|
) {
|
|
42
|
-
super(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
30
|
+
super({
|
|
31
|
+
executor: new GatewayExecutor(),
|
|
32
|
+
gateway: userApi,
|
|
33
|
+
logger: logger,
|
|
34
|
+
store: {
|
|
35
|
+
storageKey: appConfig.userInfoStorageKey,
|
|
36
|
+
credentialStorageKey: appConfig.userTokenStorageKey,
|
|
37
|
+
// Not production environment persists user information, for testing and development
|
|
38
|
+
persistUserInfo: !appConfig.isProduction,
|
|
49
39
|
storage: storage
|
|
50
40
|
}
|
|
51
41
|
});
|
|
@@ -53,60 +43,41 @@ export class UserService extends UserServiceInterface {
|
|
|
53
43
|
|
|
54
44
|
/**
|
|
55
45
|
* @override
|
|
46
|
+
* @returns
|
|
56
47
|
*/
|
|
57
|
-
|
|
58
|
-
return
|
|
48
|
+
getToken(): string {
|
|
49
|
+
return this.getCredential()?.token ?? '';
|
|
59
50
|
}
|
|
60
51
|
|
|
61
|
-
|
|
62
|
-
return
|
|
52
|
+
isUserInfo(value: unknown): value is UserInfo {
|
|
53
|
+
return (
|
|
54
|
+
isObject(value) &&
|
|
55
|
+
'name' in value &&
|
|
56
|
+
isString(value.name) &&
|
|
57
|
+
'email' in value &&
|
|
58
|
+
isString(value.email) &&
|
|
59
|
+
'picture' in value &&
|
|
60
|
+
isString(value.picture)
|
|
61
|
+
);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
async onBefore(): Promise<void> {
|
|
69
|
-
if (this.isAuthenticated()) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const userToken = this.getToken();
|
|
64
|
+
isUserCredential(value: unknown): value is UserCredential {
|
|
65
|
+
return isObject(value) && 'token' in value && isString(value.token);
|
|
66
|
+
}
|
|
74
67
|
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
override isAuthenticated(): boolean {
|
|
69
|
+
if (!super.isAuthenticated()) {
|
|
70
|
+
return false;
|
|
77
71
|
}
|
|
78
72
|
|
|
79
|
-
if (
|
|
80
|
-
|
|
73
|
+
if (!this.isUserInfo(this.getUser())) {
|
|
74
|
+
return false;
|
|
81
75
|
}
|
|
82
76
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
override async logout(): Promise<void> {
|
|
88
|
-
await super.logout();
|
|
89
|
-
|
|
90
|
-
this.routerService.reset();
|
|
91
|
-
this.routerService.gotoLogin();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
override async register(
|
|
95
|
-
params: RegisterFormData
|
|
96
|
-
): Promise<LoginResponseData> {
|
|
97
|
-
const response = (await this.api.register(
|
|
98
|
-
params
|
|
99
|
-
)) as UserApiLoginTransaction['response'];
|
|
100
|
-
|
|
101
|
-
if (response.data?.token) {
|
|
102
|
-
try {
|
|
103
|
-
await this.userInfo({ token: response.data?.token });
|
|
104
|
-
this.store.authSuccess();
|
|
105
|
-
} catch (error) {
|
|
106
|
-
this.store.authFailed(error);
|
|
107
|
-
}
|
|
77
|
+
if (!this.isUserCredential(this.getCredential())) {
|
|
78
|
+
return false;
|
|
108
79
|
}
|
|
109
80
|
|
|
110
|
-
|
|
81
|
+
return true;
|
|
111
82
|
}
|
|
112
83
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
envBlackList,
|
|
3
|
+
envPrefix,
|
|
4
|
+
browserGlobalsName,
|
|
5
|
+
omitInjectedGlobals
|
|
6
|
+
} from '@config/common';
|
|
2
7
|
import { Bootstrap } from '@qlover/corekit-bridge';
|
|
3
|
-
import { isObject } from 'lodash';
|
|
8
|
+
import { isObject, omit } from 'lodash';
|
|
4
9
|
import type { IOCInterface, IOCRegister } from '@/base/port/IOCInterface';
|
|
5
10
|
import type { IOCIdentifierMap } from '@config/IOCIdentifier';
|
|
6
11
|
import * as globals from '../globals';
|
|
@@ -78,7 +83,7 @@ export class BootstrapClient {
|
|
|
78
83
|
blackList: envBlackList
|
|
79
84
|
},
|
|
80
85
|
globalOptions: {
|
|
81
|
-
sources: globals,
|
|
86
|
+
sources: omit(globals, omitInjectedGlobals),
|
|
82
87
|
target: browserGlobalsName
|
|
83
88
|
}
|
|
84
89
|
});
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { I } from '@config/IOCIdentifier';
|
|
2
2
|
import { AiApiBootstarp } from '@/base/apis/AiApi';
|
|
3
3
|
import { FeApiBootstarp } from '@/base/apis/feApi/FeApiBootstarp';
|
|
4
4
|
import { UserApiBootstarp } from '@/base/apis/userApi/UserApiBootstarp';
|
|
5
5
|
import type { IOCIdentifierMap } from '@config/IOCIdentifier';
|
|
6
6
|
import { IocIdentifierTest } from './IocIdentifierTest';
|
|
7
7
|
import { printBootstrap } from './PrintBootstrap';
|
|
8
|
+
import { saveAppInfo } from './SaveAppInfo';
|
|
8
9
|
import type {
|
|
9
10
|
BootstrapExecutorPlugin,
|
|
10
11
|
EnvConfigInterface,
|
|
@@ -24,18 +25,19 @@ export class BootstrapsRegistry implements BootstrapsRegistryInterface {
|
|
|
24
25
|
) {}
|
|
25
26
|
|
|
26
27
|
get appConfig(): EnvConfigInterface {
|
|
27
|
-
return this.IOC(
|
|
28
|
+
return this.IOC(I.AppConfig);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
register(): BootstrapExecutorPlugin[] {
|
|
31
32
|
const IOC = this.IOC;
|
|
32
33
|
|
|
33
34
|
const bootstrapList = [
|
|
34
|
-
IOC(
|
|
35
|
+
IOC(I.I18nServiceInterface),
|
|
35
36
|
new UserApiBootstarp(),
|
|
36
37
|
new FeApiBootstarp(),
|
|
37
38
|
AiApiBootstarp,
|
|
38
|
-
|
|
39
|
+
saveAppInfo,
|
|
40
|
+
IOC(I.I18nKeyErrorPlugin)
|
|
39
41
|
];
|
|
40
42
|
|
|
41
43
|
if (!this.appConfig.isProduction) {
|
|
@@ -43,8 +45,6 @@ export class BootstrapsRegistry implements BootstrapsRegistryInterface {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
bootstrapList.push(IocIdentifierTest);
|
|
46
|
-
// TODO: 需要使用到
|
|
47
|
-
bootstrapList.push(IOC(IOCIdentifier.ProcesserExecutorInterface));
|
|
48
48
|
|
|
49
49
|
return bootstrapList;
|
|
50
50
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { I } from '@config/IOCIdentifier';
|
|
2
|
+
import type { AppConfig } from '@/base/cases/AppConfig';
|
|
3
|
+
import type { BootstrapExecutorPlugin } from '@qlover/corekit-bridge';
|
|
4
|
+
import type { SyncStorageInterface } from '@qlover/fe-corekit';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 保存应用信息到本地存储
|
|
8
|
+
*
|
|
9
|
+
* 包含以下:
|
|
10
|
+
*
|
|
11
|
+
* - 应用名称
|
|
12
|
+
* - 应用版本
|
|
13
|
+
*/
|
|
14
|
+
export const saveAppInfo: BootstrapExecutorPlugin = {
|
|
15
|
+
pluginName: 'SaveAppInfo',
|
|
16
|
+
onSuccess({ parameters: { ioc, logger } }) {
|
|
17
|
+
const appConfig = ioc.get<AppConfig>(I.AppConfig);
|
|
18
|
+
const localStorage = ioc.get<SyncStorageInterface<string>>(I.LocalStorage);
|
|
19
|
+
|
|
20
|
+
const key = appConfig.appName + '_appInfo';
|
|
21
|
+
localStorage.setItem(key, {
|
|
22
|
+
appName: appConfig.appName,
|
|
23
|
+
appVersion: appConfig.appVersion
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
logger.info(`Saved app info to localStorage: ${key}`);
|
|
27
|
+
}
|
|
28
|
+
};
|