@liujitcn/kratos-admin-core 0.0.20 → 0.0.23
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/README.md +2 -2
- package/dist/package/declarations/src/api/base/language.d.ts +8 -0
- package/dist/package/declarations/src/components/Dialog/ProDialog.vue.d.ts +1 -0
- package/dist/package/declarations/src/components/Dict/index.vue.d.ts +4 -3
- package/dist/package/declarations/src/components/Dict/value.d.ts +11 -0
- package/dist/package/declarations/src/components/LocaleSwitch/index.vue.d.ts +3 -0
- package/dist/package/declarations/src/index.d.ts +2 -0
- package/dist/package/declarations/src/locales/generated.d.ts +3382 -0
- package/dist/package/declarations/src/locales/index.d.ts +53 -0
- package/dist/package/declarations/src/modules/index.d.ts +7 -2
- package/dist/package/declarations/src/request.d.ts +1 -0
- package/dist/package/declarations/src/routers/modules/staticRouter.d.ts +1 -0
- package/dist/package/declarations/src/rpc/base/v1/config.d.ts +13 -1
- package/dist/package/declarations/src/rpc/base/v1/language.d.ts +20 -0
- package/dist/package/declarations/src/rpc/base/v1/login.d.ts +13 -1
- package/dist/package/declarations/src/rpc/system/admin/v1/auth.d.ts +1 -1
- package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +9 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/base_translation.d.ts +75 -0
- package/dist/package/declarations/src/rpc/system/admin/v1/common.d.ts +13 -0
- package/dist/package/declarations/src/stores/interface/index.d.ts +2 -0
- package/dist/package/declarations/src/stores/modules/auth.d.ts +6 -6
- package/dist/package/declarations/src/stores/runtime.d.ts +1 -0
- package/dist/package/declarations/src/utils/dict.d.ts +2 -2
- package/dist/package/declarations/src/utils/index.d.ts +1 -1
- package/dist/package/declarations/src/utils/oauthProvider.d.ts +2 -0
- package/dist/package/declarations/src/utils/passwordCrypto.d.ts +1 -1
- package/dist/package/declarations/src/utils/passwordStrength.d.ts +0 -7
- package/dist/package/src/App.vue +5 -2
- package/dist/package/src/api/base/language.ts +20 -0
- package/dist/package/src/api/base/oauth.ts +0 -1
- package/dist/package/src/api/system/auth.ts +0 -1
- package/dist/package/src/bootstrap.ts +57 -2
- package/dist/package/src/components/CronExpression/index.vue +80 -82
- package/dist/package/src/components/Dialog/FormDialog.vue +10 -5
- package/dist/package/src/components/Dialog/ProDialog.vue +10 -4
- package/dist/package/src/components/Dict/index.vue +26 -9
- package/dist/package/src/components/Dict/value.ts +18 -0
- package/dist/package/src/components/ECharts/config/index.ts +6 -1
- package/dist/package/src/components/ErrorMessage/index.vue +3 -1
- package/dist/package/src/components/ImportExcel/index.vue +29 -18
- package/dist/package/src/components/LocaleSwitch/index.vue +28 -0
- package/dist/package/src/components/PasswordStrength/index.vue +8 -5
- package/dist/package/src/components/ProForm/components/DynamicList.vue +8 -3
- package/dist/package/src/components/ProForm/components/KvList.vue +14 -6
- package/dist/package/src/components/ProForm/index.vue +2 -2
- package/dist/package/src/components/ProTable/components/ColSetting.vue +7 -5
- package/dist/package/src/components/ProTable/components/TableColumn.vue +2 -1
- package/dist/package/src/components/ProTable/index.vue +36 -11
- package/dist/package/src/components/SearchForm/components/SearchFormItem.vue +9 -4
- package/dist/package/src/components/SearchForm/index.vue +6 -3
- package/dist/package/src/components/SelectFilter/index.vue +4 -1
- package/dist/package/src/components/SelectIcon/index.vue +8 -4
- package/dist/package/src/components/TreeFilter/index.vue +14 -6
- package/dist/package/src/components/Upload/File.vue +18 -13
- package/dist/package/src/components/Upload/Files.vue +22 -15
- package/dist/package/src/components/Upload/Img.vue +14 -11
- package/dist/package/src/components/Upload/Imgs.vue +15 -12
- package/dist/package/src/components/WangEditor/index.vue +12 -4
- package/dist/package/src/directives/modules/copy.ts +2 -1
- package/dist/package/src/hooks/useDownload.ts +3 -2
- package/dist/package/src/hooks/useHandleData.ts +5 -4
- package/dist/package/src/hooks/useTheme.ts +2 -1
- package/dist/package/src/hooks/useTime.ts +11 -2
- package/dist/package/src/index.ts +2 -0
- package/dist/package/src/layouts/components/Header/ToolBarRight.vue +2 -0
- package/dist/package/src/layouts/components/Header/components/AssemblySize.vue +8 -6
- package/dist/package/src/layouts/components/Header/components/Avatar.vue +11 -9
- package/dist/package/src/layouts/components/Header/components/Breadcrumb.vue +11 -3
- package/dist/package/src/layouts/components/Header/components/Fullscreen.vue +4 -2
- package/dist/package/src/layouts/components/Header/components/InfoDialog.vue +6 -3
- package/dist/package/src/layouts/components/Header/components/PasswordDialog.vue +6 -3
- package/dist/package/src/layouts/components/Header/components/SearchMenu.vue +5 -3
- package/dist/package/src/layouts/components/Header/components/ThemeSetting.vue +3 -1
- package/dist/package/src/layouts/components/Main/index.vue +1 -0
- package/dist/package/src/layouts/components/Tabs/components/MoreButton.vue +9 -7
- package/dist/package/src/layouts/components/Tabs/index.vue +15 -1
- package/dist/package/src/layouts/components/ThemeDrawer/index.vue +27 -24
- package/dist/package/src/locales/README.md +15 -0
- package/dist/package/src/locales/en-US.json +283 -0
- package/dist/package/src/locales/es-ES.json +283 -0
- package/dist/package/src/locales/fr-FR.json +283 -0
- package/dist/package/src/locales/generated.ts +57 -0
- package/dist/package/src/locales/index.ts +222 -0
- package/dist/package/src/locales/ja-JP.json +283 -0
- package/dist/package/src/locales/ko-KR.json +283 -0
- package/dist/package/src/locales/zh-CN.json +283 -0
- package/dist/package/src/locales/zh-TW.json +283 -0
- package/dist/package/src/modules/index.ts +7 -2
- package/dist/package/src/modules/kratosAdmin.ts +5 -1
- package/dist/package/src/request.ts +8 -1
- package/dist/package/src/routers/index.ts +4 -1
- package/dist/package/src/routers/modules/dynamicRouter.ts +5 -4
- package/dist/package/src/routers/modules/staticRouter.ts +8 -4
- package/dist/package/src/rpc/base/v1/config.ts +14 -1
- package/dist/package/src/rpc/base/v1/language.ts +31 -0
- package/dist/package/src/rpc/base/v1/login.ts +14 -1
- package/dist/package/src/rpc/system/admin/v1/auth.ts +1 -1
- package/dist/package/src/rpc/system/admin/v1/base_dict.ts +9 -0
- package/dist/package/src/rpc/system/admin/v1/base_translation.ts +90 -0
- package/dist/package/src/rpc/system/admin/v1/common.ts +21 -0
- package/dist/package/src/stores/interface/index.ts +2 -0
- package/dist/package/src/stores/modules/config.ts +7 -3
- package/dist/package/src/stores/modules/user.ts +2 -1
- package/dist/package/src/stores/runtime.ts +1 -0
- package/dist/package/src/styles/element.scss +2 -0
- package/dist/package/src/utils/color.ts +5 -4
- package/dist/package/src/utils/dict.ts +27 -4
- package/dist/package/src/utils/eleValidate.ts +3 -2
- package/dist/package/src/utils/errorHandler.ts +9 -8
- package/dist/package/src/utils/index.ts +9 -8
- package/dist/package/src/utils/oauthProvider.ts +15 -10
- package/dist/package/src/utils/passwordCrypto.ts +4 -3
- package/dist/package/src/utils/passwordStrength.ts +1 -16
- package/dist/package/src/utils/request.ts +13 -8
- package/dist/package/src/views/error/403.vue +3 -1
- package/dist/package/src/views/error/404.vue +3 -1
- package/dist/package/src/views/error/500.vue +3 -1
- package/dist/package/src/views/error/pending.vue +5 -2
- package/dist/package/src/views/login/components/LoginForm.vue +58 -29
- package/dist/package/src/views/login/index.scss +6 -0
- package/dist/package/src/views/login/index.vue +2 -0
- package/dist/package/types/generated/auto-imports.d.ts +129 -111
- package/dist/package/types/generated/components.d.ts +67 -67
- package/package.json +4 -2
- package/types/generated/auto-imports.d.ts +129 -111
- package/types/generated/components.d.ts +67 -67
- package/vite.config.ts +12 -0
- package/dist/package/declarations/src/rpc/base/v1/enum.d.ts +0 -43
- package/dist/package/declarations/src/rpc/system/common/v1/enum.d.ts +0 -67
- package/dist/package/src/rpc/base/v1/enum.ts +0 -54
- package/dist/package/src/rpc/system/common/v1/enum.ts +0 -80
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defLoginService } from "../api/base/login";
|
|
2
|
-
import { PasswordCryptoScene } from "../rpc/base/v1/
|
|
2
|
+
import { PasswordCryptoScene } from "../rpc/base/v1/login";
|
|
3
3
|
import type { PasswordCrypto } from "../rpc/common/v1/types";
|
|
4
|
+
import { t } from "../locales";
|
|
4
5
|
|
|
5
6
|
export const PASSWORD_CRYPTO_SCENE = PasswordCryptoScene;
|
|
6
7
|
export type { PasswordCryptoScene };
|
|
@@ -33,7 +34,7 @@ function arrayBufferToBase64(buffer: ArrayBuffer) {
|
|
|
33
34
|
function getSubtleCrypto() {
|
|
34
35
|
const cryptoApi = globalThis.crypto;
|
|
35
36
|
if (!cryptoApi?.subtle) {
|
|
36
|
-
throw new Error("
|
|
37
|
+
throw new Error(t("core.password.crypto_unsupported"));
|
|
37
38
|
}
|
|
38
39
|
return cryptoApi;
|
|
39
40
|
}
|
|
@@ -42,7 +43,7 @@ function getSubtleCrypto() {
|
|
|
42
43
|
export async function encryptPassword(password: string, scene: PasswordCryptoScene): Promise<PasswordCrypto> {
|
|
43
44
|
const plainPassword = password.trim();
|
|
44
45
|
if (!plainPassword) {
|
|
45
|
-
throw new Error("
|
|
46
|
+
throw new Error(t("core.password.required"));
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
const cryptoApi = getSubtleCrypto();
|
|
@@ -9,18 +9,10 @@ export interface PasswordStrengthResult {
|
|
|
9
9
|
strengthScore: number;
|
|
10
10
|
/** 强度等级。 */
|
|
11
11
|
level: PasswordStrengthLevel;
|
|
12
|
-
/** 强度文案。 */
|
|
13
|
-
text: string;
|
|
14
12
|
/** 是否达到允许提交的最高强度。 */
|
|
15
13
|
isValid: boolean;
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
/** 密码强度错误提示。 */
|
|
19
|
-
export const PASSWORD_STRENGTH_ERROR_MESSAGE = "密码需同时包含大小写字母、数字、特殊字符,且长度不少于 8 位";
|
|
20
|
-
|
|
21
|
-
/** 密码强度说明文案。 */
|
|
22
|
-
export const PASSWORD_STRENGTH_TIP = "需同时包含大小写字母、数字、特殊字符,且长度不少于 8 位,达到最高强度后才可提交。";
|
|
23
|
-
|
|
24
16
|
/**
|
|
25
17
|
* 计算密码强度结果,供表单展示和校验统一复用。
|
|
26
18
|
*
|
|
@@ -33,7 +25,6 @@ export function getPasswordStrength(password?: string): PasswordStrengthResult {
|
|
|
33
25
|
ruleScore: 0,
|
|
34
26
|
strengthScore: 0,
|
|
35
27
|
level: "empty",
|
|
36
|
-
text: "未输入",
|
|
37
28
|
isValid: false
|
|
38
29
|
};
|
|
39
30
|
}
|
|
@@ -49,7 +40,6 @@ export function getPasswordStrength(password?: string): PasswordStrengthResult {
|
|
|
49
40
|
ruleScore,
|
|
50
41
|
strengthScore: 3,
|
|
51
42
|
level: "high",
|
|
52
|
-
text: "高",
|
|
53
43
|
isValid: true
|
|
54
44
|
};
|
|
55
45
|
}
|
|
@@ -58,7 +48,6 @@ export function getPasswordStrength(password?: string): PasswordStrengthResult {
|
|
|
58
48
|
ruleScore,
|
|
59
49
|
strengthScore: 2,
|
|
60
50
|
level: "medium",
|
|
61
|
-
text: "中",
|
|
62
51
|
isValid: false
|
|
63
52
|
};
|
|
64
53
|
}
|
|
@@ -66,7 +55,6 @@ export function getPasswordStrength(password?: string): PasswordStrengthResult {
|
|
|
66
55
|
ruleScore,
|
|
67
56
|
strengthScore: 1,
|
|
68
57
|
level: "low",
|
|
69
|
-
text: "低",
|
|
70
58
|
isValid: false
|
|
71
59
|
};
|
|
72
60
|
}
|
|
@@ -79,8 +67,5 @@ export function getPasswordStrength(password?: string): PasswordStrengthResult {
|
|
|
79
67
|
*/
|
|
80
68
|
export function validatePasswordStrengthValue(password?: string) {
|
|
81
69
|
const result = getPasswordStrength(password);
|
|
82
|
-
return {
|
|
83
|
-
valid: result.isValid,
|
|
84
|
-
message: result.isValid ? "" : PASSWORD_STRENGTH_ERROR_MESSAGE
|
|
85
|
-
};
|
|
70
|
+
return { valid: result.isValid };
|
|
86
71
|
}
|
|
@@ -5,6 +5,7 @@ import router from "../routers";
|
|
|
5
5
|
import { LOGIN_URL } from "../config";
|
|
6
6
|
import pinia from "../stores";
|
|
7
7
|
import { useUserStore } from "../stores/modules/user";
|
|
8
|
+
import { getLocaleRequestHeaders, t } from "../locales";
|
|
8
9
|
|
|
9
10
|
const apiBasePath = import.meta.env.VITE_APP_BASE_API || "";
|
|
10
11
|
const apiTargetUrl = import.meta.env.VITE_API_URL || import.meta.env.VITE_APP_API_URL || "";
|
|
@@ -13,6 +14,7 @@ const SESSION_URL = "/v1/base/session";
|
|
|
13
14
|
const TOKEN_URL = "/v1/base/token";
|
|
14
15
|
const CAPTCHA_URL = "/v1/base/captcha";
|
|
15
16
|
const CONFIG_URL = "/v1/base/config";
|
|
17
|
+
const LANGUAGE_URL = "/v1/base/language";
|
|
16
18
|
const PASSWORD_PUBLIC_KEY_URL = "/v1/base/password-public-key";
|
|
17
19
|
const OAUTH_PROVIDER_URL = "/v1/base/oauth/provider";
|
|
18
20
|
const OAUTH_AUTHORIZATION_URL = "/v1/base/oauth/authorization";
|
|
@@ -26,6 +28,7 @@ const NO_AUTH_URL_SET = new Set([
|
|
|
26
28
|
TOKEN_URL,
|
|
27
29
|
CAPTCHA_URL,
|
|
28
30
|
CONFIG_URL,
|
|
31
|
+
LANGUAGE_URL,
|
|
29
32
|
PASSWORD_PUBLIC_KEY_URL,
|
|
30
33
|
OAUTH_PROVIDER_URL,
|
|
31
34
|
OAUTH_AUTHORIZATION_URL,
|
|
@@ -39,6 +42,7 @@ const AUTH_EXPIRED_EXCLUDED_URL_SET = new Set([
|
|
|
39
42
|
TOKEN_URL,
|
|
40
43
|
CAPTCHA_URL,
|
|
41
44
|
CONFIG_URL,
|
|
45
|
+
LANGUAGE_URL,
|
|
42
46
|
PASSWORD_PUBLIC_KEY_URL,
|
|
43
47
|
OAUTH_PROVIDER_URL,
|
|
44
48
|
OAUTH_AUTHORIZATION_URL,
|
|
@@ -156,9 +160,9 @@ export function handleAuthExpired() {
|
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
isHandlingAuthExpired = true;
|
|
159
|
-
ElMessageBox.confirm("
|
|
160
|
-
confirmButtonText: "
|
|
161
|
-
cancelButtonText: "
|
|
163
|
+
ElMessageBox.confirm(t("core.auth.session_expired"), t("common.title.notice"), {
|
|
164
|
+
confirmButtonText: t("core.auth.login_again"),
|
|
165
|
+
cancelButtonText: t("common.action.cancel"),
|
|
162
166
|
type: "warning",
|
|
163
167
|
closeOnClickModal: false,
|
|
164
168
|
closeOnPressEscape: false
|
|
@@ -183,6 +187,7 @@ service.interceptors.request.use(
|
|
|
183
187
|
async (config: InternalAxiosRequestConfig) => {
|
|
184
188
|
const skipAuth = shouldSkipAuth(config);
|
|
185
189
|
const accessToken = skipAuth ? "" : await getRequestAccessToken();
|
|
190
|
+
Object.assign(config.headers, getLocaleRequestHeaders());
|
|
186
191
|
// 登录、验证码、刷新令牌接口不携带旧 token,避免请求头污染。
|
|
187
192
|
if (!skipAuth && accessToken) {
|
|
188
193
|
config.headers.Authorization = accessToken;
|
|
@@ -207,7 +212,7 @@ service.interceptors.response.use(
|
|
|
207
212
|
return response.data;
|
|
208
213
|
}
|
|
209
214
|
|
|
210
|
-
ElMessage.error(message || "
|
|
215
|
+
ElMessage.error(message || t("common.message.system_error"));
|
|
211
216
|
return Promise.reject(new Error(message || "Error"));
|
|
212
217
|
},
|
|
213
218
|
async (error: AxiosError) => {
|
|
@@ -235,11 +240,11 @@ service.interceptors.response.use(
|
|
|
235
240
|
if (message) {
|
|
236
241
|
ElMessage.error(message);
|
|
237
242
|
} else {
|
|
238
|
-
ElMessage.error("
|
|
243
|
+
ElMessage.error(t("common.message.system_error"));
|
|
239
244
|
}
|
|
240
245
|
}
|
|
241
246
|
} else if (!shouldSkipErrorMessage(requestConfig)) {
|
|
242
|
-
ElMessage.error(error.message || "
|
|
247
|
+
ElMessage.error(error.message || t("common.message.system_error"));
|
|
243
248
|
}
|
|
244
249
|
return Promise.reject(error.message);
|
|
245
250
|
}
|
|
@@ -278,13 +283,13 @@ async function handleTokenRefresh(promptOnFailure = true) {
|
|
|
278
283
|
async function refreshAccessToken() {
|
|
279
284
|
const userStore = getUserStore();
|
|
280
285
|
if (!userStore.refreshToken) {
|
|
281
|
-
return Promise.reject(new Error("
|
|
286
|
+
return Promise.reject(new Error(t("core.auth.refresh_token_missing")));
|
|
282
287
|
}
|
|
283
288
|
|
|
284
289
|
const response = await refreshService.post(
|
|
285
290
|
TOKEN_URL,
|
|
286
291
|
{ refresh_token: userStore.refreshToken },
|
|
287
|
-
{ headers: { Authorization: "no-auth" } }
|
|
292
|
+
{ headers: { Authorization: "no-auth", ...getLocaleRequestHeaders() } }
|
|
288
293
|
);
|
|
289
294
|
const data = response.data;
|
|
290
295
|
userStore.updateTokenAuth(
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts" name="403">
|
|
2
2
|
import errorImage from "../../assets/images/403.png";
|
|
3
3
|
import ErrorMessage from "../../components/ErrorMessage/index.vue";
|
|
4
|
+
import { useLocaleStore } from "../../locales";
|
|
5
|
+
const { t } = useLocaleStore();
|
|
4
6
|
</script>
|
|
5
7
|
|
|
6
8
|
<template>
|
|
7
|
-
<ErrorMessage code="403" :image="errorImage" message="
|
|
9
|
+
<ErrorMessage code="403" :image="errorImage" :message="t('core.error.403.detail')" />
|
|
8
10
|
</template>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts" name="404">
|
|
2
2
|
import errorImage from "../../assets/images/404.png";
|
|
3
3
|
import ErrorMessage from "../../components/ErrorMessage/index.vue";
|
|
4
|
+
import { useLocaleStore } from "../../locales";
|
|
5
|
+
const { t } = useLocaleStore();
|
|
4
6
|
</script>
|
|
5
7
|
|
|
6
8
|
<template>
|
|
7
|
-
<ErrorMessage code="404" :image="errorImage" message="
|
|
9
|
+
<ErrorMessage code="404" :image="errorImage" :message="t('core.error.404.detail')" />
|
|
8
10
|
</template>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts" name="500">
|
|
2
2
|
import errorImage from "../../assets/images/500.png";
|
|
3
3
|
import ErrorMessage from "../../components/ErrorMessage/index.vue";
|
|
4
|
+
import { useLocaleStore } from "../../locales";
|
|
5
|
+
const { t } = useLocaleStore();
|
|
4
6
|
</script>
|
|
5
7
|
|
|
6
8
|
<template>
|
|
7
|
-
<ErrorMessage code="500" :image="errorImage" message="
|
|
9
|
+
<ErrorMessage code="500" :image="errorImage" :message="t('core.error.500.detail')" />
|
|
8
10
|
</template>
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
<script setup lang="ts" name="Pending"
|
|
1
|
+
<script setup lang="ts" name="Pending">
|
|
2
|
+
import { useLocaleStore } from "../../locales";
|
|
3
|
+
const { t } = useLocaleStore();
|
|
4
|
+
</script>
|
|
2
5
|
|
|
3
6
|
<template>
|
|
4
7
|
<div class="route-pending page-card">
|
|
5
|
-
<el-empty description="
|
|
8
|
+
<el-empty :description="t('core.error.pending.detail')" />
|
|
6
9
|
</div>
|
|
7
10
|
</template>
|
|
8
11
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" size="large">
|
|
3
3
|
<el-form-item prop="tenant_code">
|
|
4
|
-
<el-input v-model="loginForm.tenant_code" placeholder="
|
|
4
|
+
<el-input v-model="loginForm.tenant_code" :placeholder="t('core.login.tenant_code')">
|
|
5
5
|
<template #prefix>
|
|
6
6
|
<el-icon class="el-input__icon">
|
|
7
7
|
<office-building />
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</el-input>
|
|
11
11
|
</el-form-item>
|
|
12
12
|
<el-form-item prop="user_name">
|
|
13
|
-
<el-input v-model="loginForm.user_name" placeholder="
|
|
13
|
+
<el-input v-model="loginForm.user_name" :placeholder="t('core.login.user_name')">
|
|
14
14
|
<template #prefix>
|
|
15
15
|
<el-icon class="el-input__icon">
|
|
16
16
|
<user />
|
|
@@ -19,7 +19,13 @@
|
|
|
19
19
|
</el-input>
|
|
20
20
|
</el-form-item>
|
|
21
21
|
<el-form-item prop="password">
|
|
22
|
-
<el-input
|
|
22
|
+
<el-input
|
|
23
|
+
v-model="loginForm.password"
|
|
24
|
+
type="password"
|
|
25
|
+
:placeholder="t('core.login.password')"
|
|
26
|
+
show-password
|
|
27
|
+
autocomplete="new-password"
|
|
28
|
+
>
|
|
23
29
|
<template #prefix>
|
|
24
30
|
<el-icon class="el-input__icon">
|
|
25
31
|
<lock />
|
|
@@ -29,7 +35,11 @@
|
|
|
29
35
|
</el-form-item>
|
|
30
36
|
<el-form-item v-if="!isBehaviorCaptcha" prop="captcha_code">
|
|
31
37
|
<div class="captcha-row">
|
|
32
|
-
<el-input
|
|
38
|
+
<el-input
|
|
39
|
+
v-model="loginForm.captcha_code"
|
|
40
|
+
:placeholder="t('core.login.captcha')"
|
|
41
|
+
@keyup.enter="handleLogin(loginFormRef)"
|
|
42
|
+
>
|
|
33
43
|
<template #prefix>
|
|
34
44
|
<el-icon class="el-input__icon">
|
|
35
45
|
<Key />
|
|
@@ -41,7 +51,7 @@
|
|
|
41
51
|
class="captcha-image"
|
|
42
52
|
:style="{ width: captchaImageWidth }"
|
|
43
53
|
:src="captcha_base64"
|
|
44
|
-
alt="
|
|
54
|
+
:alt="t('core.login.captcha_alt')"
|
|
45
55
|
@load="handleCaptchaImageLoad"
|
|
46
56
|
@click="getCaptcha"
|
|
47
57
|
/>
|
|
@@ -49,28 +59,35 @@
|
|
|
49
59
|
</el-form-item>
|
|
50
60
|
</el-form>
|
|
51
61
|
<div class="login-btn">
|
|
52
|
-
<el-button :icon="CircleClose" round size="large" @click="resetForm(loginFormRef)">
|
|
53
|
-
<el-button
|
|
54
|
-
|
|
62
|
+
<el-button :icon="CircleClose" round size="large" @click="resetForm(loginFormRef)">{{ t("common.action.reset") }}</el-button>
|
|
63
|
+
<el-button
|
|
64
|
+
:icon="UserFilled"
|
|
65
|
+
round
|
|
66
|
+
size="large"
|
|
67
|
+
type="primary"
|
|
68
|
+
:loading="loading || oauthTicketLoading"
|
|
69
|
+
@click="handleLogin(loginFormRef)"
|
|
70
|
+
>
|
|
71
|
+
{{ t("common.action.login") }}
|
|
55
72
|
</el-button>
|
|
56
73
|
</div>
|
|
57
74
|
<div v-if="oauthProviders.length" class="oauth-login">
|
|
58
75
|
<div class="oauth-divider">
|
|
59
|
-
<span
|
|
76
|
+
<span>{{ t("core.login.other_methods") }}</span>
|
|
60
77
|
</div>
|
|
61
78
|
<div class="oauth-provider-list">
|
|
62
79
|
<el-tooltip
|
|
63
80
|
v-for="provider in oauthProviders"
|
|
64
81
|
:key="provider.provider"
|
|
65
|
-
:content="provider.
|
|
82
|
+
:content="provider.nameKey.includes('.') ? t(provider.nameKey) : provider.nameKey"
|
|
66
83
|
placement="top"
|
|
67
84
|
:trigger="['hover', 'focus']"
|
|
68
85
|
>
|
|
69
86
|
<button
|
|
70
87
|
class="oauth-provider-button"
|
|
71
88
|
type="button"
|
|
72
|
-
:aria-label="provider.
|
|
73
|
-
:title="provider.
|
|
89
|
+
:aria-label="provider.nameKey.includes('.') ? t(provider.nameKey) : provider.nameKey"
|
|
90
|
+
:title="provider.nameKey.includes('.') ? t(provider.nameKey) : provider.nameKey"
|
|
74
91
|
:disabled="oauthTicketLoading || oauthLoadingProvider === provider.provider"
|
|
75
92
|
@click="handleOauthLogin(provider)"
|
|
76
93
|
>
|
|
@@ -133,6 +150,7 @@ import { PASSWORD_CRYPTO_SCENE, encryptPassword } from "../../../utils/passwordC
|
|
|
133
150
|
import { useConfigStore } from "../../../stores/modules/config";
|
|
134
151
|
import { Click as GoCaptchaClick, Rotate as GoCaptchaRotate, Slide as GoCaptchaSlide } from "go-captcha-vue";
|
|
135
152
|
import "go-captcha-vue/dist/style.css";
|
|
153
|
+
import { useLocaleStore } from "../../../locales";
|
|
136
154
|
|
|
137
155
|
const router = useRouter();
|
|
138
156
|
const route = useRoute();
|
|
@@ -141,6 +159,7 @@ const configStore = useConfigStore();
|
|
|
141
159
|
const dictStore = useDictStore();
|
|
142
160
|
const tabsStore = useTabsStore();
|
|
143
161
|
const keepAliveStore = useKeepAliveStore();
|
|
162
|
+
const { t } = useLocaleStore();
|
|
144
163
|
|
|
145
164
|
/** 登录表单实例类型。 */
|
|
146
165
|
type FormInstance = InstanceType<typeof ElForm>;
|
|
@@ -150,12 +169,12 @@ const defaultCaptchaImageWidth = 96;
|
|
|
150
169
|
const captchaImageWidth = ref(`${defaultCaptchaImageWidth}px`);
|
|
151
170
|
const behaviorDialogVisible = ref(false);
|
|
152
171
|
const behaviorLoading = ref(false);
|
|
153
|
-
const loginRules =
|
|
154
|
-
tenant_code: [{ required: true, message: "
|
|
155
|
-
user_name: [{ required: true, message: "
|
|
156
|
-
password: [{ required: true, message: "
|
|
157
|
-
captcha_code: [{ required: true, message: "
|
|
158
|
-
});
|
|
172
|
+
const loginRules = computed(() => ({
|
|
173
|
+
tenant_code: [{ required: true, message: t("core.login.tenant_code"), trigger: "blur" }],
|
|
174
|
+
user_name: [{ required: true, message: t("core.login.user_name"), trigger: "blur" }],
|
|
175
|
+
password: [{ required: true, message: t("core.login.password"), trigger: "blur" }],
|
|
176
|
+
captcha_code: [{ required: true, message: t("core.login.captcha"), trigger: "blur" }]
|
|
177
|
+
}));
|
|
159
178
|
|
|
160
179
|
const loading = ref(false);
|
|
161
180
|
const oauthLoadingProvider = ref("");
|
|
@@ -245,7 +264,9 @@ const behaviorCaptchaSource = reactive({
|
|
|
245
264
|
thumbHeight: 60,
|
|
246
265
|
thumbSize: 150
|
|
247
266
|
});
|
|
248
|
-
const behaviorCaptchaDisplayHeight = computed(() =>
|
|
267
|
+
const behaviorCaptchaDisplayHeight = computed(() =>
|
|
268
|
+
Math.round((behaviorCaptchaSource.height * behaviorCaptchaDisplayWidth) / behaviorCaptchaSource.width)
|
|
269
|
+
);
|
|
249
270
|
const behaviorCaptchaScaleX = computed(() => behaviorCaptchaDisplayWidth / behaviorCaptchaSource.width);
|
|
250
271
|
const behaviorCaptchaScaleY = computed(() => behaviorCaptchaDisplayHeight.value / behaviorCaptchaSource.height);
|
|
251
272
|
const rotateCaptchaScale = computed(() => rotateCaptchaDisplaySize / behaviorCaptchaSource.width);
|
|
@@ -260,10 +281,12 @@ const toDisplayCaptchaY = (value: number) => Math.round(value * behaviorCaptchaS
|
|
|
260
281
|
const toDisplayRotateSize = (value: number) => Math.round(value * rotateCaptchaScale.value);
|
|
261
282
|
|
|
262
283
|
/** 将前端展示 X 坐标换算回服务端原始坐标。 */
|
|
263
|
-
const toOriginalCaptchaX = (value: number) =>
|
|
284
|
+
const toOriginalCaptchaX = (value: number) =>
|
|
285
|
+
Math.min(behaviorCaptchaSource.width, Math.max(0, Math.round(value / behaviorCaptchaScaleX.value)));
|
|
264
286
|
|
|
265
287
|
/** 将前端展示 Y 坐标换算回服务端原始坐标。 */
|
|
266
|
-
const toOriginalCaptchaY = (value: number) =>
|
|
288
|
+
const toOriginalCaptchaY = (value: number) =>
|
|
289
|
+
Math.min(behaviorCaptchaSource.height, Math.max(0, Math.round(value / behaviorCaptchaScaleY.value)));
|
|
267
290
|
const slideCaptchaConfig = computed(() => ({
|
|
268
291
|
width: behaviorCaptchaDisplayWidth,
|
|
269
292
|
height: behaviorCaptchaDisplayHeight.value,
|
|
@@ -273,7 +296,7 @@ const slideCaptchaConfig = computed(() => ({
|
|
|
273
296
|
verticalPadding: 0,
|
|
274
297
|
horizontalPadding: 0,
|
|
275
298
|
iconSize: 20,
|
|
276
|
-
title: "
|
|
299
|
+
title: t("core.login.behavior_puzzle")
|
|
277
300
|
}));
|
|
278
301
|
const clickCaptchaConfig = computed(() => ({
|
|
279
302
|
width: behaviorCaptchaDisplayWidth,
|
|
@@ -283,10 +306,10 @@ const clickCaptchaConfig = computed(() => ({
|
|
|
283
306
|
showTheme: false,
|
|
284
307
|
verticalPadding: 0,
|
|
285
308
|
horizontalPadding: 0,
|
|
286
|
-
buttonText: "
|
|
309
|
+
buttonText: t("core.login.behavior_confirm"),
|
|
287
310
|
iconSize: 20,
|
|
288
311
|
dotSize: 20,
|
|
289
|
-
title: "
|
|
312
|
+
title: t("core.login.behavior_click")
|
|
290
313
|
}));
|
|
291
314
|
const rotateCaptchaConfig = computed(() => ({
|
|
292
315
|
width: behaviorCaptchaDisplayWidth,
|
|
@@ -296,7 +319,7 @@ const rotateCaptchaConfig = computed(() => ({
|
|
|
296
319
|
verticalPadding: 0,
|
|
297
320
|
horizontalPadding: 0,
|
|
298
321
|
iconSize: 20,
|
|
299
|
-
title: "
|
|
322
|
+
title: t("core.login.behavior_rotate")
|
|
300
323
|
}));
|
|
301
324
|
const slideCaptchaEvents = {
|
|
302
325
|
refresh: () => getCaptcha(),
|
|
@@ -307,7 +330,10 @@ const clickCaptchaEvents = {
|
|
|
307
330
|
refresh: () => getCaptcha(),
|
|
308
331
|
close: () => closeBehaviorCaptcha(),
|
|
309
332
|
confirm: (dots: ClickCaptchaPoint[], reset: () => void) =>
|
|
310
|
-
verifyBehaviorCaptcha(
|
|
333
|
+
verifyBehaviorCaptcha(
|
|
334
|
+
JSON.stringify(dots.map(dot => ({ x: toOriginalCaptchaX(dot.x), y: toOriginalCaptchaY(dot.y) }))),
|
|
335
|
+
reset
|
|
336
|
+
)
|
|
311
337
|
};
|
|
312
338
|
const rotateCaptchaEvents = {
|
|
313
339
|
refresh: () => getCaptcha(),
|
|
@@ -402,7 +428,7 @@ const finishLogin = async () => {
|
|
|
402
428
|
await navigateTo(router, getLoginRedirectPath());
|
|
403
429
|
ElNotification({
|
|
404
430
|
title: getTimeState(),
|
|
405
|
-
message: "
|
|
431
|
+
message: t("core.login.welcome"),
|
|
406
432
|
type: "success",
|
|
407
433
|
duration: 3000
|
|
408
434
|
});
|
|
@@ -500,7 +526,7 @@ const verifyCaptchaToken = async (captchaCode: string) => {
|
|
|
500
526
|
const submitLogin = async (captchaToken: string) => {
|
|
501
527
|
loading.value = true;
|
|
502
528
|
try {
|
|
503
|
-
const password = await encryptPassword(loginForm.password, PASSWORD_CRYPTO_SCENE.
|
|
529
|
+
const password = await encryptPassword(loginForm.password, PASSWORD_CRYPTO_SCENE.PASSWORD_CRYPTO_SCENE_LOGIN);
|
|
504
530
|
const loginRequest: LoginRequest = {
|
|
505
531
|
tenant_code: loginForm.tenant_code,
|
|
506
532
|
user_name: loginForm.user_name,
|
|
@@ -735,13 +761,16 @@ watch(
|
|
|
735
761
|
height: auto;
|
|
736
762
|
min-height: 24px;
|
|
737
763
|
margin-bottom: 6px;
|
|
764
|
+
align-items: flex-start;
|
|
738
765
|
}
|
|
739
766
|
|
|
740
767
|
:global(.behavior-captcha-dialog .go-captcha .gc-header span),
|
|
741
768
|
:global(.behavior-captcha-dialog .go-captcha .gc-header .gc-text) {
|
|
769
|
+
min-width: 0;
|
|
742
770
|
font-size: 14px;
|
|
743
771
|
line-height: 22px;
|
|
744
|
-
white-space:
|
|
772
|
+
white-space: normal;
|
|
773
|
+
overflow-wrap: anywhere;
|
|
745
774
|
}
|
|
746
775
|
|
|
747
776
|
:global(.behavior-captcha-dialog .go-captcha .gc-body) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<div class="login-container flx-center">
|
|
3
3
|
<div class="login-box">
|
|
4
4
|
<SwitchDark class="dark" />
|
|
5
|
+
<LocaleSwitch class="locale" />
|
|
5
6
|
<div class="login-left">
|
|
6
7
|
<img class="login-left-img" :src="backgroundUrl" alt="login" />
|
|
7
8
|
</div>
|
|
@@ -20,6 +21,7 @@
|
|
|
20
21
|
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
|
21
22
|
import LoginForm from "./components/LoginForm.vue";
|
|
22
23
|
import SwitchDark from "../../components/SwitchDark/index.vue";
|
|
24
|
+
import LocaleSwitch from "../../components/LocaleSwitch/index.vue";
|
|
23
25
|
import { useConfigStore } from "../../stores/modules/config";
|
|
24
26
|
|
|
25
27
|
const configStore = useConfigStore();
|