smart-admin-web 10.14.0 → 10.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/api/index.d.ts +37 -0
- package/dist/api/index.js +35 -14
- package/dist/api/index.js.map +1 -1
- package/dist/api/schema.d.ts +381 -3
- package/dist/assets/icons/ph-subset.json.js +3 -3
- package/dist/assets/smart-logo.svg.js +5 -0
- package/dist/assets/smart-logo.svg.js.map +1 -0
- package/dist/components/SmartLogo.vue.d.ts +3 -0
- package/dist/components/SmartLogo.vue.js +1 -1
- package/dist/components/SmartLogo2.vue.js +22 -64
- package/dist/components/SmartLogo2.vue.js.map +1 -1
- package/dist/composables/useLoginHero.d.ts +2 -0
- package/dist/composables/useLoginHero.js +22 -0
- package/dist/composables/useLoginHero.js.map +1 -0
- package/dist/composables/usePageTitle.js +16 -14
- package/dist/composables/usePageTitle.js.map +1 -1
- package/dist/composables/useSite.d.ts +5 -0
- package/dist/composables/useSite.js +16 -13
- package/dist/composables/useSite.js.map +1 -1
- package/dist/index.js +92 -91
- package/dist/lib/favicon.d.ts +1 -0
- package/dist/lib/favicon.js +12 -0
- package/dist/lib/favicon.js.map +1 -0
- package/dist/lib/loginHero.d.ts +16 -0
- package/dist/lib/loginHero.js +33 -0
- package/dist/lib/loginHero.js.map +1 -0
- package/dist/lib/logoCrop.d.ts +25 -0
- package/dist/lib/logoCrop.js +22 -0
- package/dist/lib/logoCrop.js.map +1 -0
- package/dist/lib/runtime.d.ts +2 -0
- package/dist/lib/runtime.js +1 -1
- package/dist/lib/runtime.js.map +1 -1
- package/dist/lib/securityRules.d.ts +26 -0
- package/dist/lib/securityRules.js +86 -0
- package/dist/lib/securityRules.js.map +1 -0
- package/dist/locales/en-US.d.ts +242 -28
- package/dist/locales/en-US.js +262 -58
- package/dist/locales/en-US.js.map +1 -1
- package/dist/locales/zh-CN.d.ts +242 -28
- package/dist/locales/zh-CN.js +257 -58
- package/dist/locales/zh-CN.js.map +1 -1
- package/dist/router/viewRegistry.js +10 -10
- package/dist/router/viewRegistry.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/utils/oauthBrand.d.ts +34 -9
- package/dist/utils/oauthBrand.js +70 -74
- package/dist/utils/oauthBrand.js.map +1 -1
- package/dist/views/login/components/LoginHeroPanel.vue.d.ts +18 -0
- package/dist/views/login/components/LoginHeroPanel.vue.js +8 -0
- package/dist/views/login/components/LoginHeroPanel.vue.js.map +1 -0
- package/dist/views/login/components/LoginHeroPanel2.vue.js +66 -0
- package/dist/views/login/components/LoginHeroPanel2.vue.js.map +1 -0
- package/dist/views/login/skins/SplitPanel.vue.js +1 -1
- package/dist/views/login/skins/SplitPanel2.vue.js +39 -59
- package/dist/views/login/skins/SplitPanel2.vue.js.map +1 -1
- package/dist/views/system/config/components/AdminMock.vue.js +8 -0
- package/dist/views/system/config/components/AdminMock.vue.js.map +1 -0
- package/dist/views/system/config/components/AdminMock2.vue.js +76 -0
- package/dist/views/system/config/components/AdminMock2.vue.js.map +1 -0
- package/dist/views/system/config/components/AdvancedSection.vue.js +5 -0
- package/dist/views/system/config/components/AdvancedSection.vue.js.map +1 -0
- package/dist/views/system/config/components/AdvancedSection2.vue.js +135 -0
- package/dist/views/system/config/components/AdvancedSection2.vue.js.map +1 -0
- package/dist/views/system/config/components/BrandSection.vue.d.ts +7 -0
- package/dist/views/system/config/components/BrandSection.vue.js +8 -0
- package/dist/views/system/config/components/BrandSection.vue.js.map +1 -0
- package/dist/views/system/config/components/BrandSection2.vue.js +264 -0
- package/dist/views/system/config/components/BrandSection2.vue.js.map +1 -0
- package/dist/views/system/config/components/CfgGroup.vue.d.ts +18 -0
- package/dist/views/system/config/components/CfgGroup.vue.js +8 -0
- package/dist/views/system/config/components/CfgGroup.vue.js.map +1 -0
- package/dist/views/system/config/components/CfgGroup2.vue.js +22 -0
- package/dist/views/system/config/components/CfgGroup2.vue.js.map +1 -0
- package/dist/views/system/config/components/CfgRow.vue.d.ts +26 -0
- package/dist/views/system/config/components/CfgRow.vue.js +9 -0
- package/dist/views/system/config/components/CfgRow.vue.js.map +1 -0
- package/dist/views/system/config/components/CfgRow2.vue.js +53 -0
- package/dist/views/system/config/components/CfgRow2.vue.js.map +1 -0
- package/dist/views/system/config/components/CfgSegment.vue.d.ts +28 -0
- package/dist/views/system/config/components/CfgSegment.vue.js +8 -0
- package/dist/views/system/config/components/CfgSegment.vue.js.map +1 -0
- package/dist/views/system/config/components/CfgSegment2.vue.js +44 -0
- package/dist/views/system/config/components/CfgSegment2.vue.js.map +1 -0
- package/dist/views/system/config/components/ConfigFormModal.vue.js +5 -2
- package/dist/views/system/config/components/ConfigFormModal.vue.js.map +1 -1
- package/dist/views/system/config/components/ConfigFormModal2.vue.js +66 -56
- package/dist/views/system/config/components/ConfigFormModal2.vue.js.map +1 -1
- package/dist/views/system/config/components/JobSection.vue.js +8 -0
- package/dist/views/system/config/components/JobSection.vue.js.map +1 -0
- package/dist/views/system/config/components/JobSection2.vue.js +138 -0
- package/dist/views/system/config/components/JobSection2.vue.js.map +1 -0
- package/dist/views/system/config/components/{GroupExtraConfig.vue.d.ts → LoginMock.vue.d.ts} +3 -4
- package/dist/views/system/config/components/LoginMock.vue.js +8 -0
- package/dist/views/system/config/components/LoginMock.vue.js.map +1 -0
- package/dist/views/system/config/components/LoginMock2.vue.js +121 -0
- package/dist/views/system/config/components/LoginMock2.vue.js.map +1 -0
- package/dist/views/system/config/components/LogoCropper.vue.d.ts +10 -0
- package/dist/views/system/config/components/LogoCropper.vue.js +8 -0
- package/dist/views/system/config/components/LogoCropper.vue.js.map +1 -0
- package/dist/views/system/config/components/LogoCropper2.vue.js +122 -0
- package/dist/views/system/config/components/LogoCropper2.vue.js.map +1 -0
- package/dist/views/system/config/components/LogoEditor.vue.js +8 -0
- package/dist/views/system/config/components/LogoEditor.vue.js.map +1 -0
- package/dist/views/system/config/components/LogoEditor2.vue.js +163 -0
- package/dist/views/system/config/components/LogoEditor2.vue.js.map +1 -0
- package/dist/views/system/config/components/ProviderSheet.vue.d.ts +17 -0
- package/dist/views/system/config/components/ProviderSheet.vue.js +8 -0
- package/dist/views/system/config/components/ProviderSheet.vue.js.map +1 -0
- package/dist/views/system/config/components/ProviderSheet2.vue.js +343 -0
- package/dist/views/system/config/components/ProviderSheet2.vue.js.map +1 -0
- package/dist/views/system/config/components/ScaleToFit.vue.d.ts +17 -0
- package/dist/views/system/config/components/ScaleToFit.vue.js +8 -0
- package/dist/views/system/config/components/ScaleToFit.vue.js.map +1 -0
- package/dist/views/system/config/components/ScaleToFit2.vue.js +41 -0
- package/dist/views/system/config/components/ScaleToFit2.vue.js.map +1 -0
- package/dist/views/system/config/components/SectionLayout.vue.d.ts +28 -0
- package/dist/views/system/config/components/SectionLayout.vue.js +8 -0
- package/dist/views/system/config/components/SectionLayout.vue.js.map +1 -0
- package/dist/views/system/config/components/SectionLayout2.vue.js +45 -0
- package/dist/views/system/config/components/SectionLayout2.vue.js.map +1 -0
- package/dist/views/system/config/components/SecuritySection.vue.js +8 -0
- package/dist/views/system/config/components/SecuritySection.vue.js.map +1 -0
- package/dist/views/system/config/components/SecuritySection2.vue.js +416 -0
- package/dist/views/system/config/components/SecuritySection2.vue.js.map +1 -0
- package/dist/views/system/config/components/SensitiveSection.vue.js +8 -0
- package/dist/views/system/config/components/SensitiveSection.vue.js.map +1 -0
- package/dist/views/system/config/components/SensitiveSection2.vue.js +209 -0
- package/dist/views/system/config/components/SensitiveSection2.vue.js.map +1 -0
- package/dist/views/system/config/components/SigninSection.vue.js +8 -0
- package/dist/views/system/config/components/SigninSection.vue.js.map +1 -0
- package/dist/views/system/config/components/SigninSection2.vue.js +201 -0
- package/dist/views/system/config/components/SigninSection2.vue.js.map +1 -0
- package/dist/views/system/config/components/UploadSection.vue.d.ts +3 -0
- package/dist/views/system/config/components/UploadSection.vue.js +8 -0
- package/dist/views/system/config/components/UploadSection.vue.js.map +1 -0
- package/dist/views/system/config/components/UploadSection2.vue.js +167 -0
- package/dist/views/system/config/components/UploadSection2.vue.js.map +1 -0
- package/dist/views/system/config/draft.d.ts +148 -0
- package/dist/views/system/config/draft.js +170 -0
- package/dist/views/system/config/draft.js.map +1 -0
- package/dist/views/system/config/flash.d.ts +2 -0
- package/dist/views/system/config/flash.js +9 -0
- package/dist/views/system/config/flash.js.map +1 -0
- package/dist/views/system/config/groups.d.ts +35 -7
- package/dist/views/system/config/groups.js +99 -14
- package/dist/views/system/config/groups.js.map +1 -1
- package/dist/views/system/config/index.vue.js +4 -1
- package/dist/views/system/config/index.vue.js.map +1 -1
- package/dist/views/system/config/index2.vue.js +180 -115
- package/dist/views/system/config/index2.vue.js.map +1 -1
- package/dist/views/system/config/providerForm.d.ts +33 -0
- package/dist/views/system/config/providerForm.js +63 -0
- package/dist/views/system/config/providerForm.js.map +1 -0
- package/package.json +4 -4
- package/dist/views/system/config/components/ExternalAuthConfig.vue.js +0 -8
- package/dist/views/system/config/components/ExternalAuthConfig.vue.js.map +0 -1
- package/dist/views/system/config/components/ExternalAuthConfig2.vue.js +0 -218
- package/dist/views/system/config/components/ExternalAuthConfig2.vue.js.map +0 -1
- package/dist/views/system/config/components/GroupExtraConfig.vue.js +0 -8
- package/dist/views/system/config/components/GroupExtraConfig.vue.js.map +0 -1
- package/dist/views/system/config/components/GroupExtraConfig2.vue.js +0 -108
- package/dist/views/system/config/components/GroupExtraConfig2.vue.js.map +0 -1
- package/dist/views/system/config/components/HighSensConfig.vue.js +0 -5
- package/dist/views/system/config/components/HighSensConfig.vue.js.map +0 -1
- package/dist/views/system/config/components/HighSensConfig2.vue.js +0 -134
- package/dist/views/system/config/components/HighSensConfig2.vue.js.map +0 -1
- package/dist/views/system/config/components/JobConfig.vue.js +0 -5
- package/dist/views/system/config/components/JobConfig.vue.js.map +0 -1
- package/dist/views/system/config/components/JobConfig2.vue.js +0 -116
- package/dist/views/system/config/components/JobConfig2.vue.js.map +0 -1
- package/dist/views/system/config/components/OtherConfig.vue.js +0 -5
- package/dist/views/system/config/components/OtherConfig.vue.js.map +0 -1
- package/dist/views/system/config/components/OtherConfig2.vue.js +0 -121
- package/dist/views/system/config/components/OtherConfig2.vue.js.map +0 -1
- package/dist/views/system/config/components/SecurityConfig.vue.js +0 -8
- package/dist/views/system/config/components/SecurityConfig.vue.js.map +0 -1
- package/dist/views/system/config/components/SecurityConfig2.vue.js +0 -456
- package/dist/views/system/config/components/SecurityConfig2.vue.js.map +0 -1
- package/dist/views/system/config/components/SysBaseConfig.vue.js +0 -5
- package/dist/views/system/config/components/SysBaseConfig.vue.js.map +0 -1
- package/dist/views/system/config/components/SysBaseConfig2.vue.js +0 -107
- package/dist/views/system/config/components/SysBaseConfig2.vue.js.map +0 -1
- package/dist/views/system/config/components/UploadConfig.vue.js +0 -5
- package/dist/views/system/config/components/UploadConfig.vue.js.map +0 -1
- package/dist/views/system/config/components/UploadConfig2.vue.js +0 -135
- package/dist/views/system/config/components/UploadConfig2.vue.js.map +0 -1
- /package/dist/views/system/config/components/{ExternalAuthConfig.vue.d.ts → AdminMock.vue.d.ts} +0 -0
- /package/dist/views/system/config/components/{HighSensConfig.vue.d.ts → AdvancedSection.vue.d.ts} +0 -0
- /package/dist/views/system/config/components/{JobConfig.vue.d.ts → JobSection.vue.d.ts} +0 -0
- /package/dist/views/system/config/components/{OtherConfig.vue.d.ts → LogoEditor.vue.d.ts} +0 -0
- /package/dist/views/system/config/components/{SecurityConfig.vue.d.ts → SecuritySection.vue.d.ts} +0 -0
- /package/dist/views/system/config/components/{SysBaseConfig.vue.d.ts → SensitiveSection.vue.d.ts} +0 -0
- /package/dist/views/system/config/components/{UploadConfig.vue.d.ts → SigninSection.vue.d.ts} +0 -0
package/dist/utils/oauthBrand.js
CHANGED
|
@@ -1,97 +1,93 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
const
|
|
3
|
-
function
|
|
4
|
-
return
|
|
1
|
+
import { t as v } from "../locales/index.js";
|
|
2
|
+
const b = 4, w = ["github", "wechat", "wecom", "dingtalk", "gitee", "qq"], N = new Set(w), S = !1;
|
|
3
|
+
function y(e) {
|
|
4
|
+
return v(`oauth.brand.${e}`);
|
|
5
5
|
}
|
|
6
|
-
function
|
|
7
|
-
return
|
|
6
|
+
function B() {
|
|
7
|
+
return w.map((e) => ({ code: e, displayName: y(e) }));
|
|
8
8
|
}
|
|
9
|
-
const
|
|
10
|
-
function
|
|
11
|
-
const t = new Map(n.map((
|
|
12
|
-
|
|
13
|
-
i.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
displayName: (
|
|
18
|
-
icon: (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
const L = ["wecom"], A = ["wecom", "dingtalk", "github", "wechat"];
|
|
10
|
+
function E(e, n) {
|
|
11
|
+
const s = new Set(e.types.map((t) => t.type)), i = new Map(n.map((t) => [t.code, t])), a = new Map(e.providers.map((t) => [t.code, t])), o = [], l = /* @__PURE__ */ new Set(), u = (t, h) => {
|
|
12
|
+
l.add(t);
|
|
13
|
+
const r = a.get(t), f = (r == null ? void 0 : r.source) === "code", m = f || (r ? s.has(r.type) : s.has(t)) ? r != null && r.configured ? "configured" : "unconfigured" : "notInstalled", c = i.get(t), d = m === "configured";
|
|
14
|
+
o.push({
|
|
15
|
+
code: t,
|
|
16
|
+
type: (r == null ? void 0 : r.type) ?? (h ? t : ""),
|
|
17
|
+
displayName: (r == null ? void 0 : r.displayName) || (g(t) ? y(t) : t),
|
|
18
|
+
icon: (r == null ? void 0 : r.icon) ?? null,
|
|
19
|
+
state: m,
|
|
20
|
+
source: f ? "code" : r ? "db" : "none",
|
|
21
|
+
registered: d,
|
|
22
|
+
enabled: d && !!(c != null && c.enabled),
|
|
23
|
+
linkByAccount: d && !!(c != null && c.linkByAccount)
|
|
22
24
|
});
|
|
23
|
-
}
|
|
24
|
-
for (const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
displayName: o.displayName,
|
|
28
|
-
icon: o.icon,
|
|
29
|
-
registered: !0,
|
|
30
|
-
enabled: o.enabled,
|
|
31
|
-
linkByAccount: o.linkByAccount ?? !1
|
|
32
|
-
}));
|
|
33
|
-
return r;
|
|
25
|
+
};
|
|
26
|
+
for (const t of A) u(t, !0);
|
|
27
|
+
for (const t of e.providers) l.has(t.code) || u(t.code, !1);
|
|
28
|
+
return o;
|
|
34
29
|
}
|
|
35
|
-
function
|
|
36
|
-
if (
|
|
37
|
-
const
|
|
38
|
-
return !
|
|
30
|
+
function C(e) {
|
|
31
|
+
if (e == null) return !1;
|
|
32
|
+
const n = e.trim();
|
|
33
|
+
return !n || /^https?:\/\//i.test(n) || n.startsWith("//") || /^data:/i.test(n) ? !1 : /^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9._-]*$/i.test(n);
|
|
39
34
|
}
|
|
40
|
-
function
|
|
41
|
-
return !!
|
|
35
|
+
function g(e) {
|
|
36
|
+
return !!e && N.has(e.toLowerCase());
|
|
42
37
|
}
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
return
|
|
38
|
+
function O(e, n) {
|
|
39
|
+
const s = (e ?? "").trim().toLowerCase();
|
|
40
|
+
return g(s) ? { kind: "brand", code: s } : C(n) ? { kind: "iconify", name: n.trim() } : { kind: "letter", letter: (e ?? "?").trim().charAt(0).toUpperCase() || "?" };
|
|
46
41
|
}
|
|
47
|
-
const
|
|
48
|
-
function
|
|
49
|
-
if (!/wxwork/i.test(
|
|
42
|
+
const p = "smart.sso.wecomAutoLogin";
|
|
43
|
+
function k(e) {
|
|
44
|
+
if (!/wxwork/i.test(e.userAgent) || !e.providers.some((n) => n.code === "wecom")) return !1;
|
|
50
45
|
try {
|
|
51
|
-
return
|
|
46
|
+
return e.storage.getItem(p) ? !1 : (e.storage.setItem(p, "1"), !0);
|
|
52
47
|
} catch {
|
|
53
48
|
return !1;
|
|
54
49
|
}
|
|
55
50
|
}
|
|
56
|
-
function
|
|
57
|
-
const
|
|
58
|
-
return
|
|
51
|
+
function P(e, n = b) {
|
|
52
|
+
const s = e.slice();
|
|
53
|
+
return s.length <= n ? { visible: s, overflow: [] } : { visible: s.slice(0, n), overflow: s.slice(n) };
|
|
59
54
|
}
|
|
60
|
-
function
|
|
61
|
-
const
|
|
62
|
-
for (const
|
|
63
|
-
const i = [],
|
|
64
|
-
for (const
|
|
65
|
-
|
|
66
|
-
code:
|
|
67
|
-
displayName:
|
|
68
|
-
icon:
|
|
55
|
+
function D(e, n) {
|
|
56
|
+
const s = /* @__PURE__ */ new Map();
|
|
57
|
+
for (const o of n) s.set(o.provider, o);
|
|
58
|
+
const i = [], a = /* @__PURE__ */ new Set();
|
|
59
|
+
for (const o of e)
|
|
60
|
+
a.add(o.code), i.push({
|
|
61
|
+
code: o.code,
|
|
62
|
+
displayName: o.displayName,
|
|
63
|
+
icon: o.icon,
|
|
69
64
|
enabled: !0,
|
|
70
|
-
binding:
|
|
65
|
+
binding: s.get(o.code)
|
|
71
66
|
});
|
|
72
|
-
for (const
|
|
73
|
-
|
|
74
|
-
code:
|
|
75
|
-
displayName:
|
|
67
|
+
for (const o of n)
|
|
68
|
+
a.has(o.provider) || i.push({
|
|
69
|
+
code: o.provider,
|
|
70
|
+
displayName: o.displayName && o.displayName.trim() || o.provider,
|
|
76
71
|
icon: null,
|
|
77
72
|
enabled: !1,
|
|
78
|
-
binding:
|
|
73
|
+
binding: o
|
|
79
74
|
});
|
|
80
75
|
return i;
|
|
81
76
|
}
|
|
82
77
|
export {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
78
|
+
w as BRAND_CODES,
|
|
79
|
+
L as LINK_BY_ACCOUNT_CODES,
|
|
80
|
+
A as OFFICIAL_TYPES,
|
|
81
|
+
S as PREVIEW_ALL_SSO_BRANDS,
|
|
82
|
+
b as SSO_VISIBLE_MAX,
|
|
83
|
+
y as brandDisplayName,
|
|
84
|
+
E as buildConfigProviderRows,
|
|
85
|
+
k as claimWeComAutoLogin,
|
|
86
|
+
g as isBrandCode,
|
|
87
|
+
C as isIconifyName,
|
|
88
|
+
D as mergeBindingRows,
|
|
89
|
+
B as previewAllBrandProviders,
|
|
90
|
+
O as resolveProviderIcon,
|
|
91
|
+
P as splitLoginProviders
|
|
96
92
|
};
|
|
97
93
|
//# sourceMappingURL=oauthBrand.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauthBrand.js","sources":["../../src/utils/oauthBrand.ts"],"sourcesContent":["// 外部登录品牌 UI 纯逻辑:可被 vitest 直接驱动,不依赖浏览器。\n// 契约见 docs/adr/0007-external-login-brand-ui-and-providers.md。\nimport { t } from '#/locales'\n\n/** 登录页最多平铺的品牌圆钮数;超出进「…」菜单。 */\nexport const SSO_VISIBLE_MAX = 4\n\n/** 预置精修品牌标的 provider code(大小写不敏感)。 */\nexport const BRAND_CODES = ['github', 'wechat', 'wecom', 'dingtalk', 'gitee', 'qq'] as const\nexport type BrandCode = (typeof BRAND_CODES)[number]\n\nconst BRAND_SET = new Set<string>(BRAND_CODES)\n\n/**\n * 登录页临时展示全部品牌圆标(图标验收用)。\n * true:铺全 6 个,不做 N=4 溢出;false:恢复仅后端 enabled providers。\n * 图标验收时在本地把 false 改成 true,验收完改回来,不要带着 true 提交。\n */\nexport const PREVIEW_ALL_SSO_BRANDS = false\n\n/**\n * 内置品牌显示名。走 i18n 而非硬编码中文常量表 —— 硬编码在英文界面下会露出「微信/企业微信/钉钉」。\n * 调用方须在 computed 里取值,切语言才会重算。\n */\nexport function brandDisplayName(code: BrandCode): string {\n return t(`oauth.brand.${code}`)\n}\n\n/** 图标预览用的假 provider 列表(与后端是否启用无关)。 */\nexport function previewAllBrandProviders(): SsoProviderLike[] {\n return BRAND_CODES.map(code => ({ code, displayName: brandDisplayName(code) }))\n}\n\n/**\n * 配置页卡片上给出「按账号自动关联」开关的 provider。只有企业微信的外部标识是企业统一分配的账号(userid),\n * 钉钉 / 微信 / GitHub 的标识是 unionid 或数字 id,按账号名对不上本地账号;\n * 自定义 provider 真要开(如 sub 就是工号的 OIDC),到「其他配置」加 sys.externalauth.{code}.linkByAccount。\n */\nexport const LINK_BY_ACCOUNT_CODES: readonly string[] = ['wecom']\n\n/** 配置页一行:内置品牌全展示;registered=后端已装包/已配密钥。 */\nexport type ConfigProviderRow = {\n code: string\n displayName: string\n icon?: string | null\n registered: boolean\n enabled: boolean\n /** 未绑定的外部身份按账号名关联同名本地账号(sys.externalauth.{code}.linkByAccount) */\n linkByAccount: boolean\n}\n\n/**\n * 配置页列表 = 预置品牌(全量) + 其它已注册 code(如 oidc-demo)。\n * 未注册项 registered=false、两个开关强制 false(未部署的方式开了也没用)。\n */\nexport function buildConfigProviderRows(\n registered: readonly {\n code: string\n displayName: string\n icon?: string | null\n enabled: boolean\n linkByAccount?: boolean\n }[],\n): ConfigProviderRow[] {\n const byCode = new Map(registered.map(p => [p.code, p]))\n const rows: ConfigProviderRow[] = []\n const seen = new Set<string>()\n\n for (const code of BRAND_CODES) {\n seen.add(code)\n const r = byCode.get(code)\n rows.push({\n code,\n displayName: r?.displayName || brandDisplayName(code),\n icon: r?.icon ?? null,\n registered: !!r,\n enabled: r ? r.enabled : false,\n linkByAccount: r?.linkByAccount ?? false,\n })\n }\n for (const p of registered) {\n if (seen.has(p.code)) continue\n seen.add(p.code)\n rows.push({\n code: p.code,\n displayName: p.displayName,\n icon: p.icon,\n registered: true,\n enabled: p.enabled,\n linkByAccount: p.linkByAccount ?? false,\n })\n }\n return rows\n}\n\nexport type SsoProviderLike = {\n code: string\n displayName: string\n icon?: string | null\n}\n\nexport type BindingLike = {\n provider: string\n displayName?: string | null\n boundAt: string\n}\n\nexport type IconResolve =\n | { kind: 'brand'; code: BrandCode }\n | { kind: 'iconify'; name: string }\n | { kind: 'letter'; letter: string }\n\nexport type BindingRow = {\n code: string\n displayName: string\n icon?: string | null\n /** false = 运营已关但仍有绑定 */\n enabled: boolean\n binding?: BindingLike\n}\n\n/** 是否为可渲染的 Iconify 名称;拒绝 URL / data URI。 */\nexport function isIconifyName(icon: string | null | undefined): boolean {\n if (icon == null) return false\n const s = icon.trim()\n if (!s) return false\n if (/^https?:\\/\\//i.test(s) || s.startsWith('//') || /^data:/i.test(s)) return false\n // collection:name(离线 Iconify 常见形态)\n return /^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9._-]*$/i.test(s)\n}\n\nexport function isBrandCode(code: string | null | undefined): code is BrandCode {\n return !!code && BRAND_SET.has(code.toLowerCase())\n}\n\n/** brand map → Iconify 名 → 首字母。 */\nexport function resolveProviderIcon(code: string, icon?: string | null): IconResolve {\n const c = (code ?? '').trim().toLowerCase()\n if (isBrandCode(c)) return { kind: 'brand', code: c }\n if (isIconifyName(icon)) return { kind: 'iconify', name: icon!.trim() }\n const letter = (code ?? '?').trim().charAt(0).toUpperCase() || '?'\n return { kind: 'letter', letter }\n}\n\nconst WECOM_AUTO_LOGIN_KEY = 'smart.sso.wecomAutoLogin'\n\n/**\n * 在企业微信客户端里打开登录页时,是否直接发起企业微信登录(客户端内走网页授权,静默、不用点)。\n * 企业微信的 UA 带 wxwork(同时也带微信的 MicroMessenger,不能拿它判断)。\n * 每个浏览器会话只返回一次 true:登录失败或主动退出后再回到登录页就停下,让人自己选登录方式,不会来回跳。\n */\nexport function claimWeComAutoLogin(opts: {\n userAgent: string\n providers: readonly { code: string }[]\n storage: Pick<Storage, 'getItem' | 'setItem'>\n}): boolean {\n if (!/wxwork/i.test(opts.userAgent)) return false\n if (!opts.providers.some(p => p.code === 'wecom')) return false\n try {\n if (opts.storage.getItem(WECOM_AUTO_LOGIN_KEY)) return false\n opts.storage.setItem(WECOM_AUTO_LOGIN_KEY, '1')\n return true\n } catch {\n // 存储不可用时记不住「已经跳过一次」,宁可不自动跳\n return false\n }\n}\n\n/** 严格保序切分:前 max 平铺,其余进溢出。 */\nexport function splitLoginProviders<T>(\n providers: readonly T[],\n maxVisible = SSO_VISIBLE_MAX,\n): {\n visible: T[]\n overflow: T[]\n} {\n const list = providers.slice()\n if (list.length <= maxVisible) return { visible: list, overflow: [] }\n return { visible: list.slice(0, maxVisible), overflow: list.slice(maxVisible) }\n}\n\n/**\n * 绑定页行:已启用 providers(API 序) ∪ 仅存在于 bindings 的已停用项(接在后面)。\n * 不做 N=4 截断。\n */\nexport function mergeBindingRows(\n providers: readonly SsoProviderLike[],\n bindings: readonly BindingLike[],\n): BindingRow[] {\n const bindByProvider = new Map<string, BindingLike>()\n for (const b of bindings) bindByProvider.set(b.provider, b)\n\n const rows: BindingRow[] = []\n const seen = new Set<string>()\n\n for (const p of providers) {\n seen.add(p.code)\n rows.push({\n code: p.code,\n displayName: p.displayName,\n icon: p.icon,\n enabled: true,\n binding: bindByProvider.get(p.code),\n })\n }\n\n for (const b of bindings) {\n if (seen.has(b.provider)) continue\n rows.push({\n code: b.provider,\n displayName: (b.displayName && b.displayName.trim()) || b.provider,\n icon: null,\n enabled: false,\n binding: b,\n })\n }\n\n return rows\n}\n"],"names":["SSO_VISIBLE_MAX","BRAND_CODES","BRAND_SET","PREVIEW_ALL_SSO_BRANDS","brandDisplayName","code","t","previewAllBrandProviders","LINK_BY_ACCOUNT_CODES","buildConfigProviderRows","registered","byCode","p","rows","seen","r","isIconifyName","icon","s","isBrandCode","resolveProviderIcon","c","WECOM_AUTO_LOGIN_KEY","claimWeComAutoLogin","opts","splitLoginProviders","providers","maxVisible","list","mergeBindingRows","bindings","bindByProvider","b"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"oauthBrand.js","sources":["../../src/utils/oauthBrand.ts"],"sourcesContent":["// 外部登录品牌 UI 纯逻辑:可被 vitest 直接驱动,不依赖浏览器。\n// 契约见 docs/adr/0007-external-login-brand-ui-and-providers.md。\nimport { t } from '#/locales'\n\n/** 登录页最多平铺的品牌圆钮数;超出进「…」菜单。 */\nexport const SSO_VISIBLE_MAX = 4\n\n/** 预置精修品牌标的 provider code(大小写不敏感)。 */\nexport const BRAND_CODES = ['github', 'wechat', 'wecom', 'dingtalk', 'gitee', 'qq'] as const\nexport type BrandCode = (typeof BRAND_CODES)[number]\n\nconst BRAND_SET = new Set<string>(BRAND_CODES)\n\n/**\n * 登录页临时展示全部品牌圆标(图标验收用)。\n * true:铺全 6 个,不做 N=4 溢出;false:恢复仅后端 enabled providers。\n * 图标验收时在本地把 false 改成 true,验收完改回来,不要带着 true 提交。\n */\nexport const PREVIEW_ALL_SSO_BRANDS = false\n\n/**\n * 内置品牌显示名。走 i18n 而非硬编码中文常量表 —— 硬编码在英文界面下会露出「微信/企业微信/钉钉」。\n * 调用方须在 computed 里取值,切语言才会重算。\n */\nexport function brandDisplayName(code: BrandCode): string {\n return t(`oauth.brand.${code}`)\n}\n\n/** 图标预览用的假 provider 列表(与后端是否启用无关)。 */\nexport function previewAllBrandProviders(): SsoProviderLike[] {\n return BRAND_CODES.map(code => ({ code, displayName: brandDisplayName(code) }))\n}\n\n/**\n * 配置页卡片上给出「按账号自动关联」开关的 provider。只有企业微信的外部标识是企业统一分配的账号(userid),\n * 钉钉 / 微信 / GitHub 的标识是 unionid 或数字 id,按账号名对不上本地账号;\n * 自定义 provider 真要开(如 sub 就是工号的 OIDC),到「其他配置」加 sys.externalauth.{code}.linkByAccount。\n */\nexport const LINK_BY_ACCOUNT_CODES: readonly string[] = ['wecom']\n\n/** 服务器上有对应扩展包的官方厂商类型,按「登录方式」页的展示顺序。 */\nexport const OFFICIAL_TYPES = ['wecom', 'dingtalk', 'github', 'wechat'] as const\n\n/** 一行的状态:类型没装 / 已装未配 / 已配可用。 */\nexport type ProviderState = 'notInstalled' | 'unconfigured' | 'configured'\n\n/** 配置页一行:后端目录里有的类型与 provider,不是预置品牌全量。 */\nexport type ConfigProviderRow = {\n code: string\n /** 类型码;代码注册的 provider 没有类型,为空串 */\n type: string\n displayName: string\n icon?: string | null\n state: ProviderState\n /** db = 在本页配置;code = 消费者用代码注册(只读);none = 没有配置 */\n source: 'db' | 'code' | 'none'\n /** 已配置且可用:开关可操作,预览与登录页才会出现它 */\n registered: boolean\n enabled: boolean\n /** 未绑定的外部身份按账号名关联同名本地账号(sys.externalauth.{code}.linkByAccount) */\n linkByAccount: boolean\n}\n\ntype CatalogLike = {\n types: readonly { type: string }[]\n providers: readonly {\n code: string\n type: string\n displayName: string\n icon?: string | null\n source: string\n installed: boolean\n configured: boolean\n }[]\n}\n\ntype AdminLike = { code: string; enabled: boolean; linkByAccount?: boolean }\n\n/**\n * 配置页列表 = 四个官方厂商(按固定顺序,没装的也列出并标「未安装」)\n * + 目录里其余的 provider(OIDC 条目、代码注册的)。\n * 未配置或未安装的行开关强制关:没配好的方式开了也没用,也不写库。\n */\nexport function buildConfigProviderRows(\n catalog: CatalogLike,\n admin: readonly AdminLike[],\n): ConfigProviderRow[] {\n const installed = new Set(catalog.types.map(x => x.type))\n const adminByCode = new Map(admin.map(a => [a.code, a]))\n const byCode = new Map(catalog.providers.map(p => [p.code, p]))\n const rows: ConfigProviderRow[] = []\n const seen = new Set<string>()\n\n const push = (code: string, official: boolean) => {\n seen.add(code)\n const p = byCode.get(code)\n const fromCode = p?.source === 'code'\n const typeInstalled = fromCode || (p ? installed.has(p.type) : installed.has(code))\n const state: ProviderState = !typeInstalled\n ? 'notInstalled'\n : p?.configured\n ? 'configured'\n : 'unconfigured'\n const a = adminByCode.get(code)\n const registered = state === 'configured'\n rows.push({\n code,\n type: p?.type ?? (official ? code : ''),\n displayName: p?.displayName || (isBrandCode(code) ? brandDisplayName(code) : code),\n icon: p?.icon ?? null,\n state,\n source: fromCode ? 'code' : p ? 'db' : 'none',\n registered,\n enabled: registered && !!a?.enabled,\n linkByAccount: registered && !!a?.linkByAccount,\n })\n }\n\n for (const code of OFFICIAL_TYPES) push(code, true)\n for (const p of catalog.providers) if (!seen.has(p.code)) push(p.code, false)\n return rows\n}\n\nexport type SsoProviderLike = {\n code: string\n displayName: string\n icon?: string | null\n}\n\nexport type BindingLike = {\n provider: string\n displayName?: string | null\n boundAt: string\n}\n\nexport type IconResolve =\n | { kind: 'brand'; code: BrandCode }\n | { kind: 'iconify'; name: string }\n | { kind: 'letter'; letter: string }\n\nexport type BindingRow = {\n code: string\n displayName: string\n icon?: string | null\n /** false = 运营已关但仍有绑定 */\n enabled: boolean\n binding?: BindingLike\n}\n\n/** 是否为可渲染的 Iconify 名称;拒绝 URL / data URI。 */\nexport function isIconifyName(icon: string | null | undefined): boolean {\n if (icon == null) return false\n const s = icon.trim()\n if (!s) return false\n if (/^https?:\\/\\//i.test(s) || s.startsWith('//') || /^data:/i.test(s)) return false\n // collection:name(离线 Iconify 常见形态)\n return /^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9._-]*$/i.test(s)\n}\n\nexport function isBrandCode(code: string | null | undefined): code is BrandCode {\n return !!code && BRAND_SET.has(code.toLowerCase())\n}\n\n/** brand map → Iconify 名 → 首字母。 */\nexport function resolveProviderIcon(code: string, icon?: string | null): IconResolve {\n const c = (code ?? '').trim().toLowerCase()\n if (isBrandCode(c)) return { kind: 'brand', code: c }\n if (isIconifyName(icon)) return { kind: 'iconify', name: icon!.trim() }\n const letter = (code ?? '?').trim().charAt(0).toUpperCase() || '?'\n return { kind: 'letter', letter }\n}\n\nconst WECOM_AUTO_LOGIN_KEY = 'smart.sso.wecomAutoLogin'\n\n/**\n * 在企业微信客户端里打开登录页时,是否直接发起企业微信登录(客户端内走网页授权,静默、不用点)。\n * 企业微信的 UA 带 wxwork(同时也带微信的 MicroMessenger,不能拿它判断)。\n * 每个浏览器会话只返回一次 true:登录失败或主动退出后再回到登录页就停下,让人自己选登录方式,不会来回跳。\n */\nexport function claimWeComAutoLogin(opts: {\n userAgent: string\n providers: readonly { code: string }[]\n storage: Pick<Storage, 'getItem' | 'setItem'>\n}): boolean {\n if (!/wxwork/i.test(opts.userAgent)) return false\n if (!opts.providers.some(p => p.code === 'wecom')) return false\n try {\n if (opts.storage.getItem(WECOM_AUTO_LOGIN_KEY)) return false\n opts.storage.setItem(WECOM_AUTO_LOGIN_KEY, '1')\n return true\n } catch {\n // 存储不可用时记不住「已经跳过一次」,宁可不自动跳\n return false\n }\n}\n\n/** 严格保序切分:前 max 平铺,其余进溢出。 */\nexport function splitLoginProviders<T>(\n providers: readonly T[],\n maxVisible = SSO_VISIBLE_MAX,\n): {\n visible: T[]\n overflow: T[]\n} {\n const list = providers.slice()\n if (list.length <= maxVisible) return { visible: list, overflow: [] }\n return { visible: list.slice(0, maxVisible), overflow: list.slice(maxVisible) }\n}\n\n/**\n * 绑定页行:已启用 providers(API 序) ∪ 仅存在于 bindings 的已停用项(接在后面)。\n * 不做 N=4 截断。\n */\nexport function mergeBindingRows(\n providers: readonly SsoProviderLike[],\n bindings: readonly BindingLike[],\n): BindingRow[] {\n const bindByProvider = new Map<string, BindingLike>()\n for (const b of bindings) bindByProvider.set(b.provider, b)\n\n const rows: BindingRow[] = []\n const seen = new Set<string>()\n\n for (const p of providers) {\n seen.add(p.code)\n rows.push({\n code: p.code,\n displayName: p.displayName,\n icon: p.icon,\n enabled: true,\n binding: bindByProvider.get(p.code),\n })\n }\n\n for (const b of bindings) {\n if (seen.has(b.provider)) continue\n rows.push({\n code: b.provider,\n displayName: (b.displayName && b.displayName.trim()) || b.provider,\n icon: null,\n enabled: false,\n binding: b,\n })\n }\n\n return rows\n}\n"],"names":["SSO_VISIBLE_MAX","BRAND_CODES","BRAND_SET","PREVIEW_ALL_SSO_BRANDS","brandDisplayName","code","t","previewAllBrandProviders","LINK_BY_ACCOUNT_CODES","OFFICIAL_TYPES","buildConfigProviderRows","catalog","admin","installed","x","adminByCode","a","byCode","p","rows","seen","push","official","fromCode","state","registered","isBrandCode","isIconifyName","icon","s","resolveProviderIcon","c","WECOM_AUTO_LOGIN_KEY","claimWeComAutoLogin","opts","splitLoginProviders","providers","maxVisible","list","mergeBindingRows","bindings","bindByProvider","b"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
headline: string;
|
|
3
|
+
highlight?: string;
|
|
4
|
+
subtitle?: string;
|
|
5
|
+
features?: string[];
|
|
6
|
+
/** 以下两项供配置中心预览未保存的草稿;不传则取当前站点信息 */
|
|
7
|
+
title?: string;
|
|
8
|
+
logo?: string;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
11
|
+
title: string;
|
|
12
|
+
subtitle: string;
|
|
13
|
+
logo: string;
|
|
14
|
+
highlight: string;
|
|
15
|
+
features: string[];
|
|
16
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
17
|
+
declare const _default: typeof __VLS_export;
|
|
18
|
+
export default _default;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import o from "./LoginHeroPanel2.vue.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import e from "../../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
+
const c = /* @__PURE__ */ e(o, [["__scopeId", "data-v-a4cecbe6"]]);
|
|
5
|
+
export {
|
|
6
|
+
c as default
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=LoginHeroPanel.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginHeroPanel.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineComponent as k, computed as v, openBlock as l, createElementBlock as n, createElementVNode as s, createVNode as h, toDisplayString as a, unref as i, normalizeStyle as u, Fragment as f, renderList as g, createCommentVNode as m, createTextVNode as b } from "vue";
|
|
2
|
+
import { Icon as S } from "@iconify/vue";
|
|
3
|
+
import { useAppStore as N } from "../../../stores/app.js";
|
|
4
|
+
import { useSite as V } from "../../../composables/useSite.js";
|
|
5
|
+
import _ from "../../../components/SmartLogo.vue.js";
|
|
6
|
+
const L = { class: "login-hero-panel" }, z = { class: "logo" }, B = { class: "headline" }, C = {
|
|
7
|
+
key: 0,
|
|
8
|
+
class: "sub"
|
|
9
|
+
}, E = {
|
|
10
|
+
key: 1,
|
|
11
|
+
class: "points"
|
|
12
|
+
}, H = /* @__PURE__ */ k({
|
|
13
|
+
__name: "LoginHeroPanel",
|
|
14
|
+
props: {
|
|
15
|
+
headline: {},
|
|
16
|
+
highlight: { default: "" },
|
|
17
|
+
subtitle: { default: "" },
|
|
18
|
+
features: { default: () => [] },
|
|
19
|
+
title: { default: void 0 },
|
|
20
|
+
logo: { default: void 0 }
|
|
21
|
+
},
|
|
22
|
+
setup(t) {
|
|
23
|
+
const e = t, r = N(), { site: p } = V(), x = v(() => {
|
|
24
|
+
const c = e.highlight ? e.headline.indexOf(e.highlight) : -1;
|
|
25
|
+
return c < 0 ? [{ text: e.headline, accent: !1 }] : [
|
|
26
|
+
{ text: e.headline.slice(0, c), accent: !1 },
|
|
27
|
+
{ text: e.highlight, accent: !0 },
|
|
28
|
+
{ text: e.headline.slice(c + e.highlight.length), accent: !1 }
|
|
29
|
+
].filter((d) => d.text);
|
|
30
|
+
});
|
|
31
|
+
return (c, d) => (l(), n("div", L, [
|
|
32
|
+
s("div", z, [
|
|
33
|
+
h(_, {
|
|
34
|
+
size: 34,
|
|
35
|
+
src: t.logo
|
|
36
|
+
}, null, 8, ["src"]),
|
|
37
|
+
s("span", null, a(t.title ?? i(p).title), 1)
|
|
38
|
+
]),
|
|
39
|
+
s("div", {
|
|
40
|
+
class: "bar",
|
|
41
|
+
style: u({ background: i(r).accent })
|
|
42
|
+
}, null, 4),
|
|
43
|
+
s("h1", B, [
|
|
44
|
+
(l(!0), n(f, null, g(x.value, (o, y) => (l(), n("span", {
|
|
45
|
+
key: y,
|
|
46
|
+
style: u(o.accent ? { color: i(r).accent } : void 0)
|
|
47
|
+
}, a(o.text), 5))), 128))
|
|
48
|
+
]),
|
|
49
|
+
t.subtitle ? (l(), n("p", C, a(t.subtitle), 1)) : m("", !0),
|
|
50
|
+
t.features.length ? (l(), n("ul", E, [
|
|
51
|
+
(l(!0), n(f, null, g(t.features, (o) => (l(), n("li", { key: o }, [
|
|
52
|
+
h(i(S), {
|
|
53
|
+
icon: "ph:check-circle-duotone",
|
|
54
|
+
width: 18,
|
|
55
|
+
style: u({ color: i(r).accent })
|
|
56
|
+
}, null, 8, ["style"]),
|
|
57
|
+
b(" " + a(o), 1)
|
|
58
|
+
]))), 128))
|
|
59
|
+
])) : m("", !0)
|
|
60
|
+
]));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
export {
|
|
64
|
+
H as default
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=LoginHeroPanel2.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginHeroPanel2.vue.js","sources":["../../../../src/views/login/components/LoginHeroPanel.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { Icon } from '@iconify/vue'\nimport { useAppStore } from '#/stores/app'\nimport { useSite } from '#/composables/useSite'\nimport SmartLogo from '#/components/SmartLogo.vue'\n\nconst props = withDefaults(\n defineProps<{\n headline: string\n highlight?: string\n subtitle?: string\n features?: string[]\n /** 以下两项供配置中心预览未保存的草稿;不传则取当前站点信息 */\n title?: string\n logo?: string\n }>(),\n {\n highlight: '',\n subtitle: '',\n features: () => [],\n title: undefined,\n logo: undefined,\n },\n)\n\nconst app = useAppStore()\nconst { site } = useSite()\n\n// 只做纯文本切片,不用 v-html;强调词只会成为一个普通 span。\nconst headlineParts = computed(() => {\n const index = props.highlight ? props.headline.indexOf(props.highlight) : -1\n if (index < 0) return [{ text: props.headline, accent: false }]\n return [\n { text: props.headline.slice(0, index), accent: false },\n { text: props.highlight, accent: true },\n { text: props.headline.slice(index + props.highlight.length), accent: false },\n ].filter(part => part.text)\n})\n</script>\n\n<template>\n <div class=\"login-hero-panel\">\n <div class=\"logo\">\n <SmartLogo :size=\"34\" :src=\"logo\" />\n <span>{{ title ?? site.title }}</span>\n </div>\n <div class=\"bar\" :style=\"{ background: app.accent }\" />\n <h1 class=\"headline\">\n <span\n v-for=\"(part, index) in headlineParts\"\n :key=\"index\"\n :style=\"part.accent ? { color: app.accent } : undefined\"\n >\n {{ part.text }}\n </span>\n </h1>\n <p v-if=\"subtitle\" class=\"sub\">{{ subtitle }}</p>\n <ul v-if=\"features.length\" class=\"points\">\n <li v-for=\"feature in features\" :key=\"feature\">\n <Icon icon=\"ph:check-circle-duotone\" :width=\"18\" :style=\"{ color: app.accent }\" />\n {{ feature }}\n </li>\n </ul>\n </div>\n</template>\n\n<style scoped>\n.login-hero-panel {\n min-width: 0;\n}\n.logo {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 22px;\n font-weight: 700;\n color: #2a3c82;\n}\n.bar {\n width: 40px;\n height: 3px;\n border-radius: 2px;\n margin: 28px 0 20px;\n}\n.headline {\n font-size: 42px;\n line-height: 1.2;\n font-weight: 800;\n color: var(--color-text-primary);\n margin: 0;\n}\n.sub {\n color: var(--color-text-secondary);\n margin: 16px 0 28px;\n}\n.points {\n list-style: none;\n padding: 0;\n margin: 0;\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n.points li {\n display: flex;\n align-items: center;\n gap: 10px;\n color: var(--color-text-secondary);\n}\n</style>\n"],"names":["props","__props","app","useAppStore","site","useSite","headlineParts","computed","index","part","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_createVNode","SmartLogo","_toDisplayString","_unref","_normalizeStyle","_hoisted_3","_Fragment","_renderList","_hoisted_4","_hoisted_5","feature","Icon","_createTextVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAOA,UAAMA,IAAQC,GAmBRC,IAAMC,EAAA,GACN,EAAE,MAAAC,EAAA,IAASC,EAAA,GAGXC,IAAgBC,EAAS,MAAM;AACnC,YAAMC,IAAQR,EAAM,YAAYA,EAAM,SAAS,QAAQA,EAAM,SAAS,IAAI;AAC1E,aAAIQ,IAAQ,IAAU,CAAC,EAAE,MAAMR,EAAM,UAAU,QAAQ,IAAO,IACvD;AAAA,QACL,EAAE,MAAMA,EAAM,SAAS,MAAM,GAAGQ,CAAK,GAAG,QAAQ,GAAA;AAAA,QAChD,EAAE,MAAMR,EAAM,WAAW,QAAQ,GAAA;AAAA,QACjC,EAAE,MAAMA,EAAM,SAAS,MAAMQ,IAAQR,EAAM,UAAU,MAAM,GAAG,QAAQ,GAAA;AAAA,MAAM,EAC5E,OAAO,CAAAS,MAAQA,EAAK,IAAI;AAAA,IAC5B,CAAC;sBAICC,EAAA,GAAAC,EAsBM,OAtBNC,GAsBM;AAAA,MArBJC,EAGM,OAHNC,GAGM;AAAA,QAFJC,EAAoCC,GAAA;AAAA,UAAxB,MAAM;AAAA,UAAK,KAAKf,EAAA;AAAA,QAAA;QAC5BY,EAAsC,QAAA,MAAAI,EAA7BhB,EAAA,SAASiB,EAAAd,CAAA,EAAK,KAAK,GAAA,CAAA;AAAA,MAAA;MAE9BS,EAAuD,OAAA;AAAA,QAAlD,OAAM;AAAA,QAAO,OAAKM,EAAA,EAAA,YAAgBD,EAAAhB,CAAA,EAAI,QAAM;AAAA,MAAA;MACjDW,EAQK,MARLO,GAQK;AAAA,SAPHV,EAAA,EAAA,GAAAC,EAMOU,GAAA,MAAAC,EALmBhB,EAAA,OAAa,CAA7BG,GAAMD,YADhBG,EAMO,QAAA;AAAA,UAJJ,KAAKH;AAAA,UACL,OAAKW,EAAEV,EAAK,kBAAkBS,EAAAhB,CAAA,EAAI,OAAA,IAAW,MAAS;AAAA,QAAA,GAEpDe,EAAAR,EAAK,IAAI,GAAA,CAAA;;MAGPR,EAAA,iBAATU,EAAiD,KAAjDY,GAAiDN,EAAfhB,EAAA,QAAQ,GAAA,CAAA;MAChCA,EAAA,SAAS,UAAnBS,KAAAC,EAKK,MALLa,GAKK;AAAA,gBAJHb,EAGKU,GAAA,MAAAC,EAHiBrB,EAAA,UAAQ,CAAnBwB,YAAXd,EAGK,MAAA,EAH4B,KAAKc,KAAO;AAAA,UAC3CV,EAAkFG,EAAAQ,CAAA,GAAA;AAAA,YAA5E,MAAK;AAAA,YAA2B,OAAO;AAAA,YAAK,OAAKP,EAAA,EAAA,OAAWD,EAAAhB,CAAA,EAAI,QAAM;AAAA,UAAA;UAAMyB,EAAA,QAC/EF,CAAO,GAAA,CAAA;AAAA,QAAA;;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import o from "./SplitPanel2.vue.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import t from "../../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
-
const m = /* @__PURE__ */ t(o, [["__scopeId", "data-v-
|
|
4
|
+
const m = /* @__PURE__ */ t(o, [["__scopeId", "data-v-b4c7728a"]]);
|
|
5
5
|
export {
|
|
6
6
|
m as default
|
|
7
7
|
};
|
|
@@ -1,85 +1,65 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { useAppStore as
|
|
5
|
-
import { useSite as
|
|
6
|
-
import { rgba as
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
const
|
|
1
|
+
import { defineComponent as u, computed as g, openBlock as r, createElementBlock as i, normalizeStyle as v, createElementVNode as t, createVNode as m, unref as e, toDisplayString as s, createTextVNode as h, Fragment as y, createCommentVNode as b } from "vue";
|
|
2
|
+
import { useI18n as w } from "vue-i18n";
|
|
3
|
+
import { useLoginHero as k } from "../../../composables/useLoginHero.js";
|
|
4
|
+
import { useAppStore as S } from "../../../stores/app.js";
|
|
5
|
+
import { useSite as V } from "../../../composables/useSite.js";
|
|
6
|
+
import { rgba as d, mix as x } from "../../../theme/mix.js";
|
|
7
|
+
import F from "../LoginForm.vue.js";
|
|
8
|
+
import N from "../components/LoginHeroPanel.vue.js";
|
|
9
|
+
const B = { class: "panel" }, C = { class: "panel-inner" }, L = { class: "form-wrap" }, D = { class: "mid" }, E = { class: "form-inner" }, H = { class: "greet" }, P = { class: "greet-sub" }, U = { class: "foot" }, z = ["href"], A = {
|
|
10
10
|
key: 2,
|
|
11
11
|
class: "foot-ver"
|
|
12
|
-
},
|
|
12
|
+
}, Q = /* @__PURE__ */ u({
|
|
13
13
|
__name: "SplitPanel",
|
|
14
|
-
setup(
|
|
15
|
-
const { t:
|
|
16
|
-
"--a1":
|
|
17
|
-
"--a2":
|
|
14
|
+
setup(I) {
|
|
15
|
+
const { t: n } = w(), a = S(), { site: o, appVersion: c } = V(), l = k(), _ = (/* @__PURE__ */ new Date()).getFullYear(), f = g(() => ({
|
|
16
|
+
"--a1": d(a.accent, 0.5),
|
|
17
|
+
"--a2": d(x(a.accent, "#8B5CF6", 0.6), 0.4)
|
|
18
18
|
}));
|
|
19
|
-
return (
|
|
19
|
+
return (T, p) => (r(), i("div", {
|
|
20
20
|
class: "split",
|
|
21
|
-
style:
|
|
21
|
+
style: v(f.value)
|
|
22
22
|
}, [
|
|
23
|
-
t("div",
|
|
24
|
-
|
|
25
|
-
t("div",
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
style: a({ background: e(c).accent })
|
|
33
|
-
}, null, 4),
|
|
34
|
-
t("h1", A, [
|
|
35
|
-
r(o(e(s)("login.headlinePre")) + " ", 1),
|
|
36
|
-
t("span", {
|
|
37
|
-
style: a({ color: e(c).accent })
|
|
38
|
-
}, o(e(s)("login.headlineAccent")), 5),
|
|
39
|
-
r(" " + o(e(s)("login.headlinePost")), 1)
|
|
40
|
-
]),
|
|
41
|
-
t("p", D, o(e(n).subtitle || e(s)("login.subtitle")), 1),
|
|
42
|
-
t("ul", E, [
|
|
43
|
-
(l(!0), i(u, null, k(y.value, (m) => (l(), i("li", { key: m }, [
|
|
44
|
-
p(e(S), {
|
|
45
|
-
icon: "ph:check-circle-duotone",
|
|
46
|
-
width: 18,
|
|
47
|
-
style: a({ color: e(c).accent })
|
|
48
|
-
}, null, 8, ["style"]),
|
|
49
|
-
r(" " + o(m), 1)
|
|
50
|
-
]))), 128))
|
|
51
|
-
])
|
|
23
|
+
t("div", B, [
|
|
24
|
+
p[0] || (p[0] = t("div", { class: "panel-aurora" }, null, -1)),
|
|
25
|
+
t("div", C, [
|
|
26
|
+
m(N, {
|
|
27
|
+
headline: e(l).headline,
|
|
28
|
+
highlight: e(l).highlight,
|
|
29
|
+
subtitle: e(o).subtitle || e(n)("login.subtitle"),
|
|
30
|
+
features: e(l).features
|
|
31
|
+
}, null, 8, ["headline", "highlight", "subtitle", "features"])
|
|
52
32
|
])
|
|
53
33
|
]),
|
|
54
|
-
t("div",
|
|
55
|
-
t("div",
|
|
56
|
-
t("div",
|
|
57
|
-
t("p",
|
|
58
|
-
t("p",
|
|
59
|
-
|
|
34
|
+
t("div", L, [
|
|
35
|
+
t("div", D, [
|
|
36
|
+
t("div", E, [
|
|
37
|
+
t("p", H, s(e(n)("login.welcome")), 1),
|
|
38
|
+
t("p", P, s(e(n)("login.welcomeSub")), 1),
|
|
39
|
+
m(F, {
|
|
60
40
|
"show-logo": !1,
|
|
61
41
|
"show-title": !1,
|
|
62
42
|
"show-footer": !1
|
|
63
43
|
})
|
|
64
44
|
])
|
|
65
45
|
]),
|
|
66
|
-
t("p",
|
|
67
|
-
|
|
68
|
-
e(
|
|
46
|
+
t("p", U, [
|
|
47
|
+
h(" © " + s(e(_)) + " ", 1),
|
|
48
|
+
e(o).copyrightUrl ? (r(), i("a", {
|
|
69
49
|
key: 0,
|
|
70
|
-
href: e(
|
|
50
|
+
href: e(o).copyrightUrl,
|
|
71
51
|
target: "_blank",
|
|
72
52
|
rel: "noopener"
|
|
73
|
-
},
|
|
74
|
-
|
|
53
|
+
}, s(e(o).copyright || e(o).title), 9, z)) : (r(), i(y, { key: 1 }, [
|
|
54
|
+
h(s(e(o).copyright || e(o).title), 1)
|
|
75
55
|
], 64)),
|
|
76
|
-
e(
|
|
56
|
+
e(c) ? (r(), i("span", A, "v" + s(e(c)), 1)) : b("", !0)
|
|
77
57
|
])
|
|
78
58
|
])
|
|
79
59
|
], 4));
|
|
80
60
|
}
|
|
81
61
|
});
|
|
82
62
|
export {
|
|
83
|
-
|
|
63
|
+
Q as default
|
|
84
64
|
};
|
|
85
65
|
//# sourceMappingURL=SplitPanel2.vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SplitPanel2.vue.js","sources":["../../../../src/views/login/skins/SplitPanel.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport {
|
|
1
|
+
{"version":3,"file":"SplitPanel2.vue.js","sources":["../../../../src/views/login/skins/SplitPanel.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useLoginHero } from '#/composables/useLoginHero'\nimport { useAppStore } from '#/stores/app'\nimport { useSite } from '#/composables/useSite'\nimport { mix, rgba } from '#/theme/mix'\nimport LoginForm from '../LoginForm.vue'\nimport LoginHeroPanel from '../components/LoginHeroPanel.vue'\n\nconst { t } = useI18n()\nconst app = useAppStore()\nconst { site, appVersion } = useSite()\nconst hero = useLoginHero()\nconst year = new Date().getFullYear()\n\nconst vars = computed(() => ({\n '--a1': rgba(app.accent, 0.5),\n '--a2': rgba(mix(app.accent, '#8B5CF6', 0.6), 0.4),\n}))\n</script>\n\n<template>\n <div class=\"split\" :style=\"vars\">\n <!-- 左:品牌面板(窄屏隐藏)-->\n <div class=\"panel\">\n <div class=\"panel-aurora\" />\n <div class=\"panel-inner\">\n <LoginHeroPanel\n :headline=\"hero.headline\"\n :highlight=\"hero.highlight\"\n :subtitle=\"site.subtitle || t('login.subtitle')\"\n :features=\"hero.features\"\n />\n </div>\n </div>\n\n <!-- 右:全高工作区(居中表单 + 版权页脚);主题/语言切换在外壳全局工具药丸 -->\n <div class=\"form-wrap\">\n <div class=\"mid\">\n <div class=\"form-inner\">\n <p class=\"greet\">{{ t('login.welcome') }}</p>\n <p class=\"greet-sub\">{{ t('login.welcomeSub') }}</p>\n <LoginForm :show-logo=\"false\" :show-title=\"false\" :show-footer=\"false\" />\n </div>\n </div>\n\n <p class=\"foot\">\n © {{ year }}\n <a v-if=\"site.copyrightUrl\" :href=\"site.copyrightUrl\" target=\"_blank\" rel=\"noopener\">\n {{ site.copyright || site.title }}\n </a>\n <template v-else>{{ site.copyright || site.title }}</template>\n <span v-if=\"appVersion\" class=\"foot-ver\">v{{ appVersion }}</span>\n </p>\n </div>\n </div>\n</template>\n\n<style scoped>\n.split {\n height: 100dvh;\n display: grid;\n grid-template-columns: 1.15fr 0.85fr;\n background: var(--color-bg-body);\n}\n/* 左栏 = recessed 品牌面(body 底 + 极光),与右栏 clean container 拉开图/底关系 */\n.panel {\n position: relative;\n overflow: hidden;\n background: var(--color-bg-body);\n border-right: 1px solid var(--color-border);\n}\n/* 细网格纹理,左上淡出 */\n.panel::before {\n content: '';\n position: absolute;\n inset: 0;\n background-image:\n linear-gradient(rgba(127, 127, 127, 0.08) 1px, transparent 1px),\n linear-gradient(90deg, rgba(127, 127, 127, 0.08) 1px, transparent 1px);\n background-size: 40px 40px;\n -webkit-mask-image: radial-gradient(circle at 30% 40%, #000, transparent 72%);\n mask-image: radial-gradient(circle at 30% 40%, #000, transparent 72%);\n}\n.panel-aurora {\n position: absolute;\n inset: -20%;\n background:\n radial-gradient(40% 40% at 25% 20%, var(--a1), transparent 68%),\n radial-gradient(45% 45% at 80% 78%, var(--a2), transparent 70%);\n filter: blur(45px);\n opacity: 0.9;\n animation: panel-move 22s ease-in-out infinite alternate;\n}\n@keyframes panel-move {\n 0% {\n transform: translate3d(-3%, -2%, 0) scale(1.05);\n }\n 100% {\n transform: translate3d(3%, 3%, 0) scale(1.12);\n }\n}\n.panel-inner {\n position: relative;\n z-index: 1;\n padding: 64px 56px;\n display: flex;\n flex-direction: column;\n height: 100%;\n justify-content: center;\n}\n/* 右栏 = 全高工作区:居中表单 + 页脚(主题/语言切换在外壳全局工具) */\n.form-wrap {\n position: relative;\n display: flex;\n flex-direction: column;\n background: var(--color-bg-container);\n}\n.mid {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n}\n.form-inner {\n width: 100%;\n max-width: 340px;\n animation: fade-up 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;\n}\n.greet {\n font-size: 26px;\n font-weight: 700;\n letter-spacing: -0.01em;\n color: var(--color-text-primary);\n margin: 0 0 6px;\n}\n.greet-sub {\n font-size: var(--font-size-sm);\n color: var(--color-text-tertiary);\n margin: 0 0 26px;\n}\n.foot {\n margin: 0;\n padding: 18px 24px 22px;\n text-align: center;\n font-size: var(--font-size-sm);\n color: var(--color-text-tertiary);\n}\n.foot a {\n color: inherit;\n text-decoration: none;\n}\n.foot a:hover {\n color: var(--color-primary);\n}\n.foot-ver {\n margin-left: 8px;\n opacity: 0.75;\n}\n@keyframes fade-up {\n from {\n opacity: 0;\n transform: translateY(16px);\n }\n to {\n opacity: 1;\n transform: none;\n }\n}\n@media (max-width: 900px) {\n .split {\n grid-template-columns: 1fr;\n }\n .panel {\n display: none;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .panel-aurora,\n .form-inner {\n animation: none;\n }\n}\n</style>\n"],"names":["t","useI18n","app","useAppStore","site","appVersion","useSite","hero","useLoginHero","year","vars","computed","rgba","mix","_createElementBlock","_createElementVNode","_hoisted_1","_hoisted_2","_createVNode","LoginHeroPanel","_unref","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_toDisplayString","_hoisted_7","LoginForm","_hoisted_8","_hoisted_9","_Fragment","_createTextVNode","_openBlock","_hoisted_10"],"mappings":";;;;;;;;;;;;;;AAUA,UAAM,EAAE,GAAAA,EAAA,IAAMC,EAAA,GACRC,IAAMC,EAAA,GACN,EAAE,MAAAC,GAAM,YAAAC,EAAA,IAAeC,EAAA,GACvBC,IAAOC,EAAA,GACPC,KAAO,oBAAI,KAAA,GAAO,YAAA,GAElBC,IAAOC,EAAS,OAAO;AAAA,MAC3B,QAAQC,EAAKV,EAAI,QAAQ,GAAG;AAAA,MAC5B,QAAQU,EAAKC,EAAIX,EAAI,QAAQ,WAAW,GAAG,GAAG,GAAG;AAAA,IAAA,EACjD;2BAIAY,EAiCM,OAAA;AAAA,MAjCD,OAAM;AAAA,MAAS,SAAOJ,EAAA,KAAI;AAAA,IAAA;MAE7BK,EAUM,OAVNC,GAUM;AAAA,wBATJD,EAA4B,OAAA,EAAvB,OAAM,eAAA,GAAc,MAAA,EAAA;AAAA,QACzBA,EAOM,OAPNE,GAOM;AAAA,UANJC,EAKEC,GAAA;AAAA,YAJC,UAAUC,EAAAb,CAAA,EAAK;AAAA,YACf,WAAWa,EAAAb,CAAA,EAAK;AAAA,YAChB,UAAUa,EAAAhB,CAAA,EAAK,YAAYgB,EAAApB,CAAA,EAAC,gBAAA;AAAA,YAC5B,UAAUoB,EAAAb,CAAA,EAAK;AAAA,UAAA;;;MAMtBQ,EAiBM,OAjBNM,GAiBM;AAAA,QAhBJN,EAMM,OANNO,GAMM;AAAA,UALJP,EAIM,OAJNQ,GAIM;AAAA,YAHJR,EAA6C,KAA7CS,GAA6CC,EAAzBL,EAAApB,CAAA,EAAC,eAAA,CAAA,GAAA,CAAA;AAAA,YACrBe,EAAoD,KAApDW,GAAoDD,EAA5BL,EAAApB,CAAA,EAAC,kBAAA,CAAA,GAAA,CAAA;AAAA,YACzBkB,EAAyES,GAAA;AAAA,cAA7D,aAAW;AAAA,cAAQ,cAAY;AAAA,cAAQ,eAAa;AAAA,YAAA;;;QAIpEZ,EAOI,KAPJa,GAOI;AAAA,YAPY,QACZH,EAAGL,EAAAX,CAAA,CAAI,IAAG,KACZ,CAAA;AAAA,UAASW,EAAAhB,CAAA,EAAK,qBAAdU,EAEI,KAAA;AAAA;YAFyB,MAAMM,EAAAhB,CAAA,EAAK;AAAA,YAAc,QAAO;AAAA,YAAS,KAAI;AAAA,UAAA,GACrEqB,EAAAL,EAAAhB,CAAA,EAAK,aAAagB,EAAAhB,CAAA,EAAK,KAAK,GAAA,GAAAyB,CAAA,WAEjCf,EAA8DgB,GAAA,EAAA,KAAA,KAAA;AAAA,YAA1CC,EAAAN,EAAAL,EAAAhB,CAAA,EAAK,aAAagB,EAAAhB,CAAA,EAAK,KAAK,GAAA,CAAA;AAAA,UAAA;UACpCgB,EAAAf,CAAA,KAAZ2B,KAAAlB,EAAiE,QAAjEmB,GAAyC,QAAIb,EAAAf,CAAA,CAAU,GAAA,CAAA;;;;;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import o from "./AdminMock2.vue.js";
|
|
2
|
+
/* empty css */
|
|
3
|
+
import t from "../../../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
+
const f = /* @__PURE__ */ t(o, [["__scopeId", "data-v-7ad8e65f"]]);
|
|
5
|
+
export {
|
|
6
|
+
f as default
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=AdminMock.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminMock.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { defineComponent as f, computed as r, openBlock as e, createElementBlock as i, createElementVNode as s, withDirectives as u, createVNode as h, toDisplayString as c, unref as m, Fragment as g, renderList as k, normalizeStyle as $ } from "vue";
|
|
2
|
+
import y from "../../../../components/SmartLogo.vue.js";
|
|
3
|
+
import { LOGO_KEY as b } from "../groups.js";
|
|
4
|
+
import { useConfigDraft as w } from "../draft.js";
|
|
5
|
+
import { vFlash as v } from "../flash.js";
|
|
6
|
+
const S = { class: "mock" }, z = { class: "chrome" }, D = { class: "btab" }, E = { class: "app" }, L = { class: "side" }, x = {
|
|
7
|
+
class: "brand",
|
|
8
|
+
"data-testid": "preview-brand"
|
|
9
|
+
}, A = { class: "main" }, B = { class: "foot" }, C = { key: 0 }, F = { key: 1 }, M = /* @__PURE__ */ f({
|
|
10
|
+
__name: "AdminMock",
|
|
11
|
+
setup(N) {
|
|
12
|
+
const { values: a } = w(), l = r(() => {
|
|
13
|
+
var t;
|
|
14
|
+
return ((t = a["sys.site.title"]) == null ? void 0 : t.trim()) || "SmartAdmin";
|
|
15
|
+
}), d = r(() => {
|
|
16
|
+
var t;
|
|
17
|
+
return ((t = a["sys.site.copyright"]) == null ? void 0 : t.trim()) || l.value;
|
|
18
|
+
}), p = r(() => {
|
|
19
|
+
var t;
|
|
20
|
+
return !!((t = a["sys.site.copyrightUrl"]) != null && t.trim());
|
|
21
|
+
}), n = r(() => a[b] ?? "");
|
|
22
|
+
return (t, o) => (e(), i("div", S, [
|
|
23
|
+
s("div", z, [
|
|
24
|
+
o[0] || (o[0] = s("span", { class: "lights" }, [
|
|
25
|
+
s("i"),
|
|
26
|
+
s("i"),
|
|
27
|
+
s("i")
|
|
28
|
+
], -1)),
|
|
29
|
+
u((e(), i("span", D, [
|
|
30
|
+
h(y, {
|
|
31
|
+
size: 16,
|
|
32
|
+
src: n.value
|
|
33
|
+
}, null, 8, ["src"]),
|
|
34
|
+
s("span", null, c(l.value), 1)
|
|
35
|
+
])), [
|
|
36
|
+
[m(v), `${l.value}|${n.value}`]
|
|
37
|
+
])
|
|
38
|
+
]),
|
|
39
|
+
s("div", E, [
|
|
40
|
+
s("div", L, [
|
|
41
|
+
u((e(), i("div", x, [
|
|
42
|
+
h(y, {
|
|
43
|
+
size: 30,
|
|
44
|
+
src: n.value
|
|
45
|
+
}, null, 8, ["src"]),
|
|
46
|
+
s("span", null, c(l.value), 1)
|
|
47
|
+
])), [
|
|
48
|
+
[m(v), `${l.value}|${n.value}`]
|
|
49
|
+
]),
|
|
50
|
+
(e(), i(g, null, k(5, (_) => s("i", {
|
|
51
|
+
key: _,
|
|
52
|
+
style: $({ width: _ % 2 ? "80%" : "62%" })
|
|
53
|
+
}, null, 4)), 64))
|
|
54
|
+
]),
|
|
55
|
+
s("div", A, [
|
|
56
|
+
o[1] || (o[1] = s("div", { class: "top" }, null, -1)),
|
|
57
|
+
o[2] || (o[2] = s("div", { class: "body" }, [
|
|
58
|
+
s("i", { class: "w" }),
|
|
59
|
+
s("i"),
|
|
60
|
+
s("i"),
|
|
61
|
+
s("i")
|
|
62
|
+
], -1)),
|
|
63
|
+
u((e(), i("div", B, [
|
|
64
|
+
p.value ? (e(), i("a", C, "© " + c(d.value), 1)) : (e(), i("span", F, "© " + c(d.value), 1))
|
|
65
|
+
])), [
|
|
66
|
+
[m(v), `${d.value}|${p.value}`]
|
|
67
|
+
])
|
|
68
|
+
])
|
|
69
|
+
])
|
|
70
|
+
]));
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
export {
|
|
74
|
+
M as default
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=AdminMock2.vue.js.map
|