@qlover/create-app 0.3.1 → 0.3.3
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 +96 -0
- package/configs/_common/.github/workflows/general-check.yml +17 -29
- package/configs/_common/.github/workflows/{release.yml.template → release.yml} +16 -51
- package/package.json +3 -3
- package/templates/pack-app/fe-config.json +30 -1
- package/templates/pack-app/package.json +45 -32
- package/templates/pack-app/tsconfig.test.json +1 -1
- package/templates/react-app/config/Identifier.I18n.ts +878 -0
- package/templates/react-app/config/app.router.json +7 -7
- package/templates/react-app/config/common.ts +7 -4
- package/templates/react-app/config/theme.json +7 -88
- package/templates/react-app/package.json +9 -4
- package/templates/react-app/postcss.config.js +1 -2
- package/templates/react-app/public/locales/en/common.json +118 -1
- package/templates/react-app/public/locales/zh/common.json +118 -1
- package/templates/react-app/src/App.tsx +14 -2
- package/templates/react-app/src/base/cases/RequestLogger.ts +3 -4
- package/templates/react-app/src/base/cases/RequestStatusCatcher.ts +3 -2
- package/templates/react-app/src/base/services/I18nService.ts +31 -3
- package/templates/react-app/src/base/services/ProcesserService.ts +3 -2
- package/templates/react-app/src/core/IOC.ts +15 -9
- package/templates/react-app/src/core/bootstrap.ts +42 -53
- package/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +14 -0
- package/templates/react-app/src/core/bootstraps/index.ts +36 -7
- package/templates/react-app/src/core/globals.ts +4 -6
- package/templates/react-app/src/core/registers/RegisterApi.ts +2 -5
- package/templates/react-app/src/core/registers/RegisterCommon.ts +38 -28
- package/templates/react-app/src/core/registers/RegisterControllers.ts +5 -10
- package/templates/react-app/src/core/registers/RegisterGlobals.ts +15 -14
- package/templates/react-app/src/core/registers/index.ts +27 -12
- package/templates/react-app/src/main.tsx +1 -1
- package/templates/react-app/src/pages/404.tsx +1 -1
- package/templates/react-app/src/pages/500.tsx +1 -1
- package/templates/react-app/src/pages/auth/Login.tsx +128 -36
- package/templates/react-app/src/pages/base/About.tsx +5 -2
- package/templates/react-app/src/pages/base/ErrorIdentifier.tsx +38 -19
- package/templates/react-app/src/pages/base/Executor.tsx +447 -29
- package/templates/react-app/src/pages/base/Home.tsx +99 -93
- package/templates/react-app/src/pages/base/JSONStorage.tsx +47 -38
- package/templates/react-app/src/pages/base/Layout.tsx +5 -2
- package/templates/react-app/src/pages/base/Request.tsx +90 -208
- package/templates/react-app/src/pages/base/components/BaseHeader.tsx +13 -5
- package/templates/react-app/src/styles/css/page.css +11 -0
- package/templates/react-app/src/styles/css/tailwind.css +5 -0
- package/templates/react-app/src/styles/css/themes/_default.css +200 -0
- package/templates/react-app/src/styles/css/themes/dark.css +154 -0
- package/templates/react-app/src/styles/css/themes/index.css +3 -0
- package/templates/react-app/src/styles/css/themes/pink.css +160 -0
- package/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +56 -0
- package/templates/react-app/src/uikit/components/Loading.tsx +27 -21
- package/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +63 -13
- package/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +1 -1
- package/templates/react-app/src/uikit/controllers/RouterController.ts +3 -3
- package/templates/react-app/src/uikit/controllers/UserController.ts +1 -1
- package/templates/react-app/tailwind.config.js +1 -15
- package/templates/react-app/vite.config.ts +9 -3
- package/templates/react-app/lib/tailwind/root10px.js +0 -178
- package/templates/react-app/lib/tailwind/theme-generator.js +0 -238
- package/templates/react-app/public/locales/en/about.json +0 -3
- package/templates/react-app/public/locales/en/executor.json +0 -6
- package/templates/react-app/public/locales/en/home.json +0 -10
- package/templates/react-app/public/locales/en/jsonStorage.json +0 -11
- package/templates/react-app/public/locales/en/login.json +0 -7
- package/templates/react-app/public/locales/en/request.json +0 -15
- package/templates/react-app/public/locales/zh/about.json +0 -3
- package/templates/react-app/public/locales/zh/executor.json +0 -7
- package/templates/react-app/public/locales/zh/home.json +0 -10
- package/templates/react-app/public/locales/zh/jsonStorage.json +0 -11
- package/templates/react-app/public/locales/zh/login.json +0 -8
- package/templates/react-app/public/locales/zh/request.json +0 -15
- package/templates/react-app/src/base/port/InversifyIocInterface.ts +0 -9
- package/templates/react-app/src/uikit/styles/css/page.css +0 -3
- package/templates/react-app/src/uikit/styles/css/tailwind.css +0 -3
- /package/templates/react-app/config/{ErrorIdentifier.ts → Identifier.Error.ts} +0 -0
- /package/templates/react-app/src/{uikit/styles → styles}/css/index.css +0 -0
|
@@ -4,6 +4,9 @@ import { JSONStorageController } from '@/uikit/controllers/JSONStorageController
|
|
|
4
4
|
import { RequestController } from '@/uikit/controllers/RequestController';
|
|
5
5
|
import { useMemo } from 'react';
|
|
6
6
|
import { useSliceStore } from '@qlover/slice-store-react';
|
|
7
|
+
import { Button } from 'antd';
|
|
8
|
+
import { LoadingOutlined } from '@ant-design/icons';
|
|
9
|
+
import * as i18nKeys from '@config/Identifier.I18n';
|
|
7
10
|
|
|
8
11
|
function JSONValue({ value }: { value: unknown }) {
|
|
9
12
|
const output = useMemo(() => {
|
|
@@ -14,7 +17,7 @@ function JSONValue({ value }: { value: unknown }) {
|
|
|
14
17
|
}
|
|
15
18
|
}, [value]);
|
|
16
19
|
return (
|
|
17
|
-
<pre className="mt-1 text-sm text-
|
|
20
|
+
<pre className="mt-1 text-sm text-text-secondary font-mono bg-secondary p-2 rounded overflow-x-auto">
|
|
18
21
|
{output}
|
|
19
22
|
</pre>
|
|
20
23
|
);
|
|
@@ -27,72 +30,48 @@ export default function Request() {
|
|
|
27
30
|
const { t } = useBaseRoutePage();
|
|
28
31
|
|
|
29
32
|
return (
|
|
30
|
-
<div className="min-h-screen bg-
|
|
33
|
+
<div className="min-h-screen bg-primary py-8 px-4 sm:px-6 lg:px-8">
|
|
31
34
|
<div className="max-w-4xl mx-auto space-y-6">
|
|
32
35
|
{/* Request Timeout Information */}
|
|
33
|
-
<div className="bg-
|
|
34
|
-
<h2 className="text-lg font-medium text-
|
|
35
|
-
{t(
|
|
36
|
+
<div className="bg-secondary shadow sm:rounded-lg p-6 border border-primary">
|
|
37
|
+
<h2 className="text-lg font-medium text-text mb-2">
|
|
38
|
+
{t(i18nKeys.PAGE_REQUEST_TIMEOUT)}
|
|
36
39
|
</h2>
|
|
37
|
-
<div className="text-sm text-
|
|
40
|
+
<div className="text-sm text-text-secondary font-mono bg-base p-2 rounded">
|
|
38
41
|
{jsonStorageControllerState.requestTimeout}
|
|
39
42
|
</div>
|
|
40
43
|
</div>
|
|
41
44
|
|
|
42
45
|
{/* Hello Request Card */}
|
|
43
|
-
<div className="bg-
|
|
44
|
-
<h2 className="text-lg font-medium text-
|
|
45
|
-
|
|
46
|
+
<div className="bg-secondary shadow sm:rounded-lg p-6 border border-primary hover:bg-elevated transition-colors duration-200">
|
|
47
|
+
<h2 className="text-lg font-medium text-text mb-4">
|
|
48
|
+
{t(i18nKeys.PAGE_REQUEST_HELLO_TITLE)}
|
|
46
49
|
</h2>
|
|
47
50
|
|
|
48
|
-
<p className="text-sm text-
|
|
49
|
-
|
|
50
|
-
ApiMockPlugin, RequestLogger 插件
|
|
51
|
+
<p className="text-sm text-text-secondary mb-4">
|
|
52
|
+
{t(i18nKeys.PAGE_REQUEST_HELLO_DESCRIPTION)}
|
|
51
53
|
</p>
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
+
<Button
|
|
55
|
+
type="primary"
|
|
54
56
|
onClick={requestController.onHello}
|
|
57
|
+
loading={requestControllerState.helloState.loading}
|
|
55
58
|
>
|
|
56
|
-
{requestControllerState.helloState.loading
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
61
|
-
fill="none"
|
|
62
|
-
viewBox="0 0 24 24"
|
|
63
|
-
>
|
|
64
|
-
<circle
|
|
65
|
-
className="opacity-25"
|
|
66
|
-
cx="12"
|
|
67
|
-
cy="12"
|
|
68
|
-
r="10"
|
|
69
|
-
stroke="currentColor"
|
|
70
|
-
strokeWidth="4"
|
|
71
|
-
></circle>
|
|
72
|
-
<path
|
|
73
|
-
className="opacity-75"
|
|
74
|
-
fill="currentColor"
|
|
75
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
76
|
-
></path>
|
|
77
|
-
</svg>
|
|
78
|
-
{t('loading')}
|
|
79
|
-
</>
|
|
80
|
-
) : (
|
|
81
|
-
'Hello'
|
|
82
|
-
)}
|
|
83
|
-
</button>
|
|
59
|
+
{requestControllerState.helloState.loading
|
|
60
|
+
? t(i18nKeys.REQUEST_LOADING)
|
|
61
|
+
: t(i18nKeys.PAGE_REQUEST_HELLO_BUTTON)}
|
|
62
|
+
</Button>
|
|
84
63
|
|
|
85
64
|
<div className="mt-4 space-y-2">
|
|
86
65
|
<div>
|
|
87
|
-
<p className="text-sm font-medium text-
|
|
88
|
-
{t(
|
|
66
|
+
<p className="text-sm font-medium text-text">
|
|
67
|
+
{t(i18nKeys.REQUEST_HELLO_RESULT)}:
|
|
89
68
|
</p>
|
|
90
69
|
<JSONValue value={requestControllerState.helloState.result} />
|
|
91
70
|
</div>
|
|
92
71
|
|
|
93
72
|
<div>
|
|
94
|
-
<p className="text-sm font-medium text-
|
|
95
|
-
{t(
|
|
73
|
+
<p className="text-sm font-medium text-text">
|
|
74
|
+
{t(i18nKeys.REQUEST_HELLO_ERROR)}:
|
|
96
75
|
</p>
|
|
97
76
|
<JSONValue value={requestControllerState.helloState.error} />
|
|
98
77
|
</div>
|
|
@@ -100,105 +79,54 @@ export default function Request() {
|
|
|
100
79
|
</div>
|
|
101
80
|
|
|
102
81
|
{/* IP Information Card */}
|
|
103
|
-
<div className="bg-
|
|
104
|
-
<h2 className="text-lg font-medium text-
|
|
105
|
-
|
|
82
|
+
<div className="bg-secondary shadow sm:rounded-lg p-6 border border-primary hover:bg-elevated transition-colors duration-200">
|
|
83
|
+
<h2 className="text-lg font-medium text-text mb-4">
|
|
84
|
+
{t(i18nKeys.PAGE_REQUEST_IP_INFO_TITLE)}
|
|
106
85
|
</h2>
|
|
107
86
|
|
|
108
|
-
<p className="text-sm text-
|
|
109
|
-
|
|
110
|
-
RequestCommonPlugin, RequestLogger, ApiPickDataPlugin 插件, 其中
|
|
111
|
-
ApiPickDataPlugin 插件可以将返回类型统一扁平到 data 字段
|
|
87
|
+
<p className="text-sm text-text-secondary mb-4">
|
|
88
|
+
{t(i18nKeys.PAGE_REQUEST_IP_INFO_DESCRIPTION)}
|
|
112
89
|
</p>
|
|
113
|
-
<
|
|
114
|
-
|
|
90
|
+
<Button
|
|
91
|
+
type="primary"
|
|
115
92
|
onClick={requestController.onIpInfo}
|
|
93
|
+
loading={requestControllerState.ipInfoState.loading}
|
|
116
94
|
>
|
|
117
|
-
{requestControllerState.ipInfoState.loading
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
122
|
-
fill="none"
|
|
123
|
-
viewBox="0 0 24 24"
|
|
124
|
-
>
|
|
125
|
-
<circle
|
|
126
|
-
className="opacity-25"
|
|
127
|
-
cx="12"
|
|
128
|
-
cy="12"
|
|
129
|
-
r="10"
|
|
130
|
-
stroke="currentColor"
|
|
131
|
-
strokeWidth="4"
|
|
132
|
-
></circle>
|
|
133
|
-
<path
|
|
134
|
-
className="opacity-75"
|
|
135
|
-
fill="currentColor"
|
|
136
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
137
|
-
></path>
|
|
138
|
-
</svg>
|
|
139
|
-
{t('loading')}
|
|
140
|
-
</>
|
|
141
|
-
) : (
|
|
142
|
-
t('ipInfo')
|
|
143
|
-
)}
|
|
144
|
-
</button>
|
|
95
|
+
{requestControllerState.ipInfoState.loading
|
|
96
|
+
? t(i18nKeys.REQUEST_LOADING)
|
|
97
|
+
: t(i18nKeys.REQUEST_IP_INFO)}
|
|
98
|
+
</Button>
|
|
145
99
|
|
|
146
100
|
<div className="mt-4">
|
|
147
|
-
<p className="text-sm font-medium text-
|
|
148
|
-
{t(
|
|
101
|
+
<p className="text-sm font-medium text-text">
|
|
102
|
+
{t(i18nKeys.REQUEST_IP_INFO_RESULT)}:
|
|
149
103
|
</p>
|
|
150
104
|
<JSONValue value={requestControllerState.ipInfoState.result} />
|
|
151
105
|
</div>
|
|
152
106
|
</div>
|
|
153
107
|
|
|
154
108
|
{/* Random User Card */}
|
|
155
|
-
<div className="bg-
|
|
156
|
-
<h2 className="text-lg font-medium text-
|
|
157
|
-
|
|
109
|
+
<div className="bg-secondary shadow sm:rounded-lg p-6 border border-primary hover:bg-elevated transition-colors duration-200">
|
|
110
|
+
<h2 className="text-lg font-medium text-text mb-4">
|
|
111
|
+
{t(i18nKeys.PAGE_REQUEST_RANDOM_USER_TITLE)}
|
|
158
112
|
</h2>
|
|
159
|
-
<p className="text-sm text-
|
|
160
|
-
|
|
161
|
-
RequestCommonPlugin, ApiMockPlugin, FetchAbortPlugin,
|
|
162
|
-
RequestLogger,ApiCatchPlugin 插件, 其中 FetchAbortPlugin 可以
|
|
163
|
-
中止请求, ApiCatchPlugin 可以将捕获的错误统一到 apiCatchResult 字段
|
|
113
|
+
<p className="text-sm text-text-secondary mb-4">
|
|
114
|
+
{t(i18nKeys.PAGE_REQUEST_RANDOM_USER_DESCRIPTION)}
|
|
164
115
|
</p>
|
|
165
|
-
<
|
|
166
|
-
|
|
116
|
+
<Button
|
|
117
|
+
type="primary"
|
|
167
118
|
onClick={requestController.onRandomUser}
|
|
119
|
+
loading={requestControllerState.randomUserState.loading}
|
|
168
120
|
>
|
|
169
|
-
{requestControllerState.randomUserState.loading
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
174
|
-
fill="none"
|
|
175
|
-
viewBox="0 0 24 24"
|
|
176
|
-
>
|
|
177
|
-
<circle
|
|
178
|
-
className="opacity-25"
|
|
179
|
-
cx="12"
|
|
180
|
-
cy="12"
|
|
181
|
-
r="10"
|
|
182
|
-
stroke="currentColor"
|
|
183
|
-
strokeWidth="4"
|
|
184
|
-
></circle>
|
|
185
|
-
<path
|
|
186
|
-
className="opacity-75"
|
|
187
|
-
fill="currentColor"
|
|
188
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
189
|
-
></path>
|
|
190
|
-
</svg>
|
|
191
|
-
{t('loading')}
|
|
192
|
-
</>
|
|
193
|
-
) : (
|
|
194
|
-
t('randomUser')
|
|
195
|
-
)}
|
|
196
|
-
</button>
|
|
121
|
+
{requestControllerState.randomUserState.loading
|
|
122
|
+
? t(i18nKeys.REQUEST_LOADING)
|
|
123
|
+
: t(i18nKeys.REQUEST_RANDOM_USER)}
|
|
124
|
+
</Button>
|
|
197
125
|
|
|
198
126
|
<div className="mt-4 space-y-2">
|
|
199
127
|
<div>
|
|
200
|
-
<p className="text-sm font-medium text-
|
|
201
|
-
{t(
|
|
128
|
+
<p className="text-sm font-medium text-text">
|
|
129
|
+
{t(i18nKeys.REQUEST_RANDOM_USER_RESULT)}:
|
|
202
130
|
</p>
|
|
203
131
|
<JSONValue
|
|
204
132
|
value={requestControllerState.randomUserState.result}
|
|
@@ -206,8 +134,8 @@ export default function Request() {
|
|
|
206
134
|
</div>
|
|
207
135
|
|
|
208
136
|
<div>
|
|
209
|
-
<p className="text-sm font-medium text-
|
|
210
|
-
{t(
|
|
137
|
+
<p className="text-sm font-medium text-text">
|
|
138
|
+
{t(i18nKeys.REQUEST_RANDOM_USER_ERROR)}:
|
|
211
139
|
</p>
|
|
212
140
|
<JSONValue value={requestControllerState.randomUserState.error} />
|
|
213
141
|
</div>
|
|
@@ -215,51 +143,29 @@ export default function Request() {
|
|
|
215
143
|
</div>
|
|
216
144
|
|
|
217
145
|
{/* Api catch result */}
|
|
218
|
-
<div className="bg-
|
|
219
|
-
<h2 className="text-lg font-medium text-
|
|
220
|
-
|
|
146
|
+
<div className="bg-secondary shadow sm:rounded-lg p-6 border border-primary hover:bg-elevated transition-colors duration-200">
|
|
147
|
+
<h2 className="text-lg font-medium text-text mb-4">
|
|
148
|
+
{t(i18nKeys.PAGE_REQUEST_API_CATCH_TITLE)}
|
|
221
149
|
</h2>
|
|
222
|
-
<
|
|
223
|
-
|
|
150
|
+
<Button
|
|
151
|
+
type={
|
|
224
152
|
requestControllerState.apiCatchResultState.loading
|
|
225
|
-
? '
|
|
226
|
-
: '
|
|
227
|
-
}
|
|
153
|
+
? 'primary'
|
|
154
|
+
: 'primary'
|
|
155
|
+
}
|
|
156
|
+
danger={requestControllerState.apiCatchResultState.loading}
|
|
228
157
|
onClick={requestController.onTriggerApiCatchResult}
|
|
158
|
+
loading={requestControllerState.apiCatchResultState.loading}
|
|
229
159
|
>
|
|
230
|
-
{requestControllerState.apiCatchResultState.loading
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
235
|
-
fill="none"
|
|
236
|
-
viewBox="0 0 24 24"
|
|
237
|
-
>
|
|
238
|
-
<circle
|
|
239
|
-
className="opacity-25"
|
|
240
|
-
cx="12"
|
|
241
|
-
cy="12"
|
|
242
|
-
r="10"
|
|
243
|
-
stroke="currentColor"
|
|
244
|
-
strokeWidth="4"
|
|
245
|
-
></circle>
|
|
246
|
-
<path
|
|
247
|
-
className="opacity-75"
|
|
248
|
-
fill="currentColor"
|
|
249
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
250
|
-
></path>
|
|
251
|
-
</svg>
|
|
252
|
-
{t('stopApiCatchResult')}
|
|
253
|
-
</>
|
|
254
|
-
) : (
|
|
255
|
-
t('triggerApiCatchResult')
|
|
256
|
-
)}
|
|
257
|
-
</button>
|
|
160
|
+
{requestControllerState.apiCatchResultState.loading
|
|
161
|
+
? t(i18nKeys.PAGE_REQUEST_STOP_API_CATCH)
|
|
162
|
+
: t(i18nKeys.PAGE_REQUEST_TRIGGER_API_CATCH)}
|
|
163
|
+
</Button>
|
|
258
164
|
|
|
259
165
|
<div className="mt-4 space-y-2">
|
|
260
166
|
<div>
|
|
261
|
-
<p className="text-sm font-medium text-
|
|
262
|
-
{t(
|
|
167
|
+
<p className="text-sm font-medium text-text">
|
|
168
|
+
{t(i18nKeys.REQUEST_ABORT_RESULT)}:
|
|
263
169
|
</p>
|
|
264
170
|
<JSONValue
|
|
265
171
|
value={requestControllerState.apiCatchResultState.result}
|
|
@@ -267,8 +173,8 @@ export default function Request() {
|
|
|
267
173
|
</div>
|
|
268
174
|
|
|
269
175
|
<div>
|
|
270
|
-
<p className="text-sm font-medium text-
|
|
271
|
-
{t(
|
|
176
|
+
<p className="text-sm font-medium text-text">
|
|
177
|
+
{t(i18nKeys.REQUEST_ABORT_ERROR)}:
|
|
272
178
|
</p>
|
|
273
179
|
<JSONValue
|
|
274
180
|
value={requestControllerState.apiCatchResultState.error}
|
|
@@ -278,58 +184,34 @@ export default function Request() {
|
|
|
278
184
|
</div>
|
|
279
185
|
|
|
280
186
|
{/* Abort Request Card */}
|
|
281
|
-
<div className="bg-
|
|
282
|
-
<h2 className="text-lg font-medium text-
|
|
283
|
-
|
|
187
|
+
<div className="bg-secondary shadow sm:rounded-lg p-6 border border-primary hover:bg-elevated transition-colors duration-200">
|
|
188
|
+
<h2 className="text-lg font-medium text-text mb-4">
|
|
189
|
+
{t(i18nKeys.PAGE_REQUEST_ABORT_TITLE)}
|
|
284
190
|
</h2>
|
|
285
|
-
<
|
|
286
|
-
|
|
287
|
-
requestControllerState.abortState.loading
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}`}
|
|
191
|
+
<Button
|
|
192
|
+
type={
|
|
193
|
+
requestControllerState.abortState.loading ? 'primary' : 'primary'
|
|
194
|
+
}
|
|
195
|
+
danger={requestControllerState.abortState.loading}
|
|
291
196
|
onClick={requestController.onTriggerAbortRequest}
|
|
292
197
|
>
|
|
293
|
-
{requestControllerState.abortState.loading
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
fill="none"
|
|
299
|
-
viewBox="0 0 24 24"
|
|
300
|
-
>
|
|
301
|
-
<circle
|
|
302
|
-
className="opacity-25"
|
|
303
|
-
cx="12"
|
|
304
|
-
cy="12"
|
|
305
|
-
r="10"
|
|
306
|
-
stroke="currentColor"
|
|
307
|
-
strokeWidth="4"
|
|
308
|
-
></circle>
|
|
309
|
-
<path
|
|
310
|
-
className="opacity-75"
|
|
311
|
-
fill="currentColor"
|
|
312
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
313
|
-
></path>
|
|
314
|
-
</svg>
|
|
315
|
-
{t('stopAbortRequest')}
|
|
316
|
-
</>
|
|
317
|
-
) : (
|
|
318
|
-
t('triggerAbortRequest')
|
|
319
|
-
)}
|
|
320
|
-
</button>
|
|
198
|
+
{requestControllerState.abortState.loading && <LoadingOutlined />}
|
|
199
|
+
{requestControllerState.abortState.loading
|
|
200
|
+
? t(i18nKeys.PAGE_REQUEST_STOP_ABORT)
|
|
201
|
+
: t(i18nKeys.PAGE_REQUEST_TRIGGER_ABORT)}
|
|
202
|
+
</Button>
|
|
321
203
|
|
|
322
204
|
<div className="mt-4 space-y-2">
|
|
323
205
|
<div>
|
|
324
|
-
<p className="text-sm font-medium text-
|
|
325
|
-
{t(
|
|
206
|
+
<p className="text-sm font-medium text-text">
|
|
207
|
+
{t(i18nKeys.REQUEST_ABORT_RESULT)}:
|
|
326
208
|
</p>
|
|
327
209
|
<JSONValue value={requestControllerState.abortState.result} />
|
|
328
210
|
</div>
|
|
329
211
|
|
|
330
212
|
<div>
|
|
331
|
-
<p className="text-sm font-medium text-
|
|
332
|
-
{t(
|
|
213
|
+
<p className="text-sm font-medium text-text">
|
|
214
|
+
{t(i18nKeys.REQUEST_ABORT_ERROR)}:
|
|
333
215
|
</p>
|
|
334
216
|
<JSONValue value={requestControllerState.abortState.error} />
|
|
335
217
|
</div>
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import ThemeSwitcher from '@/uikit/components/ThemeSwitcher';
|
|
2
2
|
import LocaleLink from '@/uikit/components/LocaleLink';
|
|
3
|
+
import LanguageSwitcher from '@/uikit/components/LanguageSwitcher';
|
|
3
4
|
|
|
4
5
|
export default function BaseHeader() {
|
|
5
6
|
return (
|
|
6
|
-
<header className="h-
|
|
7
|
-
<div className="flex items-center justify-between h-full px-
|
|
7
|
+
<header className="h-14 bg-secondary border-b border-border sticky top-0 z-50">
|
|
8
|
+
<div className="flex items-center justify-between h-full px-4 mx-auto max-w-7xl">
|
|
8
9
|
<div className="flex items-center">
|
|
9
|
-
<LocaleLink
|
|
10
|
-
|
|
10
|
+
<LocaleLink
|
|
11
|
+
href="/"
|
|
12
|
+
className="flex items-center hover:opacity-80 transition-opacity"
|
|
13
|
+
>
|
|
14
|
+
<img src="/logo.svg" alt="logo" className="h-8 w-auto" />
|
|
15
|
+
<span className="ml-2 text-lg font-semibold text-text">
|
|
16
|
+
{'appName'}
|
|
17
|
+
</span>
|
|
11
18
|
</LocaleLink>
|
|
12
19
|
</div>
|
|
13
|
-
<div className="flex items-center">
|
|
20
|
+
<div className="flex items-center gap-4">
|
|
21
|
+
<LanguageSwitcher />
|
|
14
22
|
<ThemeSwitcher />
|
|
15
23
|
</div>
|
|
16
24
|
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
@theme {
|
|
2
|
+
--color-primary: rgba(var(--color-bg-base));
|
|
3
|
+
--color-secondary: rgba(var(--color-bg-secondary));
|
|
4
|
+
--color-elevated: rgba(var(--color-bg-elevated));
|
|
5
|
+
--color-text: rgba(var(--color-text-primary));
|
|
6
|
+
--color-text-secondary: rgba(var(--color-text-secondary));
|
|
7
|
+
--color-text-tertiary: rgba(var(--color-text-tertiary));
|
|
8
|
+
--color-border: rgba(var(--color-border));
|
|
9
|
+
--color-brand: rgba(var(--color-brand));
|
|
10
|
+
--color-brand-hover: rgba(var(--color-brand-hover));
|
|
11
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/* theme variables - for tailwind */
|
|
2
|
+
@layer base {
|
|
3
|
+
:root {
|
|
4
|
+
/* 基础背景色 */
|
|
5
|
+
--color-bg-base: 255 255 255;
|
|
6
|
+
--color-bg-secondary: 241 245 249; /* slate-100 */
|
|
7
|
+
--color-bg-elevated: 248 250 252; /* slate-50 */
|
|
8
|
+
|
|
9
|
+
/* 文字颜色 */
|
|
10
|
+
--color-text-primary: 15 23 42; /* slate-900 */
|
|
11
|
+
--color-text-secondary: 71 85 105; /* slate-600 */
|
|
12
|
+
--color-text-tertiary: 100 116 139; /* slate-500 */
|
|
13
|
+
|
|
14
|
+
/* 边框颜色 */
|
|
15
|
+
--color-border: 226 232 240; /* slate-200 */
|
|
16
|
+
|
|
17
|
+
/* 品牌色 */
|
|
18
|
+
--color-brand: 37 99 235; /* blue-600 */
|
|
19
|
+
--color-brand-hover: 59 130 246; /* blue-500 */
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* custom variables - for antd and custom css */
|
|
24
|
+
html,
|
|
25
|
+
.fe-theme {
|
|
26
|
+
/* Antd 主色调相关变量 - 浅蓝色主题 */
|
|
27
|
+
--fe-color-primary: #60a5fa; /* blue-400 */
|
|
28
|
+
--fe-color-primary-hover: #3b82f6; /* blue-500 */
|
|
29
|
+
--fe-color-primary-active: #2563eb; /* blue-600 */
|
|
30
|
+
--fe-color-primary-bg: rgba(96, 165, 250, 0.1); /* blue-400 with 0.1 opacity */
|
|
31
|
+
--fe-color-primary-border: #60a5fa; /* blue-400 */
|
|
32
|
+
--fe-color-primary-text: #60a5fa; /* blue-400 */
|
|
33
|
+
--fe-color-primary-text-hover: #3b82f6; /* blue-500 */
|
|
34
|
+
--fe-color-primary-text-active: #2563eb; /* blue-600 */
|
|
35
|
+
--fe-color-primary-deprecated-bg: #60a5fa; /* blue-400 */
|
|
36
|
+
--fe-color-primary-deprecated-border: #60a5fa; /* blue-400 */
|
|
37
|
+
|
|
38
|
+
/* Antd 基础变量 */
|
|
39
|
+
--fe-color-bg-container: rgb(255 255 255);
|
|
40
|
+
--fe-color-bg-elevated: rgb(248 250 252);
|
|
41
|
+
--fe-color-text: rgba(15 23 42 / 0.85);
|
|
42
|
+
--fe-color-text-secondary: rgba(15 23 42 / 0.45);
|
|
43
|
+
--fe-color-text-tertiary: rgba(15 23 42 / 0.35);
|
|
44
|
+
--fe-color-text-quaternary: rgba(15 23 42 / 0.15);
|
|
45
|
+
--fe-color-text-placeholder: rgba(15 23 42 / 0.25);
|
|
46
|
+
--fe-color-border: rgb(226 232 240);
|
|
47
|
+
|
|
48
|
+
/* Antd 组件通用变量 */
|
|
49
|
+
--fe-line-width: 1px;
|
|
50
|
+
--fe-line-type: solid;
|
|
51
|
+
--fe-border-radius: 6px;
|
|
52
|
+
--fe-motion-duration-mid: 0.2s;
|
|
53
|
+
--fe-line-height: 1.5715;
|
|
54
|
+
|
|
55
|
+
/* Antd Input 组件变量 */
|
|
56
|
+
&.ant-input-css-var {
|
|
57
|
+
/* Input 内边距 */
|
|
58
|
+
--fe-input-padding-block: 4px;
|
|
59
|
+
--fe-input-padding-block-sm: 0px;
|
|
60
|
+
--fe-input-padding-block-lg: 7px;
|
|
61
|
+
--fe-input-padding-inline: 11px;
|
|
62
|
+
--fe-input-padding-inline-sm: 7px;
|
|
63
|
+
--fe-input-padding-inline-lg: 11px;
|
|
64
|
+
|
|
65
|
+
/* Input 字体大小 */
|
|
66
|
+
--fe-input-input-font-size: 14px;
|
|
67
|
+
--fe-input-input-font-size-lg: 16px;
|
|
68
|
+
--fe-input-input-font-size-sm: 14px;
|
|
69
|
+
|
|
70
|
+
/* Input 交互状态 */
|
|
71
|
+
--fe-input-hover-border-color: #4096ff;
|
|
72
|
+
--fe-input-active-border-color: #1677ff;
|
|
73
|
+
--fe-input-active-shadow: 0 0 0 2px rgba(5, 145, 255, 0.1);
|
|
74
|
+
--fe-input-error-active-shadow: 0 0 0 2px rgba(255, 38, 5, 0.06);
|
|
75
|
+
--fe-input-warning-active-shadow: 0 0 0 2px rgba(255, 215, 5, 0.1);
|
|
76
|
+
--fe-input-hover-bg: #ffffff;
|
|
77
|
+
--fe-input-active-bg: #ffffff;
|
|
78
|
+
--fe-input-addon-bg: rgba(0, 0, 0, 0.02);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* 登录页特定样式 */
|
|
82
|
+
--login-card-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
83
|
+
--login-input-bg: var(--fe-color-bg-container);
|
|
84
|
+
--login-input-border: var(--fe-color-border);
|
|
85
|
+
--login-button-text: rgb(255 255 255);
|
|
86
|
+
--login-social-button-bg: var(--fe-color-bg-container);
|
|
87
|
+
--login-social-button-border: var(--fe-color-border);
|
|
88
|
+
|
|
89
|
+
/* Antd Button 组件变量 */
|
|
90
|
+
&.ant-btn {
|
|
91
|
+
/* 基础样式 */
|
|
92
|
+
--fe-button-font-weight: 400;
|
|
93
|
+
--fe-button-padding-inline: 15px;
|
|
94
|
+
--fe-button-padding-inline-lg: 15px;
|
|
95
|
+
--fe-button-padding-inline-sm: 7px;
|
|
96
|
+
--fe-button-padding-block: 4px;
|
|
97
|
+
--fe-button-padding-block-sm: 0px;
|
|
98
|
+
--fe-button-padding-block-lg: 7px;
|
|
99
|
+
|
|
100
|
+
/* 字体大小 */
|
|
101
|
+
--fe-button-content-font-size: 14px;
|
|
102
|
+
--fe-button-content-font-size-sm: 14px;
|
|
103
|
+
--fe-button-content-font-size-lg: 16px;
|
|
104
|
+
--fe-button-content-line-height: 1.5714285714285714;
|
|
105
|
+
--fe-button-content-line-height-sm: 1.5714285714285714;
|
|
106
|
+
--fe-button-content-line-height-lg: 1.5;
|
|
107
|
+
|
|
108
|
+
/* 浅蓝色主题 */
|
|
109
|
+
--fe-button-primary-color: #fff;
|
|
110
|
+
--fe-button-primary-bg: #60a5fa; /* blue-400 */
|
|
111
|
+
--fe-button-primary-hover-bg: #3b82f6; /* blue-500 */
|
|
112
|
+
--fe-button-primary-active-bg: #2563eb; /* blue-600 */
|
|
113
|
+
--fe-button-primary-shadow: 0 2px 0 rgba(37, 99, 235, 0.1);
|
|
114
|
+
|
|
115
|
+
/* 默认按钮 */
|
|
116
|
+
--fe-button-default-color: rgba(0, 0, 0, 0.88);
|
|
117
|
+
--fe-button-default-bg: #ffffff;
|
|
118
|
+
--fe-button-default-border-color: #d9d9d9;
|
|
119
|
+
--fe-button-default-hover-bg: #ffffff;
|
|
120
|
+
--fe-button-default-hover-color: #60a5fa;
|
|
121
|
+
--fe-button-default-hover-border-color: #60a5fa;
|
|
122
|
+
--fe-button-default-active-bg: #ffffff;
|
|
123
|
+
--fe-button-default-active-color: #2563eb;
|
|
124
|
+
--fe-button-default-active-border-color: #2563eb;
|
|
125
|
+
--fe-button-default-shadow: 0 2px 0 rgba(0, 0, 0, 0.02);
|
|
126
|
+
|
|
127
|
+
/* 其他状态 */
|
|
128
|
+
--fe-button-danger-color: #fff;
|
|
129
|
+
--fe-button-danger-shadow: 0 2px 0 rgba(255, 38, 5, 0.06);
|
|
130
|
+
--fe-button-border-color-disabled: #d9d9d9;
|
|
131
|
+
--fe-button-text-hover-bg: rgba(0, 0, 0, 0.04);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Antd 图标相关变量 */
|
|
135
|
+
--fe-color-icon: rgba(0, 0, 0, 0.45); /* 默认图标颜色 */
|
|
136
|
+
--fe-color-icon-hover: rgba(0, 0, 0, 0.88); /* 图标悬停颜色 */
|
|
137
|
+
--fe-color-icon-active: var(--fe-color-primary); /* 图标激活颜色 */
|
|
138
|
+
--fe-color-icon-disabled: rgba(0, 0, 0, 0.25); /* 禁用状态图标颜色 */
|
|
139
|
+
|
|
140
|
+
/* Antd Select 组件变量 */
|
|
141
|
+
&.ant-select-css-var {
|
|
142
|
+
--fe-select-internal_fixed_item_margin: 2px;
|
|
143
|
+
--fe-select-z-index-popup: 1050;
|
|
144
|
+
--fe-select-option-selected-color: rgba(0, 0, 0, 0.88);
|
|
145
|
+
--fe-select-option-selected-font-weight: 600;
|
|
146
|
+
--fe-select-option-selected-bg: var(--fe-color-primary-bg);
|
|
147
|
+
--fe-select-option-active-bg: rgba(0, 0, 0, 0.04);
|
|
148
|
+
--fe-select-option-padding: 5px 12px;
|
|
149
|
+
--fe-select-option-font-size: 14px;
|
|
150
|
+
--fe-select-option-line-height: 1.5714285714285714;
|
|
151
|
+
--fe-select-option-height: 32px;
|
|
152
|
+
--fe-select-selector-bg: var(--fe-color-bg-container);
|
|
153
|
+
--fe-select-clear-bg: var(--fe-color-bg-container);
|
|
154
|
+
--fe-select-single-item-height-lg: 40px;
|
|
155
|
+
--fe-select-multiple-item-bg: rgba(0, 0, 0, 0.06);
|
|
156
|
+
--fe-select-multiple-item-border-color: transparent;
|
|
157
|
+
--fe-select-multiple-item-height: 24px;
|
|
158
|
+
--fe-select-multiple-item-height-sm: 16px;
|
|
159
|
+
--fe-select-multiple-item-height-lg: 32px;
|
|
160
|
+
--fe-select-multiple-selector-bg-disabled: rgba(0, 0, 0, 0.04);
|
|
161
|
+
--fe-select-multiple-item-color-disabled: rgba(0, 0, 0, 0.25);
|
|
162
|
+
--fe-select-multiple-item-border-color-disabled: transparent;
|
|
163
|
+
--fe-select-show-arrow-padding-inline-end: 18px;
|
|
164
|
+
--fe-select-hover-border-color: var(--fe-color-primary);
|
|
165
|
+
--fe-select-active-border-color: var(--fe-color-primary-active);
|
|
166
|
+
--fe-select-active-outline-color: var(--fe-color-primary-bg);
|
|
167
|
+
--fe-select-select-affix-padding: 4px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Antd Tag 组件变量 */
|
|
171
|
+
&.ant-tag-css-var {
|
|
172
|
+
--fe-tag-default-bg: var(--fe-color-bg-container);
|
|
173
|
+
--fe-tag-default-color: var(--fe-color-text);
|
|
174
|
+
--fe-tag-default-border-color: var(--fe-color-border);
|
|
175
|
+
--fe-tag-font-size: 12px;
|
|
176
|
+
--fe-tag-line-height: 20px;
|
|
177
|
+
--fe-tag-height: 22px;
|
|
178
|
+
--fe-tag-padding-horizontal: 7px;
|
|
179
|
+
--fe-tag-margin: 0 8px 0 0;
|
|
180
|
+
--fe-tag-border-radius: 4px;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* Antd Progress 组件变量 */
|
|
184
|
+
&.ant-progress-css-var {
|
|
185
|
+
--fe-progress-default-color: var(--fe-color-primary);
|
|
186
|
+
--fe-progress-remaining-color: var(--fe-color-bg-elevated);
|
|
187
|
+
--fe-progress-text-color: var(--fe-color-text);
|
|
188
|
+
--fe-progress-line-font-size: 14px;
|
|
189
|
+
--fe-progress-circle-font-size: 14px;
|
|
190
|
+
--fe-progress-circle-text-color: var(--fe-color-text);
|
|
191
|
+
--fe-progress-circle-trail-color: var(--fe-color-bg-elevated);
|
|
192
|
+
--fe-progress-circle-stroke-width: 6px;
|
|
193
|
+
--fe-progress-line-stroke-width: 8px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Motion 动画变量 */
|
|
197
|
+
--fe-motion-duration-slow: 0.3s;
|
|
198
|
+
--fe-motion-duration-normal: 0.2s;
|
|
199
|
+
--fe-motion-duration-fast: 0.1s;
|
|
200
|
+
}
|