@liujitcn/kratos-admin-core 0.0.39 → 0.0.41
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/build/codegen-hmr.ts +37 -0
- package/build/plugins.ts +2 -0
- package/build/source-patterns.ts +7 -0
- package/dist/package/declarations/build/codegen-hmr.d.ts +3 -0
- package/dist/package/declarations/build/source-patterns.d.ts +2 -0
- package/dist/package/declarations/src/components/ProForm/components/ProFormItem.vue.d.ts +9 -4
- package/dist/package/declarations/src/components/ProForm/interface/index.d.ts +2 -0
- package/dist/package/declarations/src/index.d.ts +5 -0
- package/dist/package/declarations/src/views/login/components/LoginForm.vue.d.ts +5 -1
- package/dist/package/src/components/ProForm/components/ProFormItem.vue +5 -1
- package/dist/package/src/components/ProForm/index.vue +27 -5
- package/dist/package/src/components/ProForm/interface/index.ts +2 -0
- package/dist/package/src/index.ts +5 -5
- package/dist/package/src/views/login/components/LoginForm.vue +61 -5
- package/dist/package/src/views/login/index.vue +3 -2
- package/package.json +2 -2
- package/vite.config.ts +2 -3
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { HotPayload, Plugin, WebSocketClient } from "vite";
|
|
2
|
+
|
|
3
|
+
/** 暂缓生成期间的开发热更新,释放后统一刷新以加载完整产物。 */
|
|
4
|
+
export function codegenHmrPlugin(): Plugin {
|
|
5
|
+
return {
|
|
6
|
+
name: "admin-codegen-hmr",
|
|
7
|
+
apply: "serve",
|
|
8
|
+
configureServer(server) {
|
|
9
|
+
const clients = new Set<WebSocketClient>();
|
|
10
|
+
const send = server.ws.send.bind(server.ws);
|
|
11
|
+
let pending = false;
|
|
12
|
+
const release = (client: WebSocketClient) => {
|
|
13
|
+
clients.delete(client);
|
|
14
|
+
if (!clients.size && pending) {
|
|
15
|
+
pending = false;
|
|
16
|
+
send({ type: "full-reload", path: "*" });
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
server.ws.send = (payload: HotPayload | string, data?: unknown) => {
|
|
20
|
+
if (clients.size && typeof payload !== "string" && (payload.type === "update" || payload.type === "full-reload")) {
|
|
21
|
+
pending = true;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (typeof payload === "string") send(payload, data);
|
|
25
|
+
else send(payload);
|
|
26
|
+
};
|
|
27
|
+
server.ws.on("admin:codegen-hold", (_data, client) => {
|
|
28
|
+
if (!clients.has(client)) {
|
|
29
|
+
clients.add(client);
|
|
30
|
+
client.socket.once("close", () => release(client));
|
|
31
|
+
}
|
|
32
|
+
client.send("admin:codegen-held", {});
|
|
33
|
+
});
|
|
34
|
+
server.ws.on("admin:codegen-release", (_data, client) => release(client));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
package/build/plugins.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { codegenHmrPlugin } from "./codegen-hmr";
|
|
1
2
|
import { resolve } from "path";
|
|
2
3
|
import { PluginOption } from "vite";
|
|
3
4
|
import { VitePWA } from "vite-plugin-pwa";
|
|
@@ -37,6 +38,7 @@ export const createVitePlugins = (viteEnv: ViteEnv, options: VitePluginOptions =
|
|
|
37
38
|
const { VITE_GLOB_APP_TITLE, VITE_REPORT, VITE_DEVTOOLS, VITE_PWA, VITE_CODEINSPECTOR } = viteEnv;
|
|
38
39
|
const sourcePatterns = options.sourcePatterns;
|
|
39
40
|
return [
|
|
41
|
+
codegenHmrPlugin(),
|
|
40
42
|
vue(),
|
|
41
43
|
// vue 可以使用 jsx/tsx 语法
|
|
42
44
|
vueJsx(),
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** 为 API 和组件自动导入创建跨平台源码匹配规则,包含 npm 包内源码。 */
|
|
2
|
+
export function createSourcePatterns(sourceRoots: string[]): RegExp[] {
|
|
3
|
+
return [...new Set(sourceRoots.map(sourceRoot => sourceRoot.replaceAll("\\", "/")))].map(sourceRoot => {
|
|
4
|
+
const escapedRoot = sourceRoot.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
|
+
return new RegExp(`^${escapedRoot.replaceAll("/", "[/\\\\]")}[/\\\\].*\\.(?:vue|[jt]sx?)(?:\\?.*)?$`);
|
|
6
|
+
});
|
|
7
|
+
}
|
|
@@ -4,18 +4,23 @@ interface ProFormItemProps {
|
|
|
4
4
|
field: ProFormField;
|
|
5
5
|
model: Record<string, any>;
|
|
6
6
|
}
|
|
7
|
-
declare var
|
|
7
|
+
declare var __VLS_10: string, __VLS_11: {
|
|
8
|
+
field: ProFormField;
|
|
9
|
+
model: Record<string, any>;
|
|
10
|
+
}, __VLS_133: string, __VLS_134: {
|
|
8
11
|
option: import("element-plus").TransferDataItem;
|
|
9
12
|
field: ProFormField;
|
|
10
13
|
model: Record<string, any>;
|
|
11
|
-
},
|
|
14
|
+
}, __VLS_179: string, __VLS_180: {
|
|
12
15
|
field: ProFormField;
|
|
13
16
|
model: Record<string, any>;
|
|
14
17
|
};
|
|
15
18
|
type __VLS_Slots = {} & {
|
|
16
|
-
[K in NonNullable<typeof
|
|
19
|
+
[K in NonNullable<typeof __VLS_10>]?: (props: typeof __VLS_11) => any;
|
|
20
|
+
} & {
|
|
21
|
+
[K in NonNullable<typeof __VLS_133>]?: (props: typeof __VLS_134) => any;
|
|
17
22
|
} & {
|
|
18
|
-
[K in NonNullable<typeof
|
|
23
|
+
[K in NonNullable<typeof __VLS_179>]?: (props: typeof __VLS_180) => any;
|
|
19
24
|
};
|
|
20
25
|
declare const __VLS_base: import("vue").DefineComponent<ProFormItemProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ProFormItemProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
26
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import "./vite-env.d.ts";
|
|
2
|
+
import "./typings/global.d.ts";
|
|
3
|
+
import "./typings/utils.d.ts";
|
|
4
|
+
import "../types/generated/auto-imports.d.ts";
|
|
5
|
+
import "../types/generated/components.d.ts";
|
|
1
6
|
export * from "./modules";
|
|
2
7
|
export * from "./locales";
|
|
3
8
|
export { defLanguageService } from "./api/base/v1/language";
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import "go-captcha-vue/dist/style.css";
|
|
2
|
-
|
|
2
|
+
/** 登录表单属性,验证弹窗以外层登录卡片的中心定位。 */
|
|
3
|
+
interface LoginFormProps {
|
|
4
|
+
dialogAnchor?: HTMLElement;
|
|
5
|
+
}
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<LoginFormProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<LoginFormProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
3
7
|
declare const _default: typeof __VLS_export;
|
|
4
8
|
export default _default;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<el-input v-if="field.component === 'input'" v-model.trim="fieldValue" v-bind="fieldProps"
|
|
2
|
+
<el-input v-if="field.component === 'input'" v-model.trim="fieldValue" v-bind="fieldProps">
|
|
3
|
+
<template v-if="field.suffixSlotName" #append>
|
|
4
|
+
<slot :name="field.suffixSlotName" :field="field" :model="model" />
|
|
5
|
+
</template>
|
|
6
|
+
</el-input>
|
|
3
7
|
|
|
4
8
|
<el-input
|
|
5
9
|
v-else-if="field.component === 'password'"
|
|
@@ -16,11 +16,21 @@
|
|
|
16
16
|
</el-tooltip>
|
|
17
17
|
</div>
|
|
18
18
|
</template>
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
<div class="pro-form__control">
|
|
20
|
+
<div class="pro-form__input">
|
|
21
|
+
<ProFormItem :field="field" :model="model">
|
|
22
|
+
<template v-for="slotName in slotNames" #[slotName]="slotScope">
|
|
23
|
+
<slot :name="slotName" v-bind="slotScope" />
|
|
24
|
+
</template>
|
|
25
|
+
</ProFormItem>
|
|
26
|
+
</div>
|
|
27
|
+
<slot
|
|
28
|
+
v-if="field.suffixSlotName && field.component !== 'input'"
|
|
29
|
+
:name="field.suffixSlotName"
|
|
30
|
+
:model="model"
|
|
31
|
+
:field="field"
|
|
32
|
+
/>
|
|
33
|
+
</div>
|
|
24
34
|
</el-form-item>
|
|
25
35
|
</el-col>
|
|
26
36
|
</template>
|
|
@@ -104,6 +114,18 @@ defineExpose({
|
|
|
104
114
|
</script>
|
|
105
115
|
|
|
106
116
|
<style scoped lang="scss">
|
|
117
|
+
.pro-form__control {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: flex-start;
|
|
120
|
+
gap: 8px;
|
|
121
|
+
width: 100%;
|
|
122
|
+
min-width: 0;
|
|
123
|
+
}
|
|
124
|
+
.pro-form__input {
|
|
125
|
+
flex: 1;
|
|
126
|
+
min-width: 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
107
129
|
.pro-form__row-break {
|
|
108
130
|
flex: 0 0 100%;
|
|
109
131
|
height: 0;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import "./vite-env.d.ts";
|
|
2
|
+
import "./typings/global.d.ts";
|
|
3
|
+
import "./typings/utils.d.ts";
|
|
4
|
+
import "../types/generated/auto-imports.d.ts";
|
|
5
|
+
import "../types/generated/components.d.ts";
|
|
6
6
|
|
|
7
7
|
export * from "./modules";
|
|
8
8
|
export * from "./locales";
|
|
@@ -96,11 +96,11 @@
|
|
|
96
96
|
<ProDialog
|
|
97
97
|
v-model="behaviorDialogVisible"
|
|
98
98
|
width="364px"
|
|
99
|
-
|
|
99
|
+
:style="loginDialogStyle"
|
|
100
100
|
:show-close="false"
|
|
101
101
|
:show-footer="false"
|
|
102
102
|
append-to-body
|
|
103
|
-
class="behavior-captcha-dialog"
|
|
103
|
+
class="login-verification-dialog behavior-captcha-dialog"
|
|
104
104
|
>
|
|
105
105
|
<div v-loading="behaviorLoading" class="behavior-captcha-body">
|
|
106
106
|
<GoCaptchaSlide
|
|
@@ -126,7 +126,15 @@
|
|
|
126
126
|
/>
|
|
127
127
|
</div>
|
|
128
128
|
</ProDialog>
|
|
129
|
-
<ProDialog
|
|
129
|
+
<ProDialog
|
|
130
|
+
v-model="mfaDialogVisible"
|
|
131
|
+
:title="t('core.login.mfa_title')"
|
|
132
|
+
width="364px"
|
|
133
|
+
:style="loginDialogStyle"
|
|
134
|
+
class="login-verification-dialog"
|
|
135
|
+
append-to-body
|
|
136
|
+
:close-on-click-modal="false"
|
|
137
|
+
>
|
|
130
138
|
<ProForm
|
|
131
139
|
ref="mfaLoginFormRef"
|
|
132
140
|
:model="mfaLoginForm"
|
|
@@ -146,7 +154,15 @@
|
|
|
146
154
|
</el-button>
|
|
147
155
|
</template>
|
|
148
156
|
</ProDialog>
|
|
149
|
-
<ProDialog
|
|
157
|
+
<ProDialog
|
|
158
|
+
v-model="mfaSetupDialogVisible"
|
|
159
|
+
:title="t('core.login.mfa_setup_title')"
|
|
160
|
+
width="520px"
|
|
161
|
+
:style="loginDialogStyle"
|
|
162
|
+
class="login-verification-dialog"
|
|
163
|
+
append-to-body
|
|
164
|
+
:close-on-click-modal="false"
|
|
165
|
+
>
|
|
150
166
|
<template v-if="mfaSetupMethod !== 'webauthn'">
|
|
151
167
|
<MfaSetupPanel :uri="mfaSetupUri" />
|
|
152
168
|
<ProForm
|
|
@@ -166,12 +182,20 @@
|
|
|
166
182
|
</el-button>
|
|
167
183
|
</template>
|
|
168
184
|
</ProDialog>
|
|
169
|
-
<MfaRecoveryCodesDialog
|
|
185
|
+
<MfaRecoveryCodesDialog
|
|
186
|
+
v-model="recoveryCodesDialogVisible"
|
|
187
|
+
:codes="recoveryCodes"
|
|
188
|
+
:style="loginDialogStyle"
|
|
189
|
+
class="login-verification-dialog"
|
|
190
|
+
append-to-body
|
|
191
|
+
@confirm="finishMfaEnrollment"
|
|
192
|
+
/>
|
|
170
193
|
</template>
|
|
171
194
|
|
|
172
195
|
<script setup lang="ts">
|
|
173
196
|
import { computed, ref, reactive, onMounted, watch } from "vue";
|
|
174
197
|
import { useRoute, useRouter } from "vue-router";
|
|
198
|
+
import { useElementBounding } from "@vueuse/core";
|
|
175
199
|
import { HOME_URL } from "../../../config";
|
|
176
200
|
import { getTimeState } from "../../../utils";
|
|
177
201
|
import { defLoginService } from "../../../api/base/v1/login";
|
|
@@ -200,6 +224,19 @@ import "go-captcha-vue/dist/style.css";
|
|
|
200
224
|
import { useLocaleStore } from "../../../locales";
|
|
201
225
|
import { clearPasswordChangeRequired, handlePasswordChangeRequired } from "../../../utils/request";
|
|
202
226
|
|
|
227
|
+
/** 登录表单属性,验证弹窗以外层登录卡片的中心定位。 */
|
|
228
|
+
interface LoginFormProps {
|
|
229
|
+
dialogAnchor?: HTMLElement;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const props = defineProps<LoginFormProps>();
|
|
233
|
+
const dialogAnchorBounds = useElementBounding(() => props.dialogAnchor);
|
|
234
|
+
const loginDialogStyle = computed(() => ({
|
|
235
|
+
"--login-dialog-center-x": `${dialogAnchorBounds.left.value + dialogAnchorBounds.width.value / 2}px`,
|
|
236
|
+
"--login-dialog-center-y": `${dialogAnchorBounds.top.value + dialogAnchorBounds.height.value / 2}px`,
|
|
237
|
+
"--login-dialog-anchor-width": `${dialogAnchorBounds.width.value}px`
|
|
238
|
+
}));
|
|
239
|
+
|
|
203
240
|
const router = useRouter();
|
|
204
241
|
const route = useRoute();
|
|
205
242
|
const userStore = useUserStore();
|
|
@@ -958,6 +995,25 @@ watch(
|
|
|
958
995
|
color: var(--el-color-primary);
|
|
959
996
|
}
|
|
960
997
|
|
|
998
|
+
/* 各验证步骤共用登录卡片中心;靠近视口边缘时限制尺寸,内容在弹窗内滚动。 */
|
|
999
|
+
:global(.login-verification-dialog.el-dialog) {
|
|
1000
|
+
--login-dialog-width: min(var(--el-dialog-width), var(--login-dialog-anchor-width), calc(100vw - 32px));
|
|
1001
|
+
--login-dialog-y: clamp(25dvh, var(--login-dialog-center-y), 75dvh);
|
|
1002
|
+
|
|
1003
|
+
position: fixed;
|
|
1004
|
+
top: var(--login-dialog-y);
|
|
1005
|
+
left: clamp(
|
|
1006
|
+
calc(var(--login-dialog-width) / 2 + 16px),
|
|
1007
|
+
var(--login-dialog-center-x),
|
|
1008
|
+
calc(100vw - var(--login-dialog-width) / 2 - 16px)
|
|
1009
|
+
);
|
|
1010
|
+
width: var(--login-dialog-width);
|
|
1011
|
+
max-height: calc(min(var(--login-dialog-y), 100dvh - var(--login-dialog-y)) * 2 - 32px);
|
|
1012
|
+
margin: 0;
|
|
1013
|
+
overflow: auto;
|
|
1014
|
+
translate: -50% -50%;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
961
1017
|
:global(.behavior-captcha-dialog) {
|
|
962
1018
|
--go-captcha-theme-text-color: var(--el-text-color-primary);
|
|
963
1019
|
--go-captcha-theme-bg-color: var(--el-bg-color);
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
<div class="login-left">
|
|
7
7
|
<img class="login-left-img" :src="backgroundUrl" :alt="t('core.login.background_alt')" />
|
|
8
8
|
</div>
|
|
9
|
-
<div class="login-form">
|
|
9
|
+
<div ref="loginFormRef" class="login-form">
|
|
10
10
|
<div ref="loginLogoRef" class="login-logo">
|
|
11
11
|
<img v-show="showLogoIcon" ref="logoIconRef" class="login-icon" :src="logoUrl" alt="" />
|
|
12
12
|
<h2 ref="logoTextRef" class="logo-text" :style="{ fontSize: `${logoFontSize}px` }">{{ projectName }}</h2>
|
|
13
13
|
</div>
|
|
14
|
-
<LoginForm />
|
|
14
|
+
<LoginForm :dialog-anchor="loginFormRef" />
|
|
15
15
|
</div>
|
|
16
16
|
</div>
|
|
17
17
|
</div>
|
|
@@ -36,6 +36,7 @@ const PREFERRED_MIN_LOGO_FONT_SIZE = 30;
|
|
|
36
36
|
const MIN_LOGO_FONT_SIZE = 8;
|
|
37
37
|
const LOGO_TEXT_GAP = 16;
|
|
38
38
|
|
|
39
|
+
const loginFormRef = ref<HTMLElement>();
|
|
39
40
|
const loginLogoRef = ref<HTMLElement>();
|
|
40
41
|
const logoIconRef = ref<HTMLImageElement>();
|
|
41
42
|
const logoTextRef = ref<HTMLElement>();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liujitcn/kratos-admin-core",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.41",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "kratos-admin frontend runtime and base modules",
|
|
7
7
|
"author": {
|
|
@@ -224,7 +224,7 @@
|
|
|
224
224
|
"scripts": {
|
|
225
225
|
"build": "pnpm build:package",
|
|
226
226
|
"build:package": "node ../../scripts/build-package.mjs .",
|
|
227
|
-
"test": "tsc -p tsconfig.test.json && node --test dist/test/tests/modules.test.js dist/test/tests/dict.test.js dist/test/tests/menu.test.js",
|
|
227
|
+
"test": "tsc -p tsconfig.test.json && node --test dist/test/tests/modules.test.js dist/test/tests/dict.test.js dist/test/tests/menu.test.js dist/test/tests/source-patterns.test.js",
|
|
228
228
|
"type:check": "vue-tsc --noEmit --skipLibCheck"
|
|
229
229
|
}
|
|
230
230
|
}
|
package/vite.config.ts
CHANGED
|
@@ -8,6 +8,7 @@ import dayjs from "dayjs";
|
|
|
8
8
|
import { wrapperEnv } from "./build/getEnv";
|
|
9
9
|
import { createProxy } from "./build/proxy";
|
|
10
10
|
import { createVitePlugins } from "./build/plugins";
|
|
11
|
+
import { createSourcePatterns } from "./build/source-patterns";
|
|
11
12
|
|
|
12
13
|
const coreRoot = dirname(fileURLToPath(import.meta.url));
|
|
13
14
|
const viteLogger = createLogger();
|
|
@@ -52,9 +53,7 @@ export function defineAdminViteConfig(options: AdminViteConfigOptions = {}) {
|
|
|
52
53
|
...resolvePackageSource(root, packageName)
|
|
53
54
|
}));
|
|
54
55
|
const sourceRoots = [resolve(root, "src"), coreSourceRoot, ...modulePackages.map(item => item.sourceRoot)];
|
|
55
|
-
const sourcePatterns =
|
|
56
|
-
sourceRoot => new RegExp(`${escapeRegExp(sourceRoot)}[\\/\\\\].*\\.(?:vue|[jt]sx?)(?:\\?.*)?$`)
|
|
57
|
-
);
|
|
56
|
+
const sourcePatterns = createSourcePatterns(sourceRoots);
|
|
58
57
|
const aliases = [
|
|
59
58
|
{ find: "@", replacement: coreSourceRoot },
|
|
60
59
|
...createPackageAliases(corePackage),
|