@skyroc/scripts 2.5.0 → 2.5.1
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/dist/cli.mjs +1 -1
- package/package.json +3 -3
- package/templates/admin/package.json +0 -2
- package/templates/admin/src/assets/svg-icon/logo.svg +2 -14
- package/templates/admin/src/features/router/routeTree.gen.ts +71 -1
- package/templates/admin/src/pages/(auth)/login/code-login.tsx +79 -0
- package/templates/admin/src/pages/(auth)/login/index.tsx +22 -1
- package/templates/admin/src/pages/(auth)/login/layout.tsx +25 -23
- package/templates/admin/src/pages/(auth)/login/modules/Header.tsx +25 -0
- package/templates/admin/src/pages/(auth)/login/register.tsx +86 -0
- package/templates/admin/src/pages/(auth)/login/reset-pwd.tsx +73 -0
- package/templates/admin-shell/theme/antd/AntdProvider.tsx +1 -0
- package/templates/admin-shell/theme/antd/shared.ts +3 -3
- package/templates/admin-shell/theme/antd-algorithm/algorithm/dark/colors.ts +3 -3
- package/templates/admin-shell/theme/antd-algorithm/algorithm/default/colors.ts +1 -1
- package/templates/admin-shell/theme/presets/default.json +1 -1
- package/templates/admin.meta.json +1 -2
package/dist/cli.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyroc/scripts",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Skyroc admin CLI - changelog, release, git-commit, cleanup and other project automation scripts",
|
|
6
6
|
"keywords": [
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"tsx": "^4.21.0",
|
|
68
68
|
"typescript": "^6.0.3",
|
|
69
69
|
"vitest": "^4.0.18",
|
|
70
|
-
"@skyroc/
|
|
71
|
-
"@skyroc/
|
|
70
|
+
"@skyroc/config": "1.0.0",
|
|
71
|
+
"@skyroc/tsconfig": "1.0.0"
|
|
72
72
|
},
|
|
73
73
|
"scripts": {
|
|
74
74
|
"build": "tsdown",
|
|
@@ -43,11 +43,9 @@
|
|
|
43
43
|
"@skyroc/color": "workspace:*",
|
|
44
44
|
"@skyroc/core-state": "workspace:*",
|
|
45
45
|
"@skyroc/hooks": "workspace:*",
|
|
46
|
-
"@skyroc/logger": "workspace:*",
|
|
47
46
|
"@skyroc/service": "workspace:*",
|
|
48
47
|
"@skyroc/utils": "workspace:*",
|
|
49
48
|
"@skyroc/web-admin-devtools": "workspace:*",
|
|
50
|
-
"@skyroc/web-admin-shell": "workspace:*",
|
|
51
49
|
"@skyroc/web-ui": "workspace:*",
|
|
52
50
|
"@tanstack/react-query": "catalog:core",
|
|
53
51
|
"@tanstack/react-router": "catalog:web",
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
<svg
|
|
2
|
-
|
|
3
|
-
<path d="M57.8,92.8c1.8-2.1,3.5-4.4,5.4-6.4c7.2-7.8,16.8-11.2,26.8-13.6c11-2.6,22.2-4.8,33.2-7.5c4.9-1.2,9.6-3.2,15.2-5.1
|
|
4
|
-
c-1.8,3.4-3.1,6.5-5,9.3c-7.7,11.5-19,17.4-32.4,19.6c-5.8,1-11.8,0.9-17.6,1.7c-13.3,1.8-22.4,9.1-26.8,21.5
|
|
5
|
-
c-3,8.5-5,17.3-7.5,25.9c-0.4,1.3-0.2,2.1,1.2,2.7c21.6,9.5,42.9,8.6,63.7-2.3c0.4-0.2,0.7-0.5,1.5-1c-14.4-13.6-27-29.3-47.3-35.1
|
|
6
|
-
c0,0.1,0-0.2,0.1-0.4c8.3-5.8,22.5-8.6,31.9-2.4c5.4,3.6,10.1,8.4,15.1,12.7c5,4.3,10,8.7,15.1,13.1c3.1-3.2,6.9-7.8,9.7-13.2
|
|
7
|
-
c9-17,10.6-34.8,4.9-53.1c-0.6-1.8-0.5-3.2,0.8-4.9c2.1-2.7,3.8-5.8,6.1-9.4c1.8,4.5,3.7,8.6,4.9,12.8c12,42.2-10.7,84.2-51.6,97.7
|
|
8
|
-
c-25.5,8.4-49.7,4.9-71.7-10.4c-18.1-12.6-29.3-30-32.4-51.7c-3.2-22.3,0.5-43.4,14.4-61.8c12.7-17,29.8-27.3,51-30.5
|
|
9
|
-
c24.1-3.7,45.8,2.1,64.9,17.1c0.5,0.4,1,0.8,1.4,1.2c0.3,0.3,0.6,0.6,1.3,1.3c-3.2,2.1-6.2,4.3-9.3,6.2c-0.4,0.3-1.6-0.3-2.3-0.8
|
|
10
|
-
c-25-17.8-59.4-19-84.6,0.2c-14.3,10.9-22.4,25.6-24.9,43c-2.6,18.2,0.8,35.2,11.8,50.3c2.4,3.3,5.4,6.3,8.5,9.9
|
|
11
|
-
c1.5-5.9,2.8-11.2,4.2-16.4c2.8-10.4,5.2-20.9,8.5-31.1c4.8-15.1,15.2-25.5,30-31.2c9-3.5,18.5-6,27.8-8.8
|
|
12
|
-
c11.4-3.5,22.8-6.8,32.6-13.8c5.2-3.7,9.8-7.9,13.6-13.6c0.1,3.2,0.6,6.5,0.4,9.7c-0.6,10.7-4.3,19.9-13,26.8
|
|
13
|
-
c-7.3,5.7-15.8,8.9-24.7,11c-9.4,2.2-18.9,4-28.2,6.4c-8.9,2.3-16.9,6.6-22.3,14.3c-2.1,2.9-3.4,6.4-5.1,9.7
|
|
14
|
-
C57.3,92.6,57.5,92.7,57.8,92.8z" fill="currentColor"/>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 160" role="img" aria-label="Skyroc 天鹏">
|
|
2
|
+
<path fill="#6366F1" fill-rule="evenodd" d="M 8.31 49.69 Q 8.00 51.38 8.00 54.15 Q 8.00 56.92 8.46 59.08 Q 8.92 61.23 9.85 63.54 Q 10.77 65.85 12.31 68.15 Q 13.85 70.46 15.77 72.38 Q 17.69 74.31 19.85 75.85 Q 22.00 77.38 24.46 78.62 Q 26.92 79.85 30.85 81.00 Q 34.77 82.15 31.92 82.23 Q 29.08 82.31 27.38 82.00 Q 25.69 81.69 23.85 81.08 Q 22.00 80.46 19.23 78.92 Q 16.46 77.38 16.38 78.08 Q 16.31 78.77 16.77 80.15 Q 17.23 81.54 18.15 83.23 Q 19.08 84.92 22.08 87.92 Q 25.08 90.92 28.15 92.46 Q 31.23 94.00 36.00 94.77 Q 40.77 95.54 44.62 95.23 Q 48.46 94.92 53.85 93.69 Q 59.23 92.46 62.15 92.46 Q 65.08 92.46 67.38 93.38 Q 69.69 94.31 70.85 95.46 Q 72.00 96.62 72.46 97.54 Q 72.92 98.46 72.77 100.77 Q 72.62 103.08 71.54 105.38 Q 70.46 107.69 66.92 113.23 Q 63.38 118.77 62.92 120.31 Q 62.46 121.85 62.46 123.54 Q 62.46 125.23 63.08 126.92 Q 63.69 128.62 64.69 129.62 Q 65.69 130.62 69.00 123.92 Q 72.31 117.23 73.92 111.15 Q 75.54 105.08 75.62 108.38 Q 75.69 111.69 74.31 118.31 Q 72.92 124.92 72.77 126.92 Q 72.62 128.92 72.92 130.62 Q 73.23 132.31 74.15 134.31 Q 75.08 136.31 77.31 139.00 Q 79.54 141.69 80.00 141.69 Q 80.46 141.69 81.31 140.85 Q 82.15 140.00 83.85 137.69 Q 85.54 135.38 86.46 132.46 Q 87.38 129.54 87.23 127.08 Q 87.08 124.62 85.69 117.54 Q 84.31 110.46 84.38 107.62 Q 84.46 104.77 86.23 111.31 Q 88.00 117.85 91.00 124.23 Q 94.00 130.62 95.00 129.77 Q 96.00 128.92 96.77 127.23 Q 97.54 125.54 97.54 123.38 Q 97.54 121.23 97.08 119.85 Q 96.62 118.46 93.38 113.54 Q 90.15 108.62 88.77 105.54 Q 87.38 102.46 87.23 100.77 Q 87.08 99.08 88.00 97.38 Q 88.92 95.69 90.08 94.69 Q 91.23 93.69 93.23 92.92 Q 95.23 92.15 97.54 92.15 Q 99.85 92.15 107.08 93.69 Q 114.31 95.23 118.31 95.23 Q 122.31 95.23 126.31 94.15 Q 130.31 93.08 133.08 91.38 Q 135.85 89.69 138.69 86.54 Q 141.54 83.38 142.69 80.38 Q 143.85 77.38 139.08 79.54 Q 134.31 81.69 132.62 82.00 Q 130.92 82.31 128.23 82.23 Q 125.54 82.15 129.00 81.15 Q 132.46 80.15 135.54 78.62 Q 138.62 77.08 140.31 75.85 Q 142.00 74.62 144.69 71.77 Q 147.38 68.92 148.77 66.46 Q 150.15 64.00 150.92 61.54 Q 151.69 59.08 151.85 55.08 Q 152.00 51.08 151.54 49.08 Q 151.08 47.08 150.77 47.08 Q 150.46 47.08 147.85 51.08 Q 145.23 55.08 140.69 59.15 Q 136.15 63.23 131.08 66.00 Q 126.00 68.77 119.69 70.92 Q 113.38 73.08 109.69 74.77 Q 106.00 76.46 101.85 79.85 Q 97.69 83.23 97.46 83.15 Q 97.23 83.08 98.77 80.92 Q 100.31 78.77 103.62 75.92 Q 106.92 73.08 110.62 71.08 Q 114.31 69.08 119.54 67.08 Q 124.77 65.08 129.54 62.46 Q 134.31 59.85 137.31 57.15 Q 140.31 54.46 141.85 52.31 Q 143.38 50.15 144.77 46.31 Q 146.15 42.46 146.15 38.62 Q 146.15 34.77 145.38 32.00 Q 144.62 29.23 143.54 26.92 Q 142.46 24.62 139.92 21.46 Q 137.38 18.31 136.54 22.69 Q 135.69 27.08 134.62 29.85 Q 133.54 32.62 130.00 38.00 Q 126.46 43.38 121.62 48.08 Q 116.77 52.77 108.15 59.38 Q 99.54 66.00 95.08 70.77 Q 90.62 75.54 89.92 75.00 Q 89.23 74.46 88.46 73.08 Q 87.69 71.69 87.38 68.92 Q 87.08 66.15 88.15 63.69 Q 89.23 61.23 90.54 60.08 Q 91.85 58.92 93.15 58.54 Q 94.46 58.15 93.77 57.15 Q 93.08 56.15 88.92 56.31 Q 84.77 56.46 82.62 57.69 Q 80.46 58.92 78.69 60.85 Q 76.92 62.77 77.85 62.77 Q 78.77 62.77 76.62 66.77 Q 74.46 70.77 72.85 72.38 Q 71.23 74.00 70.15 74.46 Q 69.08 74.92 64.46 70.15 Q 59.85 65.38 51.23 58.77 Q 42.62 52.15 38.08 47.77 Q 33.54 43.38 31.54 40.77 Q 29.54 38.15 27.85 35.08 Q 26.15 32.00 25.08 28.92 Q 24.00 25.85 23.31 22.08 Q 22.62 18.31 20.23 21.31 Q 17.85 24.31 16.77 26.46 Q 15.69 28.62 14.77 31.85 Q 13.85 35.08 13.85 38.77 Q 13.85 42.46 15.23 46.31 Q 16.62 50.15 18.15 52.31 Q 19.69 54.46 23.62 57.77 Q 27.54 61.08 30.77 62.77 Q 34.00 64.46 40.00 66.77 Q 46.00 69.08 50.46 71.54 Q 54.92 74.00 57.77 76.69 Q 60.62 79.38 61.77 81.46 Q 62.92 83.54 60.46 81.23 Q 58.00 78.92 55.23 77.08 Q 52.46 75.23 49.69 74.00 Q 46.92 72.77 39.85 70.46 Q 32.77 68.15 27.69 65.23 Q 22.62 62.31 19.00 59.00 Q 15.38 55.69 12.38 51.31 Q 9.38 46.92 9.00 47.46 Q 8.62 48.00 8.31 49.69 Z"/>
|
|
15
3
|
</svg>
|
|
@@ -18,6 +18,9 @@ import { Route as authLoginOutRouteImport } from './../../pages/(auth)/login-out
|
|
|
18
18
|
import { Route as authLoginLayoutRouteImport } from './../../pages/(auth)/login/layout'
|
|
19
19
|
import { Route as authLoginIndexRouteImport } from './../../pages/(auth)/login/index'
|
|
20
20
|
import { Route as adminHomeIndexRouteImport } from './../../pages/(admin)/home/index'
|
|
21
|
+
import { Route as authLoginResetPwdRouteImport } from './../../pages/(auth)/login/reset-pwd'
|
|
22
|
+
import { Route as authLoginRegisterRouteImport } from './../../pages/(auth)/login/register'
|
|
23
|
+
import { Route as authLoginCodeLoginRouteImport } from './../../pages/(auth)/login/code-login'
|
|
21
24
|
|
|
22
25
|
const adminLayoutRoute = adminLayoutRouteImport.update({
|
|
23
26
|
id: '/(admin)',
|
|
@@ -63,6 +66,21 @@ const adminHomeIndexRoute = adminHomeIndexRouteImport.update({
|
|
|
63
66
|
path: '/home/',
|
|
64
67
|
getParentRoute: () => adminLayoutRoute,
|
|
65
68
|
} as any)
|
|
69
|
+
const authLoginResetPwdRoute = authLoginResetPwdRouteImport.update({
|
|
70
|
+
id: '/reset-pwd',
|
|
71
|
+
path: '/reset-pwd',
|
|
72
|
+
getParentRoute: () => authLoginLayoutRoute,
|
|
73
|
+
} as any)
|
|
74
|
+
const authLoginRegisterRoute = authLoginRegisterRouteImport.update({
|
|
75
|
+
id: '/register',
|
|
76
|
+
path: '/register',
|
|
77
|
+
getParentRoute: () => authLoginLayoutRoute,
|
|
78
|
+
} as any)
|
|
79
|
+
const authLoginCodeLoginRoute = authLoginCodeLoginRouteImport.update({
|
|
80
|
+
id: '/code-login',
|
|
81
|
+
path: '/code-login',
|
|
82
|
+
getParentRoute: () => authLoginLayoutRoute,
|
|
83
|
+
} as any)
|
|
66
84
|
|
|
67
85
|
export interface FileRoutesByFullPath {
|
|
68
86
|
'/': typeof IndexRoute
|
|
@@ -71,6 +89,9 @@ export interface FileRoutesByFullPath {
|
|
|
71
89
|
'/403': typeof errors403Route
|
|
72
90
|
'/404': typeof errors404Route
|
|
73
91
|
'/500': typeof errors500Route
|
|
92
|
+
'/login/code-login': typeof authLoginCodeLoginRoute
|
|
93
|
+
'/login/register': typeof authLoginRegisterRoute
|
|
94
|
+
'/login/reset-pwd': typeof authLoginResetPwdRoute
|
|
74
95
|
'/home/': typeof adminHomeIndexRoute
|
|
75
96
|
'/login/': typeof authLoginIndexRoute
|
|
76
97
|
}
|
|
@@ -80,6 +101,9 @@ export interface FileRoutesByTo {
|
|
|
80
101
|
'/403': typeof errors403Route
|
|
81
102
|
'/404': typeof errors404Route
|
|
82
103
|
'/500': typeof errors500Route
|
|
104
|
+
'/login/code-login': typeof authLoginCodeLoginRoute
|
|
105
|
+
'/login/register': typeof authLoginRegisterRoute
|
|
106
|
+
'/login/reset-pwd': typeof authLoginResetPwdRoute
|
|
83
107
|
'/home': typeof adminHomeIndexRoute
|
|
84
108
|
'/login': typeof authLoginIndexRoute
|
|
85
109
|
}
|
|
@@ -92,6 +116,9 @@ export interface FileRoutesById {
|
|
|
92
116
|
'/(errors)/403': typeof errors403Route
|
|
93
117
|
'/(errors)/404': typeof errors404Route
|
|
94
118
|
'/(errors)/500': typeof errors500Route
|
|
119
|
+
'/(auth)/login/code-login': typeof authLoginCodeLoginRoute
|
|
120
|
+
'/(auth)/login/register': typeof authLoginRegisterRoute
|
|
121
|
+
'/(auth)/login/reset-pwd': typeof authLoginResetPwdRoute
|
|
95
122
|
'/(admin)/home/': typeof adminHomeIndexRoute
|
|
96
123
|
'/(auth)/login/': typeof authLoginIndexRoute
|
|
97
124
|
}
|
|
@@ -104,10 +131,23 @@ export interface FileRouteTypes {
|
|
|
104
131
|
| '/403'
|
|
105
132
|
| '/404'
|
|
106
133
|
| '/500'
|
|
134
|
+
| '/login/code-login'
|
|
135
|
+
| '/login/register'
|
|
136
|
+
| '/login/reset-pwd'
|
|
107
137
|
| '/home/'
|
|
108
138
|
| '/login/'
|
|
109
139
|
fileRoutesByTo: FileRoutesByTo
|
|
110
|
-
to:
|
|
140
|
+
to:
|
|
141
|
+
| '/'
|
|
142
|
+
| '/login-out'
|
|
143
|
+
| '/403'
|
|
144
|
+
| '/404'
|
|
145
|
+
| '/500'
|
|
146
|
+
| '/login/code-login'
|
|
147
|
+
| '/login/register'
|
|
148
|
+
| '/login/reset-pwd'
|
|
149
|
+
| '/home'
|
|
150
|
+
| '/login'
|
|
111
151
|
id:
|
|
112
152
|
| '__root__'
|
|
113
153
|
| '/'
|
|
@@ -117,6 +157,9 @@ export interface FileRouteTypes {
|
|
|
117
157
|
| '/(errors)/403'
|
|
118
158
|
| '/(errors)/404'
|
|
119
159
|
| '/(errors)/500'
|
|
160
|
+
| '/(auth)/login/code-login'
|
|
161
|
+
| '/(auth)/login/register'
|
|
162
|
+
| '/(auth)/login/reset-pwd'
|
|
120
163
|
| '/(admin)/home/'
|
|
121
164
|
| '/(auth)/login/'
|
|
122
165
|
fileRoutesById: FileRoutesById
|
|
@@ -196,6 +239,27 @@ declare module '@tanstack/react-router' {
|
|
|
196
239
|
preLoaderRoute: typeof adminHomeIndexRouteImport
|
|
197
240
|
parentRoute: typeof adminLayoutRoute
|
|
198
241
|
}
|
|
242
|
+
'/(auth)/login/reset-pwd': {
|
|
243
|
+
id: '/(auth)/login/reset-pwd'
|
|
244
|
+
path: '/reset-pwd'
|
|
245
|
+
fullPath: '/login/reset-pwd'
|
|
246
|
+
preLoaderRoute: typeof authLoginResetPwdRouteImport
|
|
247
|
+
parentRoute: typeof authLoginLayoutRoute
|
|
248
|
+
}
|
|
249
|
+
'/(auth)/login/register': {
|
|
250
|
+
id: '/(auth)/login/register'
|
|
251
|
+
path: '/register'
|
|
252
|
+
fullPath: '/login/register'
|
|
253
|
+
preLoaderRoute: typeof authLoginRegisterRouteImport
|
|
254
|
+
parentRoute: typeof authLoginLayoutRoute
|
|
255
|
+
}
|
|
256
|
+
'/(auth)/login/code-login': {
|
|
257
|
+
id: '/(auth)/login/code-login'
|
|
258
|
+
path: '/code-login'
|
|
259
|
+
fullPath: '/login/code-login'
|
|
260
|
+
preLoaderRoute: typeof authLoginCodeLoginRouteImport
|
|
261
|
+
parentRoute: typeof authLoginLayoutRoute
|
|
262
|
+
}
|
|
199
263
|
}
|
|
200
264
|
}
|
|
201
265
|
|
|
@@ -212,10 +276,16 @@ const adminLayoutRouteWithChildren = adminLayoutRoute._addFileChildren(
|
|
|
212
276
|
)
|
|
213
277
|
|
|
214
278
|
interface authLoginLayoutRouteChildren {
|
|
279
|
+
authLoginCodeLoginRoute: typeof authLoginCodeLoginRoute
|
|
280
|
+
authLoginRegisterRoute: typeof authLoginRegisterRoute
|
|
281
|
+
authLoginResetPwdRoute: typeof authLoginResetPwdRoute
|
|
215
282
|
authLoginIndexRoute: typeof authLoginIndexRoute
|
|
216
283
|
}
|
|
217
284
|
|
|
218
285
|
const authLoginLayoutRouteChildren: authLoginLayoutRouteChildren = {
|
|
286
|
+
authLoginCodeLoginRoute: authLoginCodeLoginRoute,
|
|
287
|
+
authLoginRegisterRoute: authLoginRegisterRoute,
|
|
288
|
+
authLoginResetPwdRoute: authLoginResetPwdRoute,
|
|
219
289
|
authLoginIndexRoute: authLoginIndexRoute,
|
|
220
290
|
}
|
|
221
291
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useCaptcha } from '@skyroc/hooks';
|
|
2
|
+
import { ButtonLink } from '@shell/ui/antd';
|
|
3
|
+
import { REG_PHONE } from '@skyroc/utils';
|
|
4
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
5
|
+
|
|
6
|
+
import { useAuthFormRules } from '@/features/auth/use-auth-form-rules';
|
|
7
|
+
|
|
8
|
+
type FormValues = {
|
|
9
|
+
code: string;
|
|
10
|
+
phone: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const CodeLogin = () => {
|
|
14
|
+
const [form] = AForm.useForm<FormValues>();
|
|
15
|
+
|
|
16
|
+
const { t } = useTranslation();
|
|
17
|
+
|
|
18
|
+
const { getCaptcha, isCounting, label, loading } = useCaptcha(t('page.login.codeLogin.getCode'), getCountingLabel);
|
|
19
|
+
|
|
20
|
+
const { formRules } = useAuthFormRules();
|
|
21
|
+
|
|
22
|
+
const phone = AForm.useWatch('phone', form);
|
|
23
|
+
|
|
24
|
+
const isValidPhone = REG_PHONE.test(phone);
|
|
25
|
+
|
|
26
|
+
function handleSubmit(_params: FormValues) {
|
|
27
|
+
// request to reset password
|
|
28
|
+
showSuccessMessage(t('page.login.common.validateSuccess'));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getCountingLabel(count: number) {
|
|
32
|
+
return t('page.login.codeLogin.reGetCode', { time: count });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function sendCaptcha() {
|
|
36
|
+
getCaptcha(phone);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
useKeyPress('enter', () => {
|
|
40
|
+
form.submit();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<>
|
|
45
|
+
<h3 className="text-18px text-primary font-medium">{t('page.login.codeLogin.title')}</h3>
|
|
46
|
+
<AForm className="pt-24px" form={form} onFinish={handleSubmit}>
|
|
47
|
+
<AForm.Item name="phone" rules={formRules.phone}>
|
|
48
|
+
<AInput placeholder={t('page.login.common.phonePlaceholder')} />
|
|
49
|
+
</AForm.Item>
|
|
50
|
+
|
|
51
|
+
<AForm.Item name="code" rules={formRules.code}>
|
|
52
|
+
<div className="w-full flex-y-center gap-16px">
|
|
53
|
+
<AInput placeholder={t('page.login.common.codePlaceholder')} />
|
|
54
|
+
<AButton disabled={!isValidPhone || isCounting} loading={loading} size="large" onClick={sendCaptcha}>
|
|
55
|
+
{label}
|
|
56
|
+
</AButton>
|
|
57
|
+
</div>
|
|
58
|
+
</AForm.Item>
|
|
59
|
+
<ASpace className="w-full" orientation="vertical" size={18}>
|
|
60
|
+
<AButton block htmlType="submit" shape="round" size="large" type="primary">
|
|
61
|
+
{t('common.confirm')}
|
|
62
|
+
</AButton>
|
|
63
|
+
|
|
64
|
+
<ButtonLink block shape="round" size="large" to="..">
|
|
65
|
+
{t('page.login.common.back')}
|
|
66
|
+
</ButtonLink>
|
|
67
|
+
</ASpace>
|
|
68
|
+
</AForm>
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const Route = createFileRoute('/(auth)/login/code-login')({
|
|
74
|
+
component: CodeLogin,
|
|
75
|
+
staticData: {
|
|
76
|
+
title: 'code-login',
|
|
77
|
+
i18nKey: 'route.login_code-login'
|
|
78
|
+
}
|
|
79
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { ButtonLink } from '@shell/ui/antd';
|
|
1
2
|
import { createFileRoute } from '@tanstack/react-router';
|
|
2
3
|
|
|
3
|
-
import { useAuthFormRules } from '@/features/auth/use-auth-form-rules';
|
|
4
4
|
import { useInitLogin } from '@/features/auth/use-login';
|
|
5
|
+
import { useAuthFormRules } from '@/features/auth/use-auth-form-rules';
|
|
5
6
|
|
|
6
7
|
type AccountKey = 'admin' | 'super' | 'user';
|
|
7
8
|
|
|
@@ -19,6 +20,11 @@ const INITIAL_VALUES = {
|
|
|
19
20
|
userName: 'Soybean'
|
|
20
21
|
};
|
|
21
22
|
|
|
23
|
+
const LOGIN_ACTION_I18N_KEYS = {
|
|
24
|
+
codeLogin: 'page.login.codeLogin.title',
|
|
25
|
+
register: 'page.login.register.title'
|
|
26
|
+
} as const satisfies Record<'codeLogin' | 'register', I18n.I18nKey>;
|
|
27
|
+
|
|
22
28
|
const Login = () => {
|
|
23
29
|
const { t } = useTranslation();
|
|
24
30
|
|
|
@@ -74,9 +80,24 @@ const Login = () => {
|
|
|
74
80
|
<AInput.Password autoComplete="password" size="large" />
|
|
75
81
|
</AForm.Item>
|
|
76
82
|
<ASpace className="w-full" orientation="vertical" size={24}>
|
|
83
|
+
<div className="flex-y-center justify-between">
|
|
84
|
+
<ACheckbox>{t('page.login.pwdLogin.rememberMe')}</ACheckbox>
|
|
85
|
+
|
|
86
|
+
<ButtonLink btnType="text" to="/login/reset-pwd">
|
|
87
|
+
{t('page.login.pwdLogin.forgetPassword')}
|
|
88
|
+
</ButtonLink>
|
|
89
|
+
</div>
|
|
77
90
|
<AButton block color="primary" htmlType="submit" loading={loading} shape="round" size="large" type="primary">
|
|
78
91
|
{t('common.confirm')}
|
|
79
92
|
</AButton>
|
|
93
|
+
<div className="flex-y-center justify-between gap-12px">
|
|
94
|
+
<ButtonLink block className="flex-1" to="/login/code-login">
|
|
95
|
+
{t(LOGIN_ACTION_I18N_KEYS.codeLogin) as string}
|
|
96
|
+
</ButtonLink>
|
|
97
|
+
<ButtonLink block className="flex-1" to="/login/register">
|
|
98
|
+
{t(LOGIN_ACTION_I18N_KEYS.register) as string}
|
|
99
|
+
</ButtonLink>
|
|
100
|
+
</div>
|
|
80
101
|
<ADivider className="!m-0 !text-14px !text-#666">{t('page.login.pwdLogin.otherAccountLogin')}</ADivider>
|
|
81
102
|
<div className="flex-center gap-12px">
|
|
82
103
|
{accounts.map(item => {
|
|
@@ -1,20 +1,37 @@
|
|
|
1
|
-
import { mixColor } from '@skyroc/color';
|
|
1
|
+
import { getPaletteColorByNumber, mixColor } from '@skyroc/color';
|
|
2
|
+
import { WaveBg } from '@shell/ui/compose';
|
|
2
3
|
import { useSettingsTheme } from '@shell/theme';
|
|
3
4
|
import { Outlet, createFileRoute, redirect, useLocation } from '@tanstack/react-router';
|
|
4
5
|
import { AnimatePresence, motion } from 'motion/react';
|
|
5
6
|
import { z } from 'zod';
|
|
6
7
|
|
|
8
|
+
import Header from './modules/Header';
|
|
9
|
+
|
|
7
10
|
const COLOR_WHITE = '#ffffff';
|
|
8
11
|
|
|
9
12
|
const LoginSearchSchema = z.object({
|
|
10
13
|
redirect: z.string().startsWith('/').optional()
|
|
11
14
|
});
|
|
12
15
|
|
|
13
|
-
const
|
|
14
|
-
|
|
16
|
+
export const Route = createFileRoute('/(auth)/login')({
|
|
17
|
+
component: LoginLayout,
|
|
18
|
+
validateSearch: LoginSearchSchema,
|
|
19
|
+
beforeLoad: async ({ context, search }) => {
|
|
20
|
+
if (context.isLoggedIn) {
|
|
21
|
+
throw redirect({ to: search.redirect || context.getHomeRoute() });
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
staticData: {
|
|
25
|
+
title: 'login',
|
|
26
|
+
i18nKey: 'route.login'
|
|
27
|
+
}
|
|
28
|
+
});
|
|
15
29
|
|
|
30
|
+
function LoginLayout() {
|
|
16
31
|
const { darkMode, themeColor } = useSettingsTheme();
|
|
17
32
|
|
|
33
|
+
const bgThemeColor = darkMode ? getPaletteColorByNumber(themeColor, 600) : themeColor;
|
|
34
|
+
|
|
18
35
|
const ratio = darkMode ? 0.5 : 0.2;
|
|
19
36
|
|
|
20
37
|
const location = useLocation();
|
|
@@ -23,12 +40,11 @@ const LoginLayout = () => {
|
|
|
23
40
|
|
|
24
41
|
return (
|
|
25
42
|
<div className="relative size-full flex-center overflow-hidden bg-layout" style={{ backgroundColor: bgColor }}>
|
|
26
|
-
<
|
|
43
|
+
<WaveBg themeColor={bgThemeColor} />
|
|
44
|
+
|
|
45
|
+
<ACard className="relative z-4 w-auto rd-12px" variant="borderless">
|
|
27
46
|
<div className="w-400px lt-sm:w-300px">
|
|
28
|
-
<
|
|
29
|
-
<h1 className="m-0 text-28px font-600 text-primary">{t('system.title')}</h1>
|
|
30
|
-
<p className="m-0 mt-8px text-14px text-text-2">{t('page.login.common.loginOrRegister')}</p>
|
|
31
|
-
</div>
|
|
47
|
+
<Header />
|
|
32
48
|
|
|
33
49
|
<AnimatePresence initial={false} mode="wait">
|
|
34
50
|
<motion.main
|
|
@@ -54,18 +70,4 @@ const LoginLayout = () => {
|
|
|
54
70
|
</ACard>
|
|
55
71
|
</div>
|
|
56
72
|
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const Route = createFileRoute('/(auth)/login')({
|
|
60
|
-
component: LoginLayout,
|
|
61
|
-
validateSearch: LoginSearchSchema,
|
|
62
|
-
beforeLoad: async ({ context, search }) => {
|
|
63
|
-
if (context.isLoggedIn) {
|
|
64
|
-
throw redirect({ to: search.redirect || context.getHomeRoute() });
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
staticData: {
|
|
68
|
-
title: 'login',
|
|
69
|
-
i18nKey: 'route.login'
|
|
70
|
-
}
|
|
71
|
-
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FlipText } from '@shell/ui/compose';
|
|
2
|
+
import { ThemeSchemaSwitch, useSettingsTheme } from '@shell/theme';
|
|
3
|
+
|
|
4
|
+
import SystemLogo from '@/components/SystemLogo';
|
|
5
|
+
import { LangSwitch } from '@shell/i18n';
|
|
6
|
+
|
|
7
|
+
const Header = memo(() => {
|
|
8
|
+
const { t } = useTranslation();
|
|
9
|
+
const { header } = useSettingsTheme();
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<header className="flex-y-center justify-between">
|
|
13
|
+
<SystemLogo className="size-5xl text-primary lt-sm:size-4xl" />
|
|
14
|
+
|
|
15
|
+
<FlipText className="text-3xl text-primary font-500 lt-sm:text-2xl" word={t('system.title')} />
|
|
16
|
+
|
|
17
|
+
<div className="i-flex-col">
|
|
18
|
+
<ThemeSchemaSwitch className="text-xl lt-sm:text-lg" showTooltip={false} />
|
|
19
|
+
<LangSwitch showTooltip={false} visible={header.multilingual.visible} />
|
|
20
|
+
</div>
|
|
21
|
+
</header>
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default Header;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { useCaptcha } from '@skyroc/hooks';
|
|
2
|
+
import { ButtonLink } from '@shell/ui/antd';
|
|
3
|
+
import { REG_PHONE } from '@skyroc/utils';
|
|
4
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
5
|
+
|
|
6
|
+
import { useAuthFormRules } from '@/features/auth/use-auth-form-rules';
|
|
7
|
+
|
|
8
|
+
interface FormModel {
|
|
9
|
+
code: string;
|
|
10
|
+
confirmPassword: string;
|
|
11
|
+
password: string;
|
|
12
|
+
phone: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const Register = () => {
|
|
16
|
+
const { t } = useTranslation();
|
|
17
|
+
|
|
18
|
+
const { getCaptcha, isCounting, label, loading } = useCaptcha(t('page.login.codeLogin.getCode'), getCountingLabel);
|
|
19
|
+
|
|
20
|
+
const [form] = AForm.useForm<FormModel>();
|
|
21
|
+
|
|
22
|
+
const phone = AForm.useWatch('phone', form);
|
|
23
|
+
|
|
24
|
+
const isValidPhone = REG_PHONE.test(phone);
|
|
25
|
+
|
|
26
|
+
const { createConfirmPwdRule, formRules } = useAuthFormRules();
|
|
27
|
+
|
|
28
|
+
function handleSubmit(_params: FormModel) {
|
|
29
|
+
// request to reset password
|
|
30
|
+
showSuccessMessage(t('page.login.common.validateSuccess'));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getCountingLabel(count: number) {
|
|
34
|
+
return t('page.login.codeLogin.reGetCode', { time: count });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function sendCaptcha() {
|
|
38
|
+
getCaptcha(phone);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
useKeyPress('enter', () => {
|
|
42
|
+
form.submit();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<>
|
|
47
|
+
<h3 className="text-18px text-primary font-medium">{t('page.login.register.title')}</h3>
|
|
48
|
+
<AForm className="pt-24px" form={form} onFinish={handleSubmit}>
|
|
49
|
+
<AForm.Item name="phone" rules={formRules.phone}>
|
|
50
|
+
<AInput placeholder={t('page.login.common.phonePlaceholder')} size="large" />
|
|
51
|
+
</AForm.Item>
|
|
52
|
+
<AForm.Item name="code" rules={formRules.code}>
|
|
53
|
+
<div className="w-full flex-y-center gap-16px">
|
|
54
|
+
<AInput placeholder={t('page.login.common.codePlaceholder')} size="large" />
|
|
55
|
+
<AButton disabled={!isValidPhone || isCounting} loading={loading} size="large" onClick={sendCaptcha}>
|
|
56
|
+
{label}
|
|
57
|
+
</AButton>
|
|
58
|
+
</div>
|
|
59
|
+
</AForm.Item>
|
|
60
|
+
<AForm.Item name="password" rules={formRules.pwd}>
|
|
61
|
+
<AInput placeholder={t('page.login.common.passwordPlaceholder')} />
|
|
62
|
+
</AForm.Item>
|
|
63
|
+
<AForm.Item name="confirmPassword" rules={createConfirmPwdRule(form)}>
|
|
64
|
+
<AInput placeholder={t('page.login.common.confirmPasswordPlaceholder')} size="large" />
|
|
65
|
+
</AForm.Item>
|
|
66
|
+
<ASpace className="w-full" orientation="vertical" size={18}>
|
|
67
|
+
<AButton block htmlType="submit" shape="round" size="large" type="primary">
|
|
68
|
+
{t('common.confirm')}
|
|
69
|
+
</AButton>
|
|
70
|
+
|
|
71
|
+
<ButtonLink block shape="round" size="large" to="..">
|
|
72
|
+
{t('page.login.common.back')}
|
|
73
|
+
</ButtonLink>
|
|
74
|
+
</ASpace>
|
|
75
|
+
</AForm>
|
|
76
|
+
</>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const Route = createFileRoute('/(auth)/login/register')({
|
|
81
|
+
component: Register,
|
|
82
|
+
staticData: {
|
|
83
|
+
title: 'login_register',
|
|
84
|
+
i18nKey: 'route.login_register'
|
|
85
|
+
}
|
|
86
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ButtonLink } from '@shell/ui/antd';
|
|
2
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
3
|
+
|
|
4
|
+
import { useAuthFormRules } from '@/features/auth/use-auth-form-rules';
|
|
5
|
+
|
|
6
|
+
interface FormModel {
|
|
7
|
+
code: string;
|
|
8
|
+
confirmPassword: string;
|
|
9
|
+
password: string;
|
|
10
|
+
phone: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ResetPwd = () => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
|
|
16
|
+
const [form] = AForm.useForm<FormModel>();
|
|
17
|
+
|
|
18
|
+
const { createConfirmPwdRule, formRules } = useAuthFormRules();
|
|
19
|
+
|
|
20
|
+
function handleSubmit(_params: FormModel) {
|
|
21
|
+
// request to reset password
|
|
22
|
+
showSuccessMessage(t('page.login.common.validateSuccess'));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
useKeyPress('enter', () => {
|
|
26
|
+
form.submit();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
<h3 className="text-18px text-primary font-medium">{t('page.login.register.title')}</h3>
|
|
32
|
+
<AForm className="pt-24px" form={form} onFinish={handleSubmit}>
|
|
33
|
+
<AForm.Item name="phone" rules={formRules.phone}>
|
|
34
|
+
<AInput placeholder={t('page.login.common.phonePlaceholder')} size="large" />
|
|
35
|
+
</AForm.Item>
|
|
36
|
+
<AForm.Item name="code" rules={formRules.code}>
|
|
37
|
+
<AInput placeholder={t('page.login.common.codePlaceholder')} size="large" />
|
|
38
|
+
</AForm.Item>
|
|
39
|
+
<AForm.Item name="password" rules={formRules.pwd}>
|
|
40
|
+
<AInput.Password
|
|
41
|
+
autoComplete="password"
|
|
42
|
+
placeholder={t('page.login.common.passwordPlaceholder')}
|
|
43
|
+
size="large"
|
|
44
|
+
/>
|
|
45
|
+
</AForm.Item>
|
|
46
|
+
<AForm.Item name="confirmPassword" rules={createConfirmPwdRule(form)}>
|
|
47
|
+
<AInput.Password
|
|
48
|
+
autoComplete="confirm-password"
|
|
49
|
+
placeholder={t('page.login.common.confirmPasswordPlaceholder')}
|
|
50
|
+
size="large"
|
|
51
|
+
/>
|
|
52
|
+
</AForm.Item>
|
|
53
|
+
<ASpace className="w-full" orientation="vertical" size={18}>
|
|
54
|
+
<AButton block htmlType="submit" shape="round" size="large" type="primary">
|
|
55
|
+
{t('common.confirm')}
|
|
56
|
+
</AButton>
|
|
57
|
+
|
|
58
|
+
<ButtonLink block shape="round" size="large" to="..">
|
|
59
|
+
{t('page.login.common.back')}
|
|
60
|
+
</ButtonLink>
|
|
61
|
+
</ASpace>
|
|
62
|
+
</AForm>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const Route = createFileRoute('/(auth)/login/reset-pwd')({
|
|
68
|
+
component: ResetPwd,
|
|
69
|
+
staticData: {
|
|
70
|
+
title: 'login_reset-pwd',
|
|
71
|
+
i18nKey: 'route.login_reset-pwd'
|
|
72
|
+
}
|
|
73
|
+
});
|
|
@@ -60,6 +60,8 @@ export function getAntdTheme(colors: Theme.ThemeColor, darkMode: boolean, settin
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
token: {
|
|
63
|
+
// 先注入预设色板,再用运行时主题色覆盖语义色
|
|
64
|
+
...defaultPresetColors,
|
|
63
65
|
colorBgContainer: containerBgColor,
|
|
64
66
|
colorInverted: invertedColor,
|
|
65
67
|
colorError: error,
|
|
@@ -70,9 +72,7 @@ export function getAntdTheme(colors: Theme.ThemeColor, darkMode: boolean, settin
|
|
|
70
72
|
colorPrimary: primary,
|
|
71
73
|
borderRadius: themeRadius,
|
|
72
74
|
colorSuccess: success,
|
|
73
|
-
colorWarning: warning
|
|
74
|
-
// 使用预设的颜色
|
|
75
|
-
...defaultPresetColors
|
|
75
|
+
colorWarning: warning
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
78
|
|
|
@@ -8,8 +8,8 @@ export const DARK_TEXT_BASE = '#FFFFFF';
|
|
|
8
8
|
/**
|
|
9
9
|
* Generate color palettes (dark mode)
|
|
10
10
|
*
|
|
11
|
-
* Uses
|
|
12
|
-
*
|
|
11
|
+
* Uses a dark-mode OKLCH palette anchored at 500 so the user-provided theme color remains the semantic main color. The
|
|
12
|
+
* palette mapping follows Ant Design's dark-mode interaction rules.
|
|
13
13
|
*
|
|
14
14
|
* 档位号语义与亮色一致——50 最亮、950 最暗。暗色主题需要深色背景,因此 antd 的 1-4 档取的是色板暗端(950-700),而不是靠翻转档位号来实现。
|
|
15
15
|
*
|
|
@@ -17,7 +17,7 @@ export const DARK_TEXT_BASE = '#FFFFFF';
|
|
|
17
17
|
* 7→600),增强交互对比 - 8-10: 复用 5-7 (8→400, 9→500, 10→600),用于文字色
|
|
18
18
|
*/
|
|
19
19
|
export const generateColorPalettes: GenerateColorMap = (baseColor: string): ColorMap => {
|
|
20
|
-
const { palettes } = generateDarkModePalette(baseColor);
|
|
20
|
+
const { palettes } = generateDarkModePalette(baseColor, 500);
|
|
21
21
|
const [p50, p100, p200, p300, p400, p500, p600, p700, p800, p900, p950] = palettes;
|
|
22
22
|
|
|
23
23
|
return {
|
|
@@ -12,7 +12,7 @@ export const LIGHT_TEXT_BASE = '#1F1F1F';
|
|
|
12
12
|
* antd's 1-10 indexes
|
|
13
13
|
*/
|
|
14
14
|
export const generateColorPalettes: GenerateColorMap = (baseColor: string): ColorMap => {
|
|
15
|
-
const { palettes } = generateOklchPaletteAnchored(baseColor);
|
|
15
|
+
const { palettes } = generateOklchPaletteAnchored(baseColor, 500);
|
|
16
16
|
const [p50, p100, p200, p300, p400, p500, p600, p700, p800, p900, p950] = palettes;
|
|
17
17
|
|
|
18
18
|
return {
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
"@skyroc/color": "^2.6.0",
|
|
5
5
|
"@skyroc/core-state": "^1.0.0",
|
|
6
6
|
"@skyroc/hooks": "^1.0.0",
|
|
7
|
-
"@skyroc/logger": "^1.0.0",
|
|
8
7
|
"@skyroc/service": "^1.0.0",
|
|
9
8
|
"@skyroc/utils": "^4.0.0",
|
|
10
9
|
"@skyroc/web-admin-devtools": "^0.1.0",
|
|
@@ -31,7 +30,7 @@
|
|
|
31
30
|
"@iconify/react": "^6.0.2",
|
|
32
31
|
"@iconify/types": "^2.0.0",
|
|
33
32
|
"@sa/uno-config": "^1.0.0",
|
|
34
|
-
"@skyroc/scripts": "^2.5.
|
|
33
|
+
"@skyroc/scripts": "^2.5.1",
|
|
35
34
|
"@skyroc/web-admin-vite": "^0.1.0",
|
|
36
35
|
"@svgr/core": "^8.1.0",
|
|
37
36
|
"@svgr/plugin-jsx": "^8.1.0",
|